Этапы сокращения функции предшественника лямбда-исчисления - PullRequest
16 голосов
/ 09 января 2012

Я застреваю с описанием Википедии функции-предшественника в лямбда-исчислении.

Википедия говорит следующее:

PRED: = λnfx.n (λgh.h (gf)) (λu.x) (λu.u)

Может кто-нибудь объяснить пошаговые процессы сокращения?

Спасибо.

Ответы [ 4 ]

24 голосов
/ 10 января 2012

Итак, идея церковных цифр в том, чтобы кодировать «данные» с помощью функций, верно? Это работает путем представления значения некоторой общей операцией, которую вы выполняете с ним. Поэтому мы можем пойти и в другом направлении, что иногда может прояснить ситуацию.

Церковные цифры являются унарным представлением натуральных чисел. Итак, давайте используем Z для обозначения нуля и Sn для представления преемника n. Теперь мы можем считать вот так: Z, SZ, SSZ, SSSZ ... Эквивалентная цифра Церкви принимает два аргумента - первый соответствует S, а второй - Z - затем использует их для построения вышеуказанного шаблона. Поэтому, учитывая аргументы f и x, мы можем считать вот так: x, f x, f (f x), f (f (f x)) ...

Давайте посмотрим, что делает PRED.

Во-первых, он создает лямбду, принимающую три аргумента - n - это церковное число, предшественник которого мы, конечно, хотим, что означает, что f и x являются аргументами для получающегося числа, что, таким образом, означает что тело этой лямбды будет f применено к x на один раз меньше, чем n.

Затем он применяет n к трем аргументам. Это сложная часть.

Второй аргумент, который соответствует Z от предыдущего, это λu.x - постоянная функция, которая игнорирует один аргумент и возвращает x.

Первый аргумент, который соответствует S из более раннего, это λgh.h (g f). Мы можем переписать это как λg. (λh.h (g f)), чтобы отразить тот факт, что только самая внешняя лямбда применяется n раз. Эта функция принимает накопленный результат до g и возвращает новую функцию с одним аргументом, который применяет этот аргумент к g, примененному к f. Что, безусловно, сбивает с толку.

Так ... что здесь происходит? Рассмотрим прямую замену с S и Z. В ненулевом числе Sn n соответствует аргументу, связанному с g. Итак, помня, что f и x связаны во внешней области, мы можем считать вот так: λu.x, λh. h ((λu.x) f), λh'. h' ((λh. h ((λu.x) f)) f) ... Выполняя очевидные сокращения, мы получаем это: λu.x , λh. h x, λh'. h' (f x) ... Шаблон здесь таков, что функция передается «внутрь» одного слоя, и в этот момент S будет применять ее, а Z будет игнорировать ее. Таким образом, мы получаем одно приложение f для каждого S , за исключением самого внешнего.

Третий аргумент - это просто функция тождества, которая покорно применяется самым внешним S, возвращая конечный результат - f, примененный один раз меньше, чем число S слоев, которым соответствует n.

6 голосов
/ 13 мая 2016

Ответ Макканна объясняет это довольно хорошо.Давайте возьмем конкретный пример для Pred 3 = 2:

Рассмотрим выражение: n (λgh.h (gf)) (λu.x).Пусть K = (λgh.h (gf))

Для n = 0 мы кодируем 0 = λfx.x, поэтому при применении бета-сокращения для (λfx.x)(λgh.h(gf)) означает, что (λgh.h(gf)) заменяется 0 раз.После дальнейшего бета-сокращения мы получаем:

λfx.(λu.x)(λu.u)

уменьшается до

λfx.x

, где λfx.x = 0, как и ожидалось.

Для n = 1 мы применяем K 1 раз:

(λgh.h (g f)) (λu.x) => λh. h((λu.x) f) => λh. h x

Для n = 2 мы применяем K 2 раза:

(λgh.h (g f)) (λh. h x) => λh. h ((λh. h x) f) => λh. h (f x)

Для n = 3 мы применяем K три раза:

(λgh.h (g f)) (λh. h (f x)) => λh.h ((λh. h (f x)) f) => λh.h (f (f x))

Наконец, мы берем этот результат и применяем к нему функцию id.got

λh.h (f (f x)) (λu.u) => (λu.u)(f (f x)) => f (f x)

