【问题标题】:Implementing zipE :: Event t a -> Event t b -> Event t (a,b)实现 zipE :: Event t a -> Event t b -> Event t (a,b)
【发布时间】:2012-07-29 08:47:58
【问题描述】:

我对反应性香蕉和 FRP 不熟悉,所以如果我遗漏了一些明显的东西,我深表歉意。

对于my projectGDB/MI 前端),我对 GUI 和前端逻辑模块都使用响应式香蕉(版本 0.6.0.0)。前者效果很好,但对于后者,我显然需要额外的组合器。

其中一个是zipE :: Event t a -> Event t b -> Event t (a, b)。不幸的是,我能想出的只是 NetworkDescription monad 中的一个解决方案,它使用 changes 并且在事件类型中不是通用的:

zipE :: Event t Int -> Event t String -> NetworkDescription t (Event t (Int, String))
zipE ea eb = changes $ (,) <$> stepper 0 ea <*> stepper "" eb

当然,我对此并不满意。因此,我想问如何在不使用changes 的情况下实现一个通用的 zipE 函数(不鼓励将其用于非 GUI 目的)。

其他尝试失败,例如

zipE :: Num a => Event t a -> Event t b -> Event t (a,b)
zipE ea eb = apply (stepper (0,) ((,) <$> ea)) eb

导致元组的第一个元素被移动一个 - 我猜是由于stepper 引入的“轻微延迟”。但是我看不到如何从没有stepper(或accumB)的事件中获取行为,我看不到如何将函数应用于没有行为的事件。总的来说,在泛型类型的情况下,我看不到如何为步进器提供初始值。

【问题讨论】:

  • eaeb 不会同时触发。 (如果您知道它们将同时触发,因为它们都源自相同的基础事件,那么最好重新处理该基础事件。)当一个触发而另一个不触发时,您希望发生什么? t?
  • 戴夫,你是对的。我的活动网络需要不同的设计:-/ 感谢您指出这一点。
  • 我确实需要一个不同的事件网络。最初,我想压缩这两个事件以将元组输入f :: (a,b) -&gt; IO ()。我现在拥有的是f :: a -&gt; b -&gt; IO ()reactimate $ (f &lt;$&gt; stepper 0 aE) &lt;@&gt; bE

标签: haskell reactive-programming frp reactive-banana


【解决方案1】:

您很难定义zipE,因为它没有语义意义。如果你考虑语义定义

Event a == [(Time, a)]
Event b == [(Time, b)]

没有一种自然的方式来压缩它们,因为通常每个事件都在不同的时间。

可以使用总和而不是乘积来压缩它们。

zipE :: Event a -> Event b -> Event (Either a b)
zipE aE bE = (Left <$> aE) `mappend` (Right <$> bE)

如果您确实需要同时拥有ab,则适当的解决方案是创建一个累积在一个或另一个之上的Behavior,或者如上所述合并Either 流。

edit:在合并流上累积的一种方法示例(未经测试)。其他实现也是可能的。这不会使这两个事件同时发生,而是让您将当前状态与过去状态结合起来,这样您就可以始终拥有LeftRight 值中最近可用的值。

currentAandB :: a -> b -> Event a -> Event b -> Event (a,b)
currentAandB a0 b0 aE bE = accumE (a0,b0) (mergefn <$> zipE aE bE)
    where
        mergefn (Left a)  (_,b) = (a,b)
        mergefn (Right b) (a,_) = (a,b)

仍然需要为两个Event 流提供初始值。可以这样想:如果您只有来自 Event a 的事件,那么元组的第二部分应该有什么值?

【讨论】:

  • 约翰,谢谢你帮助我。我想更多地了解您提到的适当答案。您能否详细说明如何累积一个或另一个使两个事件同时发生?对不起,如果这很明显。我只是没看到。
  • @copton:我已经发布了一个示例,说明了一种方法。至于初始值,如果您考虑问题的初始状态,您可能会找到一个明智的答案。或者您可以使用MaybeData.Traversable.sequenceAfilterJust 的组合,仅在收到ab 后才产生输出。
猜你喜欢
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多