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

14
1 Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления. 4.2. Рекурсия в лямбда-исчислении fac = λn.(if (= n 0) 1 (* n (fac (- n 1)))) FB = λf.λn.(if (= n 0) 1 (* n (f (- n 1)))) Найти fac такой, что fac = FB fac Существует ли функция Y такая, что fac = Y FB ? Y F = F (Y F) Y-комбинатор; комбинатор фиксированной точки. Лямбда-выражение для Y-комбинатора: Y = λh.(λx.h (x x))(λx.h (x x)) Y F (λx.F (x x))(λx.F (x x)) F ((λx.F (x x))(λx.F (x x))) F (Y F) Тогда функция fac может быть записана с помощью выражения Y FB (λh.(λx.h (x x))(λx.h (x x))) (λf.λn.(if (= n 0) 1 (* n (f (- n 1))))) Это выражение неприводимо к нормальной форме!

description

4.2. Рекурсия в лямбда-исчислении. fac = λ n .( if (= n 0) 1 (* n ( fac (- n 1)))). FB = λ f . λ n .( if (= n 0) 1 (* n ( f (- n 1)))). Найти fac такой, что fac = FB fac. Существует ли функция Y такая, что fac = Y FB ?. Y F = F ( Y F ). - PowerPoint PPT Presentation

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

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

1Кубенский А.А. Функциональное программирование.Глава 4. Основы лямбда-исчисления.

4.2. Рекурсия в лямбда-исчислении

fac = λn.(if (= n 0) 1 (* n (fac (- n 1))))

FB = λf.λn.(if (= n 0) 1 (* n (f (- n 1))))

Найти fac такой, что fac = FB fac

Существует ли функция Y такая, что fac = Y FB ? Y F = F (Y F)

Y-комбинатор; комбинатор фиксированной точки.

Лямбда-выражение для Y-комбинатора: Y = λh.(λx.h (x x))(λx.h (x x))

Y F(λx.F (x x))(λx.F (x x))F ((λx.F (x x))(λx.F (x x)))F (Y F)

Тогда функция fac может быть записана с помощью выраженияY FB(λh.(λx.h (x x))(λx.h (x x))) (λf.λn.(if (= n 0) 1 (* n (f (- n 1)))))

Это выражение неприводимо к нормальной форме!

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

2Кубенский А.А. Функциональное программирование.Глава 4. Основы лямбда-исчисления.

Пример работы рекурсии, выраженной с помощью Y-комбинатора

fac 2

(Y FB) 2

FB ((Y FB)) 2 FB = λf.λn.(if (= n 0) 1 (* n (f (- n 1))))

(λn.(if (= n 0) 1 (* n ((Y FB) (- n 1))))) 2

if (= 2 0) 1 (* 2 ((Y FB) (- 2 1)))

* 2 ((Y FB) (- 2 1))

* 2 ((λn.(if (= n 0) 1 (* n ((Y FB) (- n 1))))) (- 2 1))

* 2 (if (= (- 2 1) 0) 1 (* (- 2 1) ((Y FB) (- (- 2 1) 1))))

* 2 (* 1 ((Y FB) (- (- 2 1) 1)))

* 2 (* 1 ((λn.(if (= n 0) 1 (* n ((Y FB) (- n 1))))) (- (- 2 1) 1)))

* 2 (* 1 (if (= 0 0) 1 (* (- (- 2 1) 1) ((Y FB) (- (- (- 2 1) 1) 1)))))

* 2 (* 1 1)

2

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

3Кубенский А.А. Функциональное программирование.Глава 4. Основы лямбда-исчисления.

Взаимно рекурсивные функции

f1 = F1(f1,...,fn)f2 = F2(f1,...,fn)

fn = Fn(f1,...,fn)...

T = (f1,...,fn)

TUPLE-n – набор функций кортежирования

T = TUPLE-n f1 ... fn

INDEX – функция индексации

fi = INDEX i T

T = TUPLE-n F1(INDEX 1 T,..., INDEX n T) ... Fn(INDEX 1 T,..., INDEX n T)

Это обычная функция с прямой рекурсией, которая может быть выражена с помощью Y-комбинатора:

Y (λT.TUPLE-n F1 ... Fn)

а каждая из функций fi получается применением к этому выражению функции индексации:

fi = INDEX i (Y (λT.TUPLE-n F1 ... Fn))

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

4Кубенский А.А. Функциональное программирование.Глава 4. Основы лямбда-исчисления.

4.3. Чистое лямбда-исчисление

Чистое лямбда-исчисление – это исчисление без констант и встроенных функций.Соответственно, отсутствует и δ-редукция; есть только λ-выражения и β-редукция.

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

