Лямбда-исчисление — различия между версиями
Komarov (обсуждение | вклад) |
Komarov (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
{{В разработке}} | {{В разработке}} | ||
− | |||
− | |||
''Лямбда-исчисление'' {{---}} формальная система, придуманная в 1930-х годах | ''Лямбда-исчисление'' {{---}} формальная система, придуманная в 1930-х годах | ||
Строка 7: | Строка 5: | ||
Эта концепция показала себя удобной и сейчас активно используется во многих | Эта концепция показала себя удобной и сейчас активно используется во многих | ||
языках программирования. | языках программирования. | ||
+ | |||
+ | == Лямбда-исчисление== | ||
Более формально, ''лямбда-функцию'' (или, ''лямбда-терм'') можно задать | Более формально, ''лямбда-функцию'' (или, ''лямбда-терм'') можно задать | ||
Строка 16: | Строка 16: | ||
\langle Term \rangle & ::= & \langle Variable \rangle \\ | \langle Term \rangle & ::= & \langle Variable \rangle \\ | ||
& | & \langle Term \rangle \langle Term \rangle \\ | & | & \langle Term \rangle \langle Term \rangle \\ | ||
− | & | & \lambda \langle Variable \rangle \ | + | & | & \lambda \langle Variable \rangle\ .\ \langle Term \rangle\\ |
& | & ( \langle Term \rangle )\\ | & | & ( \langle Term \rangle )\\ | ||
\langle Variable \rangle & ::= & \langle Char \rangle *\\ | \langle Variable \rangle & ::= & \langle Char \rangle *\\ | ||
Строка 29: | Строка 29: | ||
создание функции одного аргумента с заданными именем аргумента и телом функции. | создание функции одного аргумента с заданными именем аргумента и телом функции. | ||
− | Рассмотрим, например, функцию <tex>id = \lambda x \ | + | Рассмотрим, например, функцию <tex>\operatorname{id} = \lambda x\ .\ x</tex>. Эта функция принимает аргумент и |
возвращает его неизменённым. Например, | возвращает его неизменённым. Например, | ||
− | <tex>id 2 \equiv 2</tex>. Аналогично, <tex>id y | + | <tex>\operatorname{id}\ 2 \equiv 2</tex>. Аналогично, <tex>\operatorname{id}\ y \equiv y</tex>. |
− | Ещё один пример функции: <tex>sum = \lambda x \ | + | Ещё один пример функции: <tex>\operatorname{sum} = \lambda x\ .\ \lambda y\ .\ x + y</tex>. Эта функция двух аргументов, |
которая возвращает их сумму. Правда, здесь мы немного вышли за написанную выше грамматику. | которая возвращает их сумму. Правда, здесь мы немного вышли за написанную выше грамматику. | ||
− | Ну да ладно. <tex>sum 2 3 | + | Ну да ладно. <tex>\operatorname{sum}\ 2\ 3 \equiv 5</tex> |
===Приоритет операций=== | ===Приоритет операций=== | ||
− | * Применение левоассоциативно: <tex>x y z w | + | * Применение левоассоциативно: <tex>x\ y\ z\ w \equiv ((x\ y)\ z)\ w</tex> |
− | * Аппликация забирает себе всё, до чего дотянется: <tex>\lambda x \ | + | * Аппликация забирает себе всё, до чего дотянется: <tex>\lambda x\ .\ \lambda y\ .\ \lambda z\ .\ z\ y\ x \equiv \lambda x\ .\ (\lambda y\ .\ (\lambda z\ .\ ((z\ y)\ x)))</tex> |
* Скобки играют привычную роль группировки действий | * Скобки играют привычную роль группировки действий | ||
Строка 46: | Строка 46: | ||
дереве разбора были абстракции. Все остальные переменные называются свободными. | дереве разбора были абстракции. Все остальные переменные называются свободными. | ||
− | Например, в <tex>\lambda x \ | + | Например, в <tex>\lambda x\ .\ \lambda y\ .\ x</tex>, <tex>x</tex> связана, а <tex>y</tex>{{---}} свободна. А в <tex>\lambda y\ .\ x (\lambda x\ .\ x)</tex> |
в своём первом вхождении переменная <tex>x</tex> свободна, а во втором {{---}} связана. | в своём первом вхождении переменная <tex>x</tex> свободна, а во втором {{---}} связана. | ||
− | Рассмотрим функции <tex>\lambda y \ | + | Рассмотрим функции <tex>\lambda y\ .\ y</tex> и <tex>\lambda x\ .\ y</tex>. В первой из них при взгляде на <tex>y</tex> |
понятно, что она имеет отношение к переменной, по которой производилась | понятно, что она имеет отношение к переменной, по которой производилась | ||
абстракция. Если по одной и той же | абстракция. Если по одной и той же | ||
переменной абстракция производилась более одного раза, то переменная связана | переменной абстракция производилась более одного раза, то переменная связана | ||
с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в | с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в | ||
− | <tex>\lambda x \ | + | <tex>\lambda x\ .\ \lambda x\ .\ \lambda y\ .\ \lambda x\ .\ x</tex>, переменная <tex>x</tex> связана с самой правой абстракцией |
по <tex>x</tex>. | по <tex>x</tex>. | ||
===α-конверсия=== | ===α-конверсия=== | ||
− | Рассмотрим функции <tex>(\lambda x \ | + | Рассмотрим функции <tex>(\lambda x\ .\ x) z</tex> и <tex>(\lambda y\ .\ y) z</tex>. Интуитивно понятно, что они |
являются одинаковыми. | являются одинаковыми. | ||
{{Определение | {{Определение | ||
|definition=''<tex>\alpha</tex>-конверсия'' {{---}} переименование связанной переменной. Выражение | |definition=''<tex>\alpha</tex>-конверсия'' {{---}} переименование связанной переменной. Выражение | ||
− | <tex>\lambda x \ | + | <tex>\lambda x\ .\ f</tex> можно заменить на <tex>\lambda y\ .\ f[x := y]</tex>, если <tex>y</tex> не входит свободно в <tex>f</tex>, |
где <tex>f[x:=y]</tex> означает замену всех свободных вхождений <tex>x</tex> в <tex>f</tex> на <tex>y</tex>. | где <tex>f[x:=y]</tex> означает замену всех свободных вхождений <tex>x</tex> в <tex>f</tex> на <tex>y</tex>. | ||
}} | }} | ||
Строка 71: | Строка 71: | ||
''<tex>\alpha</tex>-эквивалентными'' и обозначаются <tex>f \equiv_\alpha g</tex>. | ''<tex>\alpha</tex>-эквивалентными'' и обозначаются <tex>f \equiv_\alpha g</tex>. | ||
− | Функции <tex>\lambda x \ | + | Функции <tex>\lambda x\ .\ \lambda y\ .\ x\ y\ z</tex> и <tex>\lambda a\ .\ \lambda x\ .\ a\ x\ z</tex> являются <tex>\alpha</tex>-эквивалентными, |
− | а <tex>\lambda x \ | + | а <tex>\lambda x\ .\ \lambda y\ .\ y\ z</tex> и <tex>\lambda y\ .\ \lambda x\ .\ y\ z</tex> {{---}} нет. |
===β-редукция=== | ===β-редукция=== | ||
Строка 79: | Строка 79: | ||
|definition= | |definition= | ||
<tex>\beta</tex>-редукция олицетворяет идею счёта значения функции. Выражение вида | <tex>\beta</tex>-редукция олицетворяет идею счёта значения функции. Выражение вида | ||
− | <tex>(\lambda x \ | + | <tex>(\lambda x\ .\ f)\ y</tex> можно заменить на <tex>f[x := y]</tex>, где <tex>f[x:=y]</tex>, как и ранее, означает |
замену всех свободных вхождений <tex>x</tex> в <tex>f</tex> на <tex>y</tex>. | замену всех свободных вхождений <tex>x</tex> в <tex>f</tex> на <tex>y</tex>. | ||
}} | }} | ||
Строка 87: | Строка 87: | ||
Через <tex>f \to_\beta g</tex> обозначают сведение <tex>f</tex> к <tex>g</tex> с помощью одной <tex>\beta</tex>-редукции. | Через <tex>f \to_\beta g</tex> обозначают сведение <tex>f</tex> к <tex>g</tex> с помощью одной <tex>\beta</tex>-редукции. | ||
А через <tex>f \to_\beta^* g</tex> {{---}} за ноль или более. | А через <tex>f \to_\beta^* g</tex> {{---}} за ноль или более. | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
}} | }} | ||
Строка 126: | Строка 116: | ||
число. | число. | ||
− | * <tex>\bar 0 = \lambda s \ | + | * <tex>\bar 0 = \lambda s\ .\ \lambda z\ .\ z</tex> |
− | * <tex>\bar 1 = \lambda s \ | + | * <tex>\bar 1 = \lambda s\ .\ \lambda z\ .\ s\ z</tex> |
− | * <tex>\bar 2 = \lambda s \ | + | * <tex>\bar 2 = \lambda s\ .\ \lambda z\ .\ s\ (s\ z)</tex> |
− | * <tex>\bar 3 = \lambda s \ | + | * <tex>\bar 3 = \lambda s\ .\ \lambda z\ .\ s\ (s\ (s\ z))</tex> |
Каждое число будет функцией двух аргументов: какой-то функции и начального значения. | Каждое число будет функцией двух аргументов: какой-то функции и начального значения. | ||
Строка 135: | Строка 125: | ||
результат. Если такому <<числу>> дать на вход функцию <tex>(+1)</tex> и <tex>0</tex> в качестве | результат. Если такому <<числу>> дать на вход функцию <tex>(+1)</tex> и <tex>0</tex> в качестве | ||
начального значения, то на выходе как раз будет ожидаемое от функции число: | начального значения, то на выходе как раз будет ожидаемое от функции число: | ||
− | <tex>\bar 3 (+1) 0 \equiv 3</tex>. | + | <tex>\bar 3\ (+1)\ 0 \equiv 3</tex>. |
===+1=== | ===+1=== | ||
Строка 143: | Строка 133: | ||
<tex>n+1</tex> раз применить, и начальное значение. | <tex>n+1</tex> раз применить, и начальное значение. | ||
− | <tex>\operatorname{succ} = \lambda n \ | + | <tex>\operatorname{succ} = \lambda n\ .\ \lambda s\ .\ \lambda z\ .\ s\ (n\ s\ z)</tex> |
− | Здесь <tex>n s z</tex> {{---}} <tex>n</tex> раз применённая к <tex>z</tex> функция <tex>s</tex>. Но нужно применить <tex>n+1</tex> | + | Здесь <tex>n\ s\ z</tex> {{---}} <tex>n</tex> раз применённая к <tex>z</tex> функция <tex>s</tex>. Но нужно применить <tex>n+1</tex> |
− | раз. Отсюда <tex>s (n s z)</tex>. | + | раз. Отсюда <tex>s\ (n\ s\ z)</tex>. |
===Сложение=== | ===Сложение=== | ||
Сложение двух чисел похоже на прибавление единицы. Но только надо прибавить не единицу, а второе число. | Сложение двух чисел похоже на прибавление единицы. Но только надо прибавить не единицу, а второе число. | ||
− | <tex>\operatorname{plus} = \lambda n \ | + | <tex>\operatorname{plus} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ \lambda z\ .\ n\ s\ (m\ s\ z)</tex> |
<tex>n</tex> раз применить <tex>s</tex> к применённому <tex>m</tex> раз <tex>s</tex> к <tex>z</tex> | <tex>n</tex> раз применить <tex>s</tex> к применённому <tex>m</tex> раз <tex>s</tex> к <tex>z</tex> | ||
− | <tex>(\operatorname{plus} \bar 3 \bar 3) (+1) 0 \equiv 6</tex> | + | <tex>(\operatorname{plus}\ \bar 3\ \bar 3)\ (+1)\ 0 \equiv 6</tex> |
===Умножение=== | ===Умножение=== | ||
Строка 162: | Строка 152: | ||
функции должна быть не <tex>s</tex>, а функция, применяющая <tex>n</tex> раз <tex>s</tex>. | функции должна быть не <tex>s</tex>, а функция, применяющая <tex>n</tex> раз <tex>s</tex>. | ||
− | <tex>\operatorname{mult} = \lambda n \ | + | <tex>\operatorname{mult} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ n\ (m\ s)</tex> |
− | Здесь <tex>m s</tex> {{---}} функция, которая <tex>m</tex> раз применит <tex>s</tex> к тому, что дадут ей на | + | Здесь <tex>m\ s</tex> {{---}} функция, которая <tex>m</tex> раз применит <tex>s</tex> к тому, что дадут ей на |
вход. С помощью <tex>\eta</tex>-редукции можно немного сократить эту формулу | вход. С помощью <tex>\eta</tex>-редукции можно немного сократить эту формулу | ||
− | <tex>\operatorname{mult} = \lambda n \ | + | <tex>\operatorname{mult} = \lambda n\ .\ \lambda m\ .\ \lambda s\ .\ n\ (m\ s)</tex> |
− | <tex>(\operatorname{mult} \bar 3 \bar 3) (+1) 0 \equiv 9</tex> | + | <tex>(\operatorname{mult} \bar 3\ \bar 3)\ (+1)\ 0 \equiv 9</tex> |
===Возведение в степень=== | ===Возведение в степень=== | ||
It's a kind of magic | It's a kind of magic | ||
− | <tex>\operatorname{power} = \lambda n \ | + | <tex>\operatorname{power} = \lambda n\ .\ \lambda m\ .\ m\ n</tex> |
− | <tex>(\operatorname{power} \bar 3 (\operatorname{succ} \bar 3)) (+1) 0 \equiv 81</tex> | + | <tex>(\operatorname{power}\ \bar 3\ (\operatorname{succ}\ \bar 3))\ (+1)\ 0 \equiv 81</tex> |
===Логические значения=== | ===Логические значения=== | ||
− | <tex>\operatorname{true} = \lambda a \ | + | <tex>\operatorname{true} = \lambda a\ .\ \lambda b\ .\ a</tex> |
− | <tex>\operatorname{false} = \lambda a \ | + | <tex>\operatorname{false} = \lambda a\ .\ \lambda b\ .\ b</tex> |
Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы. | Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы. | ||
Строка 187: | Строка 177: | ||
чтобы красиво написать функцию <tex>\operatorname{if}</tex>: | чтобы красиво написать функцию <tex>\operatorname{if}</tex>: | ||
− | <tex>\operatorname{if} = \lambda p \ | + | <tex>\operatorname{if} = \lambda p\ .\ \lambda t\ .\ \lambda e\ .\ p\ t\ e</tex> |
Если ей в качестве первого аргумента дадут <tex>\operatorname{true}</tex>, то вернётся <tex>t</tex>, иначе {{---}} <tex>e</tex>. | Если ей в качестве первого аргумента дадут <tex>\operatorname{true}</tex>, то вернётся <tex>t</tex>, иначе {{---}} <tex>e</tex>. | ||
Строка 193: | Строка 183: | ||
Стандартные функции булевой логики: | Стандартные функции булевой логики: | ||
− | <tex>\operatorname{and} = \lambda n \ | + | <tex>\operatorname{and} = \lambda n\ .\ \lambda m\ .\ \operatorname{if} n\ m\ \operatorname{false}</tex> |
− | <tex>\operatorname{or} = \lambda n \ | + | <tex>\operatorname{or} = \lambda n\ .\ \lambda m\ .\ \operatorname{if} n\ \operatorname{true} m</tex> |
− | <tex>\operatorname{not} = \lambda b \ | + | <tex>\operatorname{not} = \lambda b\ .\ \operatorname{if} b\ \operatorname{false} \operatorname{true}</tex> |
Ещё одной важной функцией является функция проверки, является ли число нулём: | Ещё одной важной функцией является функция проверки, является ли число нулём: | ||
− | <tex>\operatorname{isZero} = \lambda n \ | + | <tex>\operatorname{isZero} = \lambda n\ .\ n\ (\lambda c\ .\ \operatorname{false})\ \operatorname{true}</tex> |
Функция выглядит несколько странно. <tex>\lambda c -> \operatorname{false}</tex> {{---}} функция, которая независимо | Функция выглядит несколько странно. <tex>\lambda c -> \operatorname{false}</tex> {{---}} функция, которая независимо | ||
Строка 211: | Строка 201: | ||
===Пара=== | ===Пара=== | ||
− | <tex>\operatorname{pair} = \lambda a \ | + | <tex>\operatorname{pair} = \lambda a\ .\ \lambda b\ .\ \lambda t\ .\ t\ a\ b</tex> |
− | <tex>\operatorname{fst} = \lambda p \ | + | <tex>\operatorname{fst} = \lambda p\ .\ p\ \operatorname{true}</tex> |
− | <tex>\operatorname{snd} = \lambda p \ | + | <tex>\operatorname{snd} = \lambda p\ .\ p\ \operatorname{false}</tex> |
Функция <tex>\operatorname{pair}</tex> принимает два значения и запаковывает их в пару так, чтобы к ним можно было обращаться по <tex>\operatorname{fst}</tex> и <tex>\operatorname{snd}</tex>. В <tex>\operatorname{fst}</tex> и <tex>\operatorname{snd}</tex> вместо <tex>t</tex> в <tex>\operatorname{pair}</tex> будет подставлено <tex>\operatorname{true}</tex> или <tex>\operatorname{false}</tex>, возвращающие, соответственно, первый и второй аргументы, то есть <tex>a</tex> или <tex>b</tex>, соответственно. | Функция <tex>\operatorname{pair}</tex> принимает два значения и запаковывает их в пару так, чтобы к ним можно было обращаться по <tex>\operatorname{fst}</tex> и <tex>\operatorname{snd}</tex>. В <tex>\operatorname{fst}</tex> и <tex>\operatorname{snd}</tex> вместо <tex>t</tex> в <tex>\operatorname{pair}</tex> будет подставлено <tex>\operatorname{true}</tex> или <tex>\operatorname{false}</tex>, возвращающие, соответственно, первый и второй аргументы, то есть <tex>a</tex> или <tex>b</tex>, соответственно. | ||
Строка 222: | Строка 212: | ||
В отличие от всех предыдущих функций, вычитание для натуральных чисел определено только в случае, если уменьшаемое больше вычитаемого. Положим в противном случае результат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу. Тогда на её основе легко сделать, собственно, вычитание. | В отличие от всех предыдущих функций, вычитание для натуральных чисел определено только в случае, если уменьшаемое больше вычитаемого. Положим в противном случае результат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу. Тогда на её основе легко сделать, собственно, вычитание. | ||
− | <tex>\operatorname{minus} = \lambda n \ | + | <tex>\operatorname{minus} = \lambda n\ .\ \lambda m\ .\ m\ \operatorname{pred} n</tex> |
Это то же самое, что <tex>m</tex> раз вычесть единицу из <tex>n</tex>. | Это то же самое, что <tex>m</tex> раз вычесть единицу из <tex>n</tex>. | ||
Строка 228: | Строка 218: | ||
Осталось, собственно, функция для вычитания единицы. Однако, это не так просто, как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет проблематично. Если попробовать воспользоваться идеей о том, чтобы, начав от нуля, идти вперёд, и пройти на один шаг меньше, то будет не очень понятно, как же остановиться ровно за один шаг до конца. Для реализации вычитания единицы сделаем следующее. <tex>n</tex> раз выполним следующее: имея пару <tex>\langle n-1, n-2\rangle</tex> построим пару <tex>\langle n, n-1\rangle</tex>. Тогда после <tex>n</tex> шагов во втором элементе пары будет записано число <tex>n-1</tex>, которое и хочется получить. | Осталось, собственно, функция для вычитания единицы. Однако, это не так просто, как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет проблематично. Если попробовать воспользоваться идеей о том, чтобы, начав от нуля, идти вперёд, и пройти на один шаг меньше, то будет не очень понятно, как же остановиться ровно за один шаг до конца. Для реализации вычитания единицы сделаем следующее. <tex>n</tex> раз выполним следующее: имея пару <tex>\langle n-1, n-2\rangle</tex> построим пару <tex>\langle n, n-1\rangle</tex>. Тогда после <tex>n</tex> шагов во втором элементе пары будет записано число <tex>n-1</tex>, которое и хочется получить. | ||
− | <tex>\operatorname{pred} = \lambda n \ | + | <tex>\operatorname{pred} = \lambda n\ .\ \lambda s\ .\ \lambda z \to\ \operatorname{snd} ( |
n\ ( | n\ ( | ||
− | \lambda p \ | + | \lambda p\ .\ \operatorname{pair}\ (s\ (\operatorname{fst} p))\ (\operatorname{fst} p) |
)\ (\operatorname{pair}\ z\ z)</tex> | )\ (\operatorname{pair}\ z\ z)</tex> | ||
Строка 238: | Строка 228: | ||
Так как вычитание определено таким способом, чтобы для случая, в котором уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить сравнение на больше-меньше через него. Равными же числа <tex>a</tex> и <tex>b</tex> считаются, если <tex>a - b = 0 \wedge b - a = 0</tex>. | Так как вычитание определено таким способом, чтобы для случая, в котором уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить сравнение на больше-меньше через него. Равными же числа <tex>a</tex> и <tex>b</tex> считаются, если <tex>a - b = 0 \wedge b - a = 0</tex>. | ||
− | <tex>\operatorname{le} = \lambda n \ | + | <tex>\operatorname{le} = \lambda n\ .\ \lambda m\ .\ \operatorname{isZero}\ (\operatorname{minus}\ n\ m)</tex> |
− | <tex>\operatorname{less} = \lambda n \ | + | <tex>\operatorname{less} = \lambda n\ .\ \lambda m\ .\ \operatorname{le}\ n\ (\operatorname{pred} m)</tex> |
− | <tex>\operatorname{eq} = \lambda n \ | + | <tex>\operatorname{eq} = \lambda n\ .\ \lambda m\ .\ \operatorname{and}\ (\operatorname{isZero}\ (\operatorname{minus}\ n\ m))\ |
(\operatorname{isZero}\ (\operatorname{minus}\ m\ n))</tex> | (\operatorname{isZero}\ (\operatorname{minus}\ m\ n))</tex> | ||
Строка 248: | Строка 238: | ||
Попробуем выразить в лямбда-исчислении какую-нибудь функцию, использующую рекурсию. Напрмер, факториал. | Попробуем выразить в лямбда-исчислении какую-нибудь функцию, использующую рекурсию. Напрмер, факториал. | ||
− | <tex>\operatorname{fact} = \lambda x \ | + | <tex>\operatorname{fact} = \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{fact}\ (\operatorname{pred}\ x))</tex> |
Мы столкнулись с проблемой. В определении функции <tex>\operatorname{fact}</tex> используется функция <tex>\operatorname{fact}</tex>. При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом | Мы столкнулись с проблемой. В определении функции <tex>\operatorname{fact}</tex> используется функция <tex>\operatorname{fact}</tex>. При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом | ||
− | <tex>\operatorname{fact} = (\lambda f \ | + | <tex>\operatorname{fact} = (\lambda f\ .\ \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (f\ (\operatorname{pred}\ x)))\ \operatorname{fact}</tex> |
{{Определение | {{Определение | ||
Строка 263: | Строка 253: | ||
Рассмотрим следующую функцию. | Рассмотрим следующую функцию. | ||
− | <tex>\operatorname{fix} = \lambda f \ | + | <tex>\operatorname{fix} = \lambda f\ .\ (\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x))</tex> |
− | Заметим, что <tex>\operatorname{fix} \to_\beta^* \lambda f \ | + | Заметим, что <tex>\operatorname{fix} \to_\beta^* \lambda f\ .\ f\ ((\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)))</tex>. |
Или, что то же самое, | Или, что то же самое, | ||
− | <tex>\lambda f \ | + | <tex>\lambda f\ .\ (\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)) \to_\beta^*</tex> |
− | <tex>\lambda f \ | + | <tex>\lambda f\ .\ f\ ((\lambda x\ .\ f\ (x\ x))\ (\lambda x\ .\ f\ (x\ x)))</tex> |
Рассмотрим функцию | Рассмотрим функцию | ||
− | <tex>\operatorname{fact'} = \lambda f \ | + | <tex>\operatorname{fact'} = \lambda f\ .\ \lambda x\ .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{mult}\ x\ (f\ (\operatorname{pred}\ x)))</tex> |
Как было показано выше, <tex>\operatorname{fix} f \to_\beta^* f\ (\operatorname{fix} f)</tex>, то есть, <tex>\operatorname{fix}\ \operatorname{fact'} \to_\beta^* \operatorname{fact}</tex>, где <tex>\operatorname{fact}</tex> {{---}} искомая функция, считающая факториал. | Как было показано выше, <tex>\operatorname{fix} f \to_\beta^* f\ (\operatorname{fix} f)</tex>, то есть, <tex>\operatorname{fix}\ \operatorname{fact'} \to_\beta^* \operatorname{fact}</tex>, где <tex>\operatorname{fact}</tex> {{---}} искомая функция, считающая факториал. | ||
Строка 285: | Строка 275: | ||
Воспользовавшись идеей о том, что можно делать рекурсивные функции, сделаем функцию, которая будет искать частное двух чисел. | Воспользовавшись идеей о том, что можно делать рекурсивные функции, сделаем функцию, которая будет искать частное двух чисел. | ||
− | <tex>\operatorname{div'} = \lambda div \ | + | <tex>\operatorname{div'} = \lambda div\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ \bar 0\ (\operatorname{succ}\ (div\ (\operatorname{minus}\ n\ m)\ m))</tex> |
<tex>\operatorname{div} = \operatorname{fix}\ \operatorname{div'}</tex> | <tex>\operatorname{div} = \operatorname{fix}\ \operatorname{div'}</tex> | ||
Строка 291: | Строка 281: | ||
И остатка от деления | И остатка от деления | ||
− | <tex>\operatorname{mod'} = \lambda mod \ | + | <tex>\operatorname{mod'} = \lambda mod\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ n\ (mod\ (\operatorname{minus}\ n\ m)\ m)</tex> |
<tex>\operatorname{mod} = \operatorname{fix}\ \operatorname{mod'}</tex> | <tex>\operatorname{mod} = \operatorname{fix}\ \operatorname{mod'}</tex> | ||
Строка 299: | Строка 289: | ||
<tex>\operatorname{isPrimeHelp}</tex> {{---}} принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от 2 до <tex>p-1</tex>. Если на что-нибудь разделилось, то число {{---}} составное, иначе {{---}} простое. | <tex>\operatorname{isPrimeHelp}</tex> {{---}} принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от 2 до <tex>p-1</tex>. Если на что-нибудь разделилось, то число {{---}} составное, иначе {{---}} простое. | ||
− | <tex>\operatorname{isPrimeHelp'} =</tex><tex>\lambda f \ | + | <tex>\operatorname{isPrimeHelp'} =</tex><tex>\lambda f\ .\ \lambda p\ .\ \lambda i\ .\ \operatorname{if}\ (\operatorname{le}\ p\ i)\ \operatorname{true}\ (\operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ p\ i))\ \operatorname{false}\ (f\ p\ (\operatorname{succ}\ i)))</tex> |
<tex>\operatorname{isPrimeHelp} = \operatorname{fix}\ \operatorname{isPrimeHelp'}</tex> | <tex>\operatorname{isPrimeHelp} = \operatorname{fix}\ \operatorname{isPrimeHelp'}</tex> | ||
− | <tex>\operatorname{isPrime} = \lambda p \ | + | <tex>\operatorname{isPrime} = \lambda p\ .\ \operatorname{isPrimeHelp}\ p\ \bar 2</tex> |
Следующее простое число. <tex>\operatorname{nextPrime'}</tex> {{---}} следующее, больше либо равное заданного, <tex>\operatorname{nextPrime}</tex> {{---}} следующее, большее заданного. | Следующее простое число. <tex>\operatorname{nextPrime'}</tex> {{---}} следующее, больше либо равное заданного, <tex>\operatorname{nextPrime}</tex> {{---}} следующее, большее заданного. | ||
− | <tex>\operatorname{nextPrime''} = \lambda f \ | + | <tex>\operatorname{nextPrime''} = \lambda f\ .\ \lambda p\ .\ \operatorname{if}\ (\operatorname{isPrime}\ p)\ p\ (f\ (\operatorname{succ}\ p)) </tex> |
<tex>\operatorname{nextPrime'} = \operatorname{fix}\ \operatorname{nextPrime'}</tex> | <tex>\operatorname{nextPrime'} = \operatorname{fix}\ \operatorname{nextPrime'}</tex> | ||
− | <tex>\operatorname{nextPrime} = \lambda p \ | + | <tex>\operatorname{nextPrime} = \lambda p\ .\ \operatorname{nextPrime'}\ (\operatorname{succ}\ p)</tex> |
<tex>\operatorname{ithPrimeStep}</tex> пропрыгает <tex>i</tex> простых чисел вперёд. <tex>\operatorname{ithPrime}</tex> принимает число <tex>i</tex> и пропрыгивает столько простых чисел вперёд, начиная с двойки. | <tex>\operatorname{ithPrimeStep}</tex> пропрыгает <tex>i</tex> простых чисел вперёд. <tex>\operatorname{ithPrime}</tex> принимает число <tex>i</tex> и пропрыгивает столько простых чисел вперёд, начиная с двойки. | ||
− | <tex>\operatorname{ithPrimeStep'} = \lambda f \ | + | <tex>\operatorname{ithPrimeStep'} = \lambda f\ .\ \lambda p\ .\ \lambda i\ .\ \operatorname{if}\ (\operatorname{isZero}\ i)\ p\ (f\ (\operatorname{nextPrime}\ p)\ (\operatorname{pred}\ i))</tex> |
<tex>\operatorname{ithPrimeStep} = \operatorname{fix}\ \operatorname{ithPrimeStep'}</tex> | <tex>\operatorname{ithPrimeStep} = \operatorname{fix}\ \operatorname{ithPrimeStep'}</tex> | ||
− | <tex>\operatorname{ithPrime} = \lambda i \ | + | <tex>\operatorname{ithPrime} = \lambda i\ .\ \operatorname{ithPrimeStep}\ \bar 2\ i</tex> |
...и всего через 314007 <tex>\beta</tex>-редукций вы узнаете, что третье простое число {{---}} семь! | ...и всего через 314007 <tex>\beta</tex>-редукций вы узнаете, что третье простое число {{---}} семь! | ||
Строка 335: | Строка 325: | ||
<tex>\operatorname{empty} = \operatorname{pair}\ \operatorname{zero}\ \bar 1</tex> | <tex>\operatorname{empty} = \operatorname{pair}\ \operatorname{zero}\ \bar 1</tex> | ||
− | <tex>\operatorname{cons} = \lambda h \ | + | <tex>\operatorname{cons} = \lambda h\ .\ \lambda t\ .\ \operatorname{pair}\ (\operatorname{succ}\ (\operatorname{fst}\ t))\ (\operatorname{mult}\ (\operatorname{snd}\ t)\ (\operatorname{power}\ (\operatorname{ithPrime}\ (\operatorname{fst}\ t))\ h))</tex> |
− | <tex>\operatorname{head} = \lambda list \ | + | <tex>\operatorname{head} = \lambda list\ .\ \operatorname{getExponent}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list)))</tex> |
− | <tex>\operatorname{tail} = \lambda list \ | + | <tex>\operatorname{tail} = \lambda list\ .\ \operatorname{pair}\ (\operatorname{pred}\ (\operatorname{fst}\ list)) |
(\operatorname{eliminateMultiplier}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list))))</tex> | (\operatorname{eliminateMultiplier}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list))))</tex> | ||
− | <tex>\operatorname{eliminateMultiplier'} =</tex><tex> \lambda f \ | + | <tex>\operatorname{eliminateMultiplier'} =</tex><tex> \lambda f\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ n\ m))\ (f\ (\operatorname{div}\ n\ m)\ m)\ n</tex> |
<tex>\operatorname{eliminateMultiplier} = \operatorname{fix}\ \operatorname{eliminateMultiplier'}</tex> | <tex>\operatorname{eliminateMultiplier} = \operatorname{fix}\ \operatorname{eliminateMultiplier'}</tex> | ||
− | <tex>\operatorname{getExponent'} =</tex><tex> \lambda f \ | + | <tex>\operatorname{getExponent'} =</tex><tex> \lambda f\ .\ \lambda n\ .\ \lambda m\ .\ \operatorname{if}\ (\operatorname{isZero}\ (\operatorname{mod}\ n\ m))\ (\operatorname{succ}\ (f\ (\operatorname{div}\ n\ m)\ m))\ \bar 0</tex> |
<tex>\operatorname{getExponent} = \operatorname{fix}\ \operatorname{getExponent'}</tex> | <tex>\operatorname{getExponent} = \operatorname{fix}\ \operatorname{getExponent'}</tex> | ||
Строка 367: | Строка 357: | ||
==Ссылки== | ==Ссылки== | ||
+ | [http://en.wikipedia.org/wiki/Lambda-calculus Английская Википедия] | ||
+ | |||
+ | [http://ru.wikipedia.org/wiki/%D0%9B%D1%8F%D0%BC%D0%B1%D0%B4%D0%B0-%D0%B8%D1%81%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5 Русская Википедия] | ||
+ | |||
[http://rain.ifmo.ru/~komarov/Turing.lhs Тут можно это всё потыкать] | [http://rain.ifmo.ru/~komarov/Turing.lhs Тут можно это всё потыкать] | ||
[http://worrydream.com/AlligatorEggs А это игра про крокодильчиков] | [http://worrydream.com/AlligatorEggs А это игра про крокодильчиков] |
Версия 03:01, 7 декабря 2012
Лямбда-исчисление — формальная система, придуманная в 1930-х годах Алонзо Чёрчем. Лямбда-функция является, по сути, анонимной функцией. Эта концепция показала себя удобной и сейчас активно используется во многих языках программирования.
Содержание
Лямбда-исчисление
Более формально, лямбда-функцию (или, лямбда-терм) можно задать следующей грамматикой:
Определение: |
В первом случае функция является просто переменной.
Во втором происходит аппликация (применение) одной функции к другой.
Это аналогично вычислению функции-левого операнда на аргументе-правом операнде.
В третьем — абстракция по переменной. В данном случае происходит
создание функции одного аргумента с заданными именем аргумента и телом функции.
Рассмотрим, например, функцию
. Эта функция принимает аргумент и возвращает его неизменённым. Например, . Аналогично, .Ещё один пример функции:
. Эта функция двух аргументов, которая возвращает их сумму. Правда, здесь мы немного вышли за написанную выше грамматику. Ну да ладно.Приоритет операций
- Применение левоассоциативно:
- Аппликация забирает себе всё, до чего дотянется:
- Скобки играют привычную роль группировки действий
Свободные и связанные переменные
Связанными переменными называются все переменные, по которым выше в дереве разбора были абстракции. Все остальные переменные называются свободными.
Например, в
, связана, а — свободна. А в в своём первом вхождении переменная свободна, а во втором — связана.Рассмотрим функции
и . В первой из них при взгляде на понятно, что она имеет отношение к переменной, по которой производилась абстракция. Если по одной и той же переменной абстракция производилась более одного раза, то переменная связана с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в , переменная связана с самой правой абстракцией по .α-конверсия
Рассмотрим функции
и . Интуитивно понятно, что они являются одинаковыми.
Определение: |
где можно заменить на , если не входит свободно в , означает замену всех свободных вхождений в на . | -конверсия — переименование связанной переменной. Выражение
Функции, получающиеся одна из другой с помощью -конверсий, называются
-эквивалентными и обозначаются .
Функции
и являются -эквивалентными, а и — нет.β-редукция
Определение: |
замену всех свободных вхождений можно заменить на , где , как и ранее, означает в на . | -редукция олицетворяет идею счёта значения функции. Выражение вида
Определение: |
Через | обозначают сведение к с помощью одной -редукции. А через — за ноль или более.
Нотация Де Брюина
Существует также альтернативное эквивалентное определение
-исчисления. В оригинальном определении для обозначения переменных использовались имена, и была проблема с тем, что не были запрещены одинаковые имена в разных абстракциях.От этой проблемы можно избавиться следующим образом. Вместо имени переменной будет храниться натуральное число — количество абстракций в дереве разбора, на которое нужно подняться, чтобы найти ту лямбду, с которой данная переменная связана. В данной нотации получаются несколько более простые определения свободных переменных и
-редукции.Переменная называется свободной, если ей соответствует число, которое больше количества абстракций на пути до неё в дереве разбора.
При
-редукции же нужно будет ко всем свободным переменным заменяющего дерева при каждой замене прибавить число, равное разницы уровней раньше и сейчас. Это будет соответствовать тому, что эта переменная продолжит <<держаться>> за ту же лямбду, что и раньше.Нумералы Чёрча и программирование на -исчислении
Определение
Введём на основе лямбда-исчисления аналог натуральных чисел, основанный на идее, что натуральное число — это или ноль, или увеличенное на единицу натуральное число.
Каждое число будет функцией двух аргументов: какой-то функции и начального значения. Число
будет раз применять функцию к начальному значению и возвращать результат. Если такому <<числу>> дать на вход функцию и в качестве начального значения, то на выходе как раз будет ожидаемое от функции число: .+1
Функция, прибавляющая 1 к числу, должна принимать первым аргументом число. Но число — функция двух аргументов. Значит, эта функция должна принимать три аргумента: <<число>>
, которое хочется увеличить, функция, которую надо будет раз применить, и начальное значение.
Здесь
— раз применённая к функция . Но нужно применить раз. Отсюда .Сложение
Сложение двух чисел похоже на прибавление единицы. Но только надо прибавить не единицу, а второе число.
раз применить к применённому раз к
Умножение
Умножение похоже на сложение, но прибавлять надо не единицу, а второе число. Или, в терминах нумералов Чёрча, в качестве применяемой несколько раз функции должна быть не
, а функция, применяющая раз .
Здесь
— функция, которая раз применит к тому, что дадут ей на вход. С помощью -редукции можно немного сократить эту формулу
Возведение в степень
It's a kind of magic
Логические значения
Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы. Забавный факт:
. Эти функции сделаны такими для того, чтобы красиво написать функцию :
Если ей в качестве первого аргумента дадут
, то вернётся , иначе — .Стандартные функции булевой логики:
Ещё одной важной функцией является функция проверки, является ли число нулём:
Функция выглядит несколько странно.
— функция, которая независимо от того, что ей дали на вход, возвращает . Тогда, если в качестве будет дан ноль, то функция, по определению нуля, не выполнится ни разу, и будет возвращено значение по умолчанию . Иначе же функция будет запущено, и вернётся .Пара
Функция
принимает два значения и запаковывает их в пару так, чтобы к ним можно было обращаться по и . В и вместо в будет подставлено или , возвращающие, соответственно, первый и второй аргументы, то есть или , соответственно.Вычитание
В отличие от всех предыдущих функций, вычитание для натуральных чисел определено только в случае, если уменьшаемое больше вычитаемого. Положим в противном случае результат равным нулю. Пусть уже есть функция, которая вычитает из числа единицу. Тогда на её основе легко сделать, собственно, вычитание.
Это то же самое, что
раз вычесть единицу из .Осталось, собственно, функция для вычитания единицы. Однако, это не так просто, как может показаться на первый взгляд. Проблема в том, что, имея функцию, которую нужно применить для того, чтобы продвинуться вперёд, продвинуться назад будет проблематично. Если попробовать воспользоваться идеей о том, чтобы, начав от нуля, идти вперёд, и пройти на один шаг меньше, то будет не очень понятно, как же остановиться ровно за один шаг до конца. Для реализации вычитания единицы сделаем следующее.
раз выполним следующее: имея пару построим пару . Тогда после шагов во втором элементе пары будет записано число , которое и хочется получить.
Если вы ничего не поняли, не огорчайтесь. Вычитание придумал Клини, когда ему вырывали зуб мудрости. А сейчас наркоз уже не тот.
Сравнение
Так как вычитание определено таким способом, чтобы для случая, в котором уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить сравнение на больше-меньше через него. Равными же числа
и считаются, если .
Комбинатор неподвижной точки
Попробуем выразить в лямбда-исчислении какую-нибудь функцию, использующую рекурсию. Напрмер, факториал.
Мы столкнулись с проблемой. В определении функции
используется функция . При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом
Определение: |
Неподвижной точкой лямбда-функции | назовём такую функцию , что .
Лямбда исчисление обладаем замечательным свойством: у каждой функции есть неподвижная точка!
Рассмотрим следующую функцию.
Заметим, что
. Или, что то же самое,Рассмотрим функцию
Как было показано выше,
, то есть, , где — искомая функция, считающая факториал.
Это даст функцию, которая посчитает факториал числа. Но делать она это будет мееедленно-меееедленно. Для того, чтобы посчитать <tex?5!</tex> потребовалось сделать 66066
-редукций.Тут правда ничего не понятно? :'(
Деление
Воспользовавшись идеей о том, что можно делать рекурсивные функции, сделаем функцию, которая будет искать частное двух чисел.
И остатка от деления
Проверка на простоту
— принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от 2 до . Если на что-нибудь разделилось, то число — составное, иначе — простое.
Следующее простое число.
— следующее, больше либо равное заданного, — следующее, большее заданного.
пропрыгает простых чисел вперёд. принимает число и пропрыгивает столько простых чисел вперёд, начиная с двойки.
...и всего через 314007
-редукций вы узнаете, что третье простое число — семь!Списки
Для работы со списками чисел нам понадобятся следующие функции:
- — возвращает пустой список
- — принимает первый элемент и оставшийся список, склеивает их
- — вернуть голову списка
- — вернуть хвост списка
Список будем хранить в следующем виде:
. При этом, голова списка будет храниться как показатель степени при .
Выводы
На основе этого всего уже можно реализовать эмулятор машины тьюринга: с помощью пар, списков чисел можно хранить состояния. С помощью рекурсии можно обрабатывать переходы. Входная строка будет даваться, например, закодированной аналогично списку: пара из длины и числа, характеризующего список степенями простых. Я бы продолжил это писать, но уже на операции
я не дождался окончания выполнения. Скорость лямбда-исчисления как вычислителя печальна.Примеры (слабонервным не смотреть)
fact
(\f.(\x.f (x x)) (\x.f (x x))) (\f.\x.(\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) (x)) (\s.\z.s z) ((\n.\m.\s.n (m s)) (x) (f ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (x)))))
head
\list.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\n.\m.(\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) ((\f.(\x.f (x x)) (\x.f (x x))) (\mod.\n.\m.(\p.\t.\e.p t e) ((\n.\m.(\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (n) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (m))) (n) m) n (mod ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m) m)) n m)) ((\n.\s.\z.s (n s z)) (f ((\f.(\x.f (x x)) (\x.f (x x))) (\div.\n.\m.(\p.\t.\e.p t e) ((\n.\m.(\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (n) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (m))) (n) m) (\s.\z.z) ((\n.\s.\z.s (n s z)) (div ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m) m))) n m) m)) (\s.\z.z)) ((\p.p (\a.\b.b)) (list)) ((\i.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\p.\i.(\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) (i)) p (f ((\p.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\p.(\p.\t.\e.p t e) ((\p.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\p.\i.(\p.\t.\e.p t e) ((\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (p) i) (\a.\b.a) ((\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) ((\f.(\x.f (x x)) (\x.f (x x))) (\mod.\n.\m.(\p.\t.\e.p t e) ((\n.\m.(\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (n) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (m))) (n) m) n (mod ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m) m)) p i)) (\a.\b.b) (f p ((\n.\s.\z.s (n s z)) (i))))) p (\s.\z.s (s z))) (p)) p (f ((\n.\s.\z.s (n s z)) (p)))) ((\n.\s.\z.s (n s z)) (p))) (p)) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (i)))) (\s.\z.s (s z)) i) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) ((\p.p (\a.\b.a)) (list))))
tail
\list.(\a.\b.\t.t a b) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) ((\p.p (\a.\b.a)) (list))) ((\f.(\x.f (x x)) (\x.f (x x))) (\f.\n.\m.(\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) ((\f.(\x.f (x x)) (\x.f (x x))) (\mod.\n.\m.(\p.\t.\e.p t e) ((\n.\m.(\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (n) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (m))) (n) m) n (mod ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m) m)) n m)) (f ((\f.(\x.f (x x)) (\x.f (x x))) (\div.\n.\m.(\p.\t.\e.p t e) ((\n.\m.(\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (n) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (m))) (n) m) (\s.\z.z) ((\n.\s.\z.s (n s z)) (div ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m) m))) n m) m) n) ((\p.p (\a.\b.b)) (list)) ((\i.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\p.\i.(\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) (i)) p (f ((\p.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\p.(\p.\t.\e.p t e) ((\p.(\f.(\x.f (x x)) (\x.f (x x))) (\f.\p.\i.(\p.\t.\e.p t e) ((\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (p) i) (\a.\b.a) ((\p.\t.\e.p t e) ((\n.n (\c.\a.\b.b) (\a.\b.a)) ((\f.(\x.f (x x)) (\x.f (x x))) (\mod.\n.\m.(\p.\t.\e.p t e) ((\n.\m.(\n.\m.(\n.n (\c.\a.\b.b) (\a.\b.a)) ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m)) (n) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (m))) (n) m) n (mod ((\n.\m.m (\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) n) (n) m) m)) p i)) (\a.\b.b) (f p ((\n.\s.\z.s (n s z)) (i))))) p (\s.\z.s (s z))) (p)) p (f ((\n.\s.\z.s (n s z)) (p)))) ((\n.\s.\z.s (n s z)) (p))) (p)) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) (i)))) (\s.\z.s (s z)) i) ((\n.\s.\z.(\p.p (\a.\b.b)) (n (\p.(\a.\b.\t.t a b) (s ((\p.p (\a.\b.a)) (p))) ((\p.p (\a.\b.a)) (p))) ((\a.\b.\t.t a b) (z) z))) ((\p.p (\a.\b.a)) (list)))))