Quick example:
{-# LANGUAGE RankNTypes #-}
l :: (forall b. [b] -> [b]) -> Int
l f = 3
l1 :: forall a. a -> a
l1 x = x
l2 :: [Int] -> [Int]
l2 x = x
k :: ((forall b. [b] -> [b]) -> Int) -> Int
k f = 3
k1 :: (forall a. a -> a) -> Int
k1 x = 99
k2 :: ([Int] -> [Int]) -> Int
k2 x = 1000
m :: (((forall b. [b] -> [b]) -> Int) -> Int) -> Int
m f = 3
m1 :: ((forall a. a -> a) -> Int) -> Int
m1 x = 99
m2 :: (([Int] -> [Int]) -> Int) -> Int
m2 x = 1000
Here:
l l1
typechecksl l2
does not typecheckk k1
does not typecheckk k2
typechecksm m1
typechecksm m2
does not typecheck
While I am totally okay with what happens in l
and m
I don't understand the k
part. There is some kind of relation of being "more polymorphic", for instance forall a. a -> a
is more polymoprhic than forall b. [b] -> [b]
because one can just substitute a/[b]
. But why does this relation flip if the polymorphic types are on contravariant positions?
As I see k
expects "a machine that takes machine operating on any lists that produces Int". k1
is "a machine that takes any endomorphism-machine that produces int". k1
offers therefore much more than k
wants, so why doesn't it fit its requirements? I feel there is some mistake in my reasoning, but I can't get it...