2. Императивное программирование
✤
Последовательность модификаций состояния!
✤
начальное значение S0 (входные значения)!
✤
конечное значение Sn (конечное значение)!
✤
модификация с помощью команд присваивания!
✤
Sn = f(S0)!
✤
абстрагирование от низкоуровневых деталей
3. Функциональное программирование
✤
вся программа - одно [матем.] выражение!
✤
выполнение - вычисление значения выражения!
✤
языковые конструкции для облегчения чтения и
написания программ!
✤
абстрактная система для записи алгоритма ->
перевод на императивный язык низкого уровня
4. Отличительные особенности ФП
✤
не используют “переменные”!
✤
нет оператора присваивания!
✤
нет циклов!
✤
функции - обычные значения!
✤
рекурсия!
✤
могут напрямую соответствовать матем. объектам
5. Примеры
✤
Всеми любимый пример “факториал”!
✤
Сама функция:
foo n = if n == 0 then 1 else n * foo (n-1)!
✤
Матем. описание:
f(n):
n! n >= 0
n<0
6. Функции императивных языков
✤
значение зависит не только от аргументов!
✤
результатом могут быть побочные эффекты!
✤
два вызова могут приводить к разному результату!
✤
вывод: это не функции в математическом смысле
7. Лямбда-исчисление (lambda calculus)
✤
создана в начале 30х годов!
✤
формализация для написания программ!
✤
простая модель для рекурсии и вложенных сред!
✤
лямбда выражения (анонимные функции)!
8. Введение в лямбда-исчисление:
лямбда-терм
✤
Переменные!
✤
Константы!
✤
Комбинации: применение функции S к аргументу T: (S T). И S и T могут быть произвольными лямбда-термами!
✤
Абстракции произвольного лямбда терма S по переменной x: λ x . S!
✤
Exp = Var | Const | Exp Exp | λ Var . Exp!
✤
Представляется в виде дерева, а не строки. Поэтому любые
договоренности написания - не часть формальной системы.
9. Введение в лямбда-исчисление:
обзор
✤
Свободные и связанные переменные:
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
10. Введение в лямбда-исчисление:
преобразования
✤
Альфа-преобразование:
λ x . S -> λ y . S [x := y], if y ∉ FV(T)!
✤
Бета-преобразование:
(λ x .S) T -> S [x := T]!
✤
Эта-преобразование:
λ x . T x -> T, if x ∉ FV(T)!
✤
позволяют переходить к эквивалентному терму!
✤
равенство лямбда-термов!
✤
редукция лямбда-термов, в том числе к “нормальной” форме
11. Введение в лямбда-исчисление:
пример 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
12. Введение в лямбда-исчисление:
пример натуральных чисел
✤
Любое натуральное число N - это выполнение функции
suc n раз:
n = suc (suc (suc … (0)) …)!
✤
Достаточно определить
suc
iszero
чтобы поддержать
m + n
m * n
pre n
13. Введение в лямбда-исчисление:
типизация
✤
дают ясное представление о функции, если знать
область определения и значений!
✤
эффективность (int8, int64) по mem и по cpu!
✤
статическая проверка программ!
✤
модульность и скрытие данных!
✤
позволяют обойти некоторые мат. противоречия
14. типизация в ЯП
✤
строгая типизация - мягкая типизация
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!
✤
динамическая типизация - статическая типизация!
✤
полиморфизм типов!
✤
автоматический вывод типов
15. Типизированное лямбда-исчисление
✤
Каждый лямбда-терм имеет тип!
✤
терм S можно применить к терму T, если их типы
правильно соотносятся (сильная типизация):
S :: a -> b
T :: a
S T :: b!
✤
Базовые типы: Int, Bool!
✤
Конструктор типов: Int; Bool; Bool -> Bool; [Bool] -> Bool
16. Отложенные (ленивые) вычисления
✤
(λ 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!
✤
Плата: снижение эффективности при сохранении отложенных вычислений
17. Пример ленивых вычислений
✤
ones = 1 : ones
numsFrom n = n : numsFrom (n+1)
square x = x^2
squres = map square (numsFrom 1)!
✤
take 5 (numsFrom 1) -> [1,2,3,4,5]!
✤
take 5 squares -> [1,4,9,16,25]
18. real world функции
✤
как в чисто функциональном языке сделать print?!
✤
сравнение функции random:
/* c-like, нет входа, случайный результат */
long random(void);
- - haskell: generator as input, new generator as output
random :: RandomGen g => g -> (a, g)
19. Введение в haskell
✤
статическая типизация:
тип объекта фиксируется в момент компиляции!
✤
строгая типизация (imp. статическая типизация):
строго определенные типы для любых операций
присваивание переменной только значения того же типа
не допускается неявное преобразование типов!
✤
чистый язык: детерменированность и отсутствие
побочных эффектов
20. Синтаксис haskell
✤
идентификаторы: someFunction, foo, foo’, abc123.
Каждому идентификатору можно сопоставить тип!
✤
Знаки операций, приоритеты между ними:
+ , - , * , / , ++!
✤
clause функций
factorial 0 = 1
factorial n = n * factorial (n-1)!
✤
guards
factorial n | n == 0 = 1
| otherwise = n * factorial (n - 1)!
✤
indentation!
✤
backquote:
div 10 5 -> 2
10 `div` 5 -> 2
21. Введение в haskell 2
✤
элементарные типы: Int, Bool, Char, Float!
✤
Конструкторы типов: кортежи (tuples), списки,
random :: g -> (a,g)
map :: (a->b) -> [a] -> [b]!
✤
алгебраические типы данных (ADT):
data Maybe a = Just a | Nothing!
24. списки как пример простоты
“ядра языка” haskell
✤
Поддержка - на уровне библиотек.!
✤
Работа со списками
[]
[1,2,3]
1:[2,3]
[1,2] ++ [3]
(1:(2:(3:([]))))!
✤
map :: (a -> b) -> [a] -> [b]
foldl :: (a -> b -> a) -> a -> [b] -> a
head :: [a] -> a
tail :: [a] -> [a]
length :: [a] -> Int
null :: [a] -> Bool!
✤
foldl (+) 0 [1,2,3,4]
map (^2) [1,2,3,4]
head [1,2,3,4]
tail [1,2,3,4]
-> 10
-> [1,4,9,16]
-> 1
-> [2,3,4]