2013-08-13 5 views
1

Некоторые говорят, что FRP относится к обработке потоков событий без явного управления состоянием. Этот человек, например:управляющее состояние с FRP

http://www.slideshare.net/borgesleonardo/functional-reactive-programming-in-clojurescript

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

http://cs.brown.edu/~sk/Publications/Papers/Published/mgbcgbk-flapjax/

Однако экспериментировать с FRP (Flapjax), я продолжаю ударять ту же проблему: неспособность справиться с состоянием, за исключением явно, с помощью побочных эффектов.

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

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

Как это должно быть обработано в FRP?

Вот утилита Flapjax для закрытия над государством:

function worldE(init, handlers) { 
    var r = fj.receiverE(); 
    fj.forEach(function(h) { 
     h[0].mapE(function (ev) { 
      r.sendEvent(init = h[1](init, ev)); 
     }); 
    }, handlers); 
    return r; 
} 

И здесь он используется в цикле анимации:

function initialize(opts) { 
    var blitE = fj.receiverE(); 

    function accumulate(state, data) { 
     if (!state.queued) { 
      window.requestAnimationFrame(blitE.sendEvent); 
     } 
     return {queued: true, changes: _.extend({}, state.changes, data)}; 
    } 

    function dodraw(state, _) { 
     draw(state.changes); 
     return {queued: false, changes: {}}; 
    } 

    worldE({queued: false, changes: {}}, 
      [[opts.data_source, accumulate], [blitE, dodraw]]); 
} 

вещи, чтобы отметить: это больше, менее читаемыми и менее ремонтопригодны, чем эквивалентный код обратного вызова. Он по-прежнему требует явного управления состоянием. И он действует через побочные эффекты.

Есть ли лучший способ сделать это в FRP? Другой шаблон или другая библиотека?

+0

Я не знаком с flajax, но вы также можете попробовать RxJs. У этого может быть другой, лучший синтаксис. Кроме того, если вы хотите увидеть несколько более сложных примеров для FRP, взгляните на язык ELM http://elm-lang.org/ – allprog

ответ

1

Я не знаком с Flapjax, но, глядя на документы, вы можете использовать collectE, чтобы создать поток, накапливающий состояние. Затем создайте второй поток событий анимации с использованием receiverE и sendEvent.

И наконец, эмулируйте bacon.js's sampledBy (https://github.com/baconjs/bacon.js/wiki/Diagrams#sampledby), чтобы создать третий поток корней [animationFrame, state].

0

Здесь немного больше сахара flapjax: вместо использования sampledBy используйте snapshotE, который будет собирать моментальный снимок уже с помощью массива изменений для каждого события кадра. Проверьте свой раздел групп Google, я написал для него некоторый код.

0

FRP полностью посвящен управлению состоянием. Но об управлении государством без времени. Чтобы сделать это, вы должны сохранить состояние в дереве или графике. Это предотвращает изменение старого кода кода в некоторый случайный момент времени.

В состоянии FRP обновляется только в том случае, если родительский узел запускает обновление. Когда это происходит, значение события (и любое другое значение родителей) используется для вычисления значения новых узлов.

Ответы на blandw верны, поскольку collectE - это то, что вы хотите.

В collectE предыдущее значение этого узла предоставляется при запуске родительского узла. Это позволяет сохранять любое состояние, которое вы хотите, например, набор изменений. Но эта коллекция обновляется только когда родительское событие запущено.

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

Однако, чтобы обновить ответ blandw, не используйте приемник по какой-либо причине, кроме как получать события из систем non frp. Это никогда не должно происходить в середине графика FRP, но только как узел верхнего уровня без родителей. Это использование в любом другом случае нарушает всю точку FRP.

Смежные вопросы