tx2 = (\x y z -> y.z.z)
tx2
принимает три аргумента (для обсуждения я игнорирую карри), игнорирует первый и составляет второй и дважды третий.Таким образом, первый аргумент может иметь любой тип, второй и третий должны иметь тип функции, скажем,
y :: ay -> ry
z :: az -> rz
Теперь результат первого применения z
становится аргументом второго приложения z
таким образом, тип результата z
, rz
должен быть типом аргумента z
, az
, назовем это b
, поэтому
z :: b -> b
Тогда результатz
application становится аргументом y
, поэтому тип аргумента y
должен быть того же типа, что и тип результата z
, но тип результата y
полностью не ограничен выражением, поэтому
y :: b -> c
и y . z . z :: b -> c
, таким образом
tx2 :: a -> (b -> c) -> (b -> b) -> (b -> c)
Тогда следующее,
tm2 = (\i -> [sum,product]!!i)
Now, sum
и product
являются функциями изPrelude
, оба имеют тип Num a => [a] -> a
, таким образом
Prelude> :t [sum,product]
[sum,product] :: Num a => [[a] -> a]
Поскольку (!!) :: [e] -> Int -> e
, учитывая список xs
типа [e]
, выражение \i -> xs !! i
имеет тип Int -> e
.Таким образом, предполагаемый тип tm2 = \i -> [sum,product] !! i
равен
tm2 :: Num a => Int -> ([a] -> a)
Но tm2
связан простой привязкой к шаблону без сигнатуры типа, поэтому включается ограничение мономорфизма и типtm2
должен быть мономорфизирован.По правилам по умолчанию ограничение Num a
разрешается путем создания экземпляра переменной типа a
с Integer
(если явное объявление по умолчанию не говорит об обратном), поэтому вы получите
Prelude> let tm2 = \i -> [sum,product] !! i
Prelude> :t tm2
tm2 :: Int -> [Integer] -> Integer
, если не отключитеограничение мономорфизма (:set -XNoMonomorphismRestriction
).
tp2 = (\x -> \y -> (x.y.x))
Результат первого применения x
становится аргументом y
, следовательно, тип результата x
должен совпадать с аргументомтип y
.Тогда результат применения y
становится аргументом второго приложения x
, поэтому тип результата y
должен быть типом аргумента ´x`, всего
tp2 :: (a -> b) -> (b -> a) -> (a -> b)
Затем в
tf2 = (\x -> \y -> (x (y x), x, y))
единственной интересной частью является первый компонент результата, x (y x)
, поэтому x
применяется к результату применения y
, следовательно, x
должно иметьтип функции
x :: a -> b
и y
должен иметь тип результата a
.Но y
применяется к x
, поэтому его тип аргумента должен быть типа x
,
y :: (a -> b) -> a
и
tf2 :: (a -> b) -> ((a -> b) -> a) -> (b, a -> b, (a -> b) -> a)
Наконец
tg2 = (\x y z a -> y(z(z(a))))
, который, кстати, точно такой же, как tx2
, только расширенный eta, предоставляя еще один аргумент в лямбдуПоэтому происхождение типа тоже одинаково.