160 likes | 285 Vues
Глава 5 . Системы исполнения функциональных программ. 5 . 3. Функциональные модели последовательных процессов. Рассмотрим простой язык императивного программирования без функций, переходов и сложных структур данных. Выражения:. 12 25 0. Целые числа:. x myInt.
E N D
Глава 5. Системы исполнения функциональных программ 5.3. Функциональные модели последовательных процессов Рассмотрим простой язык императивного программирования без функций, переходов и сложных структур данных. Выражения: 12 25 0 • Целые числа: x myInt • Простые переменныецелого типа: (x+12) * (y-1) • Унарные и бинарные операции с целыми результатами: not (x < 5) • Логические константы и выражения (но не переменные): Операторы: • Пустой оператор: skip • Присваивание: x := x+1 • Последовательное исполнение: begin s1; s2; ... end • Условный оператор: if b then s1 else s2 • Оператор цикла: while b do s Программа начинает работу в состоянии, заданном совокупностью значений переменных(например, заданных оператором ввода данных), а результат программы – конечное состояние(например, выведенное в конце работы оператором вывода). Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.
Пример программы. Рассмотрим программу вычисления факториала. begin f := 1; while n > 1 do begin f := f * n; n := n – 1 endend В начальном состоянии существенно только значение переменной n; в конце работы результат определяется значением переменной f. Прежде всего, переведем программу в вид, удобный для обработки. data Expression = { представление выражений }data Operator = { представление операторов }data Context = { представление контекста переменных } Два способа обработки и исполнения программы: • Интерпретация: interpret :: Operator -> Context -> Context • Компиляция: compile :: Operator -> (Context -> Context) На самом деле оба способа представлены одной и той же карринговой функцией! Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.
Представление выражений и программ. data Expression = Integral Int | Logical Bool | Variable String | Unary String Expression | Binary Expression String Expression data Operator = Skip | Assignment String Expression | Sequence [Operator] | If Expression Operator Operator | While Expression Operator type Context = [(String, Expression)] interpret :: Operator -> Context -> Context eval :: Expression -> Context -> Expression intrinsic :: String -> [Expression] -> Expression eval v@(Integral n) _ = veval v@(Logical b) _ = veval (Variable x) ctx = assoc x ctxeval (Unary op ex) ctx = intrinsic op [eval ex ctx]eval (Binary e1 op e2) ctx = intrinsic op [eval e1 ctx, eval e2 ctx] intrinsic "+" [(Integral a), (Integral b)] = Integral (a+b) intrinsic "-" [(Integral a)] = Integral (-a) intrinsic "and" [(Logical a), (Logical b)] = Logical (a && b) Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.
Исполнение операторов. replace :: String -> Expression -> Context -> Context replace x val = map (\(y,v) -> (y,if x == y then val else v)) Например: replace "f" (Integral 20) [("n", (Integral 4)), ("f", (Integral 5))] даст в результате [("n", (Integral 4)), ("f", (Integral 20))] interpret :: Operator -> Context -> Context interpret Skip ctx = ctxinterpret (Assignment x expr) ctx = replace x (eval expr ctx) ctxinterpret (Sequence []) ctx = ctxinterpret (Sequence (s:seq)) ctx = interpret (Sequence seq) (interpret s ctx)interpret (If expr s1 s2) ctx = case (eval expr ctx) of (Logical True) -> interpret s1 ctx (Logical False) -> interpret s2 ctxinterpret oper@(While expr s) ctx = case (eval expr ctx) of (Logical True) -> interpret oper (interpret s ctx) (Logical False) -> ctx Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.
Пример компиляции и исполнения программы begin f := 1; while n > 1 do begin f := f * n; n := n – 1 endend program = Sequence [(Assignment "f" (Integral 1)), (While (Binary (Variable "n") ">" (Integral 1)) (Sequence [(Assignment "f" (Binary (Variable "f") "*" (Variable "n"))), (Assignment "n" (Binary (Variable "n") "-" (Integral 1)))])) ] compile program - функция преобразования контекстов interpret program [("f", (Integral 0)), ("n", (Integral 3))] [("f", (Integral 6)), ("n", (Integral 0))] Кубенский А.А. Функциональное программирование. Глава 5. Системы исполнения функциональных программ.
Глава 6. Введение в редукцию графов 6.1. Представление лямбда-выражений в виде графов Будем исходить из представления программ в виде структур данных расширенного лямбда-исчисления. Наша основная задача – корректно представить концепцию разделения переменных. Константа c. c Примитивная функция f. f λ Лямбда-выражение λx.E. x E @ Применение функции E1E2. E1 E2 C Применение конструктора C x y z. x y z Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Представление лямбда-выражений в виде графов (продолжение). Особенности представления некоторых типов выражений. Частичное применений примитивных функций и конструкторов. 1+2 + 1 2 + 1 @ @ @ 2 + 1 + 1 : 1 lst : 1 1:lst λ : @ или : t 1 lst 1 : 1 t Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Представление лямбда-выражений в виде графов (продолжение). Блоки let x = E1 in E2иletrec x1 = E1;... xk = Ek in E. let x = E1 in E2 (λx.E2) E1 @ λ E1 x E2 letrec x1 = E1;... xk = Ek in E – моделируется с помощью циклических графов. Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Примерпредставления выражения в виде графа. let twice = λf.λx.f (f x) in twice (λx.+ x 1) 2 (λf.λx.f (f x)) (λx.+ x 1) 2 @ @ 2 λ λ @ λ x f x @ @ 1 @ f + x f x Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Правила редукции графов. @ λ x @ @ 2 succ succ x x • Нахождение самого левого из самых внешних редексов: проход по «левому гребню» графа. • Копирование тела лямбда-выражения. • Подстановка аргумента вместо свободных вхождений переменной лямбда-выражения в тело. • Замещение в дереве @-узла результатом «вычислений». Некоторые особенности этой процедуры: • Тело лямбда-выражения копируется, чтобы его можно было переиспользовать; «мусор» удаляется • Подстановка аргументов производится с помощью установки ссылок; тем самым производится эффективное разделение переменных • Результат редукции замещает редуцируемое выражение, тем самым все ссылки на этот результат будут иметь новое значение Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Примерредукции графов. (λf.λx.f (f x)) (λx.+ x 1) 2 @ @ 2 λ λ @ λ x f x @ @ 1 @ f + x f x Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Примерредукции графов. (λf.λx.f (f x)) (λx.+ x 1) 2 4 @ @ 3 2 λ @ @ x @ @ 1 1 x + + Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
δ-редукция в графовом представлении Если при проходе по левому гребню находим константу, то это – примитивная функция @ @ @ + 12 @ 2 6 * 3 - сначала выполняем редукцию всех строгих аргументов; - потом формируем результат в соответствии с правилами этой примитивной функции; - результат замещает собой корень редекса. Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Общий алгоритм редукции графов (пока без учета рекурсии) while (выражение не находится в СЗНФ) {спуск от корня по левому гребню до первой вершины, отличной от @-вершины;switch (тип вершины) {case(примитивная функция):if (число аргументов k> числа пройденных @-вершин) выражение находится в СЗНФ;else {редуцировать все строгие аргументы; сформировать результат согласно правилам примитивной функции; заменить k-ю @-вершину этим результатом;}break;case (λ-вершина):if (выше нет @-вершин) выражение находится в СЗНФ;else { создать копию тела с подстановкой (разделяемого) аргумента вместо свободных вхождений переменной λ-выражения; подставить результат вместо вершины редекса (первая @-вершина вверх по гребню); }break;default: // константа-значение или конструктор if (выше нет @-вершин) выражение находится в СЗНФ;else ошибка типа !break; }} Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Использование вершин-синонимов При выполнении редукций есть одна проблема, связанная с копированием: в теле функциипеременная может быть в корне. Тогда вместо подстановки ссылки на аргумент придется делатькопию вершины, представляющей аргумент. @ Θ λ @ @ x x x @ 2 + 1 Можно вместо копирования вершины создавать «вершину-синоним» - «прозрачную» по ссылкам. При прохождении вершины-синонима можно оптимизировать их количество, убирать двойные синонимы, заменять ссылки на синоним ссылками на саму вершину. Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.
Использование вершин-синонимов (продолжение) Аналогичная проблема возникает при применении примитивных функций-селекторов, которыене преобразуют, а просто выдают аргумент или его часть (например, headили tail). head (cons (head (cons 1 nil)) nil) @ Θ head : @ Θ nil head : nil 1 Кубенский А.А. Функциональное программирование. Глава 6. Введение в редукцию графов.