在反应性香蕉

时间:2017-02-19 12:33:40

标签: haskell reactive-programming frp reactive-banana

我正在阅读Conal Elliot的论文"Declarative Event-Oriented Programming",其中的例子是使用Fran库编写的,现在已经过时了。

在我学习FRP时,我尝试使用reactive-banana来实现这些示例。我似乎没有问题(但必须认为很多 :))。我唯一不明白的是如何正确翻译弗兰的ifB

似乎有这种类型的签名:

ifB :: Behavior Bool -> Behavior a -> Behavior a -> Behavior a

但反应性香蕉只有switchB这种东西。

目前,我设法通过添加额外的"触发器"将用于切换行为的事件,如下所示:

ifB :: MonadMoment m => Event b -> BoolB -> Behavior a -> Behavior a -> m (Behavior a)
ifB trigger condB b1 b2 = switchB b2 (switcherB <@ trigger)
  where switcherB = (\x -> if x then b1 else b2) <$> condB

我不确定这是否是一个正确而好的解决方案。它表现得好吗? 以下是使用ifB

的论文摘录
editCPoint :: User -> S.Point2 -> CPoint
editCPoint u p0 = (pos, closeEnough)
  where
    pos, lastRelease :: Point2B
    --    vvv this is the ifB in question!
    pos = ifB grabbing (mouse u) lastRelease
    lastRelease = stepper p0 (release ‘snapshot_‘ pos)

    closeEnough, grabbing :: BoolB
    closeEnough = distance2 pos (mouse u) <* grabDistance
    grabbing = stepper False (grab -=> True .|. release -=> False)

    grab, release :: Event ()
    grab = lbp u ‘whenE‘ closeEnough
    release = lbr u ‘whenE‘ grabbing

grabDistance :: RealB
grabDistance = 2 * pointSize

我设法通过使用ifB的实现并为其提供cursor move事件来使此片段与reactive-banana一起使用,以便定期更新。我尝试只将鼠标按下/释放事件作为切换触发器,但它没有正常工作......

我做错了吗?关于如何做得更好的任何建议?

1 个答案:

答案 0 :(得分:4)

BehaviorApplicative个实例,足以在没有动态切换的情况下实现ifB

ifB :: Behavior Bool -> Behavior a -> Behavior a -> Behavior a
ifB bB bT bF = (\b t f -> if b then t else f) <$> bB <*> bT <*> bF

或者,使用bool中的Data.Bool

ifB :: Behavior Bool -> Behavior a -> Behavior a -> Behavior a
ifB bB bT bF = bool <$> bF <*> bT <*> bB