Сказ о том, как фронтендер на FPure конференции был

Sergey Ufocoder
15 min readJun 21, 2019

--

Совсем несерьезная заметка непрофессионала о профессиональном и профессионалах на прошедшей конференции FPure в Казани

Дисклеймер

Чтобы у вас было представление об авторе данной заметки, предупреждаю, что не являюсь специалистом в области функционального программирования, скорее похож на студента, который пытается подсмотреть и списать у отличника или взять готовое решение у старшекурсников.

Могут присутствовать умышленные или неумышленные допущения, порой даже ошибочное понимание докладов и/или используемых терминов в них.

Ниже постараюсь в сжатом виде, сквозь призму своего понимания, передать то, что происходило на конференции. Моя цель — донести тем, кто далек от мира функционального программирования, что не так страшен черт, как его малюют.

tl;tr

Fpure. 10 Бравитов из 10. Крайне рекомендую!

FPure Conf?

Двухдневная конференция в Казани по функциональному программированию (ФП), прошедшая 24–25 мая в 2019 году, и сосредоточившая множество любителей и профессионалов, а также интересующихся и сострадающих ФП в одном месте.

FPure Conf — 25 докладов, 2 вокшопа за 2 дня в 2(+1) потока и +1 я :-)

Первое, что приходит в голову, когда мы слышим о функциональном программирование — это Haskell. Однако на конференции присутствовали разработчики таких языков программирования, как: Scala, OCaml, Clojure, Haskell, Erlang и тд. Кстати заметил, если взять первые буквы этих языков программирования (ЯП), то можно получить слово Soche, один из вулканов на территории Африки, тоесть конференция обещает быть жаркой!

FPure Day #1: Opening

И первым было слово, и слово это было от организаторов.

Скромное вступительное слово одного из организаторов

Ходили слухи, что изначально организаторы планировали сделать конференцию исключительно по Scala, а не общую конференцию по ФП, но как в дальнейшем выяснилось, это не так, слухи и остались слухами.

С недавних пор, или если быть точным с 2018 года, конференция FPConf больше не проводится, и если бы не FPure, то мы бы не увидели конференции по ФП и в 2019. Есть даже немалая вероятность того, что это единственная конференция по ФП в РФ, которая пройдет в этому году.

FPure Day #1: Lectures

Доклады проходили в два потока, за исключением открывающего доклада перед ними. Можно смело утверждать, что было из чего выбирать, тематика докладов практически не пересекалась между потоками.

Однако на слишком хардорные доклады старался не ходить, вы же помните, что я фронтендом занимаюсь :)

Лекционные залы “Пушкин” (слева) и “Достоевский” (справа)

Конференция это идея!

Первым открывающим докладом был доклад “Моноид в категории эндофункторов?” от Дениса Шевченко. Для меня Денис известен как автор книги О Haskell по-человечески, рассчитанной для новичков. За этот труд, говорю ему человеческое спасибо.

Перейдем к докладу.

Вся суть функционального программирования в одной картинке:

Все что мы делаем в мире функционального программирования — это композиция и абстракция. Мы строим более сложные абстракции из простых, например, алгебра над типами, где из атомарных типов мы строим с помощью алгебраических типов данных более сложные.

Функтор, как что-то из алгебры, является категорией, отображением, его еще называют коробкой, но это нечто больше!

А что такое моноид? Формальное определение сухое и не даёт никакого глубокого понимания. Но это нечто также несёт в себе какую-то идею .

Смысл всех алгебраических абстракций, в том чтобы использовать их на практике. Они дают нам язык, которым мы можем оперировать.

Слайд из доклада, который перерос в локальный мем

Функция — это не функция! Когда мы говорим о программировании, то вычисления функции могут не закончиться, может возникнуть бесконечный (или пустой) цикл или исключение в программе. Функция в программировании — это не тоже самое, что и функция в математике.

Смысл функтора в сохранении структуры, с которой мы работаем, а смысл моноид в разложении типа. В докладе Денис говорит о том, что пора бы уже абстрактные идеи взять в руки и не оставлять их просто идеями. Разница между языками программирования заключается в возможности реализовывать эти абстрактные идеи, но не во всех ЯП это действительно удается.

Из интересных вопросов после доклада был следующий: чтобы писать красивый код нужно быть больше математиком или больше программистом? На что последовал ответ, что — программистом. Математика в умах математиков и программистов отличается. Да и вообще “мы фигачим код, главное не бояться идей математиков”.

Ссылка на презентацию, URL: https://github.com/denisshevchenko/fpure2019

Банды четырёх пока не существует в ФП

Следующий доклад в зале “Пушкин” от Алексея Пирогова из Hexlet “Функциональный дизайн и паттерны ФП”.

Уверен, некоторые из вас встречали эту таблицу, где сопоставляются подходы между объектно-ориентированым и фунциональным программированием:

Сравнение подходов ООП и ФП

Функции высших порядков — где функции могут быть значением (или могут принимать другую функцию как значение). Например, вот довольно всем известные: map, filter, flip (в Haskell).

Большую часть времени программист, применяющий парадигму ФП передаёт в качестве аргументов функции чаще другие функции, чем сами данные.

Что дальше? Смешиваем (композируем) функции, добавляем пару ложек каррирования, и посыпаем частичным применением. И самая простая паттерновая закуска готова!

Вы спросите, а где же основные блюда на столе? Вот же они: Bracket, Reader, State, Middleware и тд. Первый раз видите подобные названия? Не беда! Для начинающих шеф-поваров ниже будет предоставлена ссылка на поваренную книгу.

Без приправ конечно же не обошлось:

Во время доклада было замечено, что композиция в Haskell через точки смотрится менее богато, чем через доллар :)

После доклада люди из зала начали интересоваться, какие паттерны из мира ООП применяются в мире ФП, на что конечно же дается ответ. Так, по словам Алексея паттерн присобленец — это foldable, а фабрика — это функция с замыканием, конечно, также есть и другие паттерны, но это же совсем другая история.

А есть ли антипаттерны в ФП?! Для новичков это монады и трансформеры. Познал монаду и юзаешь постоянно? Спроси себя “не фигню ли ты делаешь”, не антипаттерн ли это?

Как понять то, что ты изобрёл? Паттерн это или нет? Если можно выделить это нечто в библиотеку, откидывай в сторону, не паттерн это.

Да и вообще, “мы не доросли до того дня, когда появится банда четырёх в мире ФП”, а если и соберется такая банда, то скорей всего это будет банда капитанов-очевидности.

Ссылка на (поваренную книгу) презентацию, URL: http://astynax.me/slides/fp-patterns.html

Спасут ли фронтендеры OCaml?

Следующий доклад в этом же зале “Пушкин” от Павла Аргентова “Multicore: прекрасный OCaml будущего”

Столкнулся с проблемой, которая начала преследовать меня всю оставшуюся конференцию, рок судьбы. Опоздал на 5 минут! Пропускаешь начало, и тут или наверстывай или бери академ.

OCaml? Это строгий, статически типизированный, мультипарадигмальный язык из семейства ML языков, а также верный друг и незаменимый товарищ.

В OCaml существуют рабочие решения для параллельных вычислений, например библиотека parmap. А для конкуррентной (не параллельной) кооперативной многозадачности библиотека lwt (один из со-авторов кстати наш земляк). Но не смотря на эти решения, этого мало!

За развитие OCaml в свое время серьезно взялась компьютерная лаборатория в Кембридже, организовав ocamllabs.io. Лабораторию поддерживают PhD-ребята. Но даже у PhD есть свои слабости, например, чем больше ты PhD, тем хуже твоя документация.

Cреди прочих важных задач, одна из решаемых лабораторией — это реализация поддержки работы на нескольких ядрах для OCaml, Multicore OCaml.

Задача разработки Multicore OCaml довольно сложная. Здесь появляются новые сущности и слои абстракций: свой рантайм (модель памяти, domains для параллелизма и fibers (внутри domains) для конкуренции, сборка мусора), свой язык (алгебра эффектов, реагенты) и прочее.

И все это, чтобы OCaml мог работать на нескольких ядрах.