Это определение числа 2.

Реализация на основе списка может быть проще для понимания, но она требует много промежуточных шагов.Так что это не так приятно, как первоначальное воплощение Церкви в ИМО.

1 голос
/ 27 августа 2017

После прочтения предыдущих ответов (хороших) я хотел бы высказать свое собственное видение вопроса в надежде, что оно кому-нибудь поможет (исправления приветствуются).Я буду использовать пример.

Прежде всего, я хотел бы добавить несколько скобок к определению, которое сделало все более понятным для меня.Давайте доработаем данную формулу до:

PRED := λn λf λx.(n (λgλh.h (g f)) (λu.x)) (λu.u)

Давайте также определим три церковные цифры, которые помогут с примером:

Zero := λfλx.x
One := λfλx. f (Zero f x)
Two := λfλx. f (One f x)
Three := λfλx. f (Two f x)

Чтобы понять, как это работает, давайте сначала сосредоточимся наэта часть формулы:

n (λgλh.h (g f)) (λu.x)

Отсюда мы можем извлечь следующие выводы: n - это цифра Церкови, применяемая функция - λgλh.h (g f), а начальные данные - λu.x

Имея это в виду, давайте попробуем пример:

PRED Three := λf λx.(Three (λgλh.h (g f)) (λu.x)) (λu.u)

Давайте сначала сосредоточимся на сокращении числа (часть, которую мы объясняли ранее):

Three (λgλh.h (g f)) (λu.x)

Который сводится к:

(λgλh.h (g f)) (Two (λgλh.h (g f)) (λu.x))
(λgλh.h (g f)) ((λgλh.h (g f)) (One (λgλh.h (g f)) (λu.x)))
(λgλh.h (g f)) ((λgλh.h (g f)) ((λgλh.h (g f)) (Zero (λgλh.h (g f)) (λu.x))))
(λgλh.h (g f)) ((λgλh.h (g f)) ((λgλh.h (g f)) ((λfλx.x) (λgλh.h (g f)) (λu.x)))) -- Here we lose one application of f
(λgλh.h (g f)) ((λgλh.h (g f)) ((λgλh.h (g f)) (λu.x)))
(λgλh.h (g f)) ((λgλh.h (g f)) (λh.h ((λu.x) f)))
(λgλh.h (g f)) ((λgλh.h (g f)) (λh.h x))
(λgλh.h (g f)) (λh.h ((λh.h x) f))
(λgλh.h (g f)) (λh.h (f x))
(λh.h ((λh.h (f x) f)))

Окончание с:

λh.h f (f x)

Итак, мы имеем:

PRED Three := λf λx.(λh.h (f (f x))) (λu.u)

Сокращение снова:

PRED Three := λf λx.((λu.u) (f (f x)))
PRED Three := λf λx.f (f x)

Как вы можете видеть из сокращений, мы в итоге применяем функцию в один раз меньше благодаря умному способу использования функций.

Используя add1 в качестве f и 0 в качестве x, мы получаем:

PRED Three add1 0 := add1 (add1 0) = 2

Надеюсь, это поможет.

0 голосов
/ 22 января 2017

Вы можете попытаться понять это определение функции предшественника (не моего любимого) в терминах продолжений.

Чтобы немного упростить этот вопрос, давайте рассмотрим следующий вариант

    PRED := λn.n (λgh.h (g S)) (λu.0) (λu.u)

затем вы можете заменить S на f, а 0 на x.

Тело функции итерирует n раз преобразование M по аргументу N. Аргумент N является функцией типа (nat -> nat) -> nat, которая ожидает продолжения для nat и возвращает nat.Изначально N = λu.0, то есть он игнорирует продолжение и просто возвращает 0. Давайте назовем текущее вычисление N.

Функция M: (nat -> nat) -> nat) -> (nat -> nat) -> nat изменяет вычисление g: (nat -> nat) -> nat следующим образом.Он принимает на входе продолжение h и применяет его к результату продолжения текущего вычисления g с помощью S.

Поскольку первоначальное вычисление проигнорировало продолжение, после одного применения M мы получаем вычисление (λh.h0), затем (λh.h (S 0)) и т. Д.

В конце мы применяем вычисление к продолжению тождества для извлечения результата.

...