
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