ifB 在 reactive-banana 中的实现

Implementation of ifB in reactive-banana

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

在我学习 FRP 的过程中,我尝试使用 reactive-banana 来实现这些示例。我似乎对此没有问题(但必须考虑很多 :))。我唯一不明白的是如何正确翻译 Fran 的 ifB.

它似乎有这样的类型签名:

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

但是 reactive-banana 对于这种事情只有 switchB

目前,我设法通过添加一个额外的 "trigger" 事件来实现,该事件将用于切换行为,如下所示:

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

我设法让这个片段与 reactive-banana 一起工作,方法是使用我的 ifB 实现并为其提供 cursor move 事件,以便它定期更新。我试图只给它提供鼠标 press/release 事件作为切换的触发器,但它没有正常工作...

我做错了吗?关于如何做得更好有什么建议吗?

Behavior有一个Applicative实例,不用动态切换就可以实现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

或者,使用 Data.Bool 中的 bool

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