1 / 14

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

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 ).

ingrid
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 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 = YFB? YF= F (Y F) Y-комбинатор; комбинатор фиксированной точки. Лямбда-выражение дляY-комбинатора:Y = λh.(λx.h (x x))(λx.h (x x)) YF (λx.F (x x))(λx.F (x x)) F ((λx.F (x x))(λx.F (x x))) F (YF) Тогда функция facможет быть записана с помощью выраженияYFB(λh.(λx.h (x x))(λx.h (x x))) (λf.λn.(if (= n 0) 1 (* n (f (- n 1))))) Это выражение неприводимо к нормальной форме! Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления.

  2. Пример работы рекурсии, выраженной с помощью Y-комбинатора fac2 (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 Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления.

  3. Взаимно рекурсивные функции T = (f1,...,fn) f1 = F1(f1,...,fn) f2 = F2(f1,...,fn) TUPLE-n – набор функций кортежирования ... fn = Fn(f1,...,fn) 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)) Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления.

  4. 4.3. Чистое лямбда-исчисление Чистое лямбда-исчисление – это исчисление без констант и встроенных функций. Соответственно, отсутствует и δ-редукция; есть только λ-выражения и β-редукция. Покажем, что выразительная сила чистого лямбда-исчисления не меньше, чем утрадиционного функционального языка программирования. 1. Функция IF, логические значения и булевы функции. IF p e1 e2  p e1 e2 TRUE = λx.λy.x TRUE e1 e2  e1 FALSE = λx.λy.y FALSE e1 e2  e2 IF = λp.λx.λy.p x y AND = λp.λq.p q FALSE OR = λp.λq.p TRUE q NOT = λp.p FALSE TRUE Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления.

  5. 4.3. Чистое лямбда-исчисление (продолжение) 2. Списки и основные функции обработки списков. CONS A B λs.s A B CONS = λx.λy.λs.s x y CAR (λs.s A B)  A CAR = λt.t TRUE CDR (λs.s A B)  B CDR = λ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 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 Дополнительные функции обработки списков 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))) Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления.

  6. 4.3. Чистое лямбда-исчисление (продолжение) 3. Целые числа и арифметика. 3а. Представление в виде списков (подсчет элементов списка). 0 = NIL SUCC = λn.CONS NIL n n = (CONS NIL (CONS NIL (... NIL))) PRED = CDR nраз EQ0 = NULL На базе этих основных функций можно построить всю арифметику. 3б. Функциональное представление (подсчет применений функции). 0 = λf.λx.x n = λf.λx.(f (f (... x))) SUCC = λn.λf.λx.(f (n f x)) PLUS = λm.λn.(m SUCC n) 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: Кубенский А.А. Функциональное программирование. Глава 4. Основы лямбда-исчисления.

  7. Вычитание PRED = λn.λf.λx.(n (λg.λh.(h (g f))) (λu.x) (λu.u)) 1 = λf.λx.(fx) 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 Преимущество функционального представления состоит в том, что основные арифметические.операции и операции сравнения удается записать без рекурсии.

  8. Глава 5. Системы исполнения функциональных программ 5.1. Интерпретаторы и компиляторы. Программа(функция) Интерпретатор Результатпримененияфункции Аргументы Схема интерпретации Исходнаяпрограмма(функция) Компилятор Результирующая(эквивалентная)программа Схема компиляции В обоих случаях исходная функция служит в качестве входных данных; в случае компиляции результатом также является функция. Для получения результата необходима интерпретация аппаратным или программным интерпретатором. Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

  9. 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) Таким образом, в чистое лямбда-исчисление введены константы, функции, связывание имен со значениями и рекурсия. Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

  10. 5.2. Представление функциональных программ. Компиляция с языка Haskellв расширенное лямбда-исчисление. 1. Исключаем все конструкции, связанные с определением и контролем типов: type, data, ::, class, instance 2. Многие конструкции переводятся (почти) без изменения: константа: c c переменная:x x примитивная функция:f f лямбда-выражение:(\x->e) (λx.e'), гдеe'– результат компиляцииe применение функции:(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. Многие конструкции, такие как фильтры, арифметические прогрессии и т.п. переводятся в вызовы соответствующих примитивных функций. Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

  11. Компиляция с языка 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_1 letrec name_1 = expr_1'; name_2 = expr_2  name_2 = expr_2'; ... ... name_k = expr_k name_k = expr_k' in Перед исполнением программы вычисляемое выражение компилируется ипомещается в блок letrecпосле in. Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

  12. Компиляция 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' Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

  13. Компиляция сопоставления с образцом и связывания 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 argof [25] -> expr ((:) 25 []) arg[1] == 1 && arg[2] == 25 && arg[3,1] == 0 Связывание: x = arg[1]; y = arg[2]; e = arg[2,2] Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

  14. Представление программ расширенного лямбда-исчисления 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))) Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.

More Related