1

有人说 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 中处理?

这是一个用于关闭状态的flajax实用程序:

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 中做到这一点?不同的模式,还是不同的库?

4

3 回答 3

1

我不熟悉 Flapjax,但是查看文档,您可以使用它collectE来创建一个累积状态的流。receiverE然后,使用and创建第二个动画帧事件流sendEvent

最后,模拟 bacon.js sampledBy( https://github.com/baconjs/bacon.js/wiki/Diagrams#sampledby ) 以创建 [animationFrame, state] 元组的第三个流。

于 2013-09-03T18:25:40.037 回答
0

这里有更多的flajax糖:而不是使用sampledBy使用snapshotE,它将在每个帧事件上对已经收集的更改数组进行快照。检查您的谷歌群组主题,我已经为它编写了一些代码。

于 2013-10-23T09:43:52.417 回答
0

FRP 完全是关于管理状态的。但它是关于没有时间管理状态的。为此,您必须将状态保留在树或图中。这可以防止任何旧代码在某个随机时间点对其进行变异。

FRP 状态仅在父节点触发更新时更新。发生这种情况时,事件值(和任何其他父值)用于计算新节点值。

blandw 上面的回答是正确的,因为 collectE 是您想要的。

在 collectE 中,该节点的先前值是在其父节点触发时提供的。这允许您存储您希望的任何状态,例如更改的集合。但是这个集合只有在父事件触发时才会更新。

因此,通过将您的状态突变限制在父母更新时,您可以节省很多麻烦。用一个基本的例子很难看出这一点。当您从事大型项目时,这一点变得更加明显。

但是,要更新 blandw 的答案,除了从非 frp 系统中获取事件之外,不要出于任何原因使用 receiverE。这绝不应该发生在 FRP 图的中间,而只能作为没有父节点的顶级节点。它在任何其他情况下的使用都违反了 FRP 的全部要点。

于 2015-08-26T04:45:47.797 回答