Тип k
обещает, что при вызове k f
каждый вызов f
будет иметь в качестве аргумента функцию типа (forall b. [b] -> [b])
.
Если мы выберем f = k1
, мы передаем в качестве входных данных функцию типа forall a. a->a
. Это не будет удовлетворено, когда k
вызывает f = k1
с менее общей функцией (типа (forall b. [b] -> [b])
).
Более конкретно, учтите это:
k :: ((forall b. [b] -> [b]) -> Int) -> Int
k f = f (\xs -> xs++xs)
k1 :: (forall a. a -> a) -> Int
k1 x = x 10 + length (x "aaa")
Оба типа чек об оплате. Однако, уменьшив k k1
, мы получим:
k k1 =
k1 (\xs -> xs++xs) =
(\xs -> xs++xs) 10 + length ((\xs -> xs++xs) "aaa") =
(10++10) + length ("aaa"++"aaa")
, который неправильно напечатан, поэтому k k1
также должен быть неправильно напечатан.
Следовательно, да - контравариантные позиции делают обратный порядок подтипирования (он же «менее общий»). Чтобы A -> B
было более общим, чем A' -> B'
, мы хотим, чтобы первое устанавливало меньше требований к входу (A
должно быть менее общим, чем A'
) и обеспечивало больше гарантий на выходе (B
must быть более общим, чем B'
).