Основы функционального программирования/Формализация функционального программирования на основе лямбда-исчисления
Материал из Викиучебника
Содержание |
Основы функционального программирования
- Вводная лекция
- Структуры данных и базисные операции:
- Конструирование функций
- Доказательство свойств функций
- Формализация функционального программирования на основе λ-исчисления
- Трансформация программ
- Объект изучения: множество определений функций.
- Предположение: будет считаться, что любая функция может быть определена при помощи некоторого λ-выражения.
- Цель исследования: установить по двум определениям функций
и
их тождество на всей области определения —
. (Здесь использована такая нотация: f — некоторая функция,
— определения этой функции в терминах λ-исчисления.)
Проблема заключается в том, что обычно при описании функций задаётся интенсионал этих функций, а потом требуется установить экстенсиональное равенство. Под экстенсионалом функции понимается её график (или таблица в виде множества пар 〈аргумент, значение〉). Под интенсионалом функции понимаются правила вычисления значения функции по заданному аргументу.
Возникает вопрос: как учесть семантику встроенных функций при сравнении их экстенсионалов (так как явно определения этих функций неизвестны)? Варианты ответов:
- Можно попытаться выразить семантику встроенных функций при помощи механизма λ-исчисления. Этот процесс можно довести до случая, когда все встроенные функции не содержат непроинтерпретированных операций.
- Говорят, что
и
семантически равны (этот факт обозначается как
), если f1(x) = f2(x) при любой интерпретации непроинтерпретированных идентификаторов.
[править] Понятие формальной системы
Формальная система представляет собой четвёрку:
,
где V — алфавит;
Φ — множество правильно построенных формул;
A — аксиомы (при этом
);
R — правила вывода.
В рассматриваемой задаче формулы имеют вид (t1 = t2), где t1 и t2 — λ-выражения. Если некоторая формула выводима в формальной системе, то этот факт записывается как
.
Говорят, что формальная система корректна, если
.
Говорят, что формальная система полна, если
.
Семантическое определение понятия «конструкция» (обозначение — Exp):
1°.
.
2°. 
3°. 
4°. 
5°. Никаких других Exp нет.
Примечание: Id — множество идентификаторов.
Говорят, что v свободна в
, если:
1°. M = v.
2°. M = (M1M2), и v свободна в M1 или в M2.
3°. M = λv'.M', и
, и v свободна в M'.
4°. M = (M'), и v свободна в M'.
Множество идентификаторов v, свободных в M, обозначается как FV(M).
Говорят, что v связана в
, если:
1°. M = λv'.M', и v = v'.
2°. M = (M1M2), и v связана в M1 или в M2 (то есть один и тот же идентификатор может быть свободен и связан в Exp).
3°. M = (M'), и v связана в M'.
Пример 26. Свободные и связанные идентификаторы.
- M = v. v — свободна.
- M = λx.xy. x — связана, y — свободна.
- M = (λv.v)v. v входит в это выражение как свободно, так и связанно.
- M = VW. V и W — свободны.
Правило подстановки: подстановка в выражение E выражения E' вместо всех свободных вхождений переменной x обозначается как
. Во время подстановки иногда случается так, что получается конфликт имён, то есть коллизия переменных. Примеры коллизий:
— корректная подстановка;
— коллизия имён переменных;
— корректная подстановка.
Точное определение базисной подстановки:
1°.
.
2°.
.
3°.
.
4°.
, при условии, что
.
5°.
, при условии, что
.
6°.
.
[править] Построение формальной системы
Таким образом, сейчас уже всё готово для того, чтобы перейти к построению формальной системы, определяющей функциональное программирование в терминах λ-исчисления.
Правильно построенные формулы выглядят так: Exp = Exp.
Аксиомы:
; |
(α) |
; |
(β) |
, в случае, если t — идентификаторы. |
(ρ) |
Правила вывода:
; |
(μ) |
; |
(ν) |
; |
(σ) |
; |
(τ) |
. |
(ξ) |
Пример 27. Доказать выводимость формулы (λx.xy)(λz.(λu.zu))v = (λv.yv)v
| (λx.xy)(λz.(λu.zu))v = (λv.yv)v; | |
| (μ): | (λx.xy)(λz.(λu.zu)) = (λv.yv); |
| (β): | (λz.(λu.zu))y = (λv.yv); |
| (α): | λu.yu = λv.yv — выводима. |
Во втором варианте формализации функционального программирования можно воспользоваться не свойством симметричности отношения « = », а свойством несимметричности отношения «
».
Во второй формальной системе правильно построенные формулы выглядят абсолютно так же, как и в первом варианте. Однако аксиомы принимают несколько иной вид:
![]() |
(α′) |
![]() |
(β′) |
![]() |
(ρ′) |
Правило вывода во втором варианте формальной системы одно:
![]() |
(π) |
По существу это правило вывода гласит, что в любом выражении можно выделить вхождения подвыражения и заменить их все любой редукцией из этого подвыражения.
Определения:
- Выражение вида λx.M называется α-редексом.
- Выражение вида (λx.M)N называется β-редексом.
- Выражения, не содержащие β-редексов, называются выражениями в нормальной форме.
Несколько теорем (без доказательств):
.
. (Теорема Чёрча—Россера).- Если E имеет нормальные формы E1 и E2, то они эквивалентны с точностью до α-конверсии, то есть различаются только обозначением связанных переменных.
[править] Стратегия редукции
1°. Нормальная редукционная стратегия (НРС). На каждом шаге редукции выбирается текстуально самый левый β-редекс. Доказано, что нормальная редукционная стратегия гарантирует получение нормальной формы выражения, если она существует.
2°. Аппликативная редукционная стратегия (АРС). На каждом шаге редукции выбирается β-редекс, не содержащий внутри себя других β-редексов. Далее будет показано, что аппликативная редукционная стратегия не всегда позволяет получить нормальную форму выражения.
Пример 28. Редукция выражения M = (λy.x)(EE), где E = λx.xx
1°. НРС:
.
2°. АРС:
.
В этом примере видно, как апликативная редукционная стратегия может привести к выпадению в дурную бесконечность. Получить нормальную форму выражения M в случае применения аппликативной редукционной стратегии невозможно.
Примечание: подчёркиванием выделен β-редекс, редуцируемый следующим шагом.
Пример 29. Редукция выражения 
1°. НРС: 
.
2°. АРС:
.
В программировании нормальная редукционная стратегия соответствует вызову по имени. То есть аргумент выражения не вычисляется до тех пор, пока к нему не возникнет обращения в теле выражения. Аппликативная редукционная стратегия соответствует вызову по значению.
[править] Соответствие между вычислениями функциональных программ и редукцией
Работа интерпретатора описывается несколькими шагами:
- В выражении необходимо выделить некоторое обращение к рекурсивной или встроенной функции с полностью означенными аргументами. Если выделенное обращение к встроенной функции существует, то происходит его выполнение и возврат к началу первого шага.
- Если выделенное на первом шаге обращение к рекурсивной функции, то вместо него подставляется тело функции с фактическими параметрами (так как они уже означены). Далее происходит переход на начало первого шага.
- Если больше обращений нет, то происходит остановка.
В принципе, вычисления в функциональной парадигме повторяют шаги редукции, но дополнительно содержат вычисления встроенных функций.
[править] Представление определений функций в виде λ-выражений
Показано, что любое определение функции можно представить в виде λ-выражения, не содержащего рекурсии. Например:
fact = λn.if n == 0 then 1 else n * fact (n – 1)
То же самое определение можно описать при помощи использования некоторого функционала:
fact = (λf.λn.if n == 0 then 1 else n * f (n – 1)) fact
Жирным шрифтом в представленном выражении выделен функционал F. Таким образом, функцию вычисления факториала можно записать так: fact = F fact. Можно видеть, что любое рекурсивное определение некоторой функции f можно представить в таком виде:
f = F f
Это выражение можно трактовать как уравнение, в котором рекурсивная функция f является неподвижной точкой функционала F. Соответственно интерпретатор функционального языка можно в таком же ключе рассматривать как численный метод решения этого уравнения.
Можно сделать предположение, что этот численный метод (то есть интерпретатор) в свою очередь может быть реализован при помощи некоторой функции Y, которая для функционала F находит его неподвижную точку (соответственно определяя искомую функцию) — f = Y F.
Свойства функции Y определяются равенством:
Y F = F (Y F)
Теорема (без доказательства):
Любой λ-терм имеет неподвижную точку.
λ-исчисление позволяет выразить любую функцию через чистое λ-выражение без использования встроенных функций. Например:
1°.
prefix = λxyz.zxy
head = λp.p(λxy.x)
tail = λp.p(λxy.y)
2°. Моделирование условных выражений:
True = λxy.x
False = λxy.y
if B then M else N = BNM, где B = {True, False}.
;
;
, в случае, если
;
;
;
;
.![\vdash \lambda x.M \to \lambda y.M[x \leftarrow y]](http://upload.wikimedia.org/math/b/d/d/bdd973b0d311dffa25aac03658eb544c.png)
![\vdash (\lambda x.M)N \to M[x \leftarrow N]](http://upload.wikimedia.org/math/8/1/6/816dcb3099207695ac88295e4f97f220.png)

