Зачем ФП обычному программисту?

Юрий Сыровецкий

Обо мне

  • Яндекс.Директ (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);
                        // expected output:
                        // Array ["exuberant", "destruction", "present"]
                    

Лямбда-абстракция = блок кода


                        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

Зачем так много языков?


                                    // Java

                                    Predicate<User> activeUserPredicate =
                                      new Predicate<User>() {
                                        @Override
                                        public boolean apply(User user) {
                                          return user.isActive();
                                        }
                                      };
                                

                                  // Scala

                                  _.isActive
                                

                                    // Go

                                    result, err := DoSomething()
                                    if err != nil {
                                        return nil, err
                                    }
                                    another, err := SomethingElse(result)
                                    if err != nil {
                                        return nil, err
                                    }
                                

                                    // Haskell

                                    result <- doSomething()
                                    another <- somethingElse(result)
                                

Выводы

  • ФП совместимо с ИП
  • ФП совместимо с ООП (F#, OCaml, Scala)
  • ФП — не ограничения, а возможности

Что дальше?

  • ru.wikipedia.org/wiki/{
    Haskell,
    F_Sharp,
    Scala
    }
  • ruhaskell.org/links