FRP - 事件流和信号 - 仅使用信号会丢失什么? [英] FRP - Event streams and Signals - what is lost in using just signals?

查看:17
本文介绍了FRP - 事件流和信号 - 仅使用信号会丢失什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在最近的经典 FRP 实现中,例如reactive-banana,有事件流和信号,它们是阶梯函数(reactive-banana 称它们为行为,但它们仍然是阶梯函数).我注意到 Elm 只使用信号,并且不区分信号和事件流.此外,reactive-banana 允许从事件流到信号(已并且可以使用 reactimate' 对行为采取行动,尽管它不被认为是好的做法),这意味着理论上我们可以应用所有事件流通过首先将信号转换为事件流,应用然后再次转换来组合信号/行为.那么,鉴于它通常更容易使用和学习一种抽象,那么分离信号和事件流有什么好处?仅使用信号并将所有事件流组合器转换为对信号进行操作有什么损失吗?

In recent implementations of Classic FRP, for instance reactive-banana, there are event streams and signals, which are step functions (reactive-banana calls them behaviours but they are nevertheless step functions). I've noticed that Elm only uses signals, and doesn't differentiate between signals and event streams. Also, reactive-banana allows to go from event streams to signals (edited: and it's sort of possible to act on behaviours using reactimate' although it not considered good practice), which kind of means that in theory we could apply all the event stream combinators on signals/behaviours by first converting the signal to event stream, applying and then converting again. So, given that it's in general easier to use and learn just one abstraction, what is the advantage of having separated signals and event streams ? Is anything lost in using just signals and converting all the event stream combinators to operate on signals ?

讨论非常有趣.我自己从讨论中得出的主要结论是,相互递归定义(反馈)和输出取决于两个输入(一个行为和一个事件源)都需要行为/事件源,但只有在一个其中的变化(<@>).

edit: The discussion has been very interesting. The main conclusions that I took from the discussion myself is that behaviours/event sources are both needed for mutually recursive definitions (feedback) and for having an output depend on two inputs (a behaviour and an event source) but only cause an action when one of them changes (<@>).

推荐答案

(澄清:在reactive-banana 中,不可能将Behavior 转换回Event. stepper 函数是单程票.有一个 changes 函数,但它的类型表明它是不纯的",并带有警告它不保留语义.)

(Clarification: In reactive-banana, it is not possible to convert a Behavior back to an Event. The stepper function is a one-way ticket. There is a changes function, but its type indicates that it is "impure" and it comes with a warning that it does not preserve the semantics.)

我相信拥有两个独立的概念会使 API 更加优雅.换句话说,它归结为 API 可用性问题.我认为这两个概念的表现完全不同,如果你有两种不同的类型,事情会更好.

I believe that having two separates concepts makes the API more elegant. In other words, it boils down to a question of API usability. I think that the two concepts behave sufficiently differently that things flow better if you have two separate types.

例如,每种类型的直接产品是不同的.一对 Behavior 等价于一对 Behavior

For example, the direct product for each type is different. A pair of Behavior is equivalent to a Behavior of pairs

(Behavior a, Behavior b) ~ Behavior (a,b)

而一对事件等价于直接的事件:

whereas a pair of Events is equivalent to an Event of a direct sum:

(Event    a, Event    b) ~ Event (EitherOrBoth a b)

如果您将两种类型合并为一种,那么这两种等价性都不再成立.

If you merge both types into one, then neither of these equivalence will hold anymore.

然而,将事件和行为分开的主要原因之一是后者没有变化或更新"的概念.乍一看,这似乎是一个遗漏,但在实践中非常有用,因为它可以简化代码.例如,考虑一个 monadic 函数 newInput,它创建一个输入 GUI 小部件,显示参数 Behavior 中指示的文本,

However, one of the main reasons for the separation of Event and Behavior is that the latter does not have a notion of changes or "updates". This may seem like an omission at first, but it is extremely useful in practice, because it leads to simpler code. For instance, consider a monadic function newInput that creates an input GUI widget that displays the text indicated in the argument Behavior,

input <- newInput (bText :: Behavior String)

现在的关键是显示的文本取决于多久行为bText可能已经更新(到相同的或不同的值),仅取决于实际值本身.这比其他情况更容易推理,在其他情况下,您必须考虑当两个连续的事件发生具有相同的值时会发生什么.您是否在用户编辑文本时重绘文本?

The key point now is that the text displayed does not depend on how often the Behavior bText may have been updated (to the same or a different value), only on the actual value itself. This is a lot easier to reason about than the other case, where you would have to think about what happens when two successive event occurrences have the same value. Do you redraw the text while the user edits it?

(当然,为了实际绘制文本,库必须与 GUI 框架交互并跟踪行为中的更改.这就是 changes 组合器的用途.但是,这可以看作是一种优化,不能从FRP 内"获得.)

(Of course, in order to actually draw the text, the library has to interface with the GUI framework and does keep track of changes in the Behavior. This is what the changes combinator is for. However, this can be seen as an optimization and is not available from "within FRP".)

分离的另一个主要原因是递归.大多数递归依赖于自身的事件是不明确的.但是,如果事件和行为之间存在相互递归,则总是允许递归

The other main reason for the separation is recursion. Most Events that recursively depend on themselves are ill-defined. However, recursion is always allowed if you have mutual recursion between an Event and a Behavior

e = ((+) <$> b) <@> einput
b = stepper 0 e

无需手动引入延迟,它只是开箱即用.

There is no need to introduce delays by hand, it just works out of the box.

这篇关于FRP - 事件流和信号 - 仅使用信号会丢失什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