FRP 是实现大多数“事件驱动”事物的正确方法吗?
Posted
技术标签:
【中文标题】FRP 是实现大多数“事件驱动”事物的正确方法吗?【英文标题】:Is FRP a proper way to implement most "event-driven" things? 【发布时间】:2012-11-09 07:01:42 【问题描述】:在我对 Haskell 的第一印象中,它是一种可以非常出色地处理“先执行后结果”事情的语言。但我找不到如何实现“事件驱动”的东西,如游戏或 HTTP/FTP/TCPSocket 服务器。
这个问题在我阅读了一些关于 FRP 的论文后得到了回答,包括 Yampa 和它创建的 FPS 游戏(Frag)。看起来 FRP 是一个很好的模型来实现像 3D 游戏这样的“重”事件驱动的东西,但是 slighter 像 HTTP 服务器或普通桌面 GUI 程序这样的事件驱动应用程序呢?如果我使用 FRP 来实现所有这些东西会出现什么缺点?
【问题讨论】:
【参考方案1】:FRP 是一种非常通用的技术,几乎可以肯定地用于实现通常会使用事件的任何东西。在 FRP 的经典演绎中,核心抽象之一是事件。不同之处在于,您不是使用回调单独操作事件,而是操作 流 事件。
您应该能够根据事件流呈现任何正常的事件驱动代码;唯一的困难是将流与现有的外部代码(如 GUI 工具包)绑定;然而,这比棘手更乏味。因此,我认为没有任何基本问题会阻止您在任何可以使用不同语言的事件的地方使用 FRP。
事实上,我在使用 FRP 来实现您所谓的“更轻”方面有过一些很好的经验:简单的 GUI 程序。我使用reactive banana 和wxWidgets 编写了一些非常简单的小图形程序。我发现生成的代码比等效的基于回调的代码更简单、更易于编写和阅读。
Reactive Banana 也可以用于 music 之类的东西,因此它显然具有广泛的适用性。除了使用它进行 GUI 编程之外,我没有尝试过任何其他东西,但其他人已经尝试过,所以它必须是可能的。
此外,您应该查看 Elm,它是一种 ML 风格的语言,用于使用 FRP 实现 Web 应用程序。它生成您需要的一切:html、CSS 和 javascript。我相信它甚至可以处理与服务器的通信。我没试过,但看起来很不错。
因此,人们显然在各种各样的领域中使用 FRP,包括那些不“重”的领域。但这并不意味着你应该在任何地方都使用它!
一方面,有可能获得不可预测的空间和时间行为。我知道 Reactive Banana 和 Elm 的创建者都付出了很多努力来减少这些,但我怀疑仍然存在一些风险。我知道在玩 Reactive Banana WX 时我有一些非常奇怪的空间泄漏,所以这肯定是需要注意的。与您习惯使用的事件驱动代码相比,使用 FRP 处理这些可能更难。当然,我在使用标准 JavaScript 时遇到过莫名其妙的内存泄漏,所以非 FRP 代码也不能幸免!
另一个考虑因素是 FRP 可能不是您特定任务的最佳或最清晰的抽象。虽然它非常适合必须完全响应的事物,但对于非常简单的代码(例如 Web 服务器)呢? (我的意思很简单,因为在不同的请求中可能不会彼此密切交互。)我想拥有一个使用基于 FRP 的编程模型来处理大量请求的 Web 框架是可能的;我只是不认为它会是最佳。
事实上,我的理解是,GHC IO 系统实际上已经在底层实现了事件驱动,因此您可以以标准的编程风格编写 Web 服务器,并获得免费使用事件的好处。因此,对于 Web 服务器代码,更简单的底层抽象可能是更好的选择。我相信 Snap 和 Yesod 等现有框架就是这样做的——它们都没有使用响应式编程风格,但它们仍然很好用。
【讨论】:
谢谢!我会尝试你提到的那些项目,看看如何开发 FRP 应用程序。 作为 reactive-banana 的作者,我当然会对任何关于神秘空间泄漏的报道感兴趣。 :) 哦,是的,这是一个很棒的库。我会整理一份错误报告。我只是怀疑这对我来说只是因为缺乏经验而感到神秘。 Haskell FRP 库能否很好地处理异步和需要并行运行的代码?我们可以以并发方式调度事件吗?【参考方案2】:您不需要使用“简单”Haskell 之外的任何东西来实现事件驱动游戏。我目前正在使用具有以下(非常高级)“架构”的 Haskell 编写 FPS:
uiMake :: IO ([UIEvent],UIState)
uiTick :: UIState -> [ApEvent] -> IO ([UIEvent],UIState)
apMake :: ([ApEvent],ApState)
apTick :: ApState -> [UIEvent] -> ([ApEvent],ApState)
-- UIState = The state of the UI
-- ApState = The state of the application (game)
-- UIEvent = Key presses, screen resolution changes etc.
-- ApEvent = Entity movements etc.
效果很好。不需要镜片、玻璃钢或其他任何“异国情调”的东西。
【讨论】:
以上是关于FRP 是实现大多数“事件驱动”事物的正确方法吗?的主要内容,如果未能解决你的问题,请参考以下文章