Инструменты разработчика на языке Elm

С момента публикации статьи Основы разработки на языке Elm (руководство по инструментарию для начинающих) прошло полтора года. За это время в инструментарии для языка разработки веб-интерфейсов Elm произошли многочисленные изменения: появилась более удобная система сборки с возможностью генерации нового проекта; для редактора Atom набор дополнений в некоторых отношениях теперь лучше, чем для популярного тогда среди разработчиков на Elm редактора LightTable; заработал инспектор состояния приложения. Давайте пройдёмся по этому набору на простом примере.


Инструменты разработчика на языке Elm: обложка


Базовые средства Elm


Elm можно установить как пакет NPM:


npm install -g elm


Есть и другие способы установить Elm. Они описываются в официальном руководстве.


Проверим версию только что установленного Elm:


elm --version


0.18.0


elm является обёрткой для вызова отдельных утилит:


  • elm-make: сборка кода на Elm;
  • elm-package: управление пакетами на Elm;
  • elm-reactor: утилита слежения за кодом на Elm для перекомпиляции и перезагрузки его в браузере;
  • elm-repl: REPL для Elm.


Управление кодом на Elm с помощью Brunch


Одним из удобнейших средств управления кодом на Elm представляется Brunch. Устанавливается Brunch как пакет NPM:


npm install -g brunch


Проверим версию только что установленного Brunch:


brunch --version


2.10.12


Вызовем Brunch для генерации кода нашего примера проекта на Elm:


brunch new --skeleton MattCheely/elm-brunch-skeleton demo-application


После генерации кода Brunch также сразу загрузит все необходимые NPM- и Elm-пакеты.


Рассмотрим сгенерированное дерево каталогов:


  • app\: исходные тексты приложения
    • assets\:
    • index.html: минимальный документ HTML5, который будет контейнером для нашего приложения
    • css\:
    • style.css: стили для примера приложения
    • elm\: исходные тексты на Elm
    • Main.elm: главный модуль приложения на Elm
    • js\: код на JavaScript
    • app.js: пример кода, работающего отдельно от кода на Elm
  • elm-stuff\: загруженные пакеты на Elm
  • node_modules\: загруженные NPM-пакеты
  • .gitignore
  • README.md
  • brunch-config.js: настройки для Brunch с учётом поддержки Elm
  • elm-packages.json: настройки для Elm, в том числе список используемых пакетов
  • package-lock.json: список зависимостей NPM (сгенерирован NPM автоматически)
  • package.json: настройки для NPM


Уже сейчас мы можем собрать наш проект:


cd demo-application
npm build


После сборки проекта появится также папка public, в которой разместятся все части нашего веб-приложения.


Давайте запустим приложение в режиме отладки:


npm start


Откроем в браузере ссылку http://localhost:3333/ и полюбуемся на прекрасное веб-приложение:


Пример приложения на Elm


В правом нижнем углу находится интерфейс инспектора состояния приложения. Щёлкнем на нём. Сейчас счётчик value имеет значение 0:


Начальное состояние приложения


Пощёлкаем на кнопках +1 и -1 и понаблюдаем как меняется состояние:


Наблюдение за изменением состояния приложения


Мы можем вернуться к любому предыдущему состоянию:


Просмотр предыдущего состояния приложения


И даже вернуться к последнему, просто нажав на кнопку Resume.


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


Настройка Atom для работы с Elm


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


Перво наперво установим дополнение language-elm:


apm install language-elm


Это дополнение предоставит базовую поддержку Elm, такую как синтаксическая подсветка кода.


Для поддержки переходов к определениям и всплывающим подсказкам с типами выражений установим пакет atom-ide-ui.


apm install atom-ide-ui


Для поддержки автодополнения поставим autocomplete-plus:


apm install autocomplete-plus


Если используете сокращённый набор кода, поставьте snippets:


apm install snippets


Наконец мы готовы установить Elmjutsu:


apm install elmjutsu


Теперь мы можем открыть наш проект в Atom:


Код Elm в Atom


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


Дополнительный, но важный инструментарий


Пожалуй самый важный инструмент из дополнительных это elm-format. С помощью этой утилиты можно приводить внешний вид программы к стандартному (общепринятому) виду. Установим его:


npm install -g elm-format


Также установим соответствующее дополнение для Atom elm-format:


apm install elm-format


Благодаря этому дополнению, каждый раз, как мы будем сохранять наш код, elm-format будет его форматировать. Если в коде будет синтаксическая ошибка, то утилита её обнаружит, и мы об этом узнаем, хотя, для выяснения наличия ошибок всё же лучше использовать компилятор. А в этом нам будет помогать дополнение для Atom linter-elm-make.


Поставим его:


apm install linter
apm install linter-elm-make


Не забудьте также зайти в настройки этих дополнений и задать все необходимые параметры.


Дополнение elm-lens показывает прямо в коде для функций и типов экспонируются ли они или являются локальными, а также сколько раз на них ссылаются. Для установки дополнения просто вызовите:


apm install elm-lens


Для поддержки REPL в Atom можно установить дополнение elm-instant:


apm install elm-instant


Если вы хотите работать с терминалом прямо в Atom, рекомендую установить дополнение platformio-ide-terminal:


apm install platformio-ide-terminal


Поэкспериментируем


Для начала откроем окно терминала в Atom, нажав кнопку + в нижней части окна, и запустим слежение за нашим кодом на Elm:


npm start


Код на Elm в Atom с запущенным слежением в терминале


Давайте внесём ошибку в код:


Код на Elm в Atom с ошибкой


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


Для непосвящённых


