Upload
ivan-glushkov
View
578
Download
0
Embed Size (px)
DESCRIPTION
Введение в функциональное программирование, которое я рассказывал в #mcst
Citation preview
Императивное программирование
✤ Последовательность модификаций состояния!
✤ начальное значение S0 (входные значения)!
✤ конечное значение Sn (конечное значение)!
✤ модификация с помощью команд присваивания!
✤ Sn = f(S0)!
✤ абстрагирование от низкоуровневых деталей
Функциональное программирование
✤ вся программа - одно [матем.] выражение!
✤ выполнение - вычисление значения выражения!
✤ языковые конструкции для облегчения чтения и написания программ!
✤ абстрактная система для записи алгоритма -> перевод на императивный язык низкого уровня
Отличительные особенности ФП
✤ не используют “переменные”!
✤ нет оператора присваивания!
✤ нет циклов!
✤ функции - обычные значения!
✤ рекурсия!
✤ могут напрямую соответствовать матем. объектам
Примеры
✤ Всеми любимый пример “факториал”!
✤ Сама функция: foo n = if n == 0 then 1 else n * foo (n-1)!
✤ Матем. описание: f(n): n! n >= 0 ⏊ n < 0
Функции императивных языков
✤ значение зависит не только от аргументов!
✤ результатом могут быть побочные эффекты!
✤ два вызова могут приводить к разному результату!
✤ вывод: это не функции в математическом смысле
Лямбда-исчисление (lambda calculus)
✤ создана в начале 30х годов!
✤ формализация для написания программ!
✤ простая модель для рекурсии и вложенных сред!
✤ лямбда выражения (анонимные функции)!
Введение в лямбда-исчисление: лямбда-терм
✤ Переменные!
✤ Константы!
✤ Комбинации: применение функции S к аргументу T: (S T). И S и T - могут быть произвольными лямбда-термами!
✤ Абстракции произвольного лямбда терма S по переменной x: λ x . S!
✤ Exp = Var | Const | Exp Exp | λ Var . Exp!
✤ Представляется в виде дерева, а не строки. Поэтому любые договоренности написания - не часть формальной системы.
Введение в лямбда-исчисление: обзор
✤ Свободные и связанные переменные:S = (λ x y . x) (λ x . z x) => FV(S) = {z}, BV(S) = {x,y}!
✤ Подстановкиприменение λx.S к аргументу T дает S[x := T]!
✤ Каррирование (R -> R -> R) = (R -> (R -> R))(λ x y . x + y) 1 2 = (λ y . 1 + y) 2 = 1 + 2 = 3
Введение в лямбда-исчисление: преобразования
✤ Альфа-преобразование: λ x . S -> λ y . S [x := y], if y ∉ FV(T)!
✤ Бета-преобразование:(λ x .S) T -> S [x := T]!
✤ Эта-преобразование: λ x . T x -> T, if x ∉ FV(T)!
✤ позволяют переходить к эквивалентному терму!
✤ равенство лямбда-термов!
✤ редукция лямбда-термов, в том числе к “нормальной” форме
Введение в лямбда-исчисление: пример Bool значений и условий
✤ Bool - тип, представляющий функцию от двух переменныхtrue ~> λ x y . x false ~> λ x y . y!
✤ if E then E1 else E2 ~> E E1 E2 Пример:if true then E1 else E2 = true E1 E2 = (λ x y . x) E1 E2 = λ y . E1 = E1!
✤ not p = if p then false else true p and q = if p then q else false p or q = if p then true else q
Введение в лямбда-исчисление: пример натуральных чисел
✤ Любое натуральное число N - это выполнение функции suc n раз: n = suc (suc (suc … (0)) …)!
✤ Достаточно определитьsuciszeroчтобы поддержатьm + n m * n pre n
Введение в лямбда-исчисление: типизация
✤ дают ясное представление о функции, если знать область определения и значений!
✤ эффективность (int8, int64) по mem и по cpu!
✤ статическая проверка программ!
✤ модульность и скрытие данных!
✤ позволяют обойти некоторые мат. противоречия
типизация в ЯП
✤ строгая типизация - мягкая типизацияint a[] = {1,2,3,4.0}; /* c - it’s ok */let a = [1,2,3,4.0] - - haskell - not ok A = [1,2,3,4,”hello”, [“world”]]. % erlang - it’s ok!
✤ динамическая типизация - статическая типизация!
✤ полиморфизм типов!
✤ автоматический вывод типов
Типизированное лямбда-исчисление
✤ Каждый лямбда-терм имеет тип!
✤ терм S можно применить к терму T, если их типы правильно соотносятся (сильная типизация): S :: a -> b T :: aS T :: b!
✤ Базовые типы: Int, Bool!
✤ Конструктор типов: Int; Bool; Bool -> Bool; [Bool] -> Bool
Отложенные (ленивые) вычисления
✤ (λ x . x + x + x) (10 + 5):(10 + 5) + (10 + 5) + (10 + 5) - нормальная редукция(15 + 15 + 15) - передача по значению!
✤ Передача по значению обычно более эффективна необходима для гибридных языков!
✤ Вызов по необходимости позволяет исп. ленивые вычисления!
✤ bottom = bottom - - Haskell: никогда не завершитсяconst1 x = 1 - - нет необходимости проверять аргументconst1 bottom -> 1 const1 (1/0) -> 1!
✤ Плата: снижение эффективности при сохранении отложенных вычислений
Пример ленивых вычислений
✤ ones = 1 : onesnumsFrom n = n : numsFrom (n+1) square x = x^2squres = map square (numsFrom 1)!
✤ take 5 (numsFrom 1) -> [1,2,3,4,5]!
✤ take 5 squares -> [1,4,9,16,25]
real world функции
✤ как в чисто функциональном языке сделать print?!
✤ сравнение функции random: /* c-like, нет входа, случайный результат */ long random(void); - - haskell: generator as input, new generator as outputrandom :: RandomGen g => g -> (a, g)
Введение в haskell
✤ статическая типизация: тип объекта фиксируется в момент компиляции!
✤ строгая типизация (imp. статическая типизация): строго определенные типы для любых операцийприсваивание переменной только значения того же типа не допускается неявное преобразование типов!
✤ чистый язык: детерменированность и отсутствие побочных эффектов
Синтаксис haskell
✤ идентификаторы: someFunction, foo, foo’, abc123. Каждому идентификатору можно сопоставить тип!
✤ Знаки операций, приоритеты между ними: + , - , * , / , ++!
✤ clause функций factorial 0 = 1 factorial n = n * factorial (n-1)!
✤ guardsfactorial n | n == 0 = 1 | otherwise = n * factorial (n - 1)!
✤ indentation!
✤ backquote:div 10 5 -> 2 10 `div` 5 -> 2
Введение в haskell 2
✤ элементарные типы: Int, Bool, Char, Float!
✤ Конструкторы типов: кортежи (tuples), списки, random :: g -> (a,g)map :: (a->b) -> [a] -> [b]!
✤ алгебраические типы данных (ADT): data Maybe a = Just a | Nothing!
haskell tools
!
✤ hoogle search!
✤ ghci repl!
✤ ghc compiler extensions
Недостатки
✤ сложность восприятия!
✤ gc mem!
✤ gc cpu
списки как пример простоты “ядра языка” haskell
✤ Поддержка - на уровне библиотек.!
✤ Работа со списками[] [1,2,3] 1:[2,3] [1,2] ++ [3](1:(2:(3:([]))))!
✤ map :: (a -> b) -> [a] -> [b]foldl :: (a -> b -> a) -> a -> [b] -> ahead :: [a] -> a tail :: [a] -> [a]length :: [a] -> Int null :: [a] -> Bool!
✤ foldl (+) 0 [1,2,3,4] -> 10 map (^2) [1,2,3,4] -> [1,4,9,16]head [1,2,3,4] -> 1 tail [1,2,3,4] -> [2,3,4]