我正在尝试在Haskell中可视化一些简单的自动物理系统(例如钟摆,机器人手臂等)。 通常这些系统可以用类似
的方程来描述 df/dt = c*f(t) + u(t)
其中u(t)
代表某种“智能控制”。这些系统看起来非常适合功能反应式编程范例。
所以我抓住了Paul Hudak的书“The Haskell School of Expression”,
并且发现那里提供的领域特定语言“FAL”(用于功能动画语言)实际上非常适合我的简单玩具系统(尽管某些功能,特别是integrate
,似乎有点懒得有效使用,但很容易解决。)
我的问题是,对于今天更先进甚至实际的应用程序来说,更成熟,最新,维护良好,性能优化的替代方案是什么?
This wiki page列出了Haskell的几个选项,但我不清楚以下几个方面:
“反应”的状态,来自Conal Eliott的项目(据我所知)是这种编程范例的发明者之一,看起来有点陈旧。我喜欢他的代码,但也许我应该尝试其他更新的替代品?在语法/性能/运行时稳定性方面,它们之间的主要区别是什么?
引用2011年survey第6节,“ ...... FRP实施仍然效率不高或性能足够可预测,无法在需要延迟保证的域中有效使用...... 的”。尽管这项调查显示了一些有趣的可能优化,但考虑到FRP存在超过15年这一事实,我得到的印象是,这个性能问题可能是非常甚至在内部难以解决一些年。这是真的吗?
该调查的同一位作者在他的blog中谈到了“时间泄漏”。问题是FRP独有的,还是我们在用纯粹的非严格语言编程时通常会遇到的问题?您是否曾经发现,如果性能不够稳定基于FRP的系统太难了?
这还是一个研究级项目吗?人们喜欢工厂工程师,机器人工程师,金融工程师等实际使用它们(用适合他们需要的各种语言)吗?
虽然我个人更喜欢Haskell实现,但我愿意接受其他建议。例如,拥有一个Erlang实现会特别有趣 - 那么拥有一个智能的,自适应的,自学的服务器进程就很容易了!
答案 0 :(得分:79)
目前主要有两个实用的Haskell库用于功能反应式编程。两者都由单身人员维护,但也接受其他Haskell程序员的代码贡献:
Netwire专注于效率,灵活性和可预测性。它有自己的事件范例,可用于传统FRP不起作用的领域,包括网络服务和复杂的模拟。风格:适用和/或箭头化。最初的作者和维护者:ErtugrulSöylemez(这是我)。
reactive-banana建立在传统的FRP范式之上。虽然它是实用的,它也可作为经典FRP研究的基础。它主要关注用户界面,并且有一个现成的wx接口。风格:适用。最初的作者和维护者:Heinrich Apfelmus。
您应该尝试这两种方法,但根据您的应用,您可能会发现其中一种更适合。
对于游戏,网络,机器人控制和模拟,您会发现Netwire非常有用。它为这些应用程序提供了现成的线,包括各种有用的差异,积分和许多用于透明事件处理的功能。有关教程,请访问我链接的页面上Control.Wire
模块的文档。
对于图形用户界面,目前您最好的选择是reactive-banana。它已经有一个wx接口(作为一个单独的库reactive-banana-wx),Heinrich在这个上下文中包含很多关于FRP的博客,包括代码示例。
回答您的其他问题:FRP不适合您需要实时可预测性的情况。这很大程度上归功于Haskell,但遗憾的是FRP很难在低级语言中实现。一旦Haskell本身变为实时就绪,FRP也将实现这一目标。从概念上讲,Netwire已经为实时应用做好了准备。
时间泄漏不再是一个问题,因为它们主要与monadic框架有关。实用的FRP实现根本不提供monadic接口。 Yampa已经开始这样做了,Netwire和反应型香蕉都是基于此。
我知道目前没有使用FRP的商业或其他大型项目。图书馆准备就绪,但我认为人们还没有 - 但是。
答案 1 :(得分:23)
虽然已有一些好的答案,但我将尝试回答您的具体问题。
由于时间泄漏问题,反应不适用于严肃的项目。 (见#3)。当前具有最相似设计的库是反应性香蕉,它是以反应性为灵感而开发的,并与Conal Elliott进行了讨论。
虽然Haskell本身不适合硬实时应用程序,但在某些情况下可以将Haskell用于软实时应用程序。我不熟悉目前的研究,但我不相信这是一个不可逾越的问题。我怀疑像Yampa这样的系统或像Atom这样的代码生成系统可能是解决这个问题的最佳方法。
“时间泄漏”是特定于可切换FRP的问题。当系统无法释放旧对象时会发生泄漏,因为如果在将来的某个时刻发生切换,可能需要它们。除了内存泄漏(可能非常严重)之外,另一个结果是,当切换发生时,系统必须暂停,同时遍历旧对象链以生成当前状态。
不可切换的frp库(例如Yampa和旧版本的反应性香蕉)不会遭受时间泄漏。可切换的frp库通常采用两种方案中的一种:要么它们具有创建FRP值的特殊“创建单元”,要么它们使用“老化”类型参数来限制可以发生切换的上下文。 elerea(可能还有netwire?)使用前者,而最近的反应性香蕉和葡萄柚使用后者。
“switchable frp”是指实现Conal函数switcher :: Behavior a -> Event (Behavior a) -> Behavior a
或相同语义的函数。这意味着网络的形状可以在运行时动态切换。
这与@ ertes关于monadic接口的陈述并不矛盾:事实证明,为Monad
提供Event
个实例会使时间泄漏成为可能,并且使用上述任何一种方法都不再可以定义等效的Monad实例。
最后,虽然FRP还有很多工作要做,但我认为一些较新的平台(reactive-banana,elerea,netwire)足够稳定和成熟,可以从中构建可靠的代码。但是你可能需要花费大量时间来学习这些细节,以便了解如何获得良好的表现。
答案 2 :(得分:20)
我要列出Mono和.Net空间中的几个项目,以及我不久前发现的Haskell空间中的一个项目。我将从Haskell开始。
根据其网站描述:
榆树旨在使前端Web开发更加愉快。它 介绍了一种新的GUI编程方法,可以纠正这种情况 HTML,CSS和JavaScript的系统性问题。榆树允许你 快速轻松地使用可视化布局,使用画布,管理 复杂的用户输入,并从回调地狱逃脱。
它有自己的FRP变体。从玩它的例子看起来很成熟。
首页描述:
Reactive Extensions(Rx)是一个用于组合异步的库 和使用可观察序列和LINQ风格的基于事件的程序 查询运算符。使用Rx,开发人员代表异步数据 使用Observables的流,使用LINQ查询异步数据流 运算符,并参数化异步数据中的并发性 使用调度程序的流。简单地说,Rx = Observables + LINQ + 调度器。
Reactive Extensions来自MSFT,并实现了许多简化处理事件的优秀运算符。几天前它是open sourced。它非常成熟并用于生产;在我看来,它将是Windows 8 API比TPL库提供的更好的API;因为observable可以既热又冷又重试/合并等,而任务总是代表热门或完成的计算,无论是运行,故障还是已完成。
我使用Rx编写服务器端代码以实现异步,但我必须承认在C#中功能写入可能有点烦人。 F#有几个包装器,但很难跟踪API开发,因为该组相对封闭,并且不像其他项目那样由MSFT推广。
它的开源采用了IL-to-JS编译器的开源,因此它可能适用于JavaScript或Elm。
你可以使用消息代理很好地绑定F#/ C#/ JS / Haskell,比如RabbitMQ和SocksJS。
首页描述:
Bling是一个基于C#的库,可以轻松编程图像,动画, 微软WPF / .NET上的交互和可视化。金光闪闪是 面向设计技术人员,有时是设计师 程序,以帮助快速原型化丰富的UI设计思路。 学生,艺术家,研究人员和业余爱好者也会找到Bling 有用的快速表达想法或可视化的工具。 Bling的API和构造针对快速编程进行了优化 丢弃代码而不是仔细编程生产 代码。
免费LtU-article。
我已经测试了这个,但没有用它来完成客户端项目。它看起来很棒,有很好的C#运算符重载,形成值之间的绑定。它使用WPF / SL /(WinRT)中的依赖项属性作为事件源。它的3D动画在合理的硬件上运行良好。如果我最终得到一个需要可视化的项目,我会用它;可能将其移植到Windows 8。
对于大多数性能要求苛刻的应用程序,反应模型的性能足够高。如果您正在考虑硬实时,我会打赌大多数GC语言都有问题。 Rx,ReactiveUI创建了一些需要GCed的小对象,因为这就是如何创建/处理订阅以及在回调的被动“monad”中进行中间值。一般来说.Net上我更喜欢基于任务的编程的反应式编程,因为回调是静态的(在编译时已知,没有分配),而任务是动态分配的(不知道,所有调用都需要一个实例,垃圾创建) - 并且lambdas编译成编译器生成的类。
显然C#和F#是严格评估的,所以时间泄漏不是问题。 JS也是如此。但是,它可能是可重放或缓存的可观察量的问题。