Зачем ФП обычному программисту?
Юрий Сыровецкий
Обо мне
- Яндекс.Директ (Python + C++)
- Яндекс.Диск (Java)
- KasperskyOS (Haskell + C)
- IO Global, Cardano (Haskell)
- ВШЭ (Haskell)
О чём этот доклад
- Почему ФП такое сложное?
- Почему в популярные ЯП тащат фичи из ФП языков?
История
- 1936 — машина Тьюринга, λ-исчисление
- 1958 — ALGOL
-
1958 — LISP
- сборка мусора
- лямбда-абстракция
- функции высших порядков
- неи зменяемые данные
- операции над списками
- C, Oberon, Pascal...
- ISWIM, Hope, ML, Miranda...
- Java, Go, Rust...
- Haskell, Scala, F#...
ФП непонятно
| type Respond = Response -> IO() |
| type Application = Request -> Respond -> IO() |
| |
| myBaseApp(request)(respond) = do |
| foo(request) |
| if bar(request) then |
| respond(baz) |
| else do |
| respond(qux_part1) |
| respond(qux_part2) |
| |
| type Middleware = Application -> Application |
| |
| myApp = authenticator(logger(myBaseApp)) |
| |
| main = runServer(80, myApp) |
Лямбда-абстракция
| const words = [ |
| 'spray', 'limit', 'elite', 'exuberant', |
| 'destruction', 'present' |
| ]; |
| |
| const result = words.filter(word => word.length > 6); |
| |
| console.log(result); |
| |
| |
Лямбда-абстракция = блок кода
| db.withTransaction(tx -> { |
| tx.select(...); |
| tx.update(...); |
| }); |
Неизменяемость —
фокус на данных
const, constexpr, final, let, val
- LINQ
- потоки и генераторы
- FRP
- Kafka
- event sourcing
List comprehension
| fruits = ["apple", "banana", "cherry", "kiwi", "mango"] |
| |
| newlist = [x for x in fruits if "a" in x] |
(SETL, 1969)
Уже (почти) здесь: тип-сумма — TypeScript, Rust
| enum WebEvent { |
| PageLoad, |
| KeyPress(char), |
| Click { x: i64, y: i64 }, |
| } |
| |
| match event { |
| PageLoad => println!("page loaded"), |
| KeyPress(c) => println!("pressed '{}'.", c), |
| Click { x, y } => { |
| println!("clicked at x={}, y={}.", x, y); |
| }, |
| } |
Уже (почти) здесь: свои макросы — Lisp, Haskell, Rust, C++
| struct Person { |
| string name; |
| int age; |
| }; |
| |
| struct Person { |
| BOOST_HANA_DEFINE_STRUCT(Person, |
| (string, name), |
| (int, age) |
| ); |
| }; |
- неудобный внешний язык
- ничего нельзя
Изнанка
| #define BOOST_HANA_PP_CONCAT(x, y) \ |
| BOOST_HANA_PP_CONCAT_PRIMITIVE(x, y) |
| |
| #define BOOST_HANA_PP_CONCAT_PRIMITIVE(x, y) \ |
| x ## y |
Ещё про макросы
| println!( |
| "{0}, this is {1}. {1}, this is {0}", |
| "Alice", |
| "Bob" |
| ); |
парсинг и специализация во время компиляции
Будущее
- Зависимые типы
- Линейные типы
Не найти работу
-
увы, на hh.ru
- Java — 5 146 вакансий
- Haskell — 19 вакансий
-
но
-
хорошие специалисты всегда везде нужны,
мидл легко найдёт несколько вариантов
- есть работы на стыке ФП + ИП
- c Хаскелем ценность выше даже в Java
Зачем так много языков?
Predicate<User> activeUserPredicate =
new Predicate<User>() {
@Override
public boolean apply(User user) {
return user.isActive();
}
};
|
_.isActive
|
result, err := DoSomething()
if err != nil {
return nil, err
}
another, err := SomethingElse(result)
if err != nil {
return nil, err
}
|
result <- doSomething()
another <- somethingElse(result)
|
Выводы
- ФП совместимо с ИП
- ФП совместимо с ООП (F#, OCaml, Scala)
- ФП — не ограничения, а возможности
Что дальше?
-
ru.wikipedia.org/wiki/{
Haskell,
F_Sharp,
Scala
}
- ruhaskell.org/links