我正在阅读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一起使用,以便定期更新。我尝试只将鼠标按下/释放事件作为切换触发器,但它没有正常工作......
我做错了吗?关于如何做得更好的任何建议?
答案 0 :(得分:4)
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
或者,使用bool
中的Data.Bool
:
ifB :: Behavior Bool -> Behavior a -> Behavior a -> Behavior a
ifB bB bT bF = bool <$> bF <*> bT <*> bB