行为普遍被定义为“随时间变化的值”s1。
为什么?时间作为不同值的依赖/参数是非常罕见的。我对 FRP 的直觉是将行为作为随事件变化的值;它更常见,更简单,我提出了一个更有效的想法,并且可扩展性足以支持时间(tick 事件)。
例如,如果您编写一个计数器,您不关心时间/关联的时间戳,您只关心“单击增加按钮”和“单击减少按钮”事件。
如果你编写一个游戏并想要一个位置/力量行为,你只关心WASD/箭头键举行的事件等(除非你禁止你的玩家在下午向左移动;多么不公平!)。
那么:为什么时间是一个考虑因素呢?为什么要时间戳?为什么有些库(例如 reactive-banana
、reactive
)将其发展到了 Future
、Moment
的程度> 值(value)观?为什么要使用事件流而不是仅仅响应事件发生?所有这些似乎都使一个简单的想法变得过于复杂(事件变化/事件驱动的值(value));有什么收获?我们在这里解决什么问题? (如果可能的话,我也希望得到一个具体的例子和一个精彩的解释)。
最佳答案
Behavior
s 不同于 Event
主要是 Behavior
现在有一个值,而 Event
仅当新事件到来时才具有值。
那么“现在”是什么意思呢?从技术上讲,所有更改都以事件流上的推或拉语义来实现,因此我们只能表示“截至此 Behavior
的最后一个事件的最新值”。但这是一个相当复杂的概念——实际上“现在”要简单得多。
为什么“现在”更简单的原因可以归结为 API。以下是 Reactive Banana 的两个示例。
最终,FRP 系统必须始终产生某种外部可见的变化。在 Reactive Banana 中,
reactimate :: Event (IO ()) -> Moment ()
促进了这一点消耗事件流的函数。没有办法拥有Behavior
触发外部变化——你总是必须做类似reactimate (someBehavior <@ sampleTickEvent)
的事情在具体时间对行为进行采样。行为是
Applicative
不像Event
s。为什么?好吧,我们假设Event
是一个应用程序,想想当我们有两个事件流时会发生什么f
和x
并写f <*> x
:由于事件发生在不同的时间,f
的机会和x
同时定义的是 ( almost certainly ) 0。所以f <*> x
总是意味着空的事件流是无用的。你真正想要的是
f <*> x
缓存每个值的最新值并“始终”获取它们的组合值。就事件流而言,这确实是一个令人困惑的概念,因此让我们考虑f
和x
为所有时间点取值。现在f <*> x
也被定义为对所有时间点取值。我们刚刚发明了Behavior
关于haskell - 为什么FRP将时间作为值(value)的一个因素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25568712/