Основы функционального программирования/Трансформация программ: различия между версиями

Содержимое удалено Содержимое добавлено
мНет описания правки
Вставлены формулы, ссылки. Прочие правки
Строка 1:
__TOC__
 
{{ОФП Содержание}}
 
Под [[w:Компьютерная программа|программой]] <math>P</math> на некотором [[w:Язык программирования|языке]] <math>L</math> понимается некоторый текст на <math>L</math>. В случае [[w:Язык функционального программирования|функционального языка]] под программой понимается набор [[w:Клоз|клозов]]. [[w:Семантика в программировании|Семантика]] же языка <math>L</math> определяется, если задан [[w:Интерпретатор|интерпретатор]] этого языка. Интерпретатор определяется формулой:
 
<math>\operatorname{Int} (P,\, d) = d’d\,'</math>
 
где <math>P </math> — программа;
где:
 
<math>d</math> — исходные [[w:Данные (вычислительная техника)|данные]];
P — программа;
 
<math>d \,'</math> исходныевыходные данные;.
 
Если интерпретатор <math>\mathrm{Int}</math> представлен в виде [[w:Лямбда-исчисление#Карринг|каррированной]] [[w:Функция (программирование)|функции]] <math>f</math> такой, что <math>f\, P\, d = d’d\,'</math>, тогда определение <math>f = M\, f</math>, а точнее [[w:Функция высшего порядка|функционал]] <math>M</math> называется [[w:Денотационная семантика|денотационной семантикой]] языка <math>L</math>. В этом случае имеет смысл <math>\lambda</math>-выражение: <math>f\, P = d\lambda d.M’M' : D \to D’D'</math>. При этом частичную функцию <math>f\, P</math> можно рассматривать как функцию fP<math>f_P</math> одного [[w:Аргумент (программирование)|аргумента]], которая есть функция, реализующая программу <math>P</math>. Как было показано в [[Основы функционального программирования/Формализация функционального программирования на основе лямбда-исчисления|предыдущей лекции]], можно построить [[w:Рекурсия|рекурсивное]] определение вида: fP<math>f_P = MPM_P\, fPf_P</math>. Такой вид изначально имеют все программы на функциональном языке. Но эту запись можно понимать двояко:
d’ — выходные данные.
 
* Это определение можно понимать просто как [[w:Строковый тип|строку символов]], подаваемую на вход интерпретатора. Функция, вычисляемая интерпретатором по тексту <math>f = M\, f</math>, обозначается как fint<math>f_\mathrm{int}</math>.
Если интерпретатор Int представлен в виде каррированной функции f такой, что f P d = d’, тогда определение f = M f, а точнее функционал M называется денотационной семантикой языка L. В этом случае имеет смысл -выражение: f P = d.M’ : D  D’. При этом частичную функцию f P можно рассматривать как функцию fP одного аргумента, которая есть функция, реализующая программу P. Как было показано в предыдущей лекции, можно построить рекурсивное определение вида: fP = MP fP. Такой вид изначально имеют все программы на функциональном языке. Но эту запись можно понимать двояко:
* <math>f = M\, f</math> — есть чистое [[w:Функция (математика)|математическое определение функции]] <math>f</math>. Решение этого уравнения обозначается как fmat<math>f_\mathrm{mat}</math>.
 
Резонный вопрос: каково соотношение этих двух функций — fint<math>f_\mathrm{int}</math> и fmat<math>f_\mathrm{mat}</math>? Надо полагать, что корректный интерпретатор как раз вычисляет fmat<math>f_\mathrm{mat}</math>.
*Это определение можно понимать просто как строку символов, подаваемую на вход интерпретатора. Функция, вычисляемая интерпретатором по тексту f = M f, обозначается как fint.
*f = M f — есть чистое математическое определение функции f. Решение этого уравнения обозначается как fmat.
 
'''Определение:''' говорят, что функция f1<math>f_1</math> менее определена, чем функция f2<math>f_2</math> (обозначается как <math>f_1 \subseteq f_2</math>), если <math>\forall x : f_1 x = y \Rightarrow f_2 x = y</math>. Если для двух функций одновременно выполняется <math>f_1 \subseteq f_2</math> и <math>f_2 \subseteq f_1</math>, то имеет место [[w:Тождество (математика)|тождество]] функций.
Резонный вопрос: каково соотношение этих двух функций — fint и fmat? Надо полагать, что корректный интерпретатор как раз вычисляет fmat.
 
Как правило, <math>f_\mathrm{int} \subseteq f_\mathrm{mat}</math> — это происходит потому, что, обычно интерпретатор реализует [[w:Аппликативная редукционная стратегия|аппликативную стратегию редукции]]. Однако в дальнейших рассуждениях будет полагаться тождество функций fint<math>f_\mathrm{int}</math> и fmat<math>f_\mathrm{mat}</math>, поэтому тексты программ будут рассматриваться как математическое определение функций. Тогда эквивалентное преобразование функциональных программ есть просто эквивалентные преобразования специального вида математических определений функций.
Определение: говорят, что функция f1 менее определена, чем функция f2 (обозначается как ), если . Если для двух функций одновременно выполняется и , то имеет место тождество функций.
 
Трансформация программ — это просто [[w:Синтаксис (программирование)|синтаксические]] преобразования, во время которых совершенно не затрагивается семантика программ, т.к.так как программа воспринимается просто как набор символов. Обозначение того факта, что один текст f1<math>f_1</math> получаем при помощи синтаксических трансформаций другого текста f2<math>f_2</math>, выглядит следующим образом: f1<math>f_1 |-\vdash f2f_2</math>.
Как правило, — это происходит потому что, обычно интерпретатор реализует аппликативную стратегию редукции. Однако в дальнейших рассуждениях будет полагаться тождество функций fint и fmat, поэтому тексты программ будут рассматриваться как математическое определение функций. Тогда эквивалентное преобразование функциональных программ есть просто эквивалентные преобразования специального вида математических определений функций.
 
Говорят, что преобразование эквивалентнокорректно, если <math>f_1 \subseteq f_2</math>.
Трансформация программ — это просто синтаксические преобразования, во время которых совершенно не затрагивается семантика программ, т.к. программа воспринимается просто как набор символов. Обозначение того факта, что один текст f1 получаем при помощи синтаксических трансформаций другого текста f2, выглядит следующим образом: f1 |- f2.
 
Говорят, что преобразование корректноэквивалентно, если <math>f_1 \equiv f_2</math>.
 
Говорят, что преобразование эквивалентно, если .
 
Далее вводится еще несколько специальных обозначений:
 
# Имеется исходный набор клозов (т.е.то есть объектов преобразования), и этот набор будет обозначаться либо DEF, либо SPEC.
# Клозы, описывающие функцию, которая содержит отображения из исходных клозов, обозначается как INV.
# Некоторые равенства, выражающие свойства внутренних (зарезервированных) функций, обозначаются как LOWLAW.
 
'''Определение:''' пусть <math>F (X)</math> — некоторое [[w:Алгебраическое выражение|выражение]] (равенство), в котором выделены все свободные вхождения [[w:Терм (логика)|терма]] <math>X</math>. Тогда <math>F [X \leftarrow M]</math> называется примером <math>F</math>. При этом считается, что <math>M</math> — это некоторое выражение.
 
== Виды преобразований ==
 
#1°. Конкретизация (instantiation) — INS.
 
<math>\frac
{E_1(X) = E_2(X)}
{E_1[X \leftarrow M] = E_2[X \leftarrow M]}
</math>
#2°. Преобразование без названия :)
 
<math>\frac
{M(Y) = N(Y),\, E_1 = E_2[X \leftarrow M'],\, M ' = M[Y \leftarrow G]}
{E_1 = E_2 [X \leftarrow N'],\ \mbox{where}\ N' = N[Y \leftarrow G]}
</math>
#Развертка3°. Развёртка (unfolding) — UNF.
 
<math>\frac
{M(Y) = N(Y),\, E_1 = E_2(M'),\, M' = M[Y \leftarrow G]}
{E_1 = E_2(N'),\ \mbox{where}\ N' = N[Y \leftarrow G ]}
</math>
#Свертка4°. Свёртка (folding) — FLD.
 
<math>\frac
{M(Y) = N(Y),\, E_1 = E_2(N'),\, N' = N[Y \leftarrow G]}
{E_1 = E_2(M'),\ \mbox{where}\ M' = M[Y \leftarrow G ]}
</math>
 
#5°. Закон (law) — LAW.
 
<math>\frac
{M(Y) = N(Y),\, E_1 = E_2(M'),\, M'=M[Y \leftarrow G ]}
{E_1 = E_2(N'),\ \mbox{where}\ N' = N[Y \leftarrow G ]}
</math>
 
#6°. Абстракция и аппликация (abstraction & application) — ABS.
 
<math>\frac{M[X \leftarrow G ] = (\lambda X.M)G,\, E_1 = E_2 \Big(M[X \leftarrow G ]\Big)}
{E_1 = E_2 \Big( (\lambda X.M)G \Big)}</math>
 
'''Пример 30. Преобразование функции <code>length</code>.'''
 
<code>length [] = 0 1 (DEF)
length (H:T) = 1 + length T 2 (DEF)
length_2 L1 L2 = length L1 + length L2 3 (SPEC)
length_2 []L1 L2 L = length []L1 + length L 4L2 (INS 3 (SPEC)
length_2 [] L = 0length [] + length L 5 4 (UNFINS 13)
= 0 + length L 6 (LAW +) 5 (*UNF 1)
= length L 6 (LAW +) (*)
length_2 (H:T) L = length (H:T) + length L 7 (INS 3)
= (1 + length T) + length L 8 (UNF 2)
= 1 + (length T + length L) 9 (LAW +)
= 1 + length_2 T L 10 (FLD 3) (**)</code>
 
Теперь остаётся взять два полученных клоза (*) и (**) и составить из них новое рекурсивное определение новой функции, не использующее вызова старой функции:
 
<code>length_2 [] L = length L
length_2 (H:T) L = 1 + length_2 T L</code>
 
Однако следует отметить, что выбор новых клозов для формирования нового определения требует дополнительных исследований, а не выполняется автоматически.
 
Подобная трансформация определений функций часто будет приводить к уменьшению сложности определения функций. Например, для функции, вычисляющей <math>N</math>-ое [[w:Числа Фибоначчи|число Фиббоначи]] можно построить определение, сложность вычисления которого линейно зависит от <math>N</math>, а не по закону Фиббоначи, как это есть для обычного определения.
 
Но трансформации следует делать обдуманно, т.к.так как можно придти к бесконечным циклам шагов FLD и UNF. Чтобы при трансформации не придти к абсурду, необходимо следить за тем, чтобы в процессе преобразования общность получаемых выражений не увеличивалась. Т.е.То есть трансформацию надо осуществлять от общего к частному.
 
=== Второй закон информатики ===
 
* Существуют [[w:Алгоритмическая неразрешимость|неразрешимые задачи]].
* Не существует эффективной реализации для [[w:Декларативный язык программирования|декларативных языков]], если они универсальны.
 
'''Концепция трансформационного синтеза:''' позволить программисту писать определения функций, не заботясь об их эффективности.
 
Однако было доказано, что по [[w:Язык спецификаций|языку спецификаций]] невозможно выработать (т.е.то есть трансформировать исходный текст) вариант функции, работающий эффективно. Если в качестве языка спецификаций рассматривать функциональный язык, то становится понятно, что программист сам должен заботиться об эффективности своих программ — концепция трансформационного синтеза здесь не пройдетпройдёт.
 
== Частичные вычисления ==
 
Пусть <math>P</math> и <math>S</math> — два языка, работающих со строками символов (это не нарушает общности рассуждений), а <math>\mathbf P</math> и <math>\mathbf S</math>[[w:Множество|множества]] синтаксически правильных программ на соответствующих языках. <math>D</math>[[w:Домен (базы данных)|домен]] всевозможных символьных последовательностей.
 
<math>P :: D \to (D^* \to D)</math>
 
Если <math>p</math> — программа из <math>\mathbf P</math>, то:
 
<math>P (p) :: D^* \to D</math>
 
<math>P (p) (<d1\langle d_1,\, ...\dots,\, dn>d_n \rangle) = d</math>, и <math>d \in D</math>
 
<math>P (r) (<y1\langle y_1,\, ...\dots,\, yn>y_n \rangle) = P (p) (<d1\langle d_1,\, ...\dots,\, dmd_m,\, y1y_1,\, ...\dots,\, yn>y_n \rangle)</math>
 
В последнем равенстве переменными yi<math>y_i</math> обозначены неизвестные данные. Для программы <math>p</math> эти <math>n</math> [[w:Переменная (программирование)|переменных]] представляют остаточный код.
 
Частичным вычислителем MIX называется программа из <math>\mathbf P</math> (хотя, частичный вычислитель может быть реализован на любом языке), такая, что:
 
<math>\forall p \in \mathbf P,\, p(x_1,\, \dots,\, x_m,\, x_{m+1},\, \dots,\, x_n) : P(\mathrm{MIX})(\langle p,\, d_1,\, \dots,\, d_m \rangle) = r</math>.
.
 
Т.е.То есть MIX — это программа, которая, получив некоторую исходную программу и данные для её известных параметров, выдаёт остаточную программу для исходной.
 
Интерпретатором языка <math>S</math> называется программа <math>\mathrm{INT} \in \mathbf P,</math> такая, что:
 
<math>\forall s \in \mathbf S,\, \langle d_1,\, \dots,\, d_n \rangle \in D^* : P(\mathrm{INT})(\langle s,\, d_1,\, \dots,\, d_n \rangle) = S(s)(\langle d_1,\, \dots,\, d_n \rangle)</math>.
.
 
Компилятором языка <math>S</math> называется программа <math>\mathrm{COMP} \in \mathbf P,</math> такая, что:
 
<math>P(\mathrm{COMP})(\langle s \rangle) = \mathrm{TARGET}</math>
.
 
<math>P(\mathrm{TARGET})(\langle d_1,\, \dots,\, d_n \rangle) = S(s)(\langle d_1,\, \dots,\, d_n \rangle)</math>.
 
Или, что то же:
 
<math>P \Big( P(\mathrm{COMP})(\langle s \rangle) \Big) (\langle d_1,\, \dots,\, d_n \rangle) = S(s)(\langle d_1,\, \dots,\, d_n \rangle)</math>.
.
 
Компилятором компиляторов языка <math>S</math> называется программа <math>\mathrm{COCOM} \in \mathbf P,</math> такая, что:
 
<math>P(\mathrm{COCOM})(\langle \mathrm{INT} \rangle) = \mathrm{COMP}</math>
Компилятором компиляторов языка S называется программа COCOM  P, такая что:
 
<math>P \biggr( P \Big( P(\mathrm{COCOM})(\langle \mathrm{INT} \rangle) \Big) (\langle s \rangle) \biggr) (\langle d_1,\, \dots,\, d_n \rangle) = S(s)(\langle d_1,\, \dots,\, d_n \rangle)</math>.
.
 
=== Проекции Футаморы[[w:Йошихико Футамура|Футамуры]] ===
 
* <math>\mathrm{TARGET} = P (\mathrm{MIX}) (<\langle \mathrm{INT},\, s> \rangle)</math>
* <math>\mathrm{COMP} = P (\mathrm{MIX}) (<\langle \mathrm{MIX},\, \mathrm{INT>} \rangle)</math>
* <math>\mathrm{COCOM} = P (\mathrm{MIX}) (<\langle \mathrm{MIX},\, \mathrm{MIX>} \rangle)</math>
 
Строго говоря, эти три утверждения являются [[w:Теорема|теоремами]], которые, однако, вполне легко [[w:Математическое доказательство|доказываются]] при помощи определений, данных выше.