Введение в функциональное...
Transcript of Введение в функциональное...
Введение в функциональноепрограммирование
Михаил Беляев28 сентября 2016
1/38
Императивное программирование
• Программа — это набор инструкций,изменяющих состояние системы
• Всё остальное (процедуры, классы и т.д.) — лишьспособы абстракции
long factorial(long i) {long result = 1;while(i > 1) {
result = result * i;--i;
}return result;
}
2/38
Императивное программирование: более формально
Выполнение программы — это переход междусостояниямиσ0 → σ1 → σ2 → σ3 → σ4 → . . . → σs
3/38
Императивное программирование: языки
Как процедурные, так и объектные языкиНачиная от Fortran и Algol и заканчивая Java и C#
4/38
Функциональное программирование
• Программа — это выражение, которое можновычислить
• Способы абстракции бывают так же разными
long factorial(long i) {return (i <= 1)?
1 :i * factorial(i-1);
}
• Выполнение программы — это вычисление этоговыражения
5/38
Функциональное программирование: языки
Начиная от первых диалектов LISP до Haskell и F#
6/38
Декларативное программирование
• Функциональный стиль программирования —частный случай декларативного стиля
• Императивная программа отвечает на вопрос«как?»
• Декларативная программа отвечает на вопрос«что?»
7/38
Декларативное программирование
• Функциональный стиль программирования —частный случай декларативного стиля
• Императивная программа отвечает на вопрос«как?»
• Декларативная программа отвечает на вопрос«что?»
7/38
Современные языки
• Современные языки имеют широкийинструментарий для работы в стиле ФП
• Как в основном императивные, так и в основномфункциональные языки пришли к некоему«гибридному» состоянию
Модно, молодёжно: Rust, Swift, Kotlin, Scala, Go, etc.
• «Старые» языки последних стандартов тоже неостают Java 8, C++11/C++14, C# 4.X, etc.
8/38
Немного истории
В начале было слово?
LISP
• 1958 год• первый функциональный языкпрограммирования
• рекурсия, условные выражения, лямбда-функции• динамическая типизация• сборка мусора• крайне простой синтаксис
9/38
Немного истории
В начале было слово?LISP
• 1958 год• первый функциональный языкпрограммирования
• рекурсия, условные выражения, лямбда-функции• динамическая типизация• сборка мусора• крайне простой синтаксис
9/38
Немного истории
В начале было слово?LISP
• 1958 год• первый функциональный языкпрограммирования
• рекурсия, условные выражения, лямбда-функции• динамическая типизация• сборка мусора• крайне простой синтаксис
9/38
Пример кода на LISP
(defun (fibonacci (n))(if (or (= n 0) (= n 1))
1(+
(fibonacci (- n 1))(fibonacci (- n 2))
))
)
10/38
Ещё немного истории
В начале была буква!
11/38
Лямбда-исчисление
Алонзо Чёрч, 30е годы XX века
Два основных принципа — аппликация и абстракцияАбстракция через λ-терм:
λ x. <выражение над x>
Аппликация (применение функции к аргументу):
f x
Вычисление = «переписывание» термов:
(λ x. y) a → y[a/x]
«Заменить все вхождения x внутри y на а»
12/38
Лямбда-исчисление
Алонзо Чёрч, 30е годы XX векаДва основных принципа — аппликация и абстракция
Абстракция через λ-терм:
λ x. <выражение над x>
Аппликация (применение функции к аргументу):
f x
Вычисление = «переписывание» термов:
(λ x. y) a → y[a/x]
«Заменить все вхождения x внутри y на а»
12/38
Лямбда-исчисление
Алонзо Чёрч, 30е годы XX векаДва основных принципа — аппликация и абстракцияАбстракция через λ-терм:
λ x. <выражение над x>
Аппликация (применение функции к аргументу):
f x
Вычисление = «переписывание» термов:
(λ x. y) a → y[a/x]
«Заменить все вхождения x внутри y на а»
12/38
Лямбда-исчисление
Алонзо Чёрч, 30е годы XX векаДва основных принципа — аппликация и абстракцияАбстракция через λ-терм:
λ x. <выражение над x>
Аппликация (применение функции к аргументу):
f x
Вычисление = «переписывание» термов:
(λ x. y) a → y[a/x]
«Заменить все вхождения x внутри y на а»
12/38
Лямбда-исчисление
Алонзо Чёрч, 30е годы XX векаДва основных принципа — аппликация и абстракцияАбстракция через λ-терм:
λ x. <выражение над x>
Аппликация (применение функции к аргументу):
f x
Вычисление = «переписывание» термов:
(λ x. y) a → y[a/x]
«Заменить все вхождения x внутри y на а» 12/38
Лямбда-исчисление
• Можно ввести рекурсию через т.н. Y-комбинатор• Можно определить структуру данных — пару• Можно определить логические (Church booleans)и натуральные (Church numerals) значения
• Через натуральные числа можно определитьцелые и вещественные
На выходе имеем Тьюринг-полный языкпрограммирования
13/38
Лямбда-исчисление
• Можно ввести рекурсию через т.н. Y-комбинатор• Можно определить структуру данных — пару• Можно определить логические (Church booleans)и натуральные (Church numerals) значения
• Через натуральные числа можно определитьцелые и вещественные
На выходе имеем Тьюринг-полный языкпрограммирования
13/38
А потом уже был LISP
• 1958 год, Стив Рассел (Steve Russell)• LISt Processor• Lots of Irritating Stupid Parentheses• Lost In a Sea of Parentheses• etc.
14/38
LISP: базовый синтаксис
• Всё — это линейный список
• Программа это тоже линейный список
• Всего два служебных символа — «(» и «)».
Первый элемент списка — это функция, дальше — еёаргументы
(* (+ 1 1) (sin (/ pi 2)))
15/38
LISP: базовый синтаксис
• Всё — это линейный список
• Программа это тоже линейный список
• Всего два служебных символа — «(» и «)».
Первый элемент списка — это функция, дальше — еёаргументы
(* (+ 1 1) (sin (/ pi 2)))
15/38
LISP: базовый синтаксис
• Всё — это линейный список
• Программа это тоже линейный список
• Всего два служебных символа — «(» и «)».
Первый элемент списка — это функция, дальше — еёаргументы
(* (+ 1 1) (sin (/ pi 2)))
15/38
Дальше
• ML — Робин Милнер (Robin Milner) — 1970е• Вывод типов (Type inference)• Алгебраические типы данных
• Miranda — Девид Тёрнер (David Turner) — 1985• Call-by-name evaluation strategy (lazy evaluation)
16/38
Анекдот
Дано: существует важная задача X и 25 способов еёрешения.
Лучшие умы человечества собираются вместе чтобыраз и навсегда представить один самый лучшийспособ.Долгие годы работы, кропотливый труд, радостьсвершения.Итог: существует важная задача X и 26 способов еёрешения.
17/38
Анекдот
Дано: существует важная задача X и 25 способов еёрешения.Лучшие умы человечества собираются вместе чтобыраз и навсегда представить один самый лучшийспособ.
Долгие годы работы, кропотливый труд, радостьсвершения.Итог: существует важная задача X и 26 способов еёрешения.
17/38
Анекдот
Дано: существует важная задача X и 25 способов еёрешения.Лучшие умы человечества собираются вместе чтобыраз и навсегда представить один самый лучшийспособ.Долгие годы работы, кропотливый труд, радостьсвершения.
Итог: существует важная задача X и 26 способов еёрешения.
17/38
Анекдот
Дано: существует важная задача X и 25 способов еёрешения.Лучшие умы человечества собираются вместе чтобыраз и навсегда представить один самый лучшийспособ.Долгие годы работы, кропотливый труд, радостьсвершения.Итог: существует важная задача X и 26 способов еёрешения.
17/38
Язык Haskell
Решение о создании языка было принято наконференции на тему функциональногопрограммирования и компьютерной архитектуры(FPCA ’87) в Портленде, штат Орегон.
18/38
Haskell — 1990 — > 20 специалистов из TOP100 вобласти языков
• Вершина функциональной мысли на моментсоздания
• Чисто функциональный язык программирования• Строгая статическая типизация• Вывод типов• Ленивое выполнение
19/38
Текущее положение дел
• LISP продолжает развитие в виде BPCL, Racket,Clojure
• ML продолжает развитие в виде OCaml/F#
20/38
Последние годы: гибридизация
• Scala — EPFL — 2003• За основу взяли Java и Haskell• Попытка «поженить» ООП и ФП со стороны ООП
• F# — Microsoft — 2005• За основу взяли диалект ML под названием OCaml• Попытка «поженить» ООП и ФП со стороны ФП
• Swift/Rust/Kotlin и так далее• Все заявляют ФП как одну из основных «фишек»• На практике это неудачные попытки поисказолотой середины
21/38
Что же такое функциональное программирование
Что такое функция в программировании?
Что такое функция в математике?Чистая функция — это функция и в математическом,и в программном смыслеМожно ли написать что-то реально работающеетолько на чистых функциях?
22/38
Что же такое функциональное программирование
Что такое функция в программировании?Что такое функция в математике?
Чистая функция — это функция и в математическом,и в программном смыслеМожно ли написать что-то реально работающеетолько на чистых функциях?
22/38
Что же такое функциональное программирование
Что такое функция в программировании?Что такое функция в математике?Чистая функция — это функция и в математическом,и в программном смысле
Можно ли написать что-то реально работающеетолько на чистых функциях?
22/38
Что же такое функциональное программирование
Что такое функция в программировании?Что такое функция в математике?Чистая функция — это функция и в математическом,и в программном смыслеМожно ли написать что-то реально работающеетолько на чистых функциях?
22/38
Что же такое функциональное программирование
Чистая функция — это функция, не содержащаяпобочных эффектов
Всё является функциями, причём чистыми
• Переменных нет, есть только константы• Циклов нет — они бессмысленны без переменных
23/38
Что же такое функциональное программирование
Чистая функция — это функция, не содержащаяпобочных эффектовВсё является функциями, причём чистыми
• Переменных нет, есть только константы• Циклов нет — они бессмысленны без переменных
23/38
Что же такое функциональное программирование
Чистая функция — это функция, не содержащаяпобочных эффектовВсё является функциями, причём чистыми
• Переменных нет, есть только константы• Циклов нет — они бессмысленны без переменных
23/38
Побочные эффекты
• Любой ввод-вывод• Модификация внешнего состояния (глобальныеи локальные переменные)
Являются ли два определения чистой функциитождественными?Т.е. означает ли отсутствие побочных эффектов то,что для одних и тех же аргументов всегда будетвыдан один и тот же результат?
24/38
Побочные эффекты
• Любой ввод-вывод• Модификация внешнего состояния (глобальныеи локальные переменные)
Являются ли два определения чистой функциитождественными?Т.е. означает ли отсутствие побочных эффектов то,что для одних и тех же аргументов всегда будетвыдан один и тот же результат?
24/38
Функции — полноценные значения
• Раз все значения являются функциями, тофункции являются значениями
• Функции можно передавать как параметры вдругие функции
• Функции можно создавать на лету(лямбда-абстракции) и возвращать как значения
• Функции высших порядков — функции,оперирующие функциями
25/38
Функции высших порядков: примеры
• map — отображение коллекции аргументов наколлекцию результатов
• filter — выделение элементов из коллекции попредикату
26/38
Другие ограничения чисто функционального кода
• Многие структуры данных (и, как следствие,алгоритмы) подразумевают изменяемоесостояние
• Простейший пример - массивы• Чтобы получить изменённый массив, нужноскопировать старый, что обычно неприемлемо
• Нужно использовать неизменяемые (immutable)структуры данных
• Константные массивы• Односвязные списки• Деревья• Более сложные связные структуры
• Неизменяемость даёт много плюсов, но всреднем гораздо сложнее для понимания
• «Дешёвая» параллельность• Персистентные структуры данных — хранениеистории с экономией памяти
• Более чёткая и формальная структура кода
27/38
Вернёмся к λ-исчислению
• Две операции — abstraction & application• Т.е. объявление функций и их применение
• ⇒ Всё — это функция.
• На самом деле, всё — это функция с однимаргументом.
• Можно ли хоть что-то напрограммировать втаких условиях???
28/38
Вернёмся к λ-исчислению
• Две операции — abstraction & application• Т.е. объявление функций и их применение
• ⇒ Всё — это функция.
• На самом деле, всё — это функция с однимаргументом.
• Можно ли хоть что-то напрограммировать втаких условиях???
28/38
Вернёмся к λ-исчислению
• Две операции — abstraction & application• Т.е. объявление функций и их применение
• ⇒ Всё — это функция.
• На самом деле, всё — это функция с однимаргументом.
• Можно ли хоть что-то напрограммировать втаких условиях???
28/38
Каррирование
Позволяет писать функции с более чем однимпараметром
Функция с 2 параметрами → Функция с 1 параметром,возвращающая функцию с 1 параметромИзобретено Хаскеллом Карри (Haskell Curry), в честькоторого и названо
λ x y. f x y === λ x. λ y. f x y
29/38
Каррирование
Позволяет писать функции с более чем однимпараметромФункция с 2 параметрами → Функция с 1 параметром,возвращающая функцию с 1 параметромИзобретено Хаскеллом Карри (Haskell Curry), в честькоторого и названо
λ x y. f x y === λ x. λ y. f x y
29/38
Принцип замыкания
Позволяет хранить данные в функциях
При объявлении функция захватывает всепеременные, имеющиеся выше её объявленияТе из них, которые реально используются,называются замыканием (closure) этой функции
a = …
b = λ x. λ f. f (a x)
В функции b теперь всегда в некоем виде хранитсяфункция a
30/38
Принцип замыкания
Позволяет хранить данные в функцияхПри объявлении функция захватывает всепеременные, имеющиеся выше её объявленияТе из них, которые реально используются,называются замыканием (closure) этой функции
a = …
b = λ x. λ f. f (a x)
В функции b теперь всегда в некоем виде хранитсяфункция a
30/38
Пары Чёрча
pair = λ x. λ y. λ f. f x y
fst = λ p. p (λ x. λ y. x)
snd = λ p. p (λ x. λ y. y)
oneAndTwo = pair a b
fst oneAndTwo ⇒ a
snd oneAndTwo ⇒ b
31/38
Пары Чёрча
pair = λ x. λ y. λ f. f x y
fst = λ p. p (λ x. λ y. x)
snd = λ p. p (λ x. λ y. y)
oneAndTwo = pair a b
fst oneAndTwo ⇒ a
snd oneAndTwo ⇒ b
31/38
Списки Чёрча
Список — это либо пустой список (nil), либо пара изэлемента и списка[1,2,3,4,5] → (1, (2, (3, (4, (5, nil)))))
Это соответствует линейному однонаправленномусвязному списку в С
32/38
Списки Чёрча
Список — это либо пустой список (nil), либо пара изэлемента и списка[1,2,3,4,5] → (1, (2, (3, (4, (5, nil)))))Это соответствует линейному однонаправленномусвязному списку в С
32/38
Булеаны Чёрча
Позволяют определить значения в рамках логики 1гопорядка
true = λ x. λ y. x
false = λ x. λ y. y
if = λ p. λ x. λ y. p x y
not = λ p. if p false true
if true a b → a
if false a b → b
Можно определить и прочие логические операции.
33/38
Булеаны Чёрча
Позволяют определить значения в рамках логики 1гопорядка
true = λ x. λ y. x
false = λ x. λ y. y
if = λ p. λ x. λ y. p x y
not = λ p. if p false true
if true a b → a
if false a b → b
Можно определить и прочие логические операции.
33/38
Булеаны Чёрча
Позволяют определить значения в рамках логики 1гопорядка
true = λ x. λ y. x
false = λ x. λ y. y
if = λ p. λ x. λ y. p x y
not = λ p. if p false true
if true a b → a
if false a b → b
Можно определить и прочие логические операции.33/38
Нумералы Чёрча
Позволяют определить целые числа
0 = λ f. λ x. x
1 = λ f. λ x. f x
2 = λ f. λ x. f (f x)
3 = λ f. λ x. f (f (f x))
и т.д.
34/38
Нумералы Чёрча
Позволяют определить целые числа
0 = λ f. λ x. x
1 = λ f. λ x. f x
2 = λ f. λ x. f (f x)
3 = λ f. λ x. f (f (f x))
и т.д.
34/38
Рекурсия
Простейшее рекурсивное выражение —омега-комбинатор
M = λ x. x x
ω = M M
Абсолютно бесполезен в реальном применении
35/38
Рекурсия
Простейшее рекурсивное выражение —омега-комбинатор
M = λ x. x x
ω = M M
Абсолютно бесполезен в реальном применении
35/38
Рекурсия
Y-комбинатор
Y = λ f.(λ x. f(x x)) (λ x. f(x x))
Y x === x (Y x)
Вместе с условным оператором позволяетреализовать полноценную рекурсию
36/38
Рекурсия
Y-комбинатор
Y = λ f.(λ x. f(x x)) (λ x. f(x x))
Y x === x (Y x)
Вместе с условным оператором позволяетреализовать полноценную рекурсию
36/38
Итог
λ-исчисление может использоваться какполноценный, Тьюринг-полный языкпрограммирования. И это за десятки лет допоявления программируемых компьютеров и досамого Тьюринга!На практике интересно в основном математикам иисследователям в области языков.В следующей лекции мы перейдём к настоящимязыкам функционального программирования.
37/38
38/38