При чтении сигнатур типов, таких как addThree :: Num a => a -> a -> a -> a
, вы должны мысленно добавлять соответствующие скобки, поскольку стрелки правильно ассоциируют
addThree :: Num a => a -> a -> a -> a
addThree :: Num a => a -> (a -> (a -> a))
что, возможно, помогает описать, как лямбда-выражения с одним аргументом достаточны для представления такой функции.
Говоря о лямбдах с карри, вы можете смотреть на вещи с нескольких сторон. Давайте рассмотрим этот внутренний фрагмент, например
\z -> x + y + z
Если бы это было все, что вам дали и попросили интерпретировать, вам пришлось бы в отчаянии всплеснуть руками — вообще нет определения того, что должны означать x
и y
. Они известны как «свободные» переменные, потому что они не ограничены лямбдой.
Чтобы дать им определение, мы должны обернуть больше лямбда-выражений, которые bind означают x
и y
.
\x -> \y -> \z -> x + y + z -- ok!
Итак, глядя изнутри наружу, выражение бессмысленно без этих внешних лямбда-выражений.
Однако, когда вы начнете вычислять выражение в приложении
(\x -> \y -> \z -> x + y + z) 1 2 3
тогда выходит другая история. Теперь вы должны обрабатывать каждую лямбда-привязку отдельно. Правило состоит в том, что для оценки лямбда-выражения, применяемого к значению, вы заменяете связанную переменную на это значение везде внутри него.
(\x -> \y -> \z -> x + y + z) 1 2
( \y -> \z -> 1 + y + z) 2
( \z -> 1 + 2 + z)
Таким образом, извне выражение \z -> x + y + z
никогда не существует, x
и y
исключаются, прежде чем мы дойдем до этого.
Однако стоит отметить, что это еще не совсем то же самое, что и c + z
! Мы не оцениваем тело внутренней лямбды до привязки третьего аргумента. В каком-то смысле невозможно узнать, что находится внутри лямбды, пока мы не придадим ей какое-то значение; (\z -> 1 + 2 + z)
полностью непрозрачен. Только после применения последнего аргумента мы можем начать вычислять добавление внутри тела.
В широком смысле это то, что известно как трудность работы «под связующим».
person
J. Abrahamson
schedule
26.12.2013