rai*_*ska 8 haskell reactive-banana
我正在学习反应性香蕉,并打算在服务器端应用程序中使用它.我在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)
Run Code Online (Sandbox Code Playgroud)
完整的可运行示例可以在Gist 1594917中找到.
这里的问题是,当一个事件(e1,e2)中出现一个新值时,sumE事件被正确触发,但它包含一个陈旧值.这显然是由于步进器的工作原理(行为的值在事件发生后稍微改变).我尝试用Discrete替换Behavior,结果相同.
是否有一种简单的方法可以使这种事件组合器正常工作?
您的诊断完全正确.这里有两个选项:您可以从Discrete via返回事件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
Run Code Online (Sandbox Code Playgroud)
现在sumE
将始终更新e1
或e2
更改.
备选方案仅使用事件,通过将传入事件转换为累积函数.这听起来很复杂,但代码相当简单.
--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')
Run Code Online (Sandbox Code Playgroud)