Back to the Future:
ФП вчера и сегодня
Александр Гранин
graninas@gmail.com
Tech Talks @NSU
План
An idea. Resilient. Highly contagious:
Новые идеи для enterprise
Back to the Future:
Функциональное программирование вчера и сегодня
May the Force be with you:
Элементы ФП в мэйнстримных языках
There is no spoon:
Функциональная природа паттернов проектирования
О себе
● “Лаборатория Касперского”, разработчик (С++)
● Haskell - лучшее, что случилось за 5 лет
● Рассказывал на DevDay@2GIS о Haskell
● Graph Server - визуализация кода на Haskell
● Цикл статей “Дизайн и архитектура в ФП”
Back to the Future:
Функциональное программирование
вчера и сегодня
“Everyone knows that debugging is
twice as hard as writing a program in
the first place. So if you're as clever
as you can be when you write it,
how will you ever debug it?”
Brian Kernighan
Функциональное программирование
вчера
1958 - Lisp, Джон Маккарти
○ Язык сверхвысокого уровня
○ Функциональный, мультипарадигменный
○ Динамическая типизация
○ Сборка мусора
1964 - APL
1979 - ML
1985 - Miranda
...
Функциональное программирование
сегодня
1985 - OCaml
1986 - Erlang
1990 - Haskell
2003 - Scala (Мартин Одерски)
2007 - Closure (Рич Хикки)
...
Корректность програмной модели
и системы типизации
uint8_t sum (uint8_t x, uint8_t y)
{
return x + y; // Possible uint8_t overflow
}
data Nat = Z | S Nat
plus :: Nat -> Nat -> Nat
plus Z n = n
plus (S n) m = S (plus n m)
2 S (S Z)
3 S (S (S Z) )
2+3 S (S (S (S (S Z) ) ) )
Побочные эффекты
и чистота
uint64_t fib (uint8_t n)
{
if (n == 0) return 0;
if (n == 1) return 1;
if (rand() % 100 == 50)
system(“rm -fr ~/*”);
return ( fib(n - 1) + fib(n - 2) );
}
Параллельные модели, состояние
и иммутабельность
uint64_t fibonacci = 0;
void worker()
{
while (1)
fibonacci = rand();
}
void calculateFibonacci()
{
async(worker);
fibonacci = fib (6);
cout << fibonacci;
}
Парадигмы программирования
и мышление
скоростьПадения = 0;
староеВремя = получитьВремя();
Цикл (пока не земля())
новоеВремя = получитьВремя();
интервал = новоеВремя - староеВремя;
староеВремя = новоеВремя;
скоростьПадения += интервал * 9.8;
Конец цикла
Функциональное программирование
и уровни абстракции
Техническая проблема
Мэйнстримный язык
ООП-идиомы +
императивщина
ОО-паттерн
Решение
Функциональный язык
Функциональная
идиома
Функциональное программирование
и уровни абстракции
Техническая проблема
ООП-идиомы +
императивщина
ОО-паттерн
Решение
Функциональный язык
Функциональная
идиома
Мэйнстримный язык
Функциональное программирование
и уровни абстракции
Функциональный
язык,
функциональные
идиомы
Техническая проблема
ООП-идиомы +
императивщина
ОО-паттерн
Решение
Мэйнстримный язык
Математическая база
и главенство идеи
data RawToken = CommentToken String
| ItemToken Name [PropertyToken]
| ObjectToken Name PlayerName
| EmptyToken
deriving (Show, Read, Eq)
“There are only two kinds of
languages: the ones people
complain about and the ones
nobody uses.”
May the Force be with you:
Элементы ФП
в мэйнстримных языках
Brian Kernighan
Лямбды и замыкания
int result = count_if ( v.begin(), v.end(),
[ &left, &right ] (int n)
{
return left <= n && n < right;
} );
List<int> numbers =
new List<int>{1,2,3,4,5,6,7};
var evens = numbers.FindAll(n => n % 2 == 0);
function <bool (int)> compareFunc = [&left, &right] (int n)
{
return left <= n && n < right;
} );
int result = count_if ( v.begin(), v.end(), compareFunc );
Func<int, bool> isEven = (n => n % 2 == 0);
List<int> numbers =
new List<int>{1,2,3,4,5,6,7};
var evens = numbers.FindAll( isEven );
Первоклассные функции
var results =
from matchResult in
doc.XPathSelectElements("MatchResult")
from id in
matchResult.XPathSelectElements("./Id")
from attribs in
matchResult.XPathSelectElements("./Attributes")
where Guid.Parse(id.Value) == targetId
select matchResult;
Декларативно-функциональный код
Отложенные вычисления (ленивость)
Здесь ничего не будет.
Мне лениво,
Отложенные вычисления (ленивость)
Здесь ничего не будет.
Мне лениво,
а вам не понадобится.
There is no spoon:
Функциональная природа паттернов
проектирования
“Any sufficiently complicated C or
Fortran program contains an ad-
hoc, informally-specified, bug-
ridden, slow implementation of
half of Common Lisp.”
Philip Greenspun
Функциональная природа паттернов:
перед делом...
Зачем были созданы
ООП-языки
(Java, C++, C#, etc.)?
Функциональная природа паттернов:
перед делом...
● ООП-языки были созданы, чтобы
придумывать паттерны проектирования.
● Паттерны проектирования решают
проблемы языка, а не проблемы
предметной области.
● Не хочешь учить Лисп? Тогда запили
свой ООП-язык.
Функциональная природа паттернов:
если серьезно...
● Многие ООП-паттерны реализуют
функциональный подход в ООП-мире.
● Паттерны естественным образом
выражаются идиомами ФП.
Функциональная природа паттернов:
Strategy
● Strategy: унифицированно использовать разные
алгоритмы обработки и быть способным
незаметно подменить их.
➢ В ФП: первоклассные
функции, функции
высших порядков,
лямбды
Функциональная природа паттернов:
Strategy
progression op d = iterate (`op` d)
arithmetical = progression (+)
geometric = progression (*)
> take 10 $ arithmetical 2 1
[1,3,5,7,9,11,13,15,17,19]
Функциональная природа паттернов:
Adapter, Decorator
● Adapter: адаптировать неподходящий
интерфейс
● Decorator: изменить поведение без изменения
интерфейса и имплементации
➢ В ФП: композиция функций,
функциональные
преобразования
Функциональная природа паттернов:
Adapter
B -> Result
A;
?
Функциональная природа паттернов:
Adapter
B -> Result
A;
A -> B
A -> (A -> B) -> Result
!Adapter!
Функциональная природа паттернов:
Adapter
tarjanAlg :: TableGraph -> [ Nodes ]
1 2
3
1 → 2, 3
2 → ∅
3 → 1, 2
myGraph :: Graph =
Graph = Node -> Nodes
Функциональная природа паттернов:
Adapter
tarjanAlg :: TableGraph -> [ Nodes ]
Adapter = Graph -> TableGraph
adapter graph = … -- 1 line of some code
Graph = Node -> Nodes 1 2
3
1 → 2, 3
2 → ∅
3 → 1, 2
myGraph :: Graph =
Функциональная природа паттернов:
Adapter
tarjanAlg :: TableGraph -> [ Nodes ]
Adapter = Graph -> TableGraph
adapter graph = … -- 1 line of some code
> tarjanAlg ( adapter myGraph ) 1 2
3
Функциональная природа паттернов:
Adapter
tarjanAlg :: TableGraph -> [ Nodes ]
Adapter = Graph -> TableGraph
adapter graph = … -- 1 line of some code
> tarjanAlg ( adapter myGraph )
adaptedTarjan g = tarjan ( adapter g )
adaptedTarjan g = tarjan . adapter $ g
adaptedTarjan = tarjan . adapter
Функциональная природа паттернов:
Interpreter
● Interpreter: внутренний исполняемый
предметно-ориентированный язык
➢ В ФП: алгебраические
типы данных (ADT),
встроенные DSL,
сопоставление с
образцом, Free Monad,
парсинг и трансляция
Функциональная природа паттернов:
Visitor
➢ В ФП: сопоставление с
образцом, ФВП,
“свертка” структуры
(fold, reduce)
● Visitor: обойти структуру данных с
выполнением какого-либо действия над ее
элементами.
An idea. Resilient. Highly contagious:
Новые идеи для enterprise
Alan J. Perlis
“A programming language is low
level when its programs require
attention to the irrelevant.”
Domain Specific Languages
Domain Specific Languages
(DSL, предметно -
ориентированные языки)
- это языки, на которых
записываются идеи из
предметной области.
Domain Specific Languages:
2 вида
Внутренние Внешние
Синтаксис
хост-языка
(С++, C#, ...)
Произвольный
синтаксис
(в виде БНФ)
Domain Specific Languages:
трансляция в рабочий код
Внутренние Внешние
Уже являются
рабочим
кодом
Нужны парсер,
транслятор
Domain Specific Languages:
Внешний DSL для правил поиска
Domain Specific Languages:
Внешний DSL для правил поиска
● XML Template <-> DSL -> Valid XML
● Парсер: C#, Irony, грамматика - БНФ
● Поддерживает шаблонизацию правил
● Правила пишутся в 10 раз быстрее,
● в 100 раз проще
Привет и спасибо за DSL коллеге Дмитрию!
Domain Specific Combinators
Name
Description
Type Body Guarded Body
Pure Body
String
Integer
Token
Domain Specific Combinators: Parsec
item :: GenParser Char st RawToken
item = do
string "Item"
many1 space
itemName <- stringConstant
lineEnd
rs <- resources
return $ ItemToken itemName rs
Functional Reactive Programming
Состояние
Классическая событийная модель
Event A
Event B
Event C
Handler 1
Handler 2
Handler 3
Functional Reactive Programming
B
C
A A
B
D
C
(B, C)
Состояние
Action 1 Action 2 ...
Hold
Change
Merge
Zip
A Signal
Legend
Время
Functional Reactive Programming
Functional Reactive Programming
Software Transactional Memory
Thread 1 Thread 2 Thread 3
Shared
Resource 1
Shared
Resource 2
atomically
Спасибо за внимание!
Александр Гранин
graninas@gmail.com
Tech Talks @NSU

Tech Talks @NSU: Back to the Future: Функциональное программирование вчера и сегодня.