Начало проекта на Elm

Что есть Elm?

Elm это язык и платформа для создания приложений, поведение которых следует определённым правилам, призванным бороться с багами и плохим кодом. Приложение в Elm представляет собой набор чистых данных (никакого IO!) и приводится в движение “сигналами” которые приходят из “каналов”. Подобный “спартанский” минимализм позволяет собирать большие приложения из простых компонентов и деплоить их в пятницу вечером.

Синтаксис чем-то похож на Haskell, но имеет сильный привкус ML. Вместо :: для типов используется :, а для списков наоборот. Кроме того, тип списка так и выглядит - List a (начиная с версии 0.14). Композиция функций это f >> g, а применение это f |> g. Монадок нет вообще.

Установка расписана на сайте и сводится, как обычно, к скачиванию бинарей или установке с Hackage. Особые эстеты монут собрать свой собственный Elm с гита.

Покажи нам код

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

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

Театр начинается с вешалки, а приложение с main. И сразу бросается в глаза тип: Signal Element. “Но где же IO?”, спросит невнимательный читатель, пропустивший вступление, и будет прав. Elm ещё более ортодоксальный чем Haskell в плане побочных эффектов и вся обработка идёт чистыми функциями.

Забавные стрелочки такую обработку как раз задают. Читается это как "С помощью функции scene сведём значения сигналов state и Window.dimensions результатом такой обработки будет элемент приложения (в этой статье нам не интересный). Всё это наводит на мысли об апликативных функторах и не зря. Но Elm выше всего этого теорката.

Эта функция является всего лишь тонкой прокладкой, которую обещают убрать в следующих версиях. Само же текущее состояние системы передаётся функции view, которая рисует по нему виртуальное DOM-дерево. Обратите внимание, что Signal пропал из типа и никаких, поэтому в аргументе state будет уже само значение на текущий момент, а не поток, из которого это значение можно получить.

А тут мы имеем дело уже с этим самым потоком. У него нет входов и выходов и это, наверно, самый мутный участок во всём коде. Этот сигнал агрегируется из нескольких (пока что только одного), затем передаётся в функцию “свёртки из прошлого” foldp. Как и в обычном фолде, нам потребуется начальное значение и функция, которая будет обновлять аккумулятор в ответ на входящие данные.

Теперь пришла пора описать вторую часть сцены. Я не стал городить хитрые и сложные интерфейсы на бустрапе, а просто вывел один элемент <p> без атрибутов и с содержимым поля message нашего стейта в качестве текстового тела HTML-элемента. Никаких императивных манипуляций, только чистые комбинаторы из модуля Html и списки, списки, списки…

Всё состояние приложения кладётся в один большой “корневой” контейнер. В Elm для этого удобнее использовать не ADT, а рекорды а-ля объекты JS. Это делать совершенно не страшно т.к. это всё же настоящий тип, а не просто словарь-свалка для значений в произвольном формате, так что обратиться к несуществующему полю или полю ненадлежащего типа компилятор вам не даст.

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

В ответ на просьбу сделать ничего функция вернёт оригинальное состояние без изменений.

Запуск

Если запустить elm-reactor в каталоге с файлом приложения и открыть в браузере его страницу… произойдёт ошибка - надо сначала доставить зависимостей:

После чего вы сможете увидеть заветный приветмир и попробовать добавить элементов в view, новых полей в State и событий в Action. Удачи!