(Убедитесь, что вы понимаете higher-order functions). В Alonzo Churchuntyped lambda calculus функция является единственным примитивным типом данных. Нет чисел, булевых элементов, списков или чего-либо еще, только функции. Функции могут иметь только один аргумент, но функции могут принимать и/или возвращать функции - не значения этих функций, а сами функции. Поэтому для представления чисел, булевых элементов, списков и других типов данных вы должны придумать умный способ анонимных функций для их поддержки. Church numerals - способ представлять natural numbers. Три наиболее примитивные конструкции в нетипизированного лямбда-исчисления являются:
λx.x
, identity function, принимает некоторую функцию и немедленно возвращает его.
λx.x x
, само приложение.
λf.λx.f x
, приложение функции, принимает функцию и аргумент и применяет функцию к аргументу.
Как вы кодируете 0, 1, 2 как ничего, кроме функций? Мы как-то должны построить в системе понятие количество. У нас есть только функции, каждая функция может применяться только к одному аргументу. Где мы можем увидеть что-то похожее на количество? Эй, мы можем применить функцию к параметру несколько раз! Очевидно, что есть смысл количества в трех повторных вызовах функции: f (f (f x))
. Так давайте кодировать его в лямбда-исчисления:
- 0 =
λf.λx.x
- 1 =
λf.λx.f x
- 2 =
λf.λx.f (f x)
- 3 =
λf.λx.f (f (f x))
И так далее. Но как вы идете от 0 до 1, или от 1 до 2? Как бы вы могли написать функцию, которая, учитывая число, вернет число, увеличивающееся на 1?Мы видим рисунок на церковных цифрах, что термин всегда начинается с λf.λx.
и после того, как у вас есть конечное повторное применение f, поэтому нам нужно как-то попасть в тело λf.λx.
и обернуть его в другой f
. Как вы меняете тело абстракции без сокращения? Ну, вы можете применить функцию, обернуть тело в функцию, а затем обернуть новое тело в старую абстракцию лямбда. Но вы не хотите изменять аргументы, поэтому вы применяете абстракции к значениям с тем же именем: ((λf.λx.f x) f) x → f x
, но ((λf.λx.f x) a) b) → a b
, что нам не нужно.
Вот почему add1
является λn.λf.λx.f ((n f) x)
: применить n
к f
, а затем x
уменьшить выражение тела, а затем применить f
к этому телу, а затем абстрактные снова с λf.λx.
. Упражнения: тоже видят, что это правда, быстро научиться β-reduction и уменьшить (λn.λf.λx.f ((n f) x)) (λf.λx.f (f x))
прирастить 2 на 1.
Теперь понимание интуиции за обертывание тела в другой вызов функции, как мы реализуем добавление 2 номера? Нам нужна функция, которая, учитывая λf.λx.f (f x)
(2) и λf.λx.f (f (f x))
(3), вернет λf.λx.f (f (f (f (f x))))
(5). Посмотрите 2. Что, если бы вы могли заменить его x
с телом 3, то есть f (f (f x))
? Чтобы получить тело из 3, это очевидно, просто примените его к f
, а затем x
. Теперь примените 2 к f
, но затем примените его к телу 3, а не к x
. Затем снова оберните его в λf.λx.
: λa.λb.λf.λx.a f (b f x)
.
Вывод: Чтобы добавить 2 номера a
и b
вместе, оба из которых представлены в виде Чёрча, вы хотите заменить в a
x
с телом b
, так что f (f x)
+ f (f (f x))
= f (f (f (f (f x))))
. Чтобы это произошло, примените a
к f
, затем к b f x
.
Хорошо, это имеет смысл. Спасибо Эли. Я делал это неправильно и пытался сделать замену в процедуре add-1, чтобы получить функцию плюса. Я понял соотношение (f^m (f^n x)), но довольно глупо не сделал переход от этого к ((m f) ((n f) x)), что очевидно сейчас, когда я думаю об этом. –