Elm 0.17

Jun. 22nd, 2016 12:52 pm
thedeemon: (office)
Elm - это хаскелеподобный чистый функциональный язык для всяких безобразий в браузере, т.е. "компилирующийся" в JavaScript. Знаменит прежде всего тем, что на нем написан визуализатор квантовой механики из предыдущего поста. :)
Три года назад я писал про тогдашний Elm, с тех пор он заметно изменился, а в последней на сегодня версии произошло существенное изменение в архитектуре, отчего большая часть старого кода и описаний перестала быть актуальной.
Изначально он появился как воплощение идей FRP, и thesis (дипломную работу?) автора Elm'a я могу всем рекомендовать как замечательное изложение идей и разных подходов к FRP, плавно переходящее в объяснение исходной архитектуры Elm'а (и без этого объяснения научиться тогдашнему Elm'у было трудно). Там вся динамика была построена на идее сигналов, когда есть обычные иммутабельные данные типов A,B,C... и есть отдельная категория типов A',B',C'... описывающих такие же данные, но меняющие свои значения со временем (навроде Time -> A'), и есть функтор Signal из первой категории во вторую. Пишешь чистый код, работающий с простыми иммутальными данными, потом этим функтором лифтишь свои чистые функции в мир динамически меняющихся значений. Есть набор внешних источников событий/данных, вроде координат мыши, т.е. уже живущих во второй категории, и нужно построить в ней функцию из нужных источников событий/данных в некое дерево контролов, элементов. А рантайм уже сам позаботится о том, чтобы все события и новые данные проходили как надо через все преобразования и получающееся на выходе дерево превращалось в DOM страницы. Ну и были во второй категории специальные комбинаторы для обращения с временнЫми потоками данных, вроде соединения, сворачивания и пр.
Потом в Elm'е появились Mailbox'ы и Elm Architecture, в которой программа описывалась двумя функциями view и update и начальным значением пользователького типа Model (содержащего все данные). update получала значение произвольного заданного пользователем типа Action (обычно это перечисление разных действий) и текущее значение модели, возвращала обновленное значение модели, а view отображала значение модели в дерево элементов, принимая одним из параметров "адрес" (значение специального типа Mailbox). Возвращаемые ф-ей view элементы в своих атрибутах могли иметь функции "что делать при нажатии/изменении", эти функции получали тот самый "адрес", чтобы слать свои оповещения туда. Так все оставалось иммутабельным и чистым, а рантайм заботился о доставке всех событий в форме пользовательского типа Action в функцию update, так осуществлялся круговорот событий-реакций в колесе сансары. Как видите, в явном виде сигналы уже не участвовали в Elm Architecture, но в разных API еще оставались.
В свежей версии 0.17 авторы сказали "прощай FRP" и выкинули все сигналы нафиг. Read more... )
thedeemon: (office)
Надысь побаловался Elm'ом - хаскелеподобным языком, компилирующимся в JavaScript (не писать же руками на этом странном языке). Вспомнил, где можно его применить - у меня на странице одного из продуктов было слайд-шоу, наскоро сделанное на флеше с использованием Flex'a, отчего простая довольно флешка весила 280 КБ. Исходников той флешки сейчас под рукой нет, видать остались на старом ноуте, так что сравнить объем не могу, но на Elm'e все уместилось в несколько строк, широко размазанных для пущей вящести. Вот они, с пояснениями.
Read more... )
Вот и весь код. На самом деле, все описания типов тут можно смело удалить, компилятор неплохо справляется с их выводом и сгенерит ту же самую программу без подсказок. Типы тут чисто для нас. Натравив конпелятор на этот код, я получил 3 КБ JavaScript'a с логикой, и ссылку на elm-runtime.js, где лежит весь-весь рантайм (включая массу неиспользуемых модулей вроде работы с Canvas и WebSockets) непожатый - около 160 КБ. Его можно closure compiler'ом ужать до 80 в базовом режиме. В продвинутом режиме, с удалением неиспользуемого кода, у меня его не получилось использовать - что-то в результате ломалось, да и выигрыш был небольшим (несколько процентов). В итоге оставил вариант с 83 КБ слегка пожатого JS, что для такой задачи все равно очень много, но все же на 200 КБ лучше, чем раньше с Flex'ом.

Работает Elm'овское FRP дискретно и push-based. Программа превращается в направленный ациклический граф, где источники сигналов, вроде every t или событий мыши, клавиатуры, окна, полей ввода и т.д. становятся вершинами-источниками (у них только исходящае дуги), а функции, преобразующие сигналы, становятся промежуточными вершинами (с входящими и выходящими дугами), main становится вершиной-приемником. Каждый раз, когда в одном из источников происходит какое-то событие (нажатие или перемещение мыши, тик таймера, нажатие кнопок и т.п.), все вершины источники генерируют по сообщению. Только там, где реально произошло событие, это сообщение с новым значением, а во всех остальных - сообщение "ничего не изменилось, старое значение такое-то". Когда в промежуточную вершину с N входами приходит N сообщений по входящим дугам, вершина проверяет, есть ли среди них новая информация или все "без изменений". Если есть новая, то вершина-функция пересчитывает свое значение с учетом новых аргументов, а иначе просто посылает вниз "без изменений", ничего не пересчитывая. В результате все работает синхронно, дискретно, и без лишних пересчетов. Есть также возможность делать нужные части графа асинхронными, чтобы долгие вычисления не замораживали весь граф (подробности могу описать отдельно, или см. доки).

Теперь о минусах. Их пока довольно много. Язык хоть и напоминает хаскель, на самом деле очень далек от него по возможностям и синтаксису. Это слегка приукрашенная просто типизированная лямбда. Есть let, но нет where. Нет do (впрочем, для него нет и повода). Паттерн-матчинг только по алгебраическим типам, простые типы не матчатся (если я правильно путаю). Есть пара псевдо-тайпклассов "Number a" и "Comparable a", но свои тайпклассы объявлять нельзя, никаких монад вам. Компилятор очень ненадежен: часто не ловит банальнейшие ошибки (вроде неизвестного идентификатора) и молча генерит код, который потом вылетает с рантайм-ошибками в браузере. Стандартная библиотека бедновата, особенно по возможным входящим сигналам - на многие события пока нельзя реагировать (например, я бы хотел реагировать на загрузку картинки - сейчас это недоступно). Документация разрозненная и неполная. Вот thesis стоит почитать, хотя бы ради обзора более ранних чужих подходов к FRP.

Profile

thedeemon: (Default)
Dmitry Popov

September 2017

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930

Syndicate

RSS Atom

Most Popular Tags

Page Summary

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 26th, 2017 07:18 am
Powered by Dreamwidth Studios