Год спустя появилась версия 0.4 уже на 72 строки с паттерн матчингом и mix (аналог combine из flyd или computed из vue). Спустя три года и десятки проектов — появилось ощущение годности делится опытом и релизить 1.0.
fantasy land
Резкое погружение в FRP человека всю жизнь писавшим классический OOP по учебнику, может взорвать голову как резкое погружение на глубину вне батискафа. Мне понадобилось несколько недель чтоб сжиться с мыслью о функциях вместо переменных. А спустя три месяца уже во всю любовался реактивным графом приложения — программу можно видеть как вены или корни/ветви дерева. Думаю мне помог простой интерес к древним языкам вроде санскрита и любовь к эльфийской Quenia. Продувать уши зажимая нос — базовый навык дайвера. Состоявшимся классическим OOP программистам потребуется сдуть пыль со своего навыка погружения в знания. Матёрым функциональщикам возможно уже ничего не поможет, но возможно они помогут нам в преодолении существующих форм и клеше описаний.
Неизвестные имена
В философии монадой называют базовую частицу мироздания — частицей бога, довольно низкоуровневое понятие. В спецификациях fantasy land, и в общем понимании FRP монада — нечто высокоуровневое, содержащее внутри функтор. В википедии есть два определения функтора в общем и OCaml контексте. В контексте alak базовая частица функтор — функция содержащая данные при изменении которых происходит обновление связанных функций/функторов. Всё, просто как в таблицах excel.
В bacon.js подобное зовётся «атомными обновлениями», RxJs так не умеет.
В alak код может выглядеть так:
import A from 'alak'
// создание функтора потока - единственное назначение библиотеки alak
const userId = A.flow();
// создание ещё трёх функторов для дочерних узлов графа
const followers = A.flow();
const profile = A.flow();
const tweets = A.flow();
//вариант связи userId -> profile ребром getProfile
const getProfile = id => api.getProfile(id).then(profile);
userId.up(getProfile);
//связь остальных узлов
userId.up(id => {
api.getFollowers(id).then(followers)
api.getTweets(id).then(tweets);
});
Запустить на codesandbox
При изменении userId произойдёт реактивное изменение followers, profile, tweets.
Всё для начала
Всё использование функтора Alak основывается на способности мыслить потоками, как в Go, но при чтении из канала из него не убывает и вся соль в построении графа с множественными связями/рёбрами, слушателями потока.
Ещё в angular.js этого было достаточно для красивого разруливания стейта запредельной сложности и запутанности. Крестом на angular2 для меня стало навязывание RxJS с сомнительной реактивностью. Увидев ReduX возникло ощущение два шага назад к реализации PureMVC.
Этим постом я, как и многие современные спикеры призываю отбросить процедурное мышление, груз ООП паттернов и начать движение к человеческому/литературному коду. Alak сегодня достаточно хорошо помогает декларативно описать реактивный граф стора.
Мы воспринимаем реактивность вью (jsx/svelte/html-шаблонизаторы) как должное.
— Так отчего у нас нет такой же реактивности в сторах?
Комментарии (21)
Nurked
15.09.2019 22:24+1Божешь тыж можешь тыж! Панэ, зачем такое писать?
Ок. Замечательно. Я бы на самом деле с удовольствием прочитал бы статью про FRP. И судя по всему у вас тут какое-то озарение, так что я бы прочитал вашу статью по FRP. Но ёлки-палки! Я программист с пятнадцатилетним стажем. Я могу собрать процессор из буханки хлеба и умею писать на более чем 40 языках. И при всём при этом мне потребовалось 20 минут на то, чтобы прочитать эти пять абзацев.
flyd, монада, функтор, фреймворки. Вы просто разбрасываетесь словами которые сами не полностью понимаете, и при этом при всём не даёте им определений, а ещё дальше погружаете нас, ваших верных читателей, в океан неизвестного.
А этот пацак все время говорит на языках, продолжения которых не знает! (с)
Не могли бы вы помочь мне и вашим остальным читателям путём написания статьи которая объясняет базовые понятия FRP, но только очень хорошо и глубого их объясняет. Чтобы мы могли проникнуться всей изумительной красотой вашей статьи.GlebYP Автор
16.09.2019 01:09Таки есть — никто не знает как дальше будет складываться управление состоянием на клиенте. Офлайн режим вряд ли отменится с грядущими блокировками и как следствием децентрализации всемирной сети и данных, что будут собираться как пазл.
Копья обломаны в поисках языка/способа описания графа данных. То, как можно в Clojure — вероятно подходит лучше всего, даже смотрел как в этой задаче применить Web Ontology Language, но пока тщетно. В мире JS недостаточно инструментария, с новыми версиями TS особенно от 2.8 появляются лучики надежды. Возможно новый подход будет успешней.
Статей о FRP вроде достаточно, к тому же первые два года использования alak я не вдуплял шо це самый настоящий функтор и даже по алгебраическим канонам. Однако это всё действительно лишь слова, и я не шибко вдаюсь в подробности что значит монада для программистов, уж шибко разнообразны могут быть реализации и толкования. ?В моих силах только в будущей (через одну) статье описать значение этих слов из своей картины мира.
Я считаю некоторые знания — не умом берутся и понимаются. Океан невозможно постичь не оказавшись в нём самостоятельно, сколько книг о нем не прочитай и фильмов не пересмотри. Только пройдя к нему свой путь и решившись нырнуть — можно понять что всё это глупости или ничего лучше в жизни нету. C очень большой вероятностью это будет совсем не то что у такого же коллеги рядом нырнувшего в эти же воды. :)
xGromMx
18.09.2019 09:49Более-менее что-то толковое github.com/funkia/hareactive (по каким-то канонам Конала Эллиота, как автора идеи FRP, что есть изоморфизм к темпоральной логике)
GlebYP Автор
18.09.2019 10:58Аватарка у Конала в твиттере под кайфом :)
Чистое FRP вероятно как тяжёлые наркотики, потом захочется scalaz и будет не слезть.
Пожалуй мне хватит одного функтора на всё.
Возможно получится более человеческий стиль.
k12th
15.09.2019 22:46+1Мы воспринимаем реактивность вью (jsx/svelte/html-шаблонизаторы) как должное.
— Так отчего у нас нет такой же реактивности в сторах?Я вот пользуюсь vuex и у меня есть реактивность в сторах:)
GlebYP Автор
16.09.2019 00:51Использование VueX/ReduX мне напоминают манипуляции с JQuery — когда у нас на всё есть отдельное действие. Последние пару лет я искал методы декларативного описания данных в сторе и связей/отношений друг с другом. Не очень удачно в плане доступности понимания решений. У нас нет привычного языка описания данных как HTML, и привычней диспатчить события, каждый раз прописывая мутации.
kovserg
15.09.2019 22:59Всегда интересовало: как организовывается завершение таких конечных автоматов, если его приспичило его немедленно остановить.
GlebYP Автор
16.09.2019 01:24Сперва это можно понять в контексте DOM через
_.stopPropagation();
Возможно тут будет подробно описано: learn.javascript.ru/event-bubbling
Нужно просто добавить остановку в том месте где приспичило остановить.
В случае alak я добавил тихое обновление узла графа без уведомления дочерних узлов.
Останавливается опционально определённая ветка.
— либо при условии, как фильтр
— либо на совсем закрывается/отрезается
andres_kovalev
16.09.2019 02:17+1По стилю изложения заметка похожа на машинный ппревод лет пять назад, когда из мешанины слов невозможно было разобрать смысл. Ну и при чем тут конечные автоматы?
GlebYP Автор
16.09.2019 03:24— Реактивные конечные автоматы.
При решении, реализация которого рассмотрена в этой заметке на примере.
Предполагаю, лет через N могут появится языки/способы описания отношения данных в подобных решениях.
Тогда изложенное в статье может стать понятней.
gatoazul
16.09.2019 13:24Такое чувство, что автор получил наркотический приход и теперь пытается нам о нем рассказать.
GlebYP Автор
16.09.2019 15:05Scf
16.09.2019 09:36Документации к проекту нет
Комментариев в исходниках тоже нет
Примеры минимальны (причем второй пример нерабочий)
В статье так и не написано, что такое flow, как они комбинируются и где там реактивность.
В общем, я ничего не понял, а вычитывать все исходники и разбираться в коде без комментариев в поисках интересных решений — на любителя занятие.
Вот пример, как надо описывать свои идеи: https://habr.com/ru/post/235121/
GlebYP Автор
16.09.2019 11:41Вдохновлялся иллюстрациями к этой статье в начале пути.
Есть мнение: код нуждающийся в комментариях — вероятно лучше переписать на понятный без комментариев. СейчасA.flow()
— означает создание нового функтора. Благодаря вам, я понял — это не самая выразительная запись, просто исторически так сложилось. Комментарий в статью добавил, в проекте не нашёл поломки примера.
Основное интересное решение — без которого нет смысла в комбинациях, я иллюстрировал анимацией в статье. Добавил в текст код и ссылку «запустить» где возможно увидеть пример комбинации на 48 строке, и помедитировать над реактивностью.
Там очень мало строк.
Нет нужды писать больше, когда самое главное остаётся незамеченным.
Многие по прежнему считают лучше использовать избыточные решения с трехтомной инструкцией по использованию. Согласен с автором статьи по вашей ссылке, собрать свой атом/функтор каждый может сам.
— Важно понять/увидеть живую идею.
KwI
16.09.2019 11:38Отличная идея, сам нахожусь в поисках и экспериментах с подобными вещами.
Есть вопрос — как отлаживаете этот реактивный граф? ИМХО вся боль такой реактивности, которую я встречал в mobx например — чертовски сложно уследить, кто где как и с чем связался и куда данные летают.GlebYP Автор
16.09.2019 11:56MobX — близок по идее, но как-то уже так приловчился работать с потоками.
В решение одном из проектов на vue можно логировать имя тега компонента, откуда произошло обращение к какому узлу графа или действию. Действия(actions) так же при изменении графа логируют своё имя. Различные типы связей так же логируются откуда куда и что. Если изменение происходит вне стора — можно указать имя, от кого мутировать граф.
— Так в консоли всегда можно отследить цепочку изменений кто кого на что менял.
Получается очень много логов, но можно фильтровать.
Планирую написать на d3 что-то вроде dev-tools, для просмотра такой активности, хотяб просто потому что это будет красиво.
mikolalex
17.09.2019 13:19Посмотрите например это: www.npmjs.com/package/mrr
Можно включить логирование как для отдельной ячейки, так и для всего графа, с выводом цепочки обновлений зависимых ячеек в консоль.
xGromMx
18.09.2019 09:44Понимание функтора напрочь отсутствует, как и многих других вещей
В жс нет понятия FRP, тут можно мыслить только RPGlebYP Автор
18.09.2019 10:38Как так? вы же написали статью для желающих изучать FRP в контексте RxJS.
И выше рекомендовали библиотеку чистого FRP для js
А https://ramdajs.com разве не FP?
В статье нет точных общих определений, только абстрактные для согласованности во всех возможных практикующих лагерях FP/RP/FRP. С акцентом на возможно новое понимание и новый контекст слов монада и функтор произошедших из философии.
Мыслите свободно.
hd_keeper
А дальше?