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 type Integer .

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: