понеділок, 24 червня 2013 р.

Elm <~ FRP ~ Magic

Добрался до Web:) А именно до Elm, который построен на идиоме функционального реактивного программирования. Это такой подход в котором с одной стороны функциональная чистота и декларативность, а с другой удобность построения интерактивного графического интерфейса. Вещи, которые могут изменятся, представляются в виде сигналов. А вся программа представляется в виде pure functional зависимостей между сигналами.

Приведу очень простой пример с WebSocket. Для этого нужен сервер который принимает сообщения, складирует их у себя и возвращает все склеенные через разделитель (конец строки). Я использовал cowboy на Erlang. Приложение тут.

Создаем поле и кнопку. Функция создания поля возвращает два объекта: сигнал графических элементов и сигнал строк. Сигнал графических элементов, а не просто графический элемент нужен потому, что поле может изменятся. А сигнал строк — это значения. Кнопка не изменяется, поэтому возвращается просто графический элемент и сигнал нажатий.

(newItemField, newItemData) = Graphics.Input.field ""
(newItemButton, newItemPressed) = Graphics.Input.button "Add Item"

Далее фильтруем сигнал данных. Результат — это сигнал, который состоит из данных второго поля, которые возникают во время нажатия кнопки.

filteredData : Signal String
filteredData = newItemPressed `sampleOn` newItemData

Функция beside возвращает элемент, который состоит из входных, размещенных определенным образом. Поскольку она работает на элементах, а у нас сигналы элементов, то нужно использовать функции схожие с map и foreach в других языках. По типу легко понять предназначение.

inputs : Signal Element
inputs = beside <~ newItemField ~ constant newItemButton

Далее подключаемся к серверу. Функция подключения принимает адрес сервера и сигнал входных сообщений (строк). Результатом есть сигнал ответов сервера. Посылка и прием сообщений асинхронный.

response : Signal String
response = WebSocket.connect 
    "ws://localhost:8080/websocket" filteredData

Парсим ответ, разделяя его на строки, далее каждую строку с помощю plainText превращаем в графический элемент, далее все элементы размещаем попорядку сверху вниз.

outputs : Signal Element
outputs = flow down . map Text.plainText . split "\n" <~ response

Далее размещаем поле и кнопку над результирующим списком и все готово. Простенько и со вкусом.

main : Signal Element
main = above <~ inputs ~ outputs

П.С. Спасибо Максиму за популяризацию Elm и Erlang среди меня.

Немає коментарів:

Дописати коментар