Reputation: 2041
Using the following definitions:
lenDigits n = length (show n)
factorial n = product [1..n]
I evaluate the following
Prelude> ((lenDigits . factorial) 199) <= 199
False
Prelude> (\i -> ((lenDigits . factorial) i) <= i) 199
True
What is the reason for such behaviour? As I see it, the first expression is just the same as the second expression with the lambdas reduced.
Upvotes: 27
Views: 1592
Reputation: 34378
Here goes a step-by-step take on this question.
Let's begin with:
((lenDigits . factorial) 199) <= 199
According to the Haskell Report...
An integer literal represents the application of the function
fromInteger
to the appropriate value of typeInteger
.
That means our first expression is actually:
((lenDigits . factorial) (fromInteger (199 :: Integer))
<= (fromInteger (199 :: Integer))
By itself, fromInteger (199 :: Integer)
has the polymorphic type Num a => a
. We now have to see whether this type is specialised in the context of the whole expression. Note that, until we find a reason for it not being so, we should assume that the polymorphic types of the two occurrences of fromInteger (199 :: Integer)
are independent (Num a => a
and Num b => b
, if you will).
lenDigits
is Show a => a -> Int
, and so the...
(lenDigits . factorial) (fromInteger (199 :: Integer))
... to the left of the <=
must be an Int
. Given that (<=)
is Ord a => a -> a -> Bool
, the fromInteger (199 :: Integer)
to the right of the <=
also has to be an Int
. The whole expression then becomes:
((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int)
While the second 199
was specialised to Int
, the first one is still polymorphic. In the absence of other type annotations, defaulting makes it specialise to Integer
when we use the expression in GHCi. Therefore, we ultimately get:
((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int)
Now, on to the second expression:
(\i -> ((lenDigits . factorial) i) <= i) 199
By the same reasoning used above, (lenDigits . factorial) i
(to the left of <=
) is an Int
, and so i
(to the right of <=
) is also an Int
. That being so, we have...
GHCi> :t \i -> (lenDigits . factorial) i <= i
\i -> (lenDigits . factorial) i <= i :: Int -> Bool
... and therefore applying it to 199
(which is actually fromInteger (199 :: Integer)
) specialises it to int, giving:
((lenDigits . factorial) (199 :: Int)) <= (199 :: Int)
The first 199
is now Int
rather than Integer
. factorial (199 :: Int)
overflows the fixed size Int
type, leading to a bogus result. One way of avoiding that would be introducing an explicit fromInteger
in order to get something equivalent to the first scenario:
GHCi> :t \i -> (lenDigits . factorial) i <= fromInteger i
\i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool
GHCi> (\i -> (lenDigits . factorial) i <= fromInteger i) 199
False
Upvotes: 8
Reputation: 3790
Because in the first expression the first 199
has type Integer
and the second has Int
. But in the second expression both have type Int
and factorial 199
can't be represented by the type Int
.
Upvotes: 26