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
我正在阅读 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