Лямбда-исчисление - это правила построения и вычисления безымянных функций.
И перейдем сразу к примерам.
Вот запись функции, которая получает на вход число и вычисляет значение, большее его на единицу:
(\x.x+1)Что здесь к чему? Сама функция записана в скобочках. Символ '\' будет впредь обозначать строчную греческую букву λ (кстати, в Haskell использется именно это обозначение, и такая безымянная функция в Haskell будет выглядеть
\x -> x+1). Далее, до точки, идут аргументы функции, а после точки -- выражение.Применение функций к аргументам записывается просто -- через пробел. Вот так:
(\x.x+1) 2Мы можем упрощать записанное нами выражение, подставляя вместо переменных их значения (бета-упрощение, бета-редукция):
(\x.x+1) 2 -- применяем бета-редукцию, подстановку значений аргументов. ==> (2+1) -- применяем дельта-редукцию, то есть, вычисление функции от аргументов. ==> 3Так оно и происходит. И даже в реальной жизни, когда идет рассуждение о программе.
Еще немного поупражняемся. Сделаем-ка функцию от двух аргументов, все ту же сумму:
(\x y.x+y)Ага, сделали. Что будет, если мы применим ее к одному аргументу? Сейчас выясним:
(\x y.x+y) 1 -- примением бета-редукцию, заменим x на 1. ==> (\y.1+y)Получили все ту же функцию увеличения на единицу, вид, так сказать, в профиль. То есть, если мы применим функцию к неполному числу аргументов, то получим другую функцию, которая должна получить оставшиеся аргументы.
И, в лучших традициях формальной математики, перепишем только что обнаруженный нами факт:
(\x y.x+y) эквивалентно (\x.(\y.x+y))Этот прием назвается карринг (currying), и именно он не стал шонфикелингом. ;)
Я еще упомяну о необходимости переименовывать переменные, чтобы после подстановки значений не возникало проблем, какой это y -- этот y является нашей переменной, или результатом подстановки?
Вот. А пока займемся другой проблемой. Посмотрим на выражение (\x.x x)(\x.x x). Попробуем его упростить:
(\x.x x) (\x.x x) -- переименуем x в самом левом выражении в z.
(\z.z z) (\x.x x) -- затем подставим вместо z его значение (\x.x x).
((\x.x x) (\x.x x)) -- где-то мы это уже видели.Мы получили невычислимое выражение. Оно настолько просто, что его можно вычислять до бесконечности. ;) И оно чуть-чуть интереснее, чем банальное деление на ноль.Зато это дает возможность продемонстрировать еще кое-что. На этот раз мы возьмем в качестве кандидата на упрощение следующее выражение -- (\x.1)((\x.x x) (\x.x x)).
Если мы начнем вычислять аргумент, то никогда не остановимся. Однако, если мы начнем сразу с тела функции ((\x.1) -- функция, которая всегда вычисляется в 1), то сразу придем к ответу -- 1. Отличие разительно, не находите?
Это пример того, как порядок вычисления выражений может оказать влияние на результат вычислений одного и того же выражения. Обычно выделяют два порядка вычислений: сперва упрощаем самый правый член в записи вычисления или сперва упрощаем самый левый член вычисления. Первый вариант приводит к тому, что сперва вычисляются все аргументы, а потом само выражение, а второй -- к тому, что мы откладываем вычисление аргументов до тех пор, пока они нам не понадобятся.
Второй вариант называется нормальным (или ленивым) порядком вычислений. Есть, даже, специальная теорема, которая доказывает, что если лямбда-выражение имеет значение, то оно всегда будет вычислено путем применения нормального порядка вычислений.
В свою очередь, первый вариант применяется энергичными (жадными) языками и легче для реализации. OCaml и LISP используют именно его.
Вообще, никакая современная программа не может обойтись без ленивых вычислений. Тот же if..then..else.. откладывает вычисления.
Кстати, а давайте сочиним условную конструкцию с помощью лямбда-исчисления? Хорошо, тем более, что это очень просто.
Что делает if c then a else b? В зависимости от значения c (condition, условия) оно выбирает либо значение a, либо значение b. Итак, конструкия if c then a else b -- это функция с тремя параметрами:
(\c.a.b.???)Нам надо выяснить, что может находиться вместо знаков вопроса.
Во-первых, там не может быть никаких if c then a else b, поскольку мы именно это и определяем. Во-вторых, там должен находится выбор значений a или b в зависимости от c, при этом на структуру самого c ограничений нет. Если мы примем значение (\a.b.a) за логическую истину, а значение (\a.b.b) -- за ложь, то можно подставить вместо знаков вопроса выражение c a b. Сейчас проверим:
(\c.a.b.c a b) (\a.b.a) 1 2 -- то же, что if true then 1 else 2. ==> (\a.b.(\x.y.x) a b) 1 2 ==> (\a.b.a) 1 2 ==> 1Вроде, правильно. Как записать
if false then 1 else 2, и во что это раскроется, я оставлю в качестве упражнения.Столь хитрые, на первый взгляд, манипуляции требуются редко, однако когда они нужны, до них легко дотянуться.
Например, в реальной программе можно легко сварганить свой собственный оператор управления выполнением, используя похожие методы. Несмотря на то, что в нашем решении практически никак не указывалось, как мы пришли к записи логических значений в виде функций, в жизни, обычно, присутствуют подсказки, на которые можно опираться. И вот такие примеры, которые дают общую идею. ;)
Ну, и в качестве заключения.
Я довольно долго исследовал всякие системы на предмет упрощения труда программиста. На данный момент я считаю, что лямбда-исчисление с ленивым порядком вычислений позволяет записать решения самым коротким способом при самой лучшей эффективности исполнения. То есть, если надо записать решение задачи короче, то будет значительно менее эффективно, при разнице в длине записи порядка десятка процентов, и не всегда в пользу не-Haskell записи (см. сравнение Haskell vs. Maude, есть такое в сети). А если надо эффективнее, то получится значительно длинее (Haskell vs. C, такое тоже есть).
На этом, пожалуй, все. ;)
June 15 2005, 17:34:05 UTC 6 years ago
пиши исчо!
Предлагаю следующие темы
1. Деревья решений. Прямая и обратная цепочка рассуждений. Алгоритм CLS
2. Логика предикатов. Основные понятия. Особенности использования кванторов.
3. Индуктивный вывод. Виды математической индукции.
4. Рекурсия. Виды рекурсий.
5. Метод доказательства от противного.
6. Приведение к префиксной нормальной форме. Основные правила.
7. Скалемизация.
8. Приведение к клаузальной нормальной форме.
9. Метод резолюции для высказываний.
10. Алгоритм унификации. НОУ. Правила допустимости подстановок.
11. Метод резолюции для предикатов. Особенности метода при использовании равенств.
12. Генетические алгоритмы. Основные характеристики. Примеры. Разновидности алгоритмов
13. Нейронные сети. Основные понятия. Вероятностные сети. Карта Кохонена. LVQ. Сети Хоппфилда и BAM. Сеть BP – SOM
June 15 2005, 17:39:43 UTC 6 years ago
Обязательно.
Как только будет время.Начну прямо с пятого пункта. ;)
А каким ветром тебя сюда занесло? ;)
August 29 2005, 09:48:44 UTC 6 years ago
Книги на русском языке по ламбда-исчислению и комбинат
По-моему, российское сообщество аппликативных вычислений разделилось по написанию: лЯмбда-исчисление и лАмбда-исчисление. Это - в порядке юмора. Но поисковые механизмы Web это различают. Имеется целый ряд книг, за последнее время изданных в России. Подробное и элементарное изложение, есть глоссарии и библиографии. Вот некоторые ссылки: http://jurinfor.exponenta.ru ; http://vew.0catch.com ; http://www.microsoft.com/Rus/Msdnaa/CurrAugust 29 2005, 09:54:56 UTC 6 years ago
Re: Книги на русском языке по ламбда-исчислению и комбин
Ага.Книга Вольфенгаген про вычисления с объектами у меня есть, но я до нее все никак не доберусь.
Ссылка на майкрософт интересна. Я сейчас эти две ссылки отдельным постом вынесу.
Anonymous
4 years ago
4 years ago
6 years ago
December 12 2006, 02:41:51 UTC 5 years ago
спасибо.
December 12 2006, 05:05:46 UTC 5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
6 months ago
December 12 2006, 05:25:22 UTC 5 years ago
December 12 2006, 07:44:46 UTC 5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
December 12 2006, 10:15:53 UTC 5 years ago
December 12 2006, 10:22:37 UTC 5 years ago
5 years ago
5 years ago
December 12 2006, 11:09:50 UTC 5 years ago
December 12 2006, 11:11:51 UTC 5 years ago
December 12 2006, 12:14:55 UTC 5 years ago
А как в функцию (\x.(\y.x+y)) "передать" y, если "извне" виден только один параметр - (\x.что-то-там)?
December 12 2006, 12:18:24 UTC 5 years ago
5 years ago
5 years ago
June 23 2008, 14:14:35 UTC 3 years ago
вопрос: что означает запись 2 переменных подряд? например, \x.xx.
будели ли верным след., хотя бы отчасти:
(\x.xx)(\y.y)=(\y.y)(\y.y)=\y.y
т.е., нечто вроде "генератора" аппликаций.
заранее спасибо.
PS: возможно, терминология немного отличается, я читаю "ламбда исчисление" Берендрегта.
June 23 2008, 14:18:03 UTC 3 years ago
Запись \x...\y...(x y) означает применение выражения x к аргументу y.
3 years ago
3 years ago
3 years ago
June 26 2008, 14:00:59 UTC 3 years ago
June 26 2008, 14:18:45 UTC 3 years ago
3 years ago
3 years ago
September 24 2008, 19:35:27 UTC 3 years ago
September 30 2008, 11:23:24 UTC 3 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
March 18 2009, 11:52:28 UTC 3 years ago
March 18 2009, 21:18:15 UTC 3 years ago
June 2 2009, 22:43:17 UTC 2 years ago
у меня вопрос можете подсказать что можно сделать вот с этим
> Непосредственно само задание:
>
> lambdaX.if(>X3)X(>X5)
>
> Что с этим нужно сделать:
> Произвести Beta-редукцию, КЛ,КЛ-редукцию, граф, редукцию графа, код де'Брюйна, КАМ-код и вычислить.
Если откликнитесть, буду очень признателен
June 3 2009, 00:45:08 UTC 2 years ago
Anonymous
October 25 2009, 21:46:31 UTC 2 years ago
Конкретно: синтаксис записи лямбда-функции таков:
\ (лямбда) x (аргумент) . (разделитель аргументов и самого тела функции) x+1 (собственно функция)
То есть '.' - это разделитель аргументов и тела функции, если я правильно понял.
Тогда что значит (\c.a.b.???) ???
Почему там аж три точки?
Надеюсь на благосклонный ответ =)
October 25 2009, 22:52:09 UTC 2 years ago
Должно быть (\a b c. f a b c), конечно.
Anonymous
November 9 2009, 22:37:53 UTC 2 years ago
Вопрос по поводу.
Есть программка для вычисления лямбда-выражений (www.cburch.com/proj/lambda).Так вот она (и не только она) говорят мне, что:
(\a.a a)(x y) => (beta-ред.) => x y (x y)
Я решительно не понимаю, почему именно так, а не
x y x y
или
(x y) (x y)
Не подскажите? Буду благодарен.
November 9 2009, 22:43:05 UTC 2 years ago
Re: Вопрос по поводу.
f - функция от двух аргументов, допустим.f a b - некоторое значение
(f a) b - карринг f.
Пусть теперь b = x y
(f a) (x y)
Раскрываем скобочки вокруг (f a), получим f a (x y).
Anonymous
April 17 2010, 21:13:37 UTC 2 years ago
Очень давно мучал этот вопрос.
Скажите, а есть ли специальная литература посвещеная вот таким вот трюкам в терминах лямбд?
April 17 2010, 21:36:21 UTC 2 years ago
October 15 2010, 09:35:52 UTC 1 year ago
В университете лямбда исчисление я так и не понял. Сейчас, имея под рукой массу лямбда-решателей, во многом разобрался, но возникли новые вопросы связанные с типизацией лямбда-выражений. Например выражение
(\x.x x) (\x.x x)не вычисляется в Haskell по причине того, что его не удаётся типизировать. Насколько я понял в первом приближении, типизация Чёрча лишает лямбда исчисление полноты по Тьюрингу. Это справедливо для сильной типизации в принципе или это ограничение как-то обходится?October 15 2010, 20:17:02 UTC 1 year ago
http://fprog.ru/2010/issue5/roman-dushk
С допущением правил вида a :: a -> a система типов становится противоречивой, начинает пропускать больше ошибок.
Тьюринг-полноты лямбда-исчисление лишает строгая типизация с простыми типами, без переменных типов. Если ввести переменные типов, то Тьюринг полнота возвращается и снова пропадает, если мы добираемся до зависимых типов (здесь опять система типов с Тьюринг-полными вычислениями становится противоречивой).
Это моё понимание проблемы на текущий момент. Возможно, я не совсем прав, так что продолжайте изучать сей интересный предмет. ;)
January 6 2011, 19:19:36 UTC 1 year ago
И что-то я озадачен двумя вещами:
1. Нужны ли переименования переменных при редукции? (у Харрисона написано, что нужны, но что-то они у меня в коде даже не возникли: внутрь (λx.(терм)) контекст просто уходит уже без назначенного x значения...)
Да, реализация у меня тупая: терм - либо атом, либо λатом.терм, либо пара (терм терм). Редукция - тупая рекурсивная с передачей контекста:
TermPtr reduce(TermPtr term, Context context)
- атом редуцируется либо в своё значение из контекста (если есть), либо сам в себя.
- λ атом.терм - атом не трогаем, для терма вызываем reduce(терм,context-атом)
- (λ атом.терм) терм2 - заменяем на reduce(терм, context+"атом=терм2")
- прочие пары (терм1 терм2) - на (reduce(терм1,context) reduce(терм2,context))
2. Что-то я туплю: если прогонять мой рекурсивный код до упора - то на (λf.λx.f(f x)) (λf.λx.f(f x)) f x он лажает... если разрешить ему выполнять за раз только одну бета-редукцию - то всё ok, но требуется не один проход по выражению. Пока пробую понять сам, но не откажусь от совета (может, на сторонний взгляд там сразу понятно, в чём косяк). Код тут не кладу, дабы не позориться =), но готов показать.
January 6 2011, 23:00:37 UTC 1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
November 9 2011, 15:54:36 UTC 6 months ago
интересно, а
> Если мы примем значение (\a.b.a) за логическую истину, а значение (\a.b.b)как это понять - функция от 3 аргументов, возвращающая ничего(nil/void и т.д.)?
>В свою очередь, первый вариант применяется энергичными (жадными) языками и легче для реализации. OCaml и LISP используют именно его.
а если, касательно лиспа, мы обернём аргументы ф-ции в лямбды без аргументов, а при использовании будем их вызывать, то код будет работать аналогично коду в нормальном порядке? В лямбда-вычислениях я так понимаю такое не сделать?
November 9 2011, 19:50:39 UTC 6 months ago
Re: интересно, а
>как это понять - функция от 3 аргументов, возвращающая ничего(nil/void и т.д.)?Функция от двух аргументов, возвращающая один из них.
>а если, касательно лиспа, мы обернём аргументы ф-ции в лямбды без аргументов, а при использовании будем их вызывать, то код будет работать аналогично коду в нормальном порядке? В лямбда-вычислениях я так понимаю такое не сделать?
Я не знаю, как работает лямбда в Лиспе, поэтому ничего не могу сказать.
6 months ago
6 months ago
6 months ago
6 months ago
March 25 2012, 06:44:17 UTC 2 months ago
«перейдем сразу к примерам.»… «(\x.x+1)»… «Сама функция записана в скобочках
до точки, идут аргументы функции, а после точки -- выражение.»…
ПОКА ВСЁ ПОНЯТНО! :О)
НО ВОТ ДАЛЕЕ:
«Посмотрим на выражение (\x.x x)(\x.x x)»
ЕСЛИ Я ПРАВИЛЬНО ПОНЯЛ, ЭТО ПРИМЕНЕНИЕ ФУНКЦИИ (\x.x x) К АРГУМЕНТУ (\x.x x). НО КАКИМ ВЫРАЖЕНИЕМ ИЛИ ВЫРАЖЕНИЕМ ЧЕГО ЯВЛЯЮТСЯ ДВЕ БУКОВКИ X ЧЕРЕЗ ПРОБЕЛ ПОСЛЕ ТОЧКИ? ОБЪЯСНИТЕ, ПОЖАЛУЙСТА, ТУПОМУ. ВЕРИТЕ, СПАТЬ НЕ МОГУ.