Просто попробуйте увидеть типы некоторых лямбда-выражений, подобных этому:
:t \x -> (\y -> x y)
\x -> (\y -> x y) :: (t1 -> t2) -> t1 -> t2
не должен быть здесь тип t1->(t2->t1->t2)
?
Аналогично
:t \x -> (\y -> (\k -> y (x k)))
\x -> (\y -> (\k -> y (x k)))
:: (t1 -> t2) -> (t2 -> t3) -> t1 -> t3
Не следует ли тип t1->(t2->(t3->t2))
?
Нет, совпадает с
t1->(t2->t1->t2)
, который является типом функции с тремя аргументами (типаt1->t2->t1->t2
,t1
иt2
), возвращаяt1
. Однако для двух аргументовt2
иx
есть только два лямбда.Вместо этого правильный тип
(Кстати, ни одна из скобок выше не нужна.)
Что такое
y
? Is является типомtypeOfResult
, поэтому для типаx y
это должен быть тип возврата.Для того, чтобы код вводил проверку, мы должен тогда иметь, что
x
- это тип функции, напримерtypeOfX
. В этом случае мы можем видеть, чтоa -> b
. Кроме того, вtypeOfResult = b
мы передаемx y
вy
, и это может ввести проверку, только еслиx
.Итак,
Компилятор использовал имена
typeOfY = a
иt1
, но это тот же тип.Круглые скобки здесь имеют значение, так как мы должны помнить, что
t2
- это функцияx
. Без скобок мы получим функцию с тремя аргументами, как описано выше.может попытаться применить те же рассуждения ко второму примеру. Начните с
a -> b
и медленно узнайте, что эти типы на самом деле.Тип
x
в\x -> \y -> x y
-t1 -> t2
, и это первый аргумент. В качестве самой внешней лямбда он сначала применяется, а затемy
Вы могли бы написать его как
\x y -> x y
, который является просто функциональным приложением в естественном порядке.