12

请原谅我,我刚刚开始研究反应性香蕉和 FRP。

reactive-banana 的作者根据我的建议做了这个例子,他创建了一个可以增加和减少的计数器。他使用 accumE 函数来累积事件。我想我能够对 Event 类型有所了解,并且能够用它测试很多东西,但后来我记得还有 Behavior。我进行了调查,但似乎该行为旨在用于类似情况;修改现有变量,就像 accumE 处理事件一样。

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

4

4 回答 4

11

我同意 Ankur 而不是 Chris:文本框是一个随时间变化的值,因此自然希望成为一种行为而不是事件。Chris 给出的不那么自然的事件选择的原因是实现问题,因此(如果准确的话)是响应式香蕉实现的不幸产物。我更愿意看到改进的实现而不是不自然地使用的范式。

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

于 2011-07-01T00:30:01.337 回答
7

从语义上讲,你有

Behavior a = Time -> a

也就是说,a是随时间变化Behavior a的类型值。通常,您对a何时a会更改一无所知,因此在单击按钮时更新文本字段被证明是一个相当糟糕的选择。也就是说,在反例中很容易获得表达数字当前值的行为。只需在事件流上使用,或者以相同的方式从头开始构建它,除了使用而不是.Behavior astepperaccumBaccumE

通常,连接到输入和输出的东西总是Events,因此Behavior在内部用于中间结果。

假设在给定的示例中,您要添加一个记住当前值的新按钮,例如简单计算器上的记忆功能。您将首先添加一个记忆按钮和一个用于记忆值的文本字段:

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

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

let currentVal = stepper 0 counter

然后,您可以连接事件,并apply在每次按下“记住”按钮时读取行为的值,并生成具有该值序列的事件。

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

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

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

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

这有帮助吗?

于 2011-06-30T12:43:51.480 回答
6

图书馆作者发言。:-)

显然,克里斯史密斯可以读心,因为他准确地描述了我的想法。:-)

康纳尔亚瑟也有道理。从概念上讲,计数器是一个随时间变化的值,而不是事件发生的序列。因此,将其视为 aBehavior会更合适。

不幸的是,行为并没有任何关于它们何时会改变的信息,它们是“仅限民意调查”的。现在,我可以尝试实现各种巧妙的方案,以最大限度地减少轮询,从而实现 GUI 元素的有效更新。(Conal 在原始论文中做了类似的事情。)但我采用了“没有魔法”的理念:图书馆用户应负责通过事件自己管理更新。

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

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预期的类型。这将包含在响应式香蕉库的未来版本中。

编辑:我已经发布了响应香蕉版本 0.4,其中包括新类型,现在称为Discrete.

于 2011-07-04T14:55:23.450 回答
5

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

于 2011-06-30T12:35:17.113 回答