Как это позволяет выражать работу?
Учитывая эту строку кода Haskell, моя задача состояла в том, чтобы оценить ее в самой простой форме.
let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20
Мне уже дали ответ (и, конечно же, он сам оценил его в GHCI): 42
Однако я хотел бы получить лучшее представление о том, как эта оценка действительно работает здесь. В общем, я думаю, что знаю, как (простые) выражения работают:
Пример
a = let y = 5 in y * 5 -- a == 25
Это оценивается как 25
, потому что мы привязываем y
к значению 5
и a
присваивается значение y*5
(часть после in
). Связывание y = 5
допустимо только в пределах области let
.
Пока единственная интерпретация (которая, по меньшей мере, оценивается до 42), такова:
let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20
-
g
(\x -> k (h x))
-
h
- (+1)
(функция (\x -> x+1)
)
-
k
(\x -> x+x)
-
20
- это вход g
, который дает k (h 20)
-
h 20
дает 20 + 1
= 21
-
k (h 20)
= k 21
= 21 + 21
= 42
Но меня смущает использование g h k
после let. Что это значит?
Ответы
Ответ 1
Подумайте о определении функции. Если вы пишете:
g h k x = k (h x)
Затем это функция, которая принимает три параметра h
, k
и x
и возвращает k (h x)
. Это эквивалентно:
g h k = \x -> k (h x)
или
g h = \k x -> k (h x)
или
g = \h k x -> k (h x)
Таким образом, мы можем передавать переменные между головкой функции и лямбда-выражением в теле. На самом деле компилятор Haskell перепишет его.
Итак, с выражением let
мы определяем функцию локального охвата, подобную той, которая определена выше. Теперь, если мы назовем g (+1) (\x -> x+x) 20
, тогда вызываем g
с помощью h = (+1)
, k = (\x -> x+x)
и x = 20
.
Итак, мы будем оценивать его как:
(\x -> x+x) ((+1) 20)
который оценивается как:
(\x -> x+x) ((+1) 20)
-> ((+1) 20)+((+1) 20)
-> 21 + 21
-> 42
Ответ 2
g h k = ...
- определение функции. Это означает, что результат применения g
к двум аргументам (с именем h
и k
) будет оцениваться частью ...
. Другими словами, это ярлык для g = \h -> \k -> ...
.
Таким образом, мы можем упростить выражение шаг за шагом следующим образом:
let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20
let g = \h -> \k -> (\x -> k (h x)) in g (+1) (\x -> x+x) 20
(\h -> \k -> (\x -> k (h x))) (+1) (\x -> x+x) 20
(\k -> (\x -> k ((+1) x))) (\x -> x+x) 20
(\x -> (\x -> x+x) ((+1) x)) 20
(\x -> x+x) ((+1) 20)
(\x -> x+x) 21
21 + 21
42