Основы функционального программирования/Формализация функционального программирования на основе лямбда-исчисления: различия между версиями
Содержимое удалено Содержимое добавлено
м «Основы функционального программирования/Формализация ФП на основе лямбда-исчисления» переименована в «[[Основы функционального прогр |
Вставлены формулы, ссылки. Прочие правки. |
||
Строка 1:
__TOC__
{{ОФП Содержание}}
* '''Объект изучения:''' [[w:Множество|множество]] определений [[w:Функция (математика)|функций]].
* '''[[w:Гипотеза|Предположение]]:''' будет считаться, что любая функция может быть определена при помощи некоторого
* '''Цель исследования:''' установить по двум определениям функций <
Проблема заключается в том, что обычно при описании функций
Возникает вопрос: как учесть [[w:Семантика в программировании|семантику]] встроенных функций при сравнении их экстенсионалов (
# Можно попытаться выразить семантику встроенных функций
# Говорят, что <
== Понятие [[w:Формальная система|формальной системы]] ==
Формальная система представляет собой
<math>P =
где <math>V</math> — [[w:Алфавит (математика)|алфавит
<math>R</math> — правила [[w:Вывод формулы|вывода]].
В рассматриваемой задаче формулы имеют вид <math>(
Говорят, что формальная система корректна, если <math>(
Говорят, что формальная система полна, если <math>(
Семантическое определение понятия «конструкция» (обозначение — <math>\mathrm{Exp}</math>):
1°. <math>v \in \mathrm{Id} \Rightarrow v \in \mathrm{Exp}</math>.
2°. <math>v \in \mathrm{Id},\, E \in \mathrm{Exp} \Rightarrow \lambda v.E \in \mathrm{Exp}</math>
3°. <math>E, E' \in \mathrm{Exp} \Rightarrow (EE') \in \mathrm{Exp}</math>
4°. <math>E \in \mathrm{Exp} \Rightarrow (E) \in \mathrm{Exp}</math>
5°. Никаких других <math>\mathrm{Exp}</math> нет.
Примечание: <math>\mathrm{Id}</math> — множество [[w:Идентификатор|идентификаторов]].
Говорят, что <math>v</math> свободна в <math>M \in \mathrm{Exp}</math>, если:
1°. <math>M = v</math>.
2°. <math>M = (M_1M_2)</math>, и <math>v</math> свободна в <math>M_1</math> или в <math>M_2</math>.
3°. <math>M = \lambda v'.M'</math>, и <math>v \neq v'</math>, и <math>v</math> свободна в <math>M'</math>.
4°. <math>M = (M')</math>, и <math>v</math> свободна в <math>M'</math>.
Множество идентификаторов <math>v</math>, свободных в <math>M</math>, обозначается как <math>FV(M)</math>.
Говорят, что <math>v</math> связана в <math>M \in \mathrm{Exp}</math>, если:
1°. <math>M = \lambda v'.M'</math>, и <math>v = v'</math>.
2°. <math>M = (M_1M_2)</math>, и <math>v</math> связана в <math>M_1</math> или в <math>M_2</math> (то есть один и тот же идентификатор может быть свободен и связан в <math>\mathrm{Exp}</math>).
3°. <math>M = (M')</math>, и <math>v</math> связана в <math>M'</math>.
'''Пример 26. Свободные и связанные идентификаторы.'''
# <math>M = v</math>. <math>v</math> — свободна.
# <math>M = \lambda x.xy</math>. <math>x</math> — связана, <math>y</math> — свободна.
# <math>M = (\lambda v.v)v</math>. <math>v</math> входит в это выражение как свободно, так и связанно.
# <math>M = VW</math>. <math>V</math> и <math>W</math> — свободны.
'''Правило подстановки:''' подстановка в выражение <math>E</math> выражения <math>E'</math> вместо всех свободных вхождений переменной <math>x</math> обозначается как <math>E[x \leftarrow E']</math>. Во время подстановки иногда случается так, что получается конфликт имён, то есть коллизия переменных. Примеры коллизий:
<math>(\lambda x.yx)[y \leftarrow \lambda z.z] = \lambda x.(\lambda z.z)x = \lambda x.x</math> — корректная подстановка;
<math>(\lambda x.yx)[y \leftarrow xx] = \lambda x.(xx)x</math> — коллизия имён переменных;
<math>(\lambda z.yz)[y \leftarrow xx] = \lambda z.(xx)z</math> — корректная подстановка.
Точное определение базисной подстановки:
1°. <math>x[x \leftarrow E'] = E'</math>.
2°. <math>y[x \leftarrow E'] = y</math>.
3°. <math>(\lambda x.E)[x \leftarrow E'] = \lambda x.E</math>.
4°. <math>(\lambda y.E)[x \leftarrow E'] = \lambda y.E[x \leftarrow E']</math>, при условии, что <math>y \not\in FV(E')</math>.
5°. <math>(\lambda y.E)[x \leftarrow E'] = \Big( \lambda z.E[y \leftarrow z] \Big) [x \leftarrow E']</math>, при условии, что <math>y \in FV(E')</math>.
6°. <math>(E_1\,E_2)[x \leftarrow E'] = \Big( E_1[x \leftarrow E']\, E_2[x \leftarrow E'] \Big)</math>.
=== Построение формальной системы ===
Таким образом, сейчас уже всё готово для того, чтобы перейти к построению формальной системы, определяющей [[w:Функциональное программирование|функциональное программирование]] в терминах λ-исчисления.
Правильно построенные формулы выглядят так: <math>\mathrm{Exp} = \mathrm{Exp}</math>.
Аксиомы:
{| width="100%"
| <math>\vdash \lambda x.E = \lambda y.E[x \leftarrow y]</math>; || align="right" | (α)
|-
| <math>\vdash (\lambda x.E)E' = E[x \leftarrow E']</math>; || align="right" | (β)
|-
| <math>\vdash t = t</math>, в случае, если <math>t</math> — идентификаторы. || align="right" | (ρ)
|}
Правила вывода:
{| width="100%"
| <math>t_1 = t_2 \Rightarrow t_1t_3 = t_2t_3</math>; || align="right" | (μ)
|-
| <math>t_1 = t_2 \Rightarrow t_3t_1 = t_3t_2</math>; || align="right" | (ν)
|-
| <math>t_1 = t_2 \Rightarrow t_2 = t_1</math>; || align="right" | (σ)
|-
| <math>t_1 = t_2,\, t_2 = t_3 \Rightarrow t_1 = t_3</math>; || align="right" | (τ)
|-
| <math>t_1 = t_2 \Rightarrow \lambda x.t_1 = \lambda x.t_2</math>. || align="right" | (ξ)
|-
|}
'''Пример 27. [[w:w:Математическое доказательство|Доказать]] выводимость формулы <math>(\lambda x.xy)(\lambda z.(\lambda u.zu))v = (\lambda v.yv)v</math>'''
{|
| || <math>(\lambda x.xy)(\lambda z.(\lambda u.zu))v = (\lambda v.yv)v</math>;
|-
| (μ): || <math>(\lambda x.xy)(\lambda z.(\lambda u.zu)) = (\lambda v.yv)</math>;
|-
| (β): || <math>(\lambda z.(\lambda u.zu))y = (\lambda v.yv)</math>;
|-
| (α): || <math>\lambda u.yu = \lambda v.yv</math> — выводима.
|}
Во втором варианте формализации функционального программирования можно воспользоваться не свойством симметричности отношения «<math>=</math>», а свойством несимметричности отношения «<math>\to</math>».
Во второй формальной системе правильно построенные формулы выглядят абсолютно так же, как и в первом варианте. Однако аксиомы принимают несколько иной вид:
{| width="100%"
| <math>\vdash \lambda x.M \to \lambda y.M[x \leftarrow y]</math> || align="right" | (α′)
|-
| <math>\vdash (\lambda x.M)N \to M[x \leftarrow N]</math> || align="right" | (β′)
|-
| <math>\vdash M \to M</math> || align="right" | (ρ′)
|}
Правило вывода во втором варианте формальной системы одно:
{| width="100%"
| <math>t_1 \to t_1',\, t_2 \to t_2' \Rightarrow t_1t_2 \to t_1't_2'</math> || align="right" | (π)
|}
По существу это правило вывода гласит, что в любом выражении можно выделить вхождения подвыражения и заменить их все любой [[w:Редукция|редукцией]] из этого подвыражения.
'''Определения:'''
* Выражение вида
* Выражение вида <math>(
* Выражения, не содержащие
Несколько [[w:Теорема|теорем]] (без доказательств):
* <math>\vdash E_1 = E_2 \Rightarrow E_1 \to E_2 \lor E_2 \to E_1</math>.
* <math>E
* Если <math>E</math> имеет нормальные формы
=== Стратегия редукции ===
2°. '''[[w:Аппликативная редукционная стратегия|Аппликативная редукционная стратегия]] (АРС).''' На каждом шаге редукции выбирается β-редекс, не содержащий внутри себя других β-редексов. Далее будет показано, что аппликативная редукционная стратегия не всегда позволяет получить нормальную форму выражения.
'''Пример 28. Редукция выражения <math>M = (\lambda y.x)(EE)</math>, где <math>E = \lambda x.xx</math>'''
1°. НРС: <math>\underline{(\lambda y.x)}(EE) = \underline{(\lambda y.x)}[y \leftarrow EE] = x</math>.
2°. АРС: <math>(\lambda y.x)\underline{(EE)} = (\lambda y.x)\underline{ \Big( (\lambda x.xx)(\lambda x.xx) \Big)} = (\lambda y.x)\underline{ \Big( (\lambda x.xx)(\lambda x.xx) \Big)} = \dots</math>.
В этом примере видно, как апликативная редукционная стратегия может привести к выпадению в [[w:Дурная бесконечность|дурную бесконечность]]. Получить нормальную форму выражения <math>M</math> в случае применения аппликативной редукционной стратегии невозможно.
''Примечание:'' подчёркиванием выделен β-редекс, редуцируемый следующим шагом.
'''Пример 29. Редукция выражения <math>M = (\lambda x.xyxx) \Big( (\lambda z.z)w \Big)</math>'''
1°. НРС: <math>\underline{(\lambda x.xyxx)} \Big( (\lambda z.z)w \Big) = \underline{ \Big( (\lambda z.z)w \Big) } y \Big( (\lambda z.z)w \Big) \Big( (\lambda z.z)w \Big) =</math>
<math>= wy \underline{ \Big( (\lambda z.z)w \Big) } \Big( (\lambda z.z)w \Big) = wyw \underline{ \Big( (\lambda z.z)w \Big) } = wyww</math>.
2°. АРС: <math>(\lambda x.xyxx) \underline{ \Big( (\lambda z.z)w \Big)} = \underline{(\lambda x.xyxx)} w = wyww</math>.
В программировании нормальная редукционная стратегия соответствует вызову по имени. То есть аргумент выражения не вычисляется до тех пор, пока к нему не возникнет обращения в теле выражения. Аппликативная редукционная стратегия соответствует вызову по значению.
== Соответствие между вычислениями функциональных программ и редукцией ==
Работа [[w:Интерпретатор|интерпретатора]] описывается несколькими шагами:
# В выражении необходимо выделить некоторое обращение к [[w:Рекурсия|рекурсивной]] или встроенной функции с полностью означенными аргументами. Если выделенное обращение к встроенной функции существует, то происходит его выполнение и возврат к началу первого шага.
# Если выделенное на первом шаге обращение к рекурсивной функции, то вместо него подставляется тело функции с фактическими параметрами (
# Если больше обращений нет, то происходит остановка.
В принципе, вычисления в функциональной парадигме повторяют шаги редукции, но дополнительно содержат вычисления встроенных функций.
=== Представление определений функций в виде λ-выражений ===
Показано, что любое определение функции можно представить в виде
<code>fact =
То же самое определение можно описать при помощи использования некоторого [[w:Функция высшего порядка|функционала]]:
<code>fact = '''(
Жирным шрифтом в представленном выражении выделен функционал <code>F</code>. Таким образом, функцию вычисления [[w:Факториал|факториала]] можно записать так: <code>fact = F fact</code>. Можно видеть, что любое рекурсивное определение некоторой функции <code>f</code> можно представить в таком виде:
<code>f = F f</code>
Это выражение можно трактовать как уравнение, в котором рекурсивная функция <code>f</code> является [[w:Неподвижная точка (математика)|неподвижной точкой]] функционала <code>F</code>. Соответственно интерпретатор функционального языка можно в таком же ключе рассматривать как численный метод решения этого уравнения.
Можно сделать предположение, что этот численный метод (
Свойства функции <code>Y</code> определяются равенством:
<code>Y F = F (Y F)</code>
'''Теорема''' (без доказательства):
Любой λ-терм имеет неподвижную точку.
Строка 204 ⟶ 235 :
λ-исчисление позволяет выразить любую функцию через чистое λ-выражение без использования встроенных функций. Например:
1°.
<code>prefix = λxyz.zxy
tail = λp.p(λxy.y)</code>
2°. Моделирование условных выражений:
<code>True = λxy.x
False = λxy.y
if B then M else N = BNM, где B = {True, False}</code>.
|