Введение в функциональное
программирование

ivan.glushkov@gmail.com!
@gliush

31.01.2014
Императивное программирование
✤

Последовательность модификаций состояния!

✤

начальное значение 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)) …)!

✤

Достаточно определить

suc

iszero

чтобы поддержать

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 :: a

S 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 : 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]
real world функции
✤

как в чисто функциональном языке сделать print?!

✤

сравнение функции random:

/* c-like, нет входа, случайный результат */

long random(void); 



- - haskell: generator as input, new generator as output

random :: RandomGen g => g -> (a, g)
Введение в haskell
✤

статическая типизация:

тип объекта фиксируется в момент компиляции!

✤

строгая типизация (imp. статическая типизация):

строго определенные типы для любых операций

присваивание переменной только значения того же типа

не допускается неявное преобразование типов!

✤

чистый язык: детерменированность и отсутствие
побочных эффектов
Синтаксис 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
Введение в 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] -> 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]
Вопросы?

✤

ivan.glushkov@gmail.com!

✤

facebook: gliush!

✤

twitter: @gliush

fp intro

  • 1.
  • 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.
    Введение в haskell2 ✤ элементарные типы: Int, Bool, Char, Float! ✤ Конструкторы типов: кортежи (tuples), списки,
 random :: g -> (a,g)
 map :: (a->b) -> [a] -> [b]! ✤ алгебраические типы данных (ADT):
 data Maybe a = Just a | Nothing!
  • 22.
    haskell tools ! ✤ hoogle search! ✤ ghcirepl! ✤ ghc compiler extensions
  • 23.
  • 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]
  • 25.