[Haskell-beginners] type error in sub-function

Alexander Batischev eual.jp at gmail.com
Sat Feb 15 20:38:38 UTC 2014


Hi,

Alejandro Gomez already posted an answer that should be enough for you
to figure out the solution by yourself, but I decided to post mine
anyway, in case you have trouble understanding how to proceed.

On Sat, Feb 15, 2014 at 01:42:15PM -0600, James Toll wrote:
> Prelude> let lower x = filter (\y -> mod x y == 0) [2..(ceiling . sqrt) x]
> Prelude> lower 36
> 
> <interactive>:6:1:
>     No instance for (RealFrac b0) arising from a use of `lower'
>     The type variable `b0' is ambiguous
>     Possible fix: add a type signature that fixes these type variable(s)
>     Note: there are several potential instances:
>       instance RealFrac Double -- Defined in `GHC.Float'
>       instance RealFrac Float -- Defined in `GHC.Float'
>       instance Integral a => RealFrac (GHC.Real.Ratio a)
>         -- Defined in `GHC.Real'
>     In the expression: lower 36
>     In an equation for `it': it = lower 36
> 
> <interactive>:6:7:
>     No instance for (Num b0) arising from the literal `36'
>     The type variable `b0' is ambiguous
>     Possible fix: add a type signature that fixes these type variable(s)
>     Note: there are several potential instances:
>       instance Num Double -- Defined in `GHC.Float'
>       instance Num Float -- Defined in `GHC.Float'
>       instance Integral a => Num (GHC.Real.Ratio a)
>         -- Defined in `GHC.Real'
>       ...plus three others
>     In the first argument of `lower', namely `36'
>     In the expression: lower 36
>     In an equation for `it': it = lower 36
> 
> 
> At this point, I’m not sure what I need to do to get his working
> properly.  It appears to be a type error, but I’m apparently not
> understanding the error message enough to fix the problem.  Any
> suggestions would be appreciated.

Your first instinct should be to look at the type signature of the
function you just wrote, so you can figure out what `b0` means:

λ: :t lower
lower :: (Floating b, Integral b, RealFrac b) => b -> [b]

See? It expects to be given something that belongs to Floating, Integral
and RealFrac typeclasses. The Haskell Report contains a nice image of
the dependencies between typeclasses along with the actual types that
instantiate them[1] From looking at it, you can deduce that there is no
type that belongs to all three typeclasses. Thus the type error.

1. https://www.haskell.org/onlinereport/classes.gif

To fix this, let's take a step back and deconstruct your function to see
where each of the constraints (the thing in the parentheses that goes
before the type) comes from.

It all starts with `sqrt`, which has the following type:

    λ: :t sqrt
    sqrt :: Floating a => a -> a

By looking at the aforementioned diagram again, you can conclude that
`a` here is either Float or Double. Next, you compose `sqrt` with
`ceiling`, which has the following type:

    λ: :t ceiling
    ceiling :: (Integral b, RealFrac a) => a -> b

Here, `a` can be Float or Double, and `b` is either Int or Integer.
After the composition you have a function with the following type:

    λ: :t (ceiling . sqrt)
    (ceiling . sqrt) :: (Floating b, Integral c, RealFrac b) => b -> c

It accepts Float or Double (which both belong to Floating and RealFrac
typeclasses) and returns Int or Integer.

But you want to feed it an Int! Unlike many other languages, Haskell
never casts (converts) types unless you order to do so.

So you need some function to convert an instance of Integral typeclass
(Int or Integer) into instance of both Floating and RealFrac, i.e.
a function with the following type:

    (Integral a, Floating b, RealFrac b) => a -> b

For that, we have Hoogle[2] Type in the signature, hit Search and you
will be presented with a list of matching functions. `fromIntegral`,
which is the second result I've been given, is *exactly* what you need.
Let's use it, rewriting `lower` as
    
    λ: let lower x = filter (\y -> mod x y == 0) [2..(ceiling . sqrt) (fromIntegral x)]
    λ: :t lower
    lower :: Integral a => a -> [a]

2. https://www.haskell.org/hoogle/

As you can see, you've got a function that accepts any instance of
Integral typeclass, i.e. Int and Integer types. Precisely what was
required.

Hope that makes sense.

-- 
Regards,
Alexander Batischev

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://www.haskell.org/pipermail/beginners/attachments/20140215/2f232930/attachment.sig>


More information about the Beginners mailing list