История развитие Multicore OCaml внутри ocamllabs

Говоря о внесение новых фич в OCaml, как утверждает Павел, они будут, и все будет совсем скоро, где скоро — это в течении 5 лет.

Для глубого погружения в тему, (и чтобы я не ввел вас в заблуждение), рекомендую ознакомиться с презентацией или дождаться публичной видеозаписи доклада.

Кто-то из зала говорит, что может, ну его, этот OCaml, давайте на F# писать, он же похож. На что Павел, авторитетно заявил, что это F# похож на OCaml, но на .net платформе, поэтому все равно, что менять шило на мыло.

Во время вопросов слово получил старый OCaml-ист, возможно потрепанный интерпрайзом, и начал делиться откровениями, говорит, писал на OCaml 7 лет назад, прошло время выстрелил Haskell и Scala, а OCaml сдулся, почему? Где мы свернули не туда? Будет ли светлое будущие? На что последовал ответ, что OCaml — язык нишевый, по большей части дело в сообществе, а начал выстреливать во фронтенде.

ReasonML, как один из вариантов будущего развития для OCaml, вы спросите, но зачем там OCaml во фронтенде? Проверка типов и человекочитаемый код после компиляции в JavaScript! Спасут ли фронтендеры OCaml? Смотрите в следующей серии!

Ссылка на презентацию, URL: https://github.com/argent-smith/multicore-presenatation

JavaScript победил Computer Science

Доклад в зале “Пушкин” от Виталия Худобахшова из компании JetBrains с названием “Как из интерпретатора сделать компилятор автоматически”?

В начале доклада упоминается GraalVM и Truffle, думал что пойдем в крестовый поход за компилятором во имя машин фон Неймовских, но армии не собрали, поскольку в зале собравшихся ветеранов в комплятор-интерпретатор-строении можно было пересчитать по пальцам одной руки.

На самом деле речь будет идти о частичных вычислениях. Когда-то в далеких 70-ых компания Oracle пыталась заниматься этим вопросом, но не получила результатов, благо сейчас все изменилось. Но даже сегодня, хоть и существуют результаты по вопросу частичных вычисленияй, этой темой в принципе занимаются не так много людей.

Частичные вычисления? Частичные вычисления — это когда некая программа (специализатор) делает глубинные вычисления и создает на основе результата вычислений новую программу. Например, берём вот такую программу x^n, которая возводит x в степень n c хитрым условием:

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

И с помощью теоретических выкладок (которые я опускаю) и “школьных” преобразований (подстановка и упрощение) наши программы приводятся к упрощенному виду. С последовательностью преобразований можно изнакомиться в презентации, ссылка ниже.

Окей, мы научились конкретизировать наши программы, но зачем? А полиномиального роста производительности не хотите ? И после этого знания мы переходим к тому, ради чего мы все свами собрались, к тому как из интерпретатора сделать компилятор.

Даем формальное определение языка программирования:

L = (P, D, S)

Где P — множество программ, D — предметная область, S — семантика.

Даем формальное определение интерпретатору:

int(p,d) = p(d),∀p ∈ P,∀d ∈ D

p(d) это результат выполнения программы p над данными d, в том время как значения p, d принадлежат множеству программ и множеству предметной области соотвественно.

Формальное определение специализатора — определение той программы, которая сама подставляет значение в указанную программу и выдает новую программу, выглядит следующим образом:

spec(p, x)(y) = p(x, y)

Кстати программа, которая в качестве аргументов использует другие программы, называется мета-программой, к коим относится, как уже не сложно догадаться, комплилятор и специализатор.

После этих опредлений один парень решил подставить одно в другое и при этом неоднакратно, так сказать пофантазировать на тему, и этим парнем был А̶л̶ь̶б̶е̶р̶т̶ ̶Э̶й̶н̶ш̶т̶е̶й̶н Футамура (Yoshikiko Futamura).

После того как применили специализатор к интерпретатору, получили понятие компиляции, что носит название первой проекцией Футамуры.

Затем провели поставновку специализатора в самого себя, получили еще одну проекцию, а именно компилятор, что является уже второей проекцией Футамуры. Когда же в эту проекцию подставили еще раз специализатор, то получили генератор компиляторов.

