反应性香蕉中的行为

时间:2011-06-30 12:03:07

标签: haskell reactive-programming reactive-banana

对不起,我刚刚开始研究反应性香蕉和FRP。

反应香蕉的作者根据我的建议制作了this例子,其中他创造了一个可以增加和减少的计数器。他使用累积函数来累积事件。我想我能够在某种程度上了解事件类型,并能够用它来测试很多东西,但后来我记得还有行为。我调查了一下,但似乎这种行为意味着在类似的情况下使用;修改现有变量,就像accumE对事件一样。

行为意味着什么,它的用例是什么?

4 个答案:

答案 0 :(得分:11)

我同意Ankur而不是Chris:文本框是一个随时间变化的值,因此自然希望成为行为而不是事件。 Chris给出不太自然的事件选择的原因是实现问题,因此(如果准确的话)是反应性香蕉实现的一个不幸的工件。我非常宁愿看到实现得到改进而不是非自然地使用的范例。

除了语义匹配之外,选择Behavior而不是Event在实用上非常有用。例如,您可以使用Applicative操作(例如liftA2)将时变文本框值与其他时变值(行为)相结合。

答案 1 :(得分:7)

从语义上讲,你有

Behavior a = Time -> a

也就是说,Behavior aa类型的值,随时间变化。一般来说,当 Behavior a发生变化时,你对一无所知,所以对于点击按钮更新文本字段来说,这是一个相当糟糕的选择。也就是说,获取表示计数器示例中数字当前值的行为很容易。只需在事件流上使用stepper,或者以相同的方式从头开始构建它,除非使用accumB而不是accumE

通常,您连接到输入和输出的内容始终为Event s,因此Behavior在内部用于中间结果。

假设在给定的示例中,您想要添加一个记住当前值的新按钮,就像简单计算器上的记忆功能一样。您可以通过为记住的值添加内存按钮和文本字段来开始:

bmem    <- button f [text := "Remember"]
memory  <- staticText f []

您需要能够随时询问当前值,因此在您的网络中,您将添加一种行为来表示它。

let currentVal = stepper 0 counter

然后你可以挂钩事件,并在每次按下Remember按钮时使用apply读取行为的值,并产生一个具有该值序列的事件。

emem <- event0 bmem command
let memoryE = apply (const <$> currentVal) emem

最后,将这个新事件连接到输出

sink memory [text :== ("", show <$> memoryE)]

如果你想在内部使用内存,那么你也需要一个Behavior作为其当前值...但由于我们只使用它来将它连接到输出,我们只需要一个事件现在。

这有帮助吗?

答案 2 :(得分:6)

图书馆作者发言。 : - )

显然,Chris Smith可以读懂思想,因为他准确地描述了我的想法。 : - )

ConalArthur也有一点意义。从概念上讲,计数器是一个随时间变化的值,而不是一系列事件发生。因此,将其视为Behavior会更合适。

不幸的是,行为没有任何关于何时会改变的信息,而是“仅民意调查”。现在,我可以尝试实现各种巧妙的方案,这将最小化轮询,从而允许GUI元素的有效更新。 (Conal在original paper中做了类似的事情。)但我采用了“没有魔法”的理念:图书馆用户应负责通过事件自己管理更新。

我目前设想的解决方案是提供除EventBehavior之外的第三类型,即Reactive(名称可能会更改),其体现了两者:从概念上讲,它是一个随时间变化的值,但它也带有一个通知变化的事件。一种可能的实现方式是

type Reactive a = (a,Event a)

changes :: Reactive a -> Event a
changes (_, e) = e

value :: Reactive a -> Behavior a
value   (x, e) = stepper x e

毫无疑问,这正是sink期望的类型。这将包含在反应香蕉库的未来版本中。

编辑:我发布了反应性香蕉version 0.4,其中包含新类型,现在称为Discrete

答案 3 :(得分:5)

通常,行为是在一段时间内发生变化的值。它是一个连续值,其中事件是离散值。在行为的情况下,始终存在值。 例如:文本框上的文本是行为,因为文本可以在一段时间内更改,但会有一个当前值,其中作为事件中的键盘笔划,因为您无法查询键盘笔划的“当前”值。