Урок 9. Комбинаторная редукция

15
1 Кубенский А.А. Функциональное программирование. Глава 7. Комбинаторная редукция. Глава 7. Комбинаторная редукция адача: избавиться от имен переменных (и, соответственно, лямбда-выражений) введением истого комбинаторного программирования, подобно тому, как это делалось в FP-системе. Введем следующие комбинаторы: Вычеркиватель (K): На самом деле тождественный комбинатор – лишний, легко убедиться, что I = S K K. S K K = λx.K x (K x) = λx.x = I K = λx.λy.x Распределитель (S): S = λf.λg.λx.f x (g x) Тождество (I): I = λx.x Для определения семантики этих комбинаторов нет нужды опираться на лямбда-выражения, лучше просто определить правила применения: S f g x = f x (g x) K x y = x I x = x еперь можно определить правила редукции графов, в которых нет лямбда выражений, а есть олько применения конструкторов и комбинаторов. Важно, что при этом можно избежать опирования, однако интенсивно используются вершины-синонимы, так как по крайней мере ва из трех введенных комбинаторов являются чистыми селекторами.

Upload: -mydls

Post on 28-Jul-2015

178 views

Category:

Education


3 download

TRANSCRIPT

Page 1: Урок 9. Комбинаторная редукция

1Кубенский А.А. Функциональное программирование.

Глава 7. Комбинаторная редукция.

Глава 7. Комбинаторная редукция

Задача: избавиться от имен переменных (и, соответственно, лямбда-выражений) введениемчистого комбинаторного программирования, подобно тому, как это делалось в FP-системе.

Введем следующие комбинаторы:

Вычеркиватель (K):

На самом деле тождественный комбинатор – лишний, легко убедиться, что I = S K K.

S K K = λx.K x (K x) = λx.x = I

K = λx.λy.x Распределитель (S): S = λf.λg.λx.f x (g x) Тождество (I): I = λx.x

Для определения семантики этих комбинаторов нет нужды опираться на лямбда-выражения,лучше просто определить правила применения:

S f g x = f x (g x)

K x y = x

I x = xТеперь можно определить правила редукции графов, в которых нет лямбда выражений, а естьтолько применения конструкторов и комбинаторов. Важно, что при этом можно избежатькопирования, однако интенсивно используются вершины-синонимы, так как по крайней мередва из трех введенных комбинаторов являются чистыми селекторами.

Page 2: Урок 9. Комбинаторная редукция

2Кубенский А.А. Функциональное программирование.

Покажем, что в самом деле можно любое замкнутое лямбда-выражение представить вкомбинаторной форме. Для этого сначала введем функцию абстрагирования abs(x, E) для комбинаторных выражений E такую, что

Правила абстрагирования от переменных

Глава 7. Комбинаторная редукция.

abs(x, E) x = E

Другими словами, abs(x, E) ведет себя точно так же, как λx.E.

Сокращенная запись для abs(x, E) – [x]E.

Очевидно, что:

[x]x = I

[x]c = K c

[x]y = K y

[x]e1 e2 = S ([x]e1) ([x]e2)S ([x]e1) ([x]e2) x = ([x]e1) x (([x]e2) x) = e1 e2

Теперь перевод любого лямбда выражения в комбинаторную форму можно производить последующим правилам:

comb(c) = c

comb(v) = v

comb(λx.e) = [x]comb(e)

comb(e1 e2) = comb(e1) comb(e2)

Page 3: Урок 9. Комбинаторная редукция

3Кубенский А.А. Функциональное программирование.

Пример перевода выражения в комбинаторную форму

Глава 7. Комбинаторная редукция.

Рассмотрим следующую функцию: λx.λy.+ x y. Заметим, что для этой функции существуеточень простая комбинаторная форма: +. Проведем преобразование этого лямбда-выражения.

comb(λx.λy.+ x y)= [x][y]comb(+ x y)= [x][y]comb(+) comb(x) comb(y)= [x][y]+ x y= [x]S ([y]+ x) ([y]y)= [x]S (S ([y]+) ([y]x)) ([y]y)= [x]S (S (K +) (K x)) I= S ([x]S (S (K +) (K x))) ([x]I)= S (S ([x]S) ([x](S (K +) (K x)))) (K I)= S (S (K S) (S ([x](S (K +)) ([x](K x))))) (K I)= S (S (K S) (S (S ([x]S) ([x](K +))) (S ([x]K) ([x]x)))) (K I)= S (S (K S) (S (S (K S) (S ([x]K) ([x]+))) (S (K K) I))) (K I)= S (S (K S) (S (S (K S) (S (K K) (K +))) (S (K K) I))) (K I)