Кодзима? Нет! Футамура гений!

Ранее мы собирались в крестовый поход, так вот выяснилось, что такие инструменты как GraalVM и Truffle реализуют первую проекцию этого гения Футамуры.

В экспериментальных целях эти инструменты были пременены к известным интерпретаторам, и далее по полученым множетелям мы теперь сможем судить о том, во сколько раз удалось ускорить выполнения программ для этих интерпретаторов:

  • ускорение в 0.83 раз для V8, JavaScript;
  • ускорение в 3.8 раз для JRuby;
  • ускорение в 5 раз для GNU R.

JavaScript не смогли победить, Computer Science проиграл! На самом деле нет, дело в том, что в V8 существуют свои внутренние оптимизации для JavaScript-программ.

Интересным замечанием из зала был такой, что порой сложно написать сторонний эквивалентный спецификации интерпретатор. Например, Ruby, где присутствовали ошибки внутри интерпретатора, тоесть работа интерпретатора отличалась от описанной в спецификации. Поэтому и специализация программ, как следствие, будет давать ошибку и все последующие проекции.

По подсказкам знатаков в компиляторостроении уже после доклада, был раскрыт тот факт, что тема проекций Футамуры совсем не нова, но для меня в тот день, это стало открытием.

Несмотря на то, что презентация публичная, ссылок на нее не нашел, пришлось продублировать на Google Диск

FPure Day #1: Results

Безусловно докладов было несколько больше, чем те, что я описал выше. И как вы уже заметили, даже слабо разбирающийся в концепциях ФП, при должном усилии, сможет выделить некоторые доносимые идеи.

Но стоит опоздать на какой-нибудь доклад или придти на тот, где требуется некоторая теоретическая подготовка, тут же возникает чувство будто пропустил пол семестра в университете и придется уходить в академический отпуск.

То чувство, когда пропустил часть доклада по функциональному программированию

По сути весь этот день я полностью провел в лекционном зале “Пушкин”, а во втором зале были не менее сложные доклады, а некоторые прям очень даже.

И чтобы у вас было представление об уровне хардкорности докладов, процитирую один из сторонних отзывов, оставленных через форму обратной связи, на доклад в зале “Достоевский”, связанный с Haskell: “ни *** не понял, но понравилось”.

FPure Day #2: Lectures

Астрологи объявили второй день конференции, хардкорность докладов растет по экспоненте, количество проводимых воркшопов увеличивается на два.

Адепт Elixir публично припарирует Phoenix-приложение во время воркшопа

Фронтенд это нормально!

Открывающим докладом второго для был доклад от Виталия Брагилевского, на тему “Краткий курс компиляторостроения на Haskell”

“Больше всего я люблю две вещи: Haskell и компиляторы” — начинает Виталий, поэтому доклад будет о написании Haskell компилятора. В качестве препарируемого компилятора используется компилятор GHC. Виталий тажке отмечает, что доклад имеет целью заинтересовать!

Компилятор — это композиция анализа и синтеза, работает компилятор в три стадии. Стадии схематично выглядят просто, но на деле все сложнее и деталей куда больше.

В теории компиляторов заботятся о фронтендерах, там есть свое понятие фронтенда. И как заверяет Виталий: “Фронтенд это нормально!”.

Фронтенд начинается с лексического анализа, где текст программы преобразуется в список токенов. Затем в дело вступает синтаксический анализ, где список токенов преобразует в абстрактное синтаксическое дерево (AST). Последняя же стадия фронтенда заканчивается семантическим анализом, где происходит создание таблицы символов и проверка типов, а не как пишут в интернетах: профессиональным выгоранием. Добавлю, что за всей работой фронтенда стоит теория автоматов и регулярных выражений.

За то, что происходит в середине компилятора GHC отвечает GHC Core. На этой стадии обычно думают о том, как вычислять то, что хотел программист. Например, то, как реализовать циклы, рекурсии, замыкания и прочие подобные вещи. Также внутри ядра присутствуют различные оптимизации.

