我研究过函数式反应式编程,但是来自命令式世界,我无法理解函数式语言如何对用户事件做出反应并调整其数据和 UI 以反映必要的更改。
我已经快速浏览了 Elm 主页上的示例,但据我了解,它本质上允许您将(更改)输出描述为(更改)输入的函数(即“在鼠标位置绘制一个矩形”,即自动更新和重绘)。
但是,通常会触发某些动作的单个事件呢?以任何允许您在窗口中编辑文档的常用应用程序为例。该窗口还有一个“新建”按钮(或菜单项),可打开另一个窗口实例。那将如何运作?如果有人能解释它背后的概念,我将不胜感激。
我研究过函数式反应式编程,但是来自命令式世界,我无法理解函数式语言如何对用户事件做出反应并调整其数据和 UI 以反映必要的更改。
我已经快速浏览了 Elm 主页上的示例,但据我了解,它本质上允许您将(更改)输出描述为(更改)输入的函数(即“在鼠标位置绘制一个矩形”,即自动更新和重绘)。
但是,通常会触发某些动作的单个事件呢?以任何允许您在窗口中编辑文档的常用应用程序为例。该窗口还有一个“新建”按钮(或菜单项),可打开另一个窗口实例。那将如何运作?如果有人能解释它背后的概念,我将不胜感激。
简短的回答是:FRP 本质上不是纯粹的功能性,因为通常对实际外部环境的反应在性质上是必不可少的。下面我描述了一种 FRP 的“纯”方法,还有基于延续的更有效但更“势在必行”的方法。
• FRP 是一种以声明方式处理时间的尝试。
• 行为是时间的函数。
◦ 行为在每个瞬间都有特定的价值。
• 事件是(时间、值)对的集合。
◦ 即它们被组织成动作流。
• 两个问题
◦ 当行为/事件不依赖于未来时,它们是明确定义的
◦ 效率:最小化开销
• FRP 是同步的:可以设置事件同时发生,并且是连续的:行为可以具有任意时间分辨率的细节。
◦ 尽管对结果进行了抽样,但没有用于指定行为的固定(最小)时间步长。
◦ 异步是指各种想法,所以问问人们的意思。
• 强制事件的惰性列表(流)将等到事件到达。
• 从时间开始到当前时间扫描事件列表,每次我们评估一个行为——非常浪费。时空。为时间流产生行为流允许忘记过去已经发生的事件。
• 下一个优化是将用户操作与采样时间配对。动作Nothing
对应于什么都没有发生时的采样时间。
• 将行为和事件从时间函数转变为输入-输出流类似于优化从 O(mn) 到 O(m + n) 时间的有序列表的交互。
• 现在我们可以反过来根据(可选,Maybe
)行为来定义事件,这些事件发生在时间点上,而不是随着时间间隔而变化。
• 这一切看起来很像流处理。
我在关于拉链、自适应编程、FRP 和 GUI 的讲座中讨论了 FRP,但它是以 OCaml 为中心的。
Atze van der Ploeg 和 Koen Classen 开发了一个更接近 Conal Elliott 和 Paul Hudak 的原始Fran的 FRP 的最新实现——它被命名为FRPNow,并且该论文以及(大约 2015 年)Haskell资源是公开的以及图书馆。
我建议在查看源代码之前先阅读论文以了解实现的概述;它们与论文中介绍的内容有很大不同。然后,您可以使用该库进行实际工作和实验 :-)
至于原来的问题:
导致 UI 更改的事件如何使用函数式反应式编程进行处理/建模?
...从 FRPNow论文的第 3 页借用:
(a) 取自Fran的函数 | |
---|---|
键入 E a ≗ (时间+ , a ) | 事件,其中Time + = Time ∪ {∞} |
实例 Monad E where return x ≗ (-∞, x ) ( ta , a ) >>= f ≗ let ( tb , x ) ≗ fa in ( max ta tb , x ) |
如何使用现有事件构建新事件 |
(...为什么用“≗”而不是“=”?见第 2 页 :-)