Изменения

Перейти к: навигация, поиск

Лямбда-исчисление

142 байта убрано, 03:01, 7 декабря 2012
Нет описания правки
{{В разработке}}
 
== Лямбда-исчисление==
''Лямбда-исчисление'' {{---}} формальная система, придуманная в 1930-х годах
Эта концепция показала себя удобной и сейчас активно используется во многих
языках программирования.
 
== Лямбда-исчисление==
Более формально, ''лямбда-функцию'' (или, ''лямбда-терм'') можно задать
\langle Term \rangle & ::= & \langle Variable \rangle \\
& | & \langle Term \rangle \langle Term \rangle \\
& | & \lambda \langle Variable \rangle \to .\ \langle Term \rangle\\
& | & ( \langle Term \rangle )\\
\langle Variable \rangle & ::= & \langle Char \rangle *\\
создание функции одного аргумента с заданными именем аргумента и телом функции.
Рассмотрим, например, функцию <tex>\operatorname{id } = \lambda x \to .\ x</tex>. Эта функция принимает аргумент и
возвращает его неизменённым. Например,
<tex>\operatorname{id }\ 2 \equiv 2</tex>. Аналогично, <tex>\operatorname{id }\ y == \equiv y</tex>.
Ещё один пример функции: <tex>\operatorname{sum } = \lambda x \to .\ \lambda y \to .\ x + y|</tex>. Эта функция двух аргументов,
которая возвращает их сумму. Правда, здесь мы немного вышли за написанную выше грамматику.
Ну да ладно. <tex>\operatorname{sum }\ 2 \ 3 == \equiv 5</tex>
===Приоритет операций===
* Применение левоассоциативно: <tex>x \ y \ z \ w == \equiv ((x \ y) \ z) \ w</tex>* Аппликация забирает себе всё, до чего дотянется: <tex>\lambda x \to .\ \lambda y \to .\ \lambda z \to .\ z \ y \ x \equiv \lambda x \to .\ (\lambda y \to .\ (\lambda z \to .\ ((z \ y) \ x)))</tex>
* Скобки играют привычную роль группировки действий
дереве разбора были абстракции. Все остальные переменные называются свободными.
Например, в <tex>\lambda x \to .\ \lambda y \to .\ x</tex>, <tex>x</tex> связана, а <tex>y</tex>{{---}} свободна. А в <tex>\lambda y \to .\ x (\lambda x \to .\ x)</tex>
в своём первом вхождении переменная <tex>x</tex> свободна, а во втором {{---}} связана.
Рассмотрим функции <tex>\lambda y \to .\ y</tex> и <tex>\lambda x \to .\ y</tex>. В первой из них при взгляде на <tex>y</tex>
понятно, что она имеет отношение к переменной, по которой производилась
абстракция. Если по одной и той же
переменной абстракция производилась более одного раза, то переменная связана
с самым поздним (самым нижним в дереве разбора) абстрагированием. Например, в
<tex>\lambda x \to .\ \lambda x \to .\ \lambda y \to .\ \lambda x \to .\ x</tex>, переменная <tex>x</tex> связана с самой правой абстракцией
по <tex>x</tex>.
===α-конверсия===
Рассмотрим функции <tex>(\lambda x \to .\ x) z</tex> и <tex>(\lambda y \to .\ y) z</tex>. Интуитивно понятно, что они
являются одинаковыми.
{{Определение
|definition=''<tex>\alpha</tex>-конверсия'' {{---}} переименование связанной переменной. Выражение
<tex>\lambda x \to .\ f</tex> можно заменить на <tex>\lambda y \to .\ 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>\alpha</tex>-эквивалентными'' и обозначаются <tex>f \equiv_\alpha g</tex>.
Функции <tex>\lambda x \to .\ \lambda y \to .\ x \ y \ z</tex> и <tex>\lambda a \to .\ \lambda x \to .\ a \ x \ z</tex> являются <tex>\alpha</tex>-эквивалентными,а <tex>\lambda x \to .\ \lambda y \to .\ y \ z</tex> и <tex>\lambda y \to .\ \lambda x \to .\ y \ z</tex> {{---}} нет.
===β-редукция===
|definition=
<tex>\beta</tex>-редукция олицетворяет идею счёта значения функции. Выражение вида
<tex>(\lambda x \to .\ f) \ y</tex> можно заменить на <tex>f[x := y]</tex>, где <tex>f[x:=y]</tex>, как и ранее, означает
замену всех свободных вхождений <tex>x</tex> в <tex>f</tex> на <tex>y</tex>.
}}
Через <tex>f \to_\beta g</tex> обозначают сведение <tex>f</tex> к <tex>g</tex> с помощью одной <tex>\beta</tex>-редукции.
А через <tex>f \to_\beta^* g</tex> {{---}} за ноль или более.
}}
 