Изучая GHC Core, можно заметить, то как происходит последовательное приближение теории к практике (к внутреннему языку), например тип CoreExpr отражает формальное описание синтаксиса.

Бекенд последняя стадия компилятора и необходима для кодогегерации. Здесь код преобразуется в STG (Spinless Tagless G-machine), откуда из STG преобразуется в Cmm (низкоуровневый язык с явным стеком), а это уже последние внутренние представление кода внутри компилятора.

Промежуточный код для haskell-программы на STG, складывающей числа 2 и 3.
Промежуточный код для haskell-программы на Cmm, складывающей числа 2 и 3.

Затем у этого кода есть три пути, во что он может быть сгенерирован: ASM, LLVM, C.

Стадии работы Haskell-компилятора, но более детально

Заинтересовали компиляторы? Что делать дальше? Читайте книжки! Например, книги от Andre W. Appel про компиляторы. А если у вас интерес к Haskell, знайте, что в будущем ожидается книга от Виталия Брагилевского, Haskell in Depth.

Закончился доклад, последовали вопросы. Вот например, спрашивают: может ли закончиться эпоха доминирования GHC, каково ваше отношение? На что был дан ответ: “Скорей бы! Но настоящих конкурентов пока не видно”.

Вопрос: Компилятор это чёрный ящик? Можно ли добраться до представления внутреннего дерева? И как после уверяет Виталий: “Конечно, компилятор — это такая же библиотека”.

Нео, нам нужны зависимые типы!

Перешёл в соседний зал, парни из компании Serokell, Ринат
Стрюнгис и Даня Рогозин, уже во всю делают доклад на тему “Разработка, основанная на типах, в Numeric Haskell: подходы и проблемы” в зале “Достоевский”. Ну а я что? Опоздал на 5 минут! Благо это не было фатальным.

Haskell используется в компании судя по всему как основной язык программированияю. Они даже стали применять его в машинном обучении.

Матрица — один из основных математических объектов в области машинного обучения, и к сожалению статическая типизация, а именно сходимость типов во время компиляции, не поможет выявить потенциальные ошибки во время исполнения программы.

И как поясняют докладчики, значительный класс возникающих ошибок был связан именно с размерностью матриц. Более того, появляющиеся исключения во время исполнения программы вовсе не информативны. В частности над одной из ошибок разработчики просидели около недели.

Пример неинформативного исключения

Эту задачу можно решить используя зависимые типы, но беда, в Haskell их нет! Как быть? Эмулировать! Но мы должны помнинить, что компилятор потребует пруфов работы нашей программы, тоесть доказательств, что она корректна.

Решение проблемы

Одним из решений проблемы является библиотека Dimensions, и благо на производительность она практически не влияет. Другим решение является использование библиотеки type-natural, которая интегрирована с Singletons, первая дает нам функционал для работы с натуральными числами, а вторая реализует зависимые типы, и все это, чтобы завести в Haskell засимые типы.

Если у вас несложный код , несложный алгоритм , тогда можно так не заморачиваться с “зависимыми типами” в вашей Haskell-программе, но если все-таки решились, то помните вам придется приложить усилия, чтобы доказать корректность программы компилятору.

Подробные разбительства, URL: https://serokell.io/blog/dimensions-and-haskell-introduction

Поиски НЛО с помощью Haskell

Следующий доклад Free Monad и Final Tagless от Александра Гранина в зале “Пушкин”. Возникает то чувство, когда ты пришел без опозданий, но это никак не помогло, и плюс тот факт, что за время перерыва не удалось выучить Haskell, а градус новых понятий и абстракций растет еще сильнее. Но как обычно мы постараемся разобраться, в чем дело и передать все в упрощенном виде.

Как выяснилось в самом начале, Free monad и Final tagless — это такие два подходы к инверсии зависимостей, подозреваю вы возможно уже сталкивались с этим понятием в мире ООП.

“Извечные вопросы” к инверсии зависимостей: как, когда и почему?

Для изучения и демонстрации разницы между подходами было написано приложение по регистрации метеоров, где астрономы фиксируют активность небесных объектов (прикрытие для поисков НЛО) и вносят свои записи в каталог.

