In the normal case ( forall n. Num n => (n -> n) -> (Int, Double) ) we first select a n and then provide a function. Thus, we could pass a function like Int -> Int , Double -> Double , Rational -> Rational , etc.
In the case of the 2nd rank ( (forall n. Num n => n -> n) -> (Int, Double) ) we must provide a function before we know n . This means that the function should work for any n ; none of the examples listed in the previous example will work.
We need this for the sample code, because the passed function f applies to two different types: a Int and a Double . Therefore, he must work for both of them.
The first case is normal, because how type variables work by default. If you don't have forall at all, your type signature is equivalent to having it at the very beginning. (This is called the prenex form.) Thus, Num n => (n -> n) -> (Int, Double) implicitly matches forall n. Num n => (n -> n) -> (Int, Double) forall n. Num n => (n -> n) -> (Int, Double) .
What type of function works for any n ? This is for sure forall n. Num n => n -> n forall n. Num n => n -> n .
source share