Недавно, просматривая интересные репозитории на github в поисках вдохновения я наткнулся на проект Elm — функциональный реактивный язык программирования, созданный для веб, потомок ML и Haskell. У меня нет большого опыта в функциональном программировании, но посмотрев посадочную страницу, я увлекся этим творением на несколько часов, позабыв о работе и окружающем мире. Меня сразу вдохновила та простота, которая, как мне казалось раньше не присуща функциональным языкам программирования.
Еще раз повторюсь, что я не силен в функциональном программировании, плохо знаком с математическими концепциями, на которых оно строится и изучению Elm удлелил, пока что, не очень много времени. Я считаю, что лучше бы эту статью написал кто-то другой, более осведомленный, но, таковых не нашлось, а до тех пор, я решил возложить эту ношу на себя, быть может, моя статья поможет кому-то открыть для себя прелести функционального программирования для веб, или по новому взглянуть на, казалось бы привычные вещи. Большинство материалов, представленных в статье взяты из официальной документации и переведены в довольно свободной форме. Всех страждующих, прошу под кат.


Для начала, давайте напишем наше первое приложение на 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 class="welcome-message">Hello, World!</span>


Но это все не очень интересно, ведь для генерации простого HTML-кода в одну строку нам пришлось написать целых 4 строчки на Elm, пока что не очень впечатляет, но стоит только заглянуть в основные концепции архитектуры языка и все становится на свои места.

Вся логика программ на Elm разделена на 3 понятные и простые части, уже, так или иначе, знакомые многим в веб разработке:
  • Model(модель)
  • Update(обновление)
  • View(представление)


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

Комментарии (22)


  1. ConstSe
    06.07.2015 00:17
    +26

    «Меня сразу вдохновила та простата» — исправьте. Думал в личку написать, но пусть уж другие тоже поржут над опечаткой. :)


    1. hlogeon Автор
      06.07.2015 00:23
      +7

      Спасибо. Хорошо, что я не пишу на медицинские темы.


      1. Alexeyco
        06.07.2015 12:08
        +1

        А может быть, наоборот, зря?


  1. ShadowsMind
    06.07.2015 10:21

    Хм, elm-compiler написал на Haskell, необычный выбор авторов надо сказать.


    1. hlogeon Автор
      06.07.2015 10:40
      +2

      Это чем же?


    1. roman_kashitsyn
      06.07.2015 11:11
      +4

      Что необычного в написании компилятора Haskell-подобного языка на Haskell, одном из лучших языков для написания компиляторов?


      1. ShadowsMind
        06.07.2015 11:15
        +1

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


        1. roman_kashitsyn
          06.07.2015 11:33
          +3

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

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


        1. hlogeon Автор
          06.07.2015 11:46
          +2

          Elm хорошее подтверждение Вашему заблуждению. И еще можно посмотреть на github реализации различных, вполне практичных вещей на Haskell. У меня часто возникает чувство: «Черт, почему я еще не пишу на Haskell»


  1. dborovikov
    06.07.2015 11:31

    Скажите, а в чем основное отличие Elm от PureScript?


    1. hlogeon Автор
      06.07.2015 12:03

      Отличий довольно много, что понимать под ОСНОВНЫМ, я не понимаю. Можете ознакомится вот с этой статьей
      www.slant.co/topics/1515/compare/~elm_vs_purescript_vs_haste


    1. dotneter
      06.07.2015 12:05

      Elm проще. Нет тайпклассов, соответственно нет развесистой библиотеки этих же тайпклассов. Язык заточен под одну парадигму. PureScript более универсальный например при желании можно использовать тот же jQuery.


      1. hlogeon Автор
        06.07.2015 12:18

        Разработчики учли важность возможности использования ELM с существующими библиотеками и сделали вот это:
        elm-lang.org/guide/interop


        1. dotneter
          06.07.2015 12:43

          Да, общаться можно через порты, как вы себе представляете через них использовать jQuery?


          1. hlogeon Автор
            06.07.2015 14:29

            как вы себе представляете через них использовать jQuery?

            Jquery действительно никак, но
            а) Нет видимых причин использовать jQuery с Elm
            б) Если всеже возникла такая необходимость, то любой функционал можно написать на elm, благо, на нём это займет совсем немного времени, и принести пользу сообществу, опубликовав пакет.
            в) я не вижу никакого ограничение на использование чистого JS в elm-проекте

            Под в) я имею ввиду примерно такую конструкцию во View
              script [type "text-javascript"] [src "myAwesomeScript.js"] 
            


  1. vintage
    08.07.2015 06:49

    Как на elm реализуются компоненты (виджеты)?


    1. hlogeon Автор
      08.07.2015 21:26

      Модули


      1. vintage
        09.07.2015 01:46

        Хотелось бы более конкретный пример.


  1. potan
    08.07.2015 14:31

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


    1. vintage
      08.07.2015 19:38

      Зачем вам рекурсивные сигналы?


      1. potan
        08.07.2015 19:52

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


        1. vintage
          09.07.2015 01:50
          -1

          Мне кажется вы пытаетесь использовать инструмент не по назначению.