Схематичечное представление приложение в виде 3-ех слоев

Ценность всего приложения по регистрации метеоров (или если говорить о приложениях вцелом) представляет средний слой, то есть слой бизнес логики.

Перед тем как сравнивать подходы реализуется свой предметный язык, исключительно для задачи регистрации метеоров (DSL). После для этого языка реализуется свой интерпретатор, а также отдельно рантайм и так далее и тому подобное (смотри выше схему).

Дамы и господа! На ваших глаза состоится бой, представляю соперников: в левом красном углу ринга Free Monad, в правом синем углу ринга Final Tagless. Бокс!

Описание интерпретатора с помощью Free Monad (слева) и Final Tagless (справа)

После описания частей приложения, на примере интерпретатора, легко обнаружить, что для Free Monad приходится постоянно писать повторяющийся код (boilerplate), также не понятно как композировать Free Monad.

Но самый острый вопрос — вопрос производительности, и чтобы отбросить все сомнения в сторону, необходимы тесты. Для чистоты эксперимента, вводится также реализация на Church Encoded Free Monad. Далее сравниваются скорости работы интерпретаторов, то есть количество зарегистрированных метеоров для каждого из подходов.

Сколько требуется времени для регистрации метеоров

Для предварительного результата важна сама скорость роста, и если для Free Monad она квадратичная, то для Church Encoded Free Monad и Final Tagless она линейная, а это требудет дополнительных измерений.

Одновременно с проводимым “тестом” выше, происходило логирование результатов. И вот уже с их помощью, мы можем сделать однозначный вывод, что решение на Final Tagless относительно Free Monad может быть как быстрее, так и медленеей, все зависит от используемого движка: Free Monad или Church Encoded Free Monad.

Далее переходим к сравнению решений для слоя бизнес-логики. В результате которого, по мнению рефери Александра, у бойца Final Tagless в синем углу ринга, явные потери и он проигрывает.

Возможно у тех, кто уже следит за подобного рода спортивными поединками, или даже является фанатом, могут возникнуть вполне ризонные негодования и возмущения, однако рефери предлагает самостоятельно вынести вердикт, и предоставляет записи всех острых моментов поединка, поскольку никак не сомневается в собственном решение.

Репозиторий с экспериментом, URL: https://github.com/graninas/Hydra

Александр призывает не верить ему на слово, и в качестве вывода, который делает в конце, говорит доверять прежде всего измерениям, проводить эксперементы, как в физике, самостоятельно и опираться на полученные презультаты.

Ссылка на презентацию, URL: Final Tagless vs Free Monad

На досуге Александр, пишет книгу “Functional Design and Architecture”, которая имеет непосредственное отношение к теме доклада, URL: https://github.com/graninas/Functional-Design-and-Architecture

Final boss

Если жизнь это игра и конференция один из ее уровней, то сейчас мы нарвались на 80-level босса (не путать с боссом-вертолетом). На случай, если дойдете до этого босса, ниже читы, запись прохождения уровня:

Олег Нижников. “После монад. Стрелочная и моноидальная композиция.” Неофициальная запись доклада

Заключение

̶О̶б̶о̶р̶з̶е̶л̶ Обозрел 7 из 25 докладов, хотя присутствовал на 12, некоторые оказались для меня сильно узкоспециализированными, тоесть не актуальными, в том время как другие требовали неплохой начальной подготовки и были отложены для дальнейшего изучения.

Стоит помнить, что любой митап или конференция это люди в первую очередь, а потом уже идеи. Именно благодаря им, их открытости, их желанию делиться своим опытом и пониманием всех этих ФП абстракций сокращается дистанция в развитии между друг другом, а это, уверен, дает почву для новых открытий.

И завершить свое повествование хотелось бы цитатой одного известного в узких кругах хаскелиста, который рассуждал о практической пользе теории категории: “Мы не можем скормить абстрактную математику нашему компилятору, мы не можем запустить её на исполнение. Но мы можем применить её к нашему разуму, и сделать это можно через язык, потому что язык определяет наше мышление.”

UPD 12.08.19: Официальные видеозаписи докладов

--

--