Это самое сложное выражение для функции сложения в курсе. Проверим, что при примененииэтого выражения к константам, скажем, 2 и 3, мы действительно получим 5

Page 4: Урок 9. Комбинаторная редукция

4Кубенский А.А. Функциональное программирование.

Проверка правильности преобразования в комбинаторную форму.

Глава 7. Комбинаторная редукция.

S (S (K S) (S (S (K S) (S (K K) (K +))) (S (K K) I))) (K I) 2

= (S (K S) (S (S (K S) (S (K K) (K +))) (S (K K) I))) 2 ((K I) 2)

= S (K S) (S (S (K S) (S (K K) (K +))) (S (K K) I)) 2 (K I 2)

= (K S) 2 (S (S (K S) (S (K K) (K +))) (S (K K) I) 2) I

= K S 2 ((S (K S) (S (K K) (K +))) 2 (S (K K) I 2)) I

= S (S (K S) (S (K K) (K +)) 2 (K K 2 (I 2))) I

= S (K S 2 (S (K K) (K +) 2) (K 2)) I

= S (S (K K 2 (K + 2)) (K 2)) I

= S (S (K +) (K 2)) I

Здесь видно, как атомы «+» и «2» привязаны к комбинаторам K, «ожидая» применения ихко второму аргументу.

S (S (K +) (K 2)) I 3= S (K +) (K 2) 3 (I 3)= K + 3 (K 2 3) 3= + 2 3= 5

Page 5: Урок 9. Комбинаторная редукция

5Кубенский А.А. Функциональное программирование.

Оптимизация Карри

Глава 7. Комбинаторная редукция.

Если хочется упростить сложное комбинаторное выражение, то можно попробовать применитьэквивалентные преобразования выражений. Введем следующие правила.

S (K E1) (K E2) = K (E1 E2) (правило 1)

S (K E1) I = E1 (правило 2)

В корректности этих преобразований можно убедиться, установив, что при применении к одномуи тому же аргументу получается один и тот же результат.

S (K E1) (K E2) X = K E1 X (K E2 X) = E1 E2 = K (E1 E2) X

S (K E1) I X = K E1 X (I X) = E1 X

Еще один путь снизить сложность выражений – ввести дополнительные комбинаторы, например:

B F G X = F (G X) (композитор)

C F X Y = F Y X (перестановщик).

S (K E1) E2 = B E1 E2 (правило 3)

S E1 (K E2) = C E1 E2 (правило 4)

и дополнительные оптимизационные правила:

S (K E1) E2 X = K E1 X (E2 X) = E1 (E2 X) = B E1 E2 X

S E1 (K E2) X = E1 X (K E2 X) = E1 X E2 = C E1 E2 X

в справедливости которых можно убедиться путем следующих преобразований:

Page 6: Урок 9. Комбинаторная редукция

6Кубенский А.А. Функциональное программирование.

Оптимизация Карри

Глава 7. Комбинаторная редукция.

Попробуем проверить правила (1 – 4) на практике, преобразовав наше длинное выражение дляфункции сложения.

S (K E1) (K E2) = K (E1 E2) (правило 1)S (K E1) I = E1 (правило 2)S (K E1) E2 = B E1 E2 (правило 3)S E1 (K E2) = C E1 E2 (правило 4)

