8

我正在学习响应式香蕉并打算在服务器端应用程序中使用它。我有一些 RxJs 的背景,所以我习惯在那里将事件与不同的组合器结合起来。所以我从简单的事件组合器示例开始。我试图制作一个简单的反应香蕉示例,它将两个整数事件组合成一个 sum 事件。我知道为了能够组合来自不同事件的值,我必须首先将它们变成行为,然后进行组合,最后将其变成一个新事件。我是这样做的:

-- Behaviors from Events e1, e2
let b1 = stepper 0 e1 :: Behavior Int
let b2 = stepper 0 e2 :: Behavior Int

-- Sum Behavior
let sumB = (+) <$> b1 <*> b2
-- Back to Event
let sumE = sumB <@ (e1 `union` e2)

完整的可运行示例可以在Gist 1594917中找到。

这里的问题是,当新值出现在其中一个事件(e1,e2)中时,sumE 事件被正确触发,但它包含一个陈旧的值。这显然是由于步进器的工作方式(行为的值在事件发生后“稍微改变”)。我尝试用 Discrete 替换 Behavior,结果相同。

有没有一种简单的方法可以使这种事件组合器正常工作?

4

1 回答 1

6

你的诊断完全正确。这里有两个选项:您可以通过 来从 Discrete 回到 Event changes,或者您可以创建累积事件。

从 Discrete 恢复可能更简单(这是我推荐的)。做就是了

-- Discretes from Events e1, e2
let d1 = stepperD 0 e1 :: Discrete Int
let d2 = stepperD 0 e2 :: Discrete Int

-- Sum Discrete
let sumD = (+) <$> d1 <*> d2
-- Back to Event
let sumE = changes sumD

NowsumE将始终更新何时e1e2更改。

替代方案仅使用事件,将传入事件转换为累积函数。听起来很复杂,但代码相当简单。

--convert each input into an accumulating tuple
let e1' = (\l (_,r) -> (l,r)) <$> e1
let e2' = (\r (l,_) -> (l,r)) <$> e2

let sumE = uncurry (+) <$> accumE (0,0) (e1' `union` e2')
于 2012-01-12T11:19:50.917 回答