От автора: вместо этой статьи рекомендую прочитать более актуальную Инструменты разработчика на языке Elm.
Elm это функциональный язык программирования для разработки веб-приложений, работающих в браузере. Elm строгий, статически типизированный. Elm похож на Haskell, однако это лишь поверхностное сходство, ведь Elm изначально заточен для быстрой разработки веб-приложений.
Эта статья представляет из себя шпаргалку для начинающих по основам разработки на языке Elm, а именно, здесь рассматривается организация проекта, инструментарий Elm и среда разработки Light Table.
Elm можно установить как пакет NPM:
npm install -g elm
Elm поддерживается в виде плагинов многими продвинутыми редакторами: Emacs, Visual Studio Code, Brackets и другими. Но, пожалуй, самая продвинутая IDE для Elm доступна в Light Table http://lighttable.com/ в виде соответствующего плагина. Домашняя страничка этого плагина: https://github.com/rundis/elm-light.
Для разработки веб-приложения на Elm потребуется пакет Elm html. Для этого переходим в каталог проекта (он может быть абсолютно пустым) и запускаем в нём следующую команду:
elm package install elm-lang/html
Во время установки elm-package
предложит добавить информацию об этом пакете в файл elm-package.json
. Соглашаемся с этим (тем более, что плагин Light Table для Elm определяет проект Elm по наличию этого файла). Затем он сообщит нам, что нужно установить зависимости этого пакета. Тоже соглашаемся. В результате получаем установленными три пакета: elm-lang/core
, elm-lang/html
и elm-lang/virtual-dom
. Пакеты устанавливаются в подкаталог elm-stuff
.
Теперь можно открыть проект в Light Table. Для этого запускаем сам редактор (в Linux команда light
, если каталог Light Table прописан в PATH) и идём в File/Open folder
, выбираем соответствующий каталог проекта.
Файл elm-package.json в проекте на языке Elm играет такую же роль, как и package.json в проектах на базе JavaScript.
После установки первого пакета мы получим 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": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0"
},
"elm-version": "0.17.0 <= v < 0.18.0"
}
Очевидно, что нужно отредактировать содержимое полей version
, summary
и repository
.
В корне проекта разместим главный модуль приложения Main.elm, например, такого содержания:
module Main exposing (main) import Html exposing (text) main = text "Hello"
(Естественно, что в большом проекте исходники будем складывать не в корень проекта, а в соответствующий подкаталог.)
Для запуска приложения нужно открыть окно команд редактора (Ctrl-Space
) и набрать elm: reactor
. В появившемся списке выберем Elm: View current elm file in browser (elm-reactor)
.
После чего должно открыться окно встроенного браузера с запущенным нашим приложением. Если видим пустое окно браузера, то, немного подождав, обновим его содержимое (Ctrl-R
). Должны увидеть надпись Hello
.
Чтобы видеть окно браузера открытым рядом с окном редактора кода, нужно вызвать контекстное меню окна браузера и выбрать пункт меню Move tab to new tabset
.
elm-reactor
предназначен для облегчения разработки приложений на Elm. Во-первых, он предоставляет статический веб-сервер для разрабатываемого приложения. Во-вторых, он следит за изменениями проекта, пересобирает его при появлении изменений и обновляет содержимое окна браузера. Правда у автора последняя функция почему-то не работала. Возможно из-за того, что плагин для Elm ещё не был адаптирован для версии 0.17.0.
Для сборки (компиляции) проекта или отдельного модуля нужно открыть окно команд (Ctrl-Space
), набрать elm: make
и выбрать соответствующий пункт меню.
При первой попытке собрать весь проект возникнет такая проблема:
Откроем elm-package.json и отредактируем его:
"make-info": {
"main": "Main.elm",
"out": "main.js"
}
В командной строке нужно в каталоге проекта запустить команду:
elm make
Для проверки модуля нужно открыть файл модуля, открыть окно команд, набрать elm: lint
и выбрать Lint selected file
. После проверки проблемные места в коде будут подчёркнуты. Чтобы посмотреть, что за проблемы, нужно сначала поставить курсор на подчёркнутое место в коде, затем вновь обратиться к окну команд и набрать linter: show
. Возле проблемного места появится всплывающее окно с комментарием.
Если нажать клавишу Enter или щёлкнуть на соответствующую кнопку в окне, можно получить исправление проблемы.
Набрав в окне команд linter:
можно увидеть и другие функции этого инструмента.
Для построения графа зависимостей нужно в окне команд набрать elm: graph
и выбрать пункт Elm: Show dependency graph
.
Для управления пакетами, как было уже сказано в самом начале, есть команда elm package
, но плагин для Light Table также предоставляет визуальное средство управления пакетами проекта. Для этого как обычно открываем окно команд, набираем в нём elm: package
и выбираем пункт Elm: Show project packages
.
REPL можно вызвать как из командной строки, запустив команду
elm repl
Так и в среде Light Table. Для этого открываем окно команд, набираем в нём elm: repl
и выбираем пункт Elm repl: Open a elm repl
.
Для запуска кода модуля в REPL нужно сначала модуль импортировать:
import Main
После чего можно вызвать какую-нибудь функцию:
Main.main
В REPL после ввода кода нужно нажимать Ctrl-Enter
.
Поиски русскоязычного сообщества Elm-разработчиков навели меня на мысль, что такового не существует, поэтому недавно я создал и начал наполнять группу во Вконтакте: https://vk.com/elm_lang_ru. Присоединяйтесь!
habr.com
Если вы совсем не знакомы с Elm, то, если вкратце, это функциональный язык программирования и платформа для написания web-приложений. Код, написанный на Elm, компилируется в JavaScript и встраивается на страницу. Более подробно про основы можно почитать например здесь на Хабре или же просто на официальном сайте . Я же хотел суммировать свой опыт, который получил, написав своё первое приложение, поэтому в статье будет большое число очевидных вещей, чуть-чуть неочевидных и много ссылок.
Своё приложение я решил сделать после написания нескольких простеньких программ и прохождения туториала Elm Tutorial. Во время прочтения примеров из туториала и написаниях примеров было довольно сложно осознать все концепции сразу, поэтому я старался не останавливаться на сложных на тот момент мне местах (роутинг, композиция) и стремился получить готовый работающий сайт.
После этого я стал писать своё приложение, которое состоит из формы, где можно задать название события, опционально урл и дату, когда событие произойдёт. После сохранения все эти данные показываются в виде небольшой карточки с обратным отсчётом до события. Код и ссылку на github pages можно найти здесь.
Очевидная вещь, хоть Elm и предназначен для фронтенда — это полностью другой язык по сравнению с JavaScript. Поэтому надо учить синтаксис, разбираться в концепциях. На официальном сайте есть небольшая дока по синтаксису, есть таблица сравнения с JavaScript. Полезно в самом начале почитать официальное руководство и попробовать запустить примеры оттуда. Есть еженедельная рассылка, где можно найти множество интересных статей, видео, примеров.
Поскольку до этого у меня практически не было опыта в использовании чистых функциональных языков программирования — мне было интересно и полезно читать материалы, которые объясняют общие концепции. Из таких материалов могу посоветовать серию из 6 статей So You Want to be a Functional Programmer, где подробно раскрываются основные концепции и книгу Mostly Adequate Guide (есть частичный перевод на русский).
Во время решения своей задачи мне очень помог пройденный туториал, пример из которого был под рукой. Он очень полезен, потому что там покрывается очень много аспектов создания сайта: от основ языка до сборки, арихтектуры, роутинга, взаимодействия с апи. Например, роутер оттуда я изначально перенёс в свою задачу практически без изменений. Потом уже, решая возникащие по ходу проблемы, разбирался как производится парсинг, как работают матчеры и так далее. Плюс этот туториал постоянно обновляет все примеры до последних версий языка (на текущий момент это 0.18).
С туториалами и примерами кода в интернете зачастую связана одна интересная особенность. В коде импортируются библиотеки, которые используют так называемый open import
. То есть встречается использование функции s
, а не UrlParser.s
. Это несколько усложняет чтение чужого кода. Всегда смотрите как, что и под каким именем импортируется в модуле. В свою очередь я сам стараюсь использовать qualified import
и это официальная рекомендация. Больше букв, но всегда сразу понятно какой используется тип или функция.
Советую обязательно подключить к вашему редактору Elm Format, который форматирует код согласно официальным гайдам. Elm Format кажется используется всеми и общий для всех синтаксис это действительно удобно.
Важно изучить архитектуру, которая считается стандартом написания приложения: TEA (The Elm Architecture). Подробней можно прочитать в официальном руководстве. Если вы знакомы с Redux’ом то это не составит труда, а если нет, то в любом случае изучение этой концепции не кажется мне чем-то сложным. Есть три основые части: модель (хранит состояние приложения), апдейт (обработчик изменений, который модифицирует модель) и вид (внешний вид нашего приложения, отрендеренный в соответствии с состоянием модели).
Соответственно наше минимальное приложение инициализируется с этими тремя частями. В более сложных случаях к ним могут добавляться подписки, функция апдейта при изменения урла, флаги из javascript и возможно что-то ещё. Но база остаётся одной всегда.
Компилятор действительно работает отлично, ошибки показываются максимально информативные и всегда можно быть уверенным, что на выходе будет рабочая программа. Это, однако, не застраховывает от необходимости внимательно следить за кодом и смотреть, что и как работает. Я хочу сказать, что поначалу компилятор вызывает восторг и кажется, что это какая-то магия. Но когда начинаешь писать реальный код, то легко вернуть из функции неправильное значение правильного типа, что компилятор пропустит.
Код можно отлаживать используя модуль Debug. Хотя даже такое привычное для JavaScript действие выполняется не просто. Debug.log это функция, которая принимает строку (просто текст перед выводом) и значение и возвращает это значение, производя при этом сайд-эффект вывода в консоль. Debug.log нельзя использовать в любом месте программы и в любой части функции. То есть её можно поставить только в том месте, где уже есть какое-то значение.
В Elm 0.18 появился дебаггер, позволяющий отслеживать состояние приложения, возвращаться во времени назад и даже экспортировать состояние с историей для открытия в другом браузере. Я писал своё приложение на версии 0.17 и пока лично дебаггером не воспользовался.
Самой большой и неразрешённой до конца для меня трудностью стало деление кода на модули. Большинство кода примеров лежит в одном файле. Официальный туториал в секции Scaling The Elm Architecture рассказывает лишь о делении на функции, базовое понятие модулей. Есть секция в туториале, есть другие примеры в интернете, но применить всё это с первого захода для своего проекта мне не удалось, так как были сложности с вставкой в модульную структуру стороннего компонента elm-datepicker, который я использую. На текущий момент я сделал разделение, которое пока что меня устраивает: основной код с апдейтами и функциями в главном файле, отдельно вынесены все типы и разметка страниц. Зато в процессе глобального рефакторинга своего приложения я обнаружил неожиданную вещь, о которой до этого много читал, но не осозновал. Рефакторинг делать абсолютно не страшно, а даже интересно. Вся система с типами, неизменяемыми данными, чистыми функциями и контролирующим это компилятором не даёт сломать код. Можно сколько угодно менять названия всего, менять структуру, создавать и удалять файлы и быть спокойным, что после успешной компиляции на выходе будет работающее приложение.
Мне было интересно попробовать что-то сильно отличное от стандартной схемы программирования в JavaScript. Это было временами непросто, потому что функциональное программирование ломает мозг и для меня, как человека, который по большей части писал только на JavaScript — порог вхождения очень высок. Простые вещи, которые в Elm делаются совсем не просто — вроде получения даты, http-запроса, вызывают поначалу недоумение и боль. С постепенным овладеванием концепциями и инструментами становится и проще и интереснее.
Каким бы ни было будущее Elm’а, я думаю, что инвестиции своего времени в его изучение оправданы. Кажется, что идеи функционального программирования проще осознать, используя чистый функциональный язык, не имея возможности в случае проблем по-быстрому написать что-то не так. И потом, даже если продолжать работать только с JavaScript — можно переносить и использовать новые идеи, и понимать пользу использования в JS функционального подхода в общем и, например, таких библиотек как FlowType, immutable.js, Ramda.
habr.com
Для начала, давайте напишем наше первое приложение на Elm и попробуем разобраться, что же происходит. Не отходя от традиций, пусть это будет наш привет Миру.
import Html exposing (span, text)
import Html.Attributes exposing (class)
main =
span [class "welcome-message"] [text "Hello, World!"]
Первые две строчки подключают модули Html и Html.Attributes, благодаря которым мы можем отображать и изменять HTML-элементы и их атрибуты на странице. Директива exposing позволяет нам использовать указанные в параметрах функции напряму, например вместо
Html.span
span
main это управляющая конструкция, которая управляет нашим приложением, большинству программ, написаных на Elm так или иначе будут содержать эту конструкцию.
Строка
span [class "welcome-message"] [text "Hello, World!"]
Сгенерирует простой HTML-код:<span>Hello, World!</span>
Но это все не очень интересно, ведь для генерации простого HTML-кода в одну строку нам пришлось написать целых 4 строчки на Elm, пока что не очень впечатляет, но стоит только заглянуть в основные концепции архитектуры языка и все становится на свои места.
Вся логика программ на Elm разделена на 3 понятные и простые части, уже, так или иначе, знакомые многим в веб разработке:
Model(модель)
Я бы охрактеризовал модель, как состояние приложения, что отличается от того, что понимается под моделью в привычном MVC. Если выразить мою мысль более подробно, то Модель в Elm будет содержать в себе все модели в понимании MVC, необходимые в данном состоянии приложению, если таковые есть. При этом Model может быть чем-то намного более простым. Например, в следующем примере, в котором мы сделаем простой счетчик, Model будет простым целым числом(Int).
Update(обновление)
Когда дело касается обновления состояния, в игру вступает update. Здесь все не более сложно, чем с моделью. Update это функция, которая говорит КАК нам нужно изменить состояние приложения(Model)
View(представление)
Преставление это то, как мы хотим отобразить состояние нашего приложения, то есть Model.
В сухом остатке, приложение на Elm работает следующим образом:
Мы получаем запрос из внешнего мира, Используем его для того, чтобы обновить нашу модель, решаем, как хотим отобразить результат. Elm решает, как эффективно отобразить наш HTML.
Читая сухой текст, довольно трудно понять что к чему, поэтому, давайте рассмотрим обещаный пример создания счетчика
module Counter where
import Html exposing (..)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick)
import StartApp
main =
StartApp.start
{ model = 0
, update = update
, view = view
}
-- MODEL
type alias Model = Int
-- UPDATE
type Action = Increment | Decrement
update : Action -> Model -> Model
update action model =
case action of
Increment -> model + 1
Decrement -> model - 1
-- VIEW
view : Signal.Address Action -> Model -> Html
view address model =
div []
[ button [ onClick address Decrement ] [ text "-" ]
, div [ countStyle ] [ text (toString model) ]
, button [ onClick address Increment ] [ text "+" ]
]
countStyle : Attribute
countStyle =
style
[ ("font-size", "20px")
, ("font-family", "monospace")
, ("display", "inline-block")
, ("width", "50px")
, ("text-align", "center")
]
В этом примере добавилась довольно важная концепция — Action(действие). Действия позволяют нам правильно реагировать на запросы полученные из внешнего мира. В данном примере мы определили два типа действий — Increment и Decrement. И, в зависимости от полученного действия принимаем решение, как изменить нашу модель.
Кстати, разработчики предусмотрели онлайн-компилятор, для того, чтобы можно было запустить один из множества доступных примеров, или попробовать написать что-то самостоятельно. Попробуйте запустить этот пример и посмотреть, что получится!
Можно еще долго рассказывать о базовых концепциях данного языка, но я думаю, что те, кому изложенный материал показался хоть чуточку интересным, сами зайдут на официальный сайт и посмотрят все, что называется своими глазами. А еще, я призываю тех, кого не заинтересовало то, что я написал, или не понравился мой стиль изложения, зайти и все же посмотреть на Elm своими глазами. В заключение, я хочу добавить пример кода с официального сайта, который генерирует игру в пинг-понг в браузере, по-моему, изящность и простота этого языка, заслуживают внимания со стороны сообщества elm-lang.org/examples/pong
habr.com
С момента публикации статьи Основы разработки на языке Elm (руководство по инструментарию для начинающих) прошло полтора года. За это время в инструментарии для языка разработки веб-интерфейсов Elm произошли многочисленные изменения: появилась более удобная система сборки с возможностью генерации нового проекта; для редактора Atom набор дополнений в некоторых отношениях теперь лучше, чем для популярного тогда среди разработчиков на Elm редактора LightTable; заработал инспектор состояния приложения. Давайте пройдёмся по этому набору на простом примере.
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. Устанавливается 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\
: исходные тексты на ElmMain.elm
: главный модуль приложения на Elmjs\
: код на JavaScriptapp.js
: пример кода, работающего отдельно от кода на Elmelm-stuff\
: загруженные пакеты на Elmnode_modules\
: загруженные NPM-пакеты.gitignore
README.md
brunch-config.js
: настройки для Brunch с учётом поддержки Elmelm-packages.json
: настройки для Elm, в том числе список используемых пакетовpackage-lock.json
: список зависимостей NPM (сгенерирован NPM автоматически)package.json
: настройки для NPMУже сейчас мы можем собрать наш проект:
cd demo-application
npm build
После сборки проекта появится также папка public
, в которой разместятся все части нашего веб-приложения.
Давайте запустим приложение в режиме отладки:
npm start
Откроем в браузере ссылку http://localhost:3333/
и полюбуемся на прекрасное веб-приложение:
В правом нижнем углу находится интерфейс инспектора состояния приложения. Щёлкнем на нём. Сейчас счётчик value
имеет значение
:
Пощёлкаем на кнопках +1
и -1
и понаблюдаем как меняется состояние:
Мы можем вернуться к любому предыдущему состоянию:
И даже вернуться к последнему, просто нажав на кнопку Resume
.
Неискушённому зрителю читателю наверное будет интересно также узнать, как устроено приложение на 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:
Для руководства по настройке и функциям 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. Давайте взглянем на тот исходный код, который нам сгенерировал 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-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» расклад был получен такой:
Проголосовало 170, воздержалось 147. Прочитало статью 13,9k, добавило в закладки 51.
Интересно, наверное, будет сравнить с результатами голосования, зафиксированными автором через неделю после публикации той статьи:
Проголосовало 99, воздержалось 76. Прочитало статью 5,5k, добавило в закладки 41.
Заметен рост благосклонности к Elm, существенно уменьшилось число тех, кто считал, что Elm не нужен, также заметно выросло число тех, кто на нём уже программирует. При этом также увеличилось число тех, кто считает язык годным, но писать на нём не собирается.
С момента публикации прошлой версии статьи (30 мая 2016) существует рускоязычное сообщество во Вконтакте. Число участников сообщества на момент написания этой статьи 179. Присоединяйтесь!
© Симоненко Евгений, 2018
habr.com
Поговорим о Elm.
Elm — функциональный язык программирования для frontend-разработки. Синтаксис похож на Haskell, но значительно упрощен и специализирован. Исходный код на Elm компилируется в нативный JavaScript. Скомпилированный JavaScript содержит код приложения, которое управляют поддеревом DOM.
Elm. Удобный и неловкий. Композиция
Elm. Удобный и неловкий. Json.Encoder и Json.Decoder
Elm. Удобный и неловкий. Http, Task
Основным элементом в архитектуре языка Elm является приложение. В общем случае каждое приложение содержит:
Все должно быть типизировано. Как следствие статическая проверка согласованности кода. Если скомпилировалось, то должно работать. А вот будет оно работать как вы ожидаете или нет — никаких гарантий. Это значительно упрощает рефакторинг.
Модель является пользовательским типом. Пользовательские типы строятся из:
Union Types позволяют объявлять тегированные типы. Возьмем для примера описания типа User:
type User = Anonymous | User String
Объявленный тип содержит информацию о типе пользователя и его данные, если он авторизован. Иначе пользователь анонимный.
Граница между Elm runtime и внешним окружением через декодеры. Декодер (Json.Decode) — функция, которая принимает на вход JSON и возвращает Elm тип. В процессе выполнения Json.Decode.decodeString или Json.Decode.decodeValue проверяется структура входных данных и соответствие типам.
Декодер возвращает тип Result, который содержит данные, в случае успеха, или ошибку.
Представление является функций от состояния, которая возвращают информацию для генерации DOM дерева. Пример:
view : Model -> Html.Html Msg
view model =
case model.user of
Anonymous ->
Html.div [] [ Html.text “Anonymous” ]
User name ->
Html.div [] [ Html.text (“Welcome ” ++ name) ]
Для генерации DOM узлов используются функции. В боевых проектах view представляет собой композицию из функций более общего порядка. Например:
view : Model -> Html.Html Msg
view model =
case model.user of
Anonymous ->
anonymousView
User name ->
userView name
anonymousView и userView пользовательские функции, которые генерируют небольшие части интерфейса.
Все события (действия пользователя, сетевые и тп) генерируют сообщения, которые доставляются в зарегистрированную при инициализации функцию. По умолчанию, эта функция имеет имя update. Функция принимает событие и модель, а возвращает новую модель и команды. Команды выполняются в Elm runtime и также могут генерировать события.
Для примера, инкремент переменной при нажатии кнопки:
update : Model -> Msg -> (Model, Cmd Msg)
update model msg =
case msg of
OnClick ->
({model | clicked = model.clicked + 1}, Cmd.none)
Подписка на события происходит при старте приложения и повторно вызывается при каждом изменении модели.
В случае возникновения события они доставляются в функцию update.
Для примера, подписка на таймер с периодом 10 секунд. При достижении 10 секунд генерируется сообщение Tick и доставляется в функцию update:
subscribe : Model -> Sub Msg
subscribe model =
Time.every 10 Tick
habr.com
В современном мире существует более 8 тысяч языков программирования. В этой статье мы расскажем про необычный язык программирования — Elm.
Программирование меняется, как и тенденции в его развития. В последнее время набирает популярность парадигма: приложения пишут таким образом, чтобы в них отсутствовали глобальные состояния, на которые имеют влияния произвольные части кода. Тенденция особенно просматривается после выхода в мир и распространения фреймворков:
Ключевыми отличиями подобного подхода являются чистейший язык функционального класса, очевидное представление состояния программы для воссоздания единой архитектуры и обработка событий посредством шины. Все события записываются в журнале и подчиняются строгому порядку с отображением времени.
Основным достоинствам подхода является возможность повторного воспроизведения события. Для запуска евента снова не потребуется восстановление аналогичных действий или их симуляции, что свойственно для остальных систем. Доступно быстрое изменение логики работы функции или пользовательского интерфейса в программе, программист сможет моментально увидеть результат действия после прохождения установленной последовательности.
Дополнительно разработчик в силах в любой период выполнения остановить процедуру и вернуть код в подходящий момент времени. Во время дебаг-отладки действие незаменимо, оно многократно ускоряет работу. Особенно полезно при отладке кратковременных евентов в UI
, вроде анимации или динамических элементов. Одним из динамических компонентов является поле для автозаполнения, где сверху показывается панель с кнопками управления, а администратору предоставляется доступ к журналу событий.
Гарантировать правильность отображения результата смогут только функции, которые преобразуют элементы из чистого вида. В других случаях нельзя достоверно утверждать, что «путешествие во времени» покажет правильный результат.
Негативной стороной вопроса в отношении применения чистого функционального языка является сложность внедрения некоторых полезных элементов, к примеру, асинхронное выполнение запросов без прерывания работы скрипта или применение инкрементов.
Для некоторых фреймворков инкрементные величины не являются проблемой, к ним относятся virtual-dom
и React-js, это справедливо по меньшей мере в отношении web-программирования. Отмечается также обратный эффект, код приобретает очевидность, ведь он пишется подобным методом, как и весь пользовательский интерфейс, вырисовывая его по новой. Функциональность и чистота языка создают дополнительное преимущество – при многократном вызове функции с одинаковым аргументом, результат подвергается кешированию, что увеличивает скорость возврата значений.
В отношении асинхронных запросов также есть выход – специальные конструкции, они не отличаются изящностью, но просты и достаточно эффективны.
С учётом всех достоинств и недостатков, делаем вывод, что язык программирования Elm способен реализовать данный подход, оставаясь чистым, быстрым и многофункциональным. После компиляции он преобразуется в JS-код, который предназначается для построения приложений по технологии HTML5, правда требуется выполнение работы и со стороны серверной части. Опробовать язык можно на официальном сайте Elm, здесь представлены живые примеры использования и продемонстрированы возможности. На сайте богатая база знаний для углублённого изучения архитектуры языка и работы с асинхронными запросами.
Негативной стороной языка Elm Software Foundation является минимальное количество обновлений. Качественная и полноценная поддержка прекратилась в 2016 года. Основателем является Эван Чаплицкий, который уделяет минимум времени развитию языка. Его основное время провождение – поездки по миру для выступлений на конференциях с целью указания причин, почему языку суждено стать будущим программирования.
Нельзя сказать, что Elm пора списывать со счётов, так как язык действительно удобный, но он приобретает небольшое количество приверженцев естественными методами. Если посмотреть на рейтинг TIOBE
, ELM
входит в число 100 популярных языков. Другой немаловажной причиной является отсутствие конкуренции, одни направлены на покрытие огромного пласта программирования, а остальные известны только в узком кругу. Всё же остаётся надежда, что Эван или NoRedInk начнут всерьёз развивать детище, тогда Elm войдёт в ряды мейнстрим-языков.
Если ваша сфера деятельности связана с Web, обязательно следует ознакомиться с Elm. Углублённого изучения не потребуется, а весёлое времяпровождение гарантировано.
itproger.com
Каждый раз начиная разговор о популярных языках программирования можно быть уверенным, что холивар неизбежен. Одним нравится С++, другим Python, третьим Rust. Как говорится, на вкус и цвет фломастеры разные. Тем не менее, попробуем и мы покопаться в апельсинах.
Если рассортировать языки программирования по их популярности, то можно условно выделить три группы. В верхнюю группу войдут такие мейнстримовые языки, как Java, JavaScript, Python, Ruby, PHP, C#, C++ и Objective-C. Учитывая, что популярность языков может со временем снижаться, то чтобы быть востребованным программистом, всегда лучше знать один-два языка из верхней группы.
Во второй группе оказываются языки, которые с большой вероятностью могут стать мейнстримом, но ещё не стали. Они уже доказали свою ценность, вокруг них выросло сильное сообщество поддержки, но многие консервативные компании пока не используют их при создании продуктов. Пожалуй, к этой группе можно отнести Scala, Go, Swift, Clojure и Haskell. Хотя ряд компаний уже используют их для создания своих сервисов, однако в целом в индустрии их присутствие не так заметно (за исключением Swift, который сейчас замещается Objective-C на роли основного языка iOS). Больше всего шансов перейти в верхнюю группу у Go и Swift, это может произойти в течение ближайших двух-трёх лет.
Большинство языков из верхней группы прочно там укоренились. Переход из топа в среднюю занимает какое-то время, а для членов средней группы может быть очень непросто в верхнюю.
В третьей группе находятся языки, которые пока не обрели широкой популярности. Некоторые из них находятся в этой группе уже несколько лет, но так и не предприняли следующие шаги, чтобы завоевать симпатии более широкого круга программистов. Некоторые языки делают лишь первые шаги, появившись в последние пару лет. Сегодня нам хочется остановиться на пяти языках из третьей группы, которые сегодня определенно начинают набирать популярность.
Elm становится всё популярнее среди JavaScript-программистов, в основном среди тех, кто отдаёт предпочтение функциональному программированию. Как и Babel, TypeScript и Dart, Elm транспилируется в JavaScript.
Rust — это язык для создания систем, который призван был во многом заменить С и С++. Тем удивительнее наблюдать стремительный рост его популярности среди веб-разработчиков. Но если вспомнить, что Rust был разработан в Mozilla, то всё становится на свои места: авторы языка хотели дать веб-разработчикам более производительный язык по сравнению с PHP, Ruby, Python или JavaScript. По результатам опросов на StackOverflow в 2016 году Rust завоевал титул «самой любимой» разработчиками технологии. Так что многие, вероятно, не согласятся с тем, что здесь он отнесён в третью группу. Вполне возможно, что его место — уже во второй.
Kotlin существует около пяти лет, но только в этом году наконец добрался до версии 1.0. Хотя язык не так популярен, как Scala, Groovy или Clojure — одни из наиболее зрелых JVM-языков, — он дистанцируется от массы конкурентов и, похоже, готов влиться в ряды лидеров этой группы. Kotlin разрабатывается компанией, создавшей популярный IDE IntelliJ IDEA. Авторы языка руководствуются принципом повышения продуктивности разработчиков. Ещё одна причина, почему Kotlin может стать широко популярен — простота создания на нём Android-приложений.
Crystal — совсем молодой язык, который замахнулся на производительность на уровне С в сфере веб-разработки. Crystal ориентирован на Ruby-программистов и использует похожий синтаксис. По мере роста количества стартапов, в которых для создания продуктов применяется Ruby, Crystal может начать играть ключевую роль, помогая выводить производительность приложений на новый уровень.
Elixir также вдохновляется экосистемой Ruby, однако он нацелен на создание высокодоступных систем с низким уровнем задержки — сфера, в которой у Rails есть проблемы, согласно мнению критиков. Производительность Elixir обеспечивается благодаря выполнению в виртуальной машине Erlang. Также важнейшую роль в жизни Elixir играет фреймворк Phoenix.
Давайте теперь посмотрим, как растёт популярность этих пяти языков, согласно данным StackOverflow и GitHub.
Каждый из языков уже оброс сообществом энтузиастов и обзавёлся еженедельной новостной рассылкой. Так что если вы подумываете о том, чтобы изучить какой-нибудь молодой язык, чьё будущее может стать достаточно радужным, то обратите внимание на героев этой подборки.
Отсутствие исключений во время runtime: код Elm имеет репутацию никогда не выкидывающего исключения во время runtime’а. Никаких «undefined is not a function.»
Невероятно полезный компилятор: многие восхищаются компилятором Elm с точки зрения полезности сообщений об ошибках. Зачастую можно услышать «если он скомпилировал, то обычно всё просто работает», даже после серьёзного рефакторинга. Это делает кодовые базы на Elm куда приятнее в сопровождении, чем JS.
Автоматическое выполнение семантического версионирования: elm-package автоматически выполняет семантическое версионирование. Если автор пакета пытается внести в API критическое изменение без учёта номера основной версии, то elm-package это заметит от откажется публиковать. Ни один другой диспетчер пакетов не выполняет так надёжно семантическое версионирование.
Быстрый и функциональный: Elm — чисто функциональный язык, гарантирующий отсутствие трансформаций или побочных эффектов. Это не только обеспечивает качественное масштабирование кода, но и позволяет отрисовывать пользовательский интерфейс быстрее, чем React, Angular и Ember.
Мощный инструментарий: elm-format позволяет форматировать исходный код в соответствии с принятыми стандартами. Больше не нужно спорить о соглашениях по стилям. Просто нажмите в редакторе Save, и ваш код станет прекрасно выглядеть. elm-test поддерживает модульное и нечёткое тестирование (fuzz testing). elm-css позволяет писать Elm-код, который компилируется в .css, так что вы можете использовать код совместно и в приложении, и в таблицах стилей, что не позволит возникнуть несогласованности данных.
Код на Elm может взаимодействовать с JavaScript, то есть его можно в небольших количествах использовать в JS-кодовой базе. Поэтому можно продолжать пользоваться гигантской экосистемой JavaScript и не изобретать колесо.
Для ознакомления с языком можно начать с guide.elm-lang.org, а продолжить с Elm in Action. В официальном блоге можно почитать и о способах применения Elm в вашей работе.
Безопасность: многие языки, подобные C, представляют собой открытые ворота для ошибок, возникающих в результате ручного управления памятью (например, висячие указатели или двойные высвобождения). Rust перенял лучшие методики из современного С++, вроде RAII и умных указателей, и превратил их в требования, благодаря которым код Rust стал безопасным по памяти.
Скорость: почти все языки работают медленнее С, потому что предоставляют абстракции, облегчающие разработку ПО, но повышающие издержки во время runtime (например, сборка мусора и динамическая диспетчеризация). В Rust упор сделан на «бесплатных абстракциях», или методах облегчения программирования, которые ничего не стоят во время runtime. Например, управление памятью выполняется в ходе компилирования, а для дженериков применяется статическая диспетчеризация (аналогично шаблонам в С++, но более безопасно по типам).
Согласованность (concurrency): в системных языках согласованный код всегда хрупок и подвержен ошибкам, учитывая особую природу программирования с использованием потоков (thread). Rust старается смягчить остроту этой проблемы с помощью гарантий на уровне типов с точки зрения того, какие значения и какими потоками могут использоваться совместно.
У Rust есть несколько отличительных особенностей:
Проверка заимствований (Borrow checker): прославленная фишка Rust — инструмент статического анализа, считывающий код и останавливающий компилирование, если есть риск возникновения ошибок памяти. Этот инструмент работает на основании регламентирования определения значений, которые принадлежат одному месту в коде или заимствованы несколькими местами, с последующим анализом того, как владение значениями изменяется по ходу жизни программы. Проверка заимствований также исключает «гонки данных» в согласованном коде, использующем тот же набор правил.
Принцип Composition over inheritance: вместо использования системы классов, основанной на наследовании, как в C++ или Java, Rust для поддержки модульного программирования использует трейты (trait) — компонуемые интерфейсы. Вместо того, чтобы определять, является ли конкретный тип частью иерархии классов, программист может описать возможности типа. Например, сказать, что тип должен быть Printable и Hashable, вместо наследования от класса PrintableHashable.
Потрясающий инструментарий: каждый ветеран C/C++ знает, какая это боль — устанавливать зависимости, компилировать код под разные платформы и сражаться с мудрёными конфигурациями CMake. Благодарая разумному диспетчеру пакетов и API с кроссплатформенной совместимостью, Rust позволяет избежать многих часов истошных криков на GCC.
Полезные ресурсы: The Rust Book и Rust by Example.
Что хотели авторы Kotlin:
Краткость: уменьшить количество шаблонного кода, необходимого для выражения определённых конструкций.
Универсальность: язык должен подходить для разработки любых промышленных приложений — веб, мобильных, настольных или серверных.
Безопасность: язык должен справляться с некоторыми распространёнными проблемами, возникающими в результате ситуаций наподобие исключений из-за нулевых ссылок.
Интероперабельность: язык должен взаимодействовать с существующими кодовыми базами на Java, библиотеками и фреймворками, чтобы можно было внедрять его постепенно и использовать уже сделанные инвестиции.
Удобство автоматизации: JetBrains создаёт программные инструменты, и в компании считают, что многие рутинные операции можно автоматизировать ради повышения эффективности и продуктивности разработки. Поэтому язык должен быть удобен с этих точек зрения.
В Kotlin всё подчинено прагматизму — решению проблем, с которыми часто сталкивались авторы языка. Это определило такие свойства языка, как:
По умолчанию безопасен с точки зрения неопределённых значений (null): типы в Kotlin по умолчанию не допускают неопределённых значений, что позволяет избегать ситуаций с нулевыми ссылками или исключениями указателей.
Делегирование первого класса: способность делегировать внешней функции функциональность члена класса, что облегчает многократное использование.
Соглашения: ряд соглашений, позволяющих писать выразительный код, делающих язык сильно типизированным и предметно-ориентированным, что облегчает рефакторинг.
Kotlin 1.0 вышел в феврале 2016, спустя пять лет разработки и масштабного тестирования на реальных проектах. На данный момент более 10 продуктов JetBrains написаны на этом языке, также его используют ряд других компаний.
Офсайт: kotlinlang.org
Это высокоуровневый, статически типизированный, полностью объектно-ориентированный язык с расширенным выведением типа и сборкой мусора.
Цели разработки Crystal:
• Синтаксис, аналогичный Ruby (но без учёта совместимости с ним)
• Статическая проверка типов, но без необходимости определять тип переменных или аргументов метода
• Возможность вызывать код на C с помощью биндингов
• Во время компилирования код оценивается на наличие шаблонных кусков и перегенерируется
• Компилирование выполняется в эффективный нативный код
Особенности языка:
Каналы: внедрение каналов в Crystal было вдохновлено CSP, они обеспечивают согласованность (concurrency). Это лёгкие потоки исполнения (thread), называющиеся Fiber, с их помощью можно легко выполнять операции в асинхронном/неблокируемом режиме.
Макросы: они позволяют избежать использования шаблонных кусков кода и обеспечивают возможность метапрограммирования. Макросы обрабатываются во время компилирования, поэтому не влияют на производительность.
Команда Crystal: мощная команда, идущая со встроенными инструментами. Она используется для создания нового проекта, компилирования, запуска набора тестов и много другого. Также доступно встроенное средство форматирования. crystal play — интерактивная песочница для быстрого прототипирования, как irb.
Выразительность: благодаря Ruby, Crystal получился очень выразительным и лёгким в понимании. Новичкам будет просто его освоить. К тому же в перспективе простота языка окупается лёгкостью сопровождения.
Полезные ссылки: Crystal Book и Crystal for Rubyists.
На данный момент Elixir в основном используется для создания веб-приложений, с использованием Cowboy (примитивный HTTP-сервер) или Phoenix (полноценный фреймворк для создания веб-приложений). Благодаря фреймворку Nerves, Elixir постепенно проникает в сферу встроенного оборудования.
Синтаксис языка чем-то похож на Ruby, а инструменты Elixir вообще покажутся знакомыми каждому «рубиисту». Команды хорошо продуманы, просты в использовании и позволяют работать с высокой продуктивностью.
Цели языка:
«Дружелюбное» функциональное программирование: возможности и преимущества функционального языка с ясным и доступным синтаксисом.
Высокая согласованность и масштабируемость: для большинства пользователей язык сам по себе не должен мешать решению серьёзных задач.
Прекрасные инструменты для разработки: набор инструментов для создания приложения, управления зависимостями, тестирования и развёртывания.
Отличительные черты:
Неизменяемые структуры данных и отсутствие побочных эффектов помогают создавать большие системы, удобные в поддержке.
Инспектирование позволяет определять дерево внутренних процессов и настраивать правила автоматического восстановления работоспособности системы.
Поиск по шаблонам является альтернативой условным конструкциям и граничным операторам (guard clauses).
Согласованность процессов без разделения ресурсов, на основе акторов, хорошо подходит для решения современных проблем с согласованностью. См. «Путь к двум миллионам подключений».
Очень эффективное управление ресурсами позволяет обслуживать большое количество пользователей даже на достаточно скромном оборудовании. См. «Почему WhatsApp нужно всего 50 инженеров для обслуживания 900 миллионов пользователей».
Код, поддерживающий возможность горячей замены, позволяет минимизировать продолжительность простоев при развёртывании.
Популярность комбинации Elixir и Phoenix растёт благодаря тому, что она позволяет создавать сложные, устойчивые веб-приложения и API, очень удобные в сопровождении, с прекрасной производительность и масштабируемостью. Поэтому многие компании, включая Pinterest и Bleacher Reports, начали использовать Elixir в ключевых компонентах своей продуктовой инфраструктуры.
В итоге хочется сказать, что делать прогнозы занятие неблагодарное. Конечно же все может стремительно измениться и в 2017 году появится язык программирования, который заткнет за пазуху все остальные. Но, как гласит народная мудрость, плохому танцору eggs-ы мешают. Так что, всем чистого кода и меньше багов на любимых языках в Новом году!
sohabr.net