[Haskell-beginners] type error in sub-function

Alexander Batischev eual.jp at gmail.com
Sat Feb 15 22:53:42 UTC 2014


Hi,

On Sat, Feb 15, 2014 at 03:52:25PM -0600, James Toll wrote:
>                                                   What I guess really
> confused me was that this worked:
> 
> Prelude> filter (\y -> mod 36 y == 0) [2..(ceiling . sqrt) 36]
> [2,3,4,6]
> 
> while this didn’t.  
> 
> Prelude> let lower x = filter (\y -> mod x y == 0) [2..(ceiling . sqrt) x]
> Prelude> lower 36
> 
> Since the former worked, I really expected the latter to work as well. 

Because in the first case, you have 36 in two places, and they have
different types. In the second case, though, both numbers are replaced
by `x`, that has one type. Something should have just clicked in your
brain, and every piece fell in place, but if not, read on.

In my previous email, I showed you what constraints a composition of
ceiling and sqrt places on `x`:

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

From here, you can see that `x` is only constrained by typeclasses
Floating and RealFrac. But `lower` has one more constraint, Integral:

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

Why is that?

Because you do `mod`:

    λ: :t mod
    mod :: Integral a => a -> a -> a

When you filter the list, `x` gets constrained by the Integral
typeclass, which leads to the situation you observe - too many
constraints, typechecker can't pick a type to satisfy them all.

And what do we do? We help the compiler using `fromIntegral`, thus
removing the Floating and RealFrac constraints from `x` (they're now
placed on a result of `fromIntegral`).

> > :t 36
> > 36 :: Num a => a
> 
> 
> I am still slightly confused about the type that I passed into the
> function. If the type of 36 is Numeric, that doesn’t seem to
> necessarily tell me that it is an Int.  Float and Double are listed
> under Numeric in the chart
> (https://www.haskell.org/onlinereport/classes.gif).

It's incorrect to say that "the type of 36 is Numeric", but I guess it's
just bad wording - you get the idea right, 36 isn't necessary Int.

There's a thing called "type defaulting". It's a set of rules that GHC
follows in order to pick a type for a thing whose type is not specified,
like 36. (Note that GHCi has slightly different, more relaxed rules.) So
when you run `filter`, GHCi has to pick some type for the results, and
it settles for Integer.

But type defaulting doesn't kick in until the very last moment. Up until
binding the result, it stays as polimorphic as possible:

    λ: :t 36
    36 :: Num a => a

The moment you bind the result, though, it gets concrete type:

    λ: let x = 36
    λ: :t x
    x :: Integer

>                                                      This seems like
> a really stupid question, but how do I know that I can’t pass
> a Numeric into a function like sqrt that is expecting a Float?
> 
> ghci> :t sqrt
> sqrt :: Floating a => a -> a

I don't know how well you understand typeclasses, so pardon me if
I explain something you already know. The thing is, each typeclass adds
some new restrictions (functions to implement) that narrow the choice of
possible instances of that typeclass. Almost every type instantiates Eq,
but only four standard ones instantiate Num. Furthermore, only two
standard types instantiate Floating. That's why you can't pass every Num
instance into sqrt - not every one of them implements all the necessary
methods.

Is that clear enough?

-- 
Regards,
Alexander Batischev

PGP key 356961A20C8BFD03
Fingerprint: CE6C 4307 9348 58E3 FD94  A00F 3569 61A2 0C8B FD03

-------------- 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/20140216/fb793b32/attachment.sig>


More information about the Beginners mailing list