Как и обещал, немного расскажу, как устроен код приложения на Elm. Давайте взглянем на тот исходный код, который нам сгенерировал Brunch:


module Main exposing (main)

import Html exposing (Html, text, div, button)
import Html.Attributes exposing (class)
import Html.Events exposing (onClick)

main : Program Never Model Msg
main =
    Html.beginnerProgram
        { model = initalModel
        , update = update
        , view = view
        }

-- Model

type alias Model =
    { value : Int
    }

initalModel : Model
initalModel =
    { value = 0
    }

-- Update

type Msg
    = Increment
    | Decrement

update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            { model | value = model.value + 1 }

        Decrement ->
            { model | value = model.value - 1 }

-- View

view : Model -> Html Msg
view model =
    div []
        [ div [ class "counter" ]
            [ text (toString model.value) ]
        , div [ class "controls" ]
            [ button [ onClick Increment ] [ text "+1" ]
            , button [ onClick Decrement ] [ text "-1" ]
            ]
        ]


Приложение на Elm оформляется как модуль Main, экспонирующий функцию main. Это мы видим в первой строке кода. Далее идёт импорт модулей. Некоторые модули импортируются по умолчанию, но модули Html, Html.Attributes и Html.Events нужно импортировать. Здесь они импортируются с экспонированием отдельных функций и типов. Это делается, чтобы не квалифицировать имя модуля, например, вместо Html.Attributes.class будем писать просто class.


Ниже объявляется и определяется функция main. В объявлении задаётся её тип. Тип функции указывается после символа :, определение происходит после знака =. Как увидим ниже, указание имён параметров и их типов осуществляется раздельно. Elm поддерживает вывод типов, однако для функций верхнего уровня хорошим тоном считается ручное указание типа.


В нашем случае функция main вызывает функцию Html.beginnerProgram, которая получает на вход структуру с тремя полями: model, update, view. Эта функция запустит цикл обработки сообщений. Параметр model получает начальное состояние приложения, которое задано в функции initialModel. Функция update вызывается всякий раз, когда происходит какое-то событие и передаётся соответствующее сообщение. После обработки сообщения вызывается функция view, занимающаяся формированием нового дерева DOM.


Далее определяется тип Model, точнее синоним типа структуры, состоящей из поля value типа Int. Тип Int, как нетрудно догадаться, представляет целые числа.


Как уже было сказано, функция initialModel возвращает начальное значение состояния, которое содержит одно поле value со значением 0. Типом состояния может быть любой тип, не только структура.


Далее определяется тип сообщения Msg. Это тип-перечисление с двумя возможными значениями: Increment и Decrement.


Функция update получает на вход сообщение и состояние приложения. Обычно код этой функции включает в себя оператор сопоставления с образцом case .. of ... Здесь происходит изменение состояния в зависимости от пришедшего сообщения: значение поля value либо увеличивается на 1, либо уменьшается на 1.


Наконец, функция view принимает состояние приложения и формирует с помощью функций модулей Html, Html.Attributes и Html.Events требуемое дерево DOM.


Установка дополнительных пакетов Elm


И последнее, но не менее важное: чтобы установить дополнительные пакеты Elm, нужно вызвать команду elm-package. Например, установим пакет elm-community/list-extra:


elm package install elm-community/list-extra


Обратите внимание, что идентификатор пакета состоит из двух частей, то есть не просто list-extra, а elm-community/list-extra.


С этой командой связан файл проекта elm-package.json. В него записываются названия и версии устанавливаемых пакетов в разделе dependencies. Например, сгенерированный Brunch файл elm-package.json выглядит так:


{
  "version": "1.0.0",
  "summary": "helpful summary of your project, less than 80 characters",
  "repository": "https://github.com/user/project.git",
  "license": "BSD3",
  "source-directories": ["app/elm"],
  "exposed-modules": [],
  "dependencies": {
    "elm-lang/core": "5.0.0 <= v < 6.0.0",
    "elm-lang/dom": "1.1.1 <= v < 2.0.0",
    "elm-lang/html": "2.0.0 <= v < 3.0.0"
  },
  "elm-version": "0.18.0 <= v < 0.19.0"
}


Репозиторий пакетов можно просматривать здесь.


Что дальше


Пожалуй лучший источник информации об Elm это его родной сайт:


  • руководство
  • примеры
  • пакеты


Вероятно стоит также перечитать статью Основы разработки на языке Elm (руководство по инструментарию для начинающих).


Опрос


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


Подведу также итоги прошлого опроса. Итак, на вопрос «Если Вы программируете на функциональных языках, то каково Ваше мнение об Elm» расклад был получен такой:


  • 28.2%: первый раз слышу, но выглядит годным
  • 21.1%: не нужен
  • 20.5%: годный, я на нём уже программирую
  • 15.8%: сыроват для продакшн
  • 14.1%: годный, но писать на нём не собираюсь


Проголосовало 170, воздержалось 147. Прочитало статью 13,9k, добавило в закладки 51.


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


  • 31%: не нужен
  • 18%: первый раз слышу, но выглядит годным
  • 18%: сыроват для продакшн
  • 18%: годный, но писать на нём не собираюсь
  • 15%: годный, я на нём уже программирую


Проголосовало 99, воздержалось 76. Прочитало статью 5,5k, добавило в закладки 41.


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


Сообщество


С момента публикации прошлой версии статьи (30 мая 2016) существует рускоязычное сообщество во Вконтакте. Число участников сообщества на момент написания этой статьи 179. Присоединяйтесь!


Ссылки


  • Elm
  • Brunch
  • Atom
  • Elmjutsu
  • elm-format



© Симоненко Евгений, 2018

© Habrahabr.ru