===η-редукция===
Рассмотрим выражение вида <tex>\lambda x \to f x</tex>. Если подставить в эту функцию значение
<tex>y</tex>, то получим: <tex>(\lambda x \to f x) y \to_\beta f y</tex>. Но если просто подставить
<tex>y</tex> в <tex>f</tex>, то получится то же самое.
 
{{Определение
|definition=
<tex>\eta</tex>-редукция {{---}} преобразование <tex>\lambda x \to f x</tex> в <tex>f</tex>.
}}
число.
* <tex>\bar 0 = \lambda s \to .\ \lambda z \to .\ z</tex>* <tex>\bar 1 = \lambda s \to .\ \lambda z \to .\ s \ z</tex>* <tex>\bar 2 = \lambda s \to .\ \lambda z \to .\ s \ (s \ z)</tex>* <tex>\bar 3 = \lambda s \to .\ \lambda z \to .\ s \ (s \ (s \ z))</tex>
Каждое число будет функцией двух аргументов: какой-то функции и начального значения.
результат. Если такому <<числу>> дать на вход функцию <tex>(+1)</tex> и <tex>0</tex> в качестве
начального значения, то на выходе как раз будет ожидаемое от функции число:
<tex>\bar 3 \ (+1) \ 0 \equiv 3</tex>.
===+1===
<tex>n+1</tex> раз применить, и начальное значение.
<tex>\operatorname{succ} = \lambda n \to .\ \lambda s \to .\ \lambda z \to .\ s \ (n \ s \ z)</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>\operatorname{plus} = \lambda n \to .\ \lambda m \to .\ \lambda s \to .\ \lambda z \to .\ n \ s \ (m \ s \ 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>s</tex>, а функция, применяющая <tex>n</tex> раз <tex>s</tex>.
<tex>\operatorname{mult} = \lambda n \to .\ \lambda m \to .\ \lambda s \to .\ n \ (m \ s)</tex>
Здесь <tex>m \ s</tex> {{---}} функция, которая <tex>m</tex> раз применит <tex>s</tex> к тому, что дадут ей на
вход. С помощью <tex>\eta</tex>-редукции можно немного сократить эту формулу
<tex>\operatorname{mult} = \lambda n \to .\ \lambda m \to .\ \lambda s \to .\ n \ (m \ s)</tex>
<tex>(\operatorname{mult} \bar 3 \ \bar 3) \ (+1) \ 0 \equiv 9</tex>
===Возведение в степень===
It's a kind of magic
<tex>\operatorname{power} = \lambda n \to .\ \lambda m \to .\ m \ n</tex>
<tex>(\operatorname{power} \ \bar 3 \ (\operatorname{succ} \ \bar 3)) \ (+1) \ 0 \equiv 81</tex>
===Логические значения===
<tex>\operatorname{true} = \lambda a \to .\ \lambda b \to .\ a</tex>
<tex>\operatorname{false} = \lambda a \to .\ \lambda b \to .\ b</tex>
Функции двух аргументов, возвращающие первый и второй, соответственное, аргументы.
чтобы красиво написать функцию <tex>\operatorname{if}</tex>:
<tex>\operatorname{if} = \lambda p \to .\ \lambda t \to .\ \lambda e \to .\ p\ t\ e</tex>
Если ей в качестве первого аргумента дадут <tex>\operatorname{true}</tex>, то вернётся <tex>t</tex>, иначе {{---}} <tex>e</tex>.
Стандартные функции булевой логики:
<tex>\operatorname{and} = \lambda n \to .\ \lambda m \to .\ \operatorname{if} n\ m\ \operatorname{false}</tex>
<tex>\operatorname{or} = \lambda n \to .\ \lambda m \to .\ \operatorname{if} n\ \operatorname{true} m</tex>
<tex>\operatorname{not} = \lambda b \to .\ \operatorname{if} b\ \operatorname{false} \operatorname{true}</tex>
Ещё одной важной функцией является функция проверки, является ли число нулём:
<tex>\operatorname{isZero} = \lambda n \to .\ n\ (\lambda c \to .\ \operatorname{false})\ \operatorname{true}</tex>
Функция выглядит несколько странно. <tex>\lambda c -> \operatorname{false}</tex> {{---}} функция, которая независимо
===Пара===
<tex>\operatorname{pair} = \lambda a \to .\ \lambda b \to .\ \lambda t \to .\ t\ a\ b</tex>
<tex>\operatorname{fst} = \lambda p \to .\ p\ \operatorname{true}</tex>
<tex>\operatorname{snd} = \lambda p \to .\ 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{minus} = \lambda n \to .\ \lambda m \to .\ m\ \operatorname{pred} n</tex>
Это то же самое, что <tex>m</tex> раз вычесть единицу из <tex>n</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 \to .\ \lambda s \to .\ \lambda z \to\ \operatorname{snd} (
n\ (
\lambda p \to .\ \operatorname{pair}\ (s\ (\operatorname{fst} p))\ (\operatorname{fst} p)
)\ (\operatorname{pair}\ z\ z)</tex>
Так как вычитание определено таким способом, чтобы для случая, в котором уменьшаемое больше, чем вычитаемое, возвращать ноль, можно определить сравнение на больше-меньше через него. Равными же числа <tex>a</tex> и <tex>b</tex> считаются, если <tex>a - b = 0 \wedge b - a = 0</tex>.
<tex>\operatorname{le} = \lambda n \to .\ \lambda m \to .\ \operatorname{isZero}\ (\operatorname{minus}\ n\ m)</tex>
<tex>\operatorname{less} = \lambda n \to .\ \lambda m \to .\ \operatorname{le}\ n\ (\operatorname{pred} m)</tex>
<tex>\operatorname{eq} = \lambda n \to .\ \lambda m \to .\ \operatorname{and}\ (\operatorname{isZero}\ (\operatorname{minus}\ n\ m))\
(\operatorname{isZero}\ (\operatorname{minus}\ m\ n))</tex>
Попробуем выразить в лямбда-исчислении какую-нибудь функцию, использующую рекурсию. Напрмер, факториал.
<tex>\operatorname{fact} = \lambda x \to .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (\operatorname{fact}\ (\operatorname{pred}\ x))</tex>
Мы столкнулись с проблемой. В определении функции <tex>\operatorname{fact}</tex> используется функция <tex>\operatorname{fact}</tex>. При формальной замене, получим бесконечную функцию. Можно попытаться решить эту проблему следующим образом
<tex>\operatorname{fact} = (\lambda f \to .\ \lambda x \to .\ \operatorname{if}\ (\operatorname{isZero}\ x)\ \bar 1\ (f\ (\operatorname{pred}\ x)))\ \operatorname{fact}</tex>
{{Определение
Рассмотрим следующую функцию.
<tex>\operatorname{fix} = \lambda f \to .\ (\lambda x \to .\ f\ (x\ x))\ (\lambda x \to .\ f\ (x\ x))</tex>
Заметим, что <tex>\operatorname{fix} \to_\beta^* \lambda f \to .\ f\ ((\lambda x \to .\ f\ (x\ x))\ (\lambda x \to .\ f\ (x\ x)))</tex>.
Или, что то же самое,
<tex>\lambda f \to .\ (\lambda x \to .\ f\ (x\ x))\ (\lambda x \to .\ f\ (x\ x)) \to_\beta^*</tex><tex>\lambda f \to .\ f\ ((\lambda x \to .\ f\ (x\ x))\ (\lambda x \to .\ f\ (x\ x)))</tex>
Рассмотрим функцию
<tex>\operatorname{fact'} = \lambda f \to .\ \lambda x \to .\ \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{div'} = \lambda div \to .\ \lambda n \to .\ \lambda m \to .\ \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{mod'} = \lambda mod \to .\ \lambda n \to .\ \lambda m \to .\ \operatorname{if}\ (\operatorname{less}\ n\ m)\ n\ (mod\ (\operatorname{minus}\ n\ m)\ m)</tex>
<tex>\operatorname{mod} = \operatorname{fix}\ \operatorname{mod'}</tex>
<tex>\operatorname{isPrimeHelp}</tex> {{---}} принимает число, которое требуется проверить на простоту и то, на что его надо опытаться поделить, перебирая это от 2 до <tex>p-1</tex>. Если на что-нибудь разделилось, то число {{---}} составное, иначе {{---}} простое.
<tex>\operatorname{isPrimeHelp'} =</tex><tex>\lambda f \to .\ \lambda p \to .\ \lambda i \to .\ \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{isPrime} = \lambda p \to .\ \operatorname{isPrimeHelp}\ p\ \bar 2</tex>
Следующее простое число. <tex>\operatorname{nextPrime'}</tex> {{---}} следующее, больше либо равное заданного, <tex>\operatorname{nextPrime}</tex> {{---}} следующее, большее заданного.
<tex>\operatorname{nextPrime''} = \lambda f \to .\ \lambda p \to .\ \operatorname{if}\ (\operatorname{isPrime}\ p)\ p\ (f\ (\operatorname{succ}\ p)) </tex>
<tex>\operatorname{nextPrime'} = \operatorname{fix}\ \operatorname{nextPrime'}</tex>
<tex>\operatorname{nextPrime} = \lambda p \to .\ \operatorname{nextPrime'}\ (\operatorname{succ}\ p)</tex>
<tex>\operatorname{ithPrimeStep}</tex> пропрыгает <tex>i</tex> простых чисел вперёд. <tex>\operatorname{ithPrime}</tex> принимает число <tex>i</tex> и пропрыгивает столько простых чисел вперёд, начиная с двойки.
<tex>\operatorname{ithPrimeStep'} = \lambda f \to .\ \lambda p \to .\ \lambda i \to .\ \operatorname{if}\ (\operatorname{isZero}\ i)\ p\ (f\ (\operatorname{nextPrime}\ p)\ (\operatorname{pred}\ i))</tex>
<tex>\operatorname{ithPrimeStep} = \operatorname{fix}\ \operatorname{ithPrimeStep'}</tex>
<tex>\operatorname{ithPrime} = \lambda i \to .\ \operatorname{ithPrimeStep}\ \bar 2\ i</tex>
...и всего через 314007 <tex>\beta</tex>-редукций вы узнаете, что третье простое число {{---}} семь!
<tex>\operatorname{empty} = \operatorname{pair}\ \operatorname{zero}\ \bar 1</tex>
<tex>\operatorname{cons} = \lambda h \to .\ \lambda t \to .\ \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 \to .\ \operatorname{getExponent}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list)))</tex>
<tex>\operatorname{tail} = \lambda list \to .\ \operatorname{pair}\ (\operatorname{pred}\ (\operatorname{fst}\ list))
(\operatorname{eliminateMultiplier}\ (\operatorname{snd}\ list)\ (\operatorname{ithPrime}\ (\operatorname{pred}\ (\operatorname{fst}\ list))))</tex>
<tex>\operatorname{eliminateMultiplier'} =</tex><tex> \lambda f \to .\ \lambda n \to .\ \lambda m \to .\ \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{getExponent'} =</tex><tex> \lambda f \to .\ \lambda n \to .\ \lambda m \to .\ \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>
==Ссылки==
[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://worrydream.com/AlligatorEggs А это игра про крокодильчиков]
403
правки

Навигация