S (S (K S) (S (S (K S) (S (K K) (K +))) (S (K K) I))) (K I)= S (S (K S) (S (S (K S) (K (K +)) (S (K K) I))) (K I)

(правило 1)

(правило 2)

= S (S (K S) (S (S (K S) (K (K +)) K)) (K I) (правило 1)

= S (S (K S) (S (K (S (K +))) K)) (K I) (правило 4)

= C (S (K S) (S (K (S (K +))) K)) I (правило 3)

= C (B S (S (K (S (K +))) K)) I (правило 3)

= C (B S (B (S (K +)) K)) I

S (S (K +) (K 2)) I

Это выражение уже значительно короче, хотя и далеко от оптимального «+». Проверьте, чтопосле применения этого выражения к 2 получится то же, выражение, которое мы уже получалираньше

Page 7: Урок 9. Комбинаторная редукция

7Кубенский А.А. Функциональное программирование.

Оптимизация Карри (продолжение)

Глава 7. Комбинаторная редукция.

Правила оптимизации и новые комбинаторы можно ввести непосредственно в алгоритмпреобразования лямбда-выражений в комбинаторную форму.

При применении этих правил преобразования могут дать гораздо более простой результат.

[x]x = I

[x]c = K c

[x]y = K y

[x]e1 e2 | FST == K M && SND == I = M | FST == K M && SND == K N = K (M N) | FST == K M = B M SND | SND == K N = C FST N | otherwise = S FST SND where FST = [x]e1 SND = [x]e2

comb(λx.λy.+ x y) = [x][y]comb(+ x y)= [x][y]comb(+) comb(x) comb(y) = [x][y]+ x y

[y]+ = K +, [y]x = K x поэтому [y]+ x = K (+ x)

= K [x]+ x = + поскольку [x]+ = K +, [x]x = I

Page 8: Урок 9. Комбинаторная редукция

8Кубенский А.А. Функциональное программирование.

Аппликативные подвыражения

Глава 7. Комбинаторная редукция.

Заметим, что если в исходном лямбда-выражении уже имелись подвыражения, имеющиеаппликативный вид (e1 e2), то при его абстрагировании от переменной, не входящей в e1 e2свободно, мы можем и не получить «естественную» форму e1 e2. Например,

Лемма 1: при применении оптимизационного правила (1) для аппликативного выражения e

comb(λx.+ 1 2) = [x]comb(+ 1 2) = [x]+ 1 2= S (S (K +) (K 1)) (K 2)

при неоптимизированных преобразованиях. Компоненты аппликативного подвыраженияраспределяются по всему выражению.

Если применять правило (1) в оптимизации Карри, то выражение приобретет вид

K (+ 1 2)

Сохранение аппликативных подвыражений важно для оптимизации вычислений, посколькупозволяет разделять такие подвыражения более эффективно и сохранять «полную ленивость».

при условии, что x не входит свободно в e.

Доказательство (по индукции): если e – константа или переменная (не равная x), тоутверждение леммы справедливо по определению абстрагирования.

[x]e = K e

Если e = e1 e2, то

[x]e = [x]e1 e2 = S ([x]e1) ([x]e2) = S (K e1) (K e2) = = K (e1 e2) = K e

Page 9: Урок 9. Комбинаторная редукция

9Кубенский А.А. Функциональное программирование.

Аппликативные подвыражения

Глава 7. Комбинаторная редукция.

Лемма 2: если e1 является подвыражением аппликативного выражения e, то при вычислении[x]e с применением оптимизационного правила (1) e1 будет также подвыражением [x]e приусловии, что x не входит в e1 свободно.

Таким образом, справедлива теорема: при применении только правила (1) сохраняются всеаппликативные подвыражения исходного лямбда-выражения. Это утверждение такженесложно доказать по индукции.

Доказательство также несложно провести по индукции по структуре выражения e.

Действительно, comb(e) = e, если e – переменная или константа, а также, если оно самоявляется аппликативным выражением.

Далее, comb(e1 e2) = comb(e1) comb(e2), и аппликативное подвыражение сохраняетсяпо индукционному предположению.Наконец, comb(λx.e) = [x]comb(e), и аппликативное подвыражение сохраняетсяпо лемме (2).

Page 10: Урок 9. Комбинаторная редукция

10Кубенский А.А. Функциональное программирование.

В графах для комбинаторных выражений не будет лямбда-вершин, только вершины-константы,вершины-примитивы (включая базовые комбинаторы), и вершины-конструкторы.

Комбинаторная редукция графов

Глава 7. Комбинаторная редукция.

Преобразования таких графов (редукции) будут происходить с помощью применения «дельта-правил», которые надо определить в том числе и для всех базовых комбинаторов. Приятно,что при этом можно полностью избежать копирования.

Если аргументов для применения «дельта-редукции» недостаточно, то граф уже находитсяв СЗНФ. Правила применения базовых комбинаторов выглядят так:

@

I ee

@

e2e1

@

K e1

@

e3@

e2@

S e1

@

e3

@ e2

@

e1

Page 11: Урок 9. Комбинаторная редукция

11Кубенский А.А. Функциональное программирование.

Комбинаторная редукция графов

Глава 7. Комбинаторная редукция.

Правила применения дополнительных базовых комбинаторов B и C выглядят так:

@

e3@

e2@

C e1

@

e3

@ e2

e1

@

e3@

e2@

B e1

@

e3e2

@e1

Эти правила приведены в самом общем виде (без использования оптимизаций).

Мы исключили копирование, но при применении функций проекторов (в частности, I и K)придется по-прежнему создавать вершины-синонимы, если на аргументы есть ссылки.

Page 12: Урок 9. Комбинаторная редукция

12Кубенский А.А. Функциональное программирование.

Рекурсия

Глава 7. Комбинаторная редукция.

До сих пор мы рассматривали только выражения, не содержащие рекурсию. Рекурсию можнореализовать, если ввести в рассмотрение Y-комбинатор. Однако, если рассмотретьY-комбинатор Карри в его лямбда-выражении Y = λh.(λx.h (x x)) (λx.h (x x)), тооказывается, что его комбинаторное представление comb(Y) слишком сложное.

На самом деле рекурсия здесь использована «не по существу», но сути дела это не меняет.

Теперь построим графы этих выражений и выражения f 2, соединяя в месте «рекурсивных»вызовов.

Для непосредственно выраженной «плоской» рекурсии можно предложить два подхода:• зацикливание графов для рекурсивных выражений;• непосредственное введение правил преобразования графов для Y-комбинатора.

Пусть имеются две взаимно рекурсивные функции в следующем выражении:

letrec f = λx.cons x (g x) g = λx.cons (sqr x) (f x)in f 2

Прежде всего преобразуем все выражения в комбинаторную форму.

f = comb(λx.cons x (g x)) = [x](cons x (g x)) = S cons gg = [x]cons (sqr x) (f x) = S (B cons sqr) f

Page 13: Урок 9. Комбинаторная редукция

13Кубенский А.А. Функциональное программирование.

Рекурсия

Глава 7. Комбинаторная редукция.

Этот граф содержит циклические связи, однако его преобразование происходит по введеннымнами ранее правилам точно так же, как и для нециклических графов.

f = comb(λx.cons x (g x)) = [x](cons x (g x)) = S cons gg = [x]cons (sqr x) (f x) = S (B cons sqr) ff 2

@

sqr

@

cons

@

S

B

@

g@

S cons

@

f

2f

@

f 2

gf

Заметим, впрочем, что результатом работы будет бесконечный список.

Page 14: Урок 9. Комбинаторная редукция

14Кубенский А.А. Функциональное программирование.

Пример преобразования циклического графа

Глава 7. Комбинаторная редукция.

@

@

S cons @

sqr

@

cons

@

S

B

@

2

@

@

@

@

:

В ленивой схеме вычислений на этом вычисление заканчивается (получен циклический список)

Page 15: Урок 9. Комбинаторная редукция

15Кубенский А.А. Функциональное программирование.

Графическое представление Y-комбинатора

Глава 7. Комбинаторная редукция.

f = λx.letrec g = e1 in e2

Пусть имеем следующее определение функции.

где в выражении e1 имеются рекурсивные ссылки на g, а в выражении e2 – как на f, так и на g.

Из-за вложенной рекурсии трудно выполнить преобразование этого выражения в комбинаторнуюформу непосредственно, однако, можно воспользоваться Y-комбинатором.

f = Y λf.λx.(λg.e2)(Y λg.e1)

comb(f) = comb(Y λf.λx.(λg.e2)(Y λg.e1)) = Y [f][x]([g]comb(e2)) (Y [g]comb(e1))

Правило для «редукции» Y-комбинатора выглядит несколько необычно, так как создаетциклический граф, однако, это вполне адекватная форма вычислений на графах.

@

eY

@

e

Для прямой рекурсии в общем случае правило преобразования выглядит так:

comb(f = e) = Y [f]e