1. Функция IF, логические значения и булевы функции.IF p e1 e2 p e1 e2TRUE e1 e2 e1FALSE e1 e2 e2

TRUE = λx.λy.xFALSE = λx.λy.yIF = λp.λx.λy.p x yAND = λp.λq.p q FALSEOR = λp.λq.p TRUE qNOT = λp.p FALSE TRUE

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

5Кубенский А.А. Функциональное программирование.Глава 4. Основы лямбда-исчисления.

2. Списки и основные функции обработки списков.

4.3. Чистое лямбда-исчисление (продолжение)

NULL (CONS A B) FALSE NULL = λt.t (λx.λy.FALSE)NULL NIL TRUE NIL = λx.TRUE

проверка: NULL NIL (λt.t (λx.λy.FALSE))(λx.TRUE) (λx.TRUE)(λx.λy.FALSE) TRUE

CONS A B λs.s A B CONS = λx.λy.λs.s x yCAR (λs.s A B) ACDR (λs.s A B) B

CAR = λt.t TRUECDR = λt.t FALSE

проверка: CAR (CONS A B) CAR ((λx.λy.λs.s x y) A B) CAR (λs.s A B) (λt.t TRUE)(λs.s A B) (λs.s A B) TRUE TRUE A B A

Дополнительные функции обработки списков

JOIN = λp.λq.IF (NULL p) q (CONS (CAR p) (JOIN (CDR p) q))избавляемся от явной рекурсии с помощью Y-комбинатораJOIN = Y (λf.λp.λq.IF (NULL p) q (CONS (CAR p) (f (CDR p) q)))

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

6Кубенский А.А. Функциональное программирование.Глава 4. Основы лямбда-исчисления.

3. Целые числа и арифметика.3а. Представление в виде списков (подсчет элементов списка).

4.3. Чистое лямбда-исчисление (продолжение)

0 = NILSUCC = λn.CONS NIL nPRED = CDR

n = (CONS NIL (CONS NIL (... NIL)))

n разEQ0 = NULLНа базе этих основных функций можно построить всю арифметику.

3б. Функциональное представление (подсчет применений функции).

0 = λf.λx.x n = λf.λx.(f (f (... x)))

n разSUCC = λn.λf.λx.(f (n f x))PLUS = λm.λn.(m SUCC n)MULT = λm.λn.(m (PLUS n) 0)EQ0 = λn.(n (λx.FALSE) TRUE)PRED = λn.λf.λx.(n (λg.λh.(h (g f))) (λu.x) (λu.u))

проверка: PRED 0 λf.λx.(0 (λg.λh.(h (g f))) (λu.x) (λu.u)) λf.λx.((λu.x) (λu.u)) λf.λx.x 0

Проверим, что PRED 1 = 0:

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

7

PRED = λn.λf.λx.(n (λg.λh.(h (g f))) (λu.x) (λu.u)) 1 = λf.λx.(f x)

Вычитание

PRED 1 = λf.λx.((λf.λx.(f x)) (λg.λh.(h (g f))) (λu.x) (λu.u)) PRED 1 = λf.λx.(((λg.λh.(h (g f))) (λu.x)) (λu.u)) PRED 1 = λf.λx.((λh.(h ((λu.x) f))) (λu.u)) PRED 1 = λf.λx.((λh.(h x)) (λu.u)) PRED 1 = λf.λx.((λu.u) x)PRED 1 = λf.λx.x = 0

Преимущество функционального представления состоит в том, что основные арифметические.операции и операции сравнения удается записать без рекурсии.

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

8Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

Глава 5. Системы исполнения функциональных программ5.1. Интерпретаторы и компиляторы.

Программа(функция)

Аргументы

Результатприменения

функцииИнтерпретатор

Схема интерпретации

Исходнаяпрограмма(функция)

Компилятор

Результирующая(эквивалентная)

программа

Схема компиляции

В обоих случаях исходная функция служит в качестве входных данных;в случае компиляции результатом также является функция.

Для получения результата необходима интерпретацияаппаратным или программным интерпретатором.

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

9Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

5.2. Представление функциональных программ.

Вводим простой функциональный язык – расширенное лямбда-исчисление;покажем, что все основные конструкции языка типа Haskell могут быть легко скомпилированы в это расширенное лямбда-исчисление.

1. Константы – целые числа, логические значения. c : 0 25 TRUE

2. Константы – примитивные функции. f : + = IF TUPLE-n INDEX

3. Лямбда-выражения. (λx.e) : λx.+ x x

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

(e1 e2) : (λx.+ x x) 2

5. Простой блок. (let x = e1 in e2) :let f = (λx.+ x x) in (f 2)

6. Рекурсивный блок. (letrec x1 = e1; x2 = e2; ... xn = en in e) :

letrec f = λn.IF (= n 0) 1 (* n (f (- n 1))) in (f 5)

Таким образом, в чистое лямбда-исчисление введены константы, функции, связывание имен со значениями и рекурсия.

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

10Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

5.2. Представление функциональных программ.

Компиляция с языка Haskell в расширенное лямбда-исчисление.

1. Исключаем все конструкции, связанные с определением и контролем типов:type, data, ::, class, instance

2. Многие конструкции переводятся (почти) без изменения:константа: c c

примитивная функция: f fлямбда-выражение: (\x->e) (λx.e'), где e' – результат компиляции e

переменная: x x

применение функции: (e1 e2) (e1' e2'); e1+e2 (+ e1' e2')блоки: (e where f = e1) (let f = e1' in e')

3. Кортежи переводятся в применения примитивной функции TUPLE-n:

кортеж: (e1, e2, e3) (TUPLE-3 e1' e2' e3')4. Применение конструкторов переводится в применение примитивной функции TUPLE-n, первым аргументом которого служит номер конструктора в определении типа:

например: [3] 3 : [] (TUPLE-3 1 3 (TUPLE-1 0))5. Многие конструкции, такие как фильтры, арифметические прогрессии и т.п. переводятся в вызовы соответствующих примитивных функций.

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

11Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

Компиляция с языка Haskell в расширенное лямбда-исчисление.

6. Определения функций, включающие образцы и условия, сначала переводятся в лямбда-выражения, содержащие конструкцию case в определяющем выражении.

например: assoc x ((y,e):lst) | x == y = e| otherwise = assoc x lst

assoc x [] = []

переходит в: assoc = \a1 -> \a2 -> case (a1, a2) of (x, ((y,e):lst)) | x == y -> e | otherwise -> assoc x lst (_, []) -> []

Конструкция case затем транслируется в расширенное лямбда-исчисление (далее).

7. Программный модуль (серия определений) транслируется в заголовок блока letrec.

name_1 = expr_1name_2 = expr_2

...name_k = expr_k

letrec name_1 = expr_1';

name_2 = expr_2';...

name_k = expr_k' in

Перед исполнением программы вычисляемое выражение компилируется и помещается в блок letrec после in.

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

12Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

Компиляция case-выраженияcase param of pattern_1 | cond_11 -> expr_11 | cond_12 -> expr_12 ... pattern_2 | cond_21 -> expr_21 ... ... pattern_k | cond_k1 -> expr_k1 ...

letrec f1 = λa.IF (образец_1) let (связывание_1) in IF cond_11' expr_11' IF cond_12' expr_12' ... (f2 a) (f2 a) f2 = λa.IF (образец_2) let (связывание_2) in IF cond_21' expr_21' IF cond_22' expr_22' ... (f3 a) (f3 a) ... fk = λa.IF (образец_k) ... error errorin f1 param'

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

13Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

Компиляция сопоставления с образцом и связыванияcase arg@(x, y) of ([], (e:_)) -> expr

Аргумент arg, удовлетворяющий образцу, должен иметь вид:

( [], ( (:) e _ ))(TUPLE-2 (TUPLE-1 0) (TUPLE-3 1 e foo))

(AND (EQ (INDEX 1 (INDEX 1 arg)) 0) (EQ (INDEX 1 (INDEX 2 arg)) 1))arg[1,1] == 0 && arg[2,1] == 1

Возможно также сопоставление с константой:

case arg of [25] -> expr

((:) 25 [])arg[1] == 1 && arg[2] == 25 && arg[3,1] == 0

Связывание:

x = arg[1]; y = arg[2]; e = arg[2,2]

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

14Кубенский А.А. Функциональное программирование.Глава 5. Системы исполнения функциональных программ.

Представление программ расширенного лямбда-исчисленияdata Expr = Integral Integer | Logical Bool -- константы

| Function String -- примитивные функции| Variable String -- переменные| Lambda String Expr -- лямбда-выражение| Application Expr Expr -- применение функции| Let String Expr Expr -- простой блок| Letrec [(String, Expr)] Expr -- рекурсивный блок

например: let plus = (λx.λy.x+y) in (plus 1 2)будет представлено в виде:

(Let "plus" (Lambda "x" (Lambda "y" (Application (Application (Function "+") (Variable "x")) (Variable "y")))) (Application (Application (Variable "plus") (Integral 1)) (Integral 2)))