Рубрика «FRP» - 2

Недавно мне выпал шанс заняться веб-приложением для взаимодействия с интерактивной доской (!) для мобильных устройств (!!) на любом стеке технологий, как серверных, так и клиентских (!!!). На этапе прототипа задача представляла собой простейший графический редактор. Заказчик изъявил желание уметь рисовать ломаные каким-нибудь способом, круги, отрезки, произвольные кривые и добавлять текст. Все вроде бы просто, однако, наученный горьким опытом GoF, Фаулера и прочих апологетов всяческих паттернов, я сразу понял, что заказчик лукавит, и что уже через неделю-месяц после прототипа ему понадобится рисовать эллипсы, прямоугольники и кучи прочих ништяков. И все это точно надо будет делать разными способами. По крайней мере, для десктопа и мобил.

Собственно, можно все сделать в лоб (для прототипа-то), но выпали выходные, пауза в задачах текущего проекта, и я решил сделать все по-хорошему. И в первый же вечер — callback hell.

А потом…
Потому что на работе больше заниматься нечем

Читать полностью »

Здравствуйте, меня зовут Дмитрий Карловский и я… профессиональный велосипедист. За свою жизнь я перепробовал множество железных коней, но в конечном счёте остановился на самодельном. Не то чтобы мне очень нравилось работать напильником, тратя кучу свободного времени на изобретение колеса, но конечный результат, где каждая кочка не отдаётся болью в нижней половине туловища, того стоит. А теперь, когда вы знаете, что я затеял всё это не просто так, а чтобы сделать мир лучше, позвольте представить вам TypeScript/JavaScript модуль $jin.atom.

Краткое содержание предыдущей серии: простейшее приложение достигло критического уровня сложности, и, чтобы совладать с оной, была введена абстракция «атом», которая вобрала в себя всю рутину, позволив разработчику сконцентрироваться на описании инвариантов в функциональном стиле, не теряя связи с объектно ориентированной платформой. Вся теория и картинки там. Тут же будет куча практики, примеров кода и дампов консоли.
Читать полностью »

В первой части мы остановились на следующей спецификации: Трансдьюсер — это функция принимающая функцию step, и возвращающая новую функцию step.

step⁰ → step¹

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

result⁰, item → result¹

Чтобы получить новый текущий результат в функции step¹, нужно вызвать функцию step⁰, передав в нее старый текущий результат и новое значение, которое мы хотим добавить. Если мы не хотим добавлять значение, то просто возвращем старый результат. Если хотим добавить одно значение, то вызываем step⁰, и то что он вернет возвращаем как новый результат. Если хотим добавить несколько значений, то вызываем step⁰ несколько раз по цепочке, это проще показать на примере реализации трансдьюсера flatten:

function flatten() {
  return function(step) {
    return function(result, item) {
      for (var i = 0; i < item.length; i++) {
        result = step(result, item[i]);
      }
      return result;
    }
  }
}

var flattenT = flatten();

_.reduce([[1, 2], [], [3]], flattenT(append), []); // => [1, 2, 3]

Т.е. нужно вызывать step несколько раз, каждый раз сохраняя текущий результат в переменную, и передавая его при следующем вызове, а в конце вернуть уже окончательный.

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

Итак, сейчас мы можем:

  1. Изменять элементы (прим. map)
  2. Пропускать элементы (прим. filter)
  3. Выдавать для одного элемента несколько новых (прим. flatten)

Читать полностью »

Рич Хикки, автор языка Clojure, недавно придумал новую концепцию — Трансдьюсеры. Их сразу добавили в Clojure, но сама идея универсальна и может быть воспроизведена в других языках.

Сразу, зачем это нужно:

  • трансдьюсеры могут улучшить производительность, т.к. позволят не создавать временные коллекции в цепочках операций map.filter.takeWhile.etc
  • могут помочь переиспользовать код
  • могут помочь интегрировать библиотеки между собой, например underscore/LoDash могут уметь создавать трансдьюсеры, а FRP библиотеки (RxJS/Bacon.js/Kefir.js) могут уметь их принимать
  • могут упростить FRP библиотеки, т.к. можно будет выбросить кучу методов, добавив один метод для поддержки трансдьюсеров

Трансдьюсеры — это попытка переосмыслить операции над коллекциями, такие как map(), filter() и пр., найти в них общую идею, и научиться совмещать вместе несколько операций для дальнейшего переиспользования.

Читать полностью »

Наверняка многие уже слышали о подходе FRP для организации асинхронного кода. На хабре уже писали об FRP (Реактивное программирование в Haskell, FRP на Bacon.js) и есть хорошие доклады на эту тему (Программировние UI с помощью FRP и Bacon.js, Functional Reactive Programming & ClojureScript, О Bacon.js от Juha Paananen — автора бекона)

Если коротко, FRP это подход похожий на Promise, но с неограниченным количеством возвращаемых значений, и бОльшим количеством методов для комбинирования / модифицирования потоков событий. Другими словами, если Promise позволяют работать со значением, которого у вас еще нет, так, будто оно у вас уже есть, то FRP позволяет работать со значением, меняющимся во времени, так, будто оно не меняется.

Вот что это дает по сравнению с обратными вызовами:

1) Поток событий (Event stream) и значение меняющаяся во времени (Property / Behavior) становятся объектами первого класса. Это значит что их можно передавать в функции и возвращать из функций.

Например, можно создать объект содержащий клики на кнопку (поток событий), и дальше делать с этим объектом всё, что можно делать с обычной переменной — передавать в функцию, возвращать из функции, сохранять как свойство другого обекта и т.д. Или можно создать объект отражающий текущий размер окна браузера (значение меняющаяся во времени).

Это позволяет гораздо лучше разделять ответственности в коде, разделять его на модули, и писать более гибкий, короткий и управляемый код.

К примеру можно написать функцию, возвращающую поток перетаскиваний (drag). В качестве параметров она будет принимать 3 потока — начало перетаскивания, движение, конец перетаскивания. Дальше можно передать в эту функцию: либо потоки для соответствующих событий мыши (mousedown, mousemove, mouseup), либо для touch событий (touchstart, touchmove, touchend). Сама же функция не будет ничего знать об источниках событий, а будет работать только с абстрактными потоками. Пример реализации на Bacon.

2) Явный state

Второе большое преимущество FRP это явное управление состоянием. Как известно, state — один из самых главных источников сложности программ, поэтому грамотное управление им позволяет писать более надежные и простые в поддержке программы. Отличный доклад от Рича Хикки о сложности (complexity) «Simple Made Easy».

FRP позволяет писать бОльшую часть кода на «чистых функциях» и управлять потоком данных (dataflow) явно (с помощью потоков событий), а состояния хранить тоже явно в Property.

Читать полностью »

Здравствуйте, меня зовут Дмитрий Карловский и я… клиент-сайд разработчик. За плечами у меня 8 лет поддержки самых различных сайтов и веб-приложений: от никому не известных интернет-магазинов, до таких гигантов как Яндекс. И всё это время я не только фигачу в продакшен, но и точу топор, чтобы быть на самом острие технологий. А теперь, когда вы знаете, что я не просто хрен с горы, позвольте рассказать вам про один архитектурный приём, которым я пользуюсь последний год.

Данная статья знакомит читателя с абстракцией «атом», предназначенной для автоматизации слежения за зависимостями между переменными и эффективного обновления их значений. Атомы могут быть реализованы на любом языке, но примеры в статье будут на javascript.

Осторожно: чтение может вызвать вывих мозга, приступ холивара, а также бессонные ночи рефакторинга.
Читать полностью »

Участвовали в Clojure Cup 2013 вместе с Саней ingspree, Сергеем Joes и Ромой rofh. Наверное, вы видели нарезку, а может и полное выступление Сани о кложурскрипте и реактивном программировании. Вот и подвернулась возможность попробовать эти технологии в бою.

Тематика соревнования — за 48 часов напилить что-нибудь, используя Clojure или ClojureScript. Из разных вариантов решено было пилить браузерный Risk, в частности потому, что все существующие приложения убоги интерфейсом, или написаны на Flash, или, ещё того хуже — Silverlight, или ещё каким-нибудь образом портят времяпровождение. Коллективно придумалось хорошее название — War Magnet.

Недолго думая, мы решили писать и сервер на Clojure, и клиент на ClojureScript, с использованием общего кода. Из четырёх участников только у Сани был хоть какой-то опыт написания на кложуре, а у остальных был только опыт решения нескольких десятков задачек на 4clojure.

Читать полностью »

Как известно, функциональный подход к программированию имеет свою специфику: в нём мы преобразовываем данные, а не меняем их. Но это накладывает свои ограничения, например при создании программ активно взаимодействующих с пользователем. В императивном языке намного проще реализовать такое поведение, ведь мы можем реагировать на какие либо события «в реальном времени», в то время как в чистых функциональных языках нам придётся откладывать общение с системой до самого конца. Однако относительно недавно стала развиваться новая парадигма программирования, решающая эту проблему. И имя ей — Functional Reactive Programming (FRP). В этой статье я попытаюсь показать основы FRP на примере написания змейки на Haskell с использованием библиотеки reactive-banana.
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js