当前的功能性反应式编程实现的状态如何?


90

我正在尝试可视化Haskell中的一些简单的自动物理系统(如摆锤,机器人手臂等)。通常,这些系统可用方程式来描述

df/dt = c*f(t) + u(t)

其中u(t)代表某种“智能控制”。这些系统看起来非常适合于功能性反应式编程范例。

因此,我抓住了保罗·休达(Paul Hudak)的著作《 The Haskell School of Expression》,发现那里展示的领域特定语言“ FAL”(用于功能动画语言)实际上对我的简单玩具系统非常满意(尽管有些功能值得注意integrate,似乎对于有效使用而言有点懒惰,但很容易修复)。

我的问题是,对于当今更高级甚至是实际的应用程序,最成熟,最新,维护良好,性能调整的替代方案是什么?

该Wiki页面列出了Haskell的几个选项,但是我不清楚以下方面:

  1. Conal Eliott的项目(据我所知)是这种编程范例的发明者之一,它的“反应性”状态看起来有些陈旧。我喜欢他的代码,但也许我应该尝试其他更多的替代方法?就语法/性能/运行时稳定性而言,它们之间的主要区别是什么?

  2. 引用2011年的一项调查的第6节,“ ... FRP实施在性能上仍然不够有效或可预测,无法在需要延迟保证的域中有效使用... ”。尽管该调查建议了一些有趣的可能的优化方法,但考虑到FRP已经存在了15年以上,我给人的印象是,至少在几年内,此性能问题可能非常或什至固有地很难解决。这是真的?

  3. 调查的同一位作者在他的博客中谈论“时间泄漏” 。问题是FRP特有的,还是使用纯非严格语言进行编程时通常遇到的问题?您是否发现过长时间稳定基于FRP的系统太难了吗?

  4. 这仍然是研究水平的项目吗?诸如工厂工程师,机器人工程师,财务工程师等人员实际上是否正在使用它们(以适合他们需求的任何语言)?

尽管我个人更喜欢Haskell实现,但我愿意接受其他建议。例如,拥有一个Erlang实现会特别有趣---那么拥有一个智能的,自适应的,自学习的服务器进程将非常容易!

Answers:


82

目前,主要有两个实用的Haskell库用于功能性反应式编程。两者都由一个人维护,但也从其他Haskell程序员那里获得代码贡献:

  • Netwire专注于效率,灵活性和可预测性。它具有自己的事件范例,可用于传统FRP无法使用的区域,包括网络服务和复杂的模拟。样式:适用性和/或箭头化。最初的作者和维护者:ErtugrulSöylemez(这是我)。

  • 反应香蕉建立在传统的FRP范例之上。尽管实用,但它也可以作为经典FRP研究的基础。它的主要重点是用户界面,并且有一个现成的wx界面。风格:适用。最初的作者和维护者:Heinrich Apfelmus。

您应该同时尝试这两种方法,但是根据您的应用程序,您可能会发现其中一种更合适。

对于游戏,网络,机器人控制和模拟,您会发现Netwire很有用。它带有针对这些应用的现成电线,包括各种有用的差速器,积分器和许多用于透明事件处理的功能。有关教程,请访问Control.Wire我链接的页面上的模块文档。

对于图形用户界面,当前最好的选择是反应香蕉。它已经有一个wx接口(作为一个单独的库react-banana-wx),Heinrich在此上下文中写了很多有关FRP的博客,包括代码示例。

要回答其他问题:FRP不适合需要实时可预测性的方案。这主要是由于Haskell,但是不幸的是,FRP很难在较低级别的语言中实现。一旦Haskell本身可以实时就绪,FRP也将到达那里。从概念上讲,Netwire可以用于实时应用程序。

时间泄漏不再是真正的问题,因为它们与monadic框架密切相关。实际的FRP实施根本不提供Monadic接口。扬帕(Yampa)已开始这样做,而Netwire和反应香蕉都以此为基础。

我知道目前没有使用FRP的商业项目或其他大规模项目。图书馆已经准备好了,但我认为人们还没有。


很好的答案,谢谢..在您的库顶部实现一些强化学习算法将是一个有趣的练习。
mnish 2012年

3
值得注意的是,最近用Haskell编写的独立游戏(Nikki和Robots)做出了使用FRP 的决定。
Alex R

23

尽管已经有了一些好的答案,但我将尝试回答您的特定问题。

  1. 由于存在时间泄漏问题,反应性不适用于严重的项目。(请参阅#3)。当前设计最相似的库是反应性香蕉,它是在反应性的启发下开发的,并与Conal Elliott进行了讨论。

  2. 尽管Haskell本身不适用于硬实时应用程序,但在某些情况下可以将Haskell用于软实时应用程序。我不熟悉当前的研究,但我不认为这是一个无法解决的问题。我怀疑是像Yampa这样的系统,还是像Atom这样的代码生成系统,可能是解决此问题的最佳方法。

  3. “时间泄漏”是可切换FRP特有的问题。当系统无法释放旧对象时会发生泄漏,因为如果将来某个时候要进行切换,可能会需要这些旧对象。除了内存泄漏(可能非常严重)外,另一个后果是,发生切换时,系统必须暂停,同时遍历旧对象链以生成当前状态。

不可转换的frp库(例如Yampa和较旧版本的Reactant-banana)不会浪费时间。可切换的frp库通常采用两种方案之一:它们具有在其中创建FRP值的特殊“ creation monad”,或者它们使用“老化”类型参数来限制可能发生切换的上下文。 elerea(可能还有netwire?)使用前者,而最近的活性香蕉和柚子则使用后者。

“可切换的frp”是指实现Conal的功能switcher :: Behavior a -> Event (Behavior a) -> Behavior a或相同语义的功能。这意味着网络的形状可以在运行时动态切换。

这与@ertes关于monadic接口的声明并没有真正矛盾:事实证明,提供Monad实例以防止Event时间泄漏是可能的,并且使用上述两种方法之一,都不再可能定义等效的Monad实例。

最后,尽管FRP仍有许多工作要做,但我认为某些较新的平台(反应型香蕉,elerea,netwire)非常稳定和成熟,可以从中构建可靠的代码。但是您可能需要花很多时间来学习内幕,才能了解如何获得良好的性能。


2
关于基于箭头的库(Yampa,netwire),它们也是可切换的。原因是箭头具有内置的老化功能,您实际上无法摆脱它。(作为
流变器


1
@HeinrichApfelmus:这是一个有趣的观点。我一般不认为基于箭头的库可以像elerea / grapefruit / current-reactive-banana一样进行切换。我认为它们的切换非常接近以前版本的反应香蕉的要求。但是,这只是一种直觉,我还没有足够的思想去描述我的意思。
John L

2
@DanBurton谢谢,我尝试记住该名称失败。我同意钠应该被认为是现代的FRP库,尽管它不像反应性香蕉那么受欢迎。
约翰L

尽管进行的讨论有些困难,但似乎表明只要可以限制GC时间,就可以实现软实时系统。无论如何,感谢您的出色回答。
mnish 2012年

20

我将列出Mono和.Net空间中的几个项目,以及不久前我发现的Haskell空间中的一个项目。我将从Haskell开始。

榆木- 链接

根据其站点的描述:

Elm旨在使前端Web开发更加愉快。它为GUI编程引入了一种新方法,可以纠正HTML,CSS和JavaScript的系统性问题。Elm允许您快速轻松地使用视觉布局,使用画布,管理复杂的用户输入以及从回调地狱逃脱。

它有自己的FRP变体。从示例中看,它似乎已经很成熟了。

反应性扩展- 链接

从其首页的描述:

Reactive Extensions(Rx)是一个库,用于使用可观察的序列和LINQ样式的查询运算符来组成异步和基于事件的程序。使用Rx,开发人员可以使用Observables表示异步数据流,使用LINQ运算符查询异步数据流,并使用Scheduler在异步数据流中参数化并发性。简而言之,Rx = Observables + LINQ + Scheduler。

Reactive Extensions来自MSFT,并实现了许多出色的运算符,可简化事件处理。它是几天前开源的。它非常成熟,已用于生产。在我看来,对于Windows 8 API来说,它应该比TPL库提供的更好。因为可观察对象既可以是热的也可以是冷的,并且可以重试/合并等,而任务总是代表热的或完成的计算,这些计算既可以运行,也可以是故障或完成。

我已经使用Rx编写了服务器端代码以实现异步性,但是我必须承认,用C#编写功能可能有点烦人。F#有几个包装器,但是很难跟踪API的开发,因为该组相对封闭,并且不像其他项目那样由MSFT推广。

它的开放源代码带有其IL-to-JS编译器的开放源代码,因此它可能与JavaScript或Elm一起很好地工作。

您可以使用RabbitMQ和SocksJS之类的消息代理将F#/ C#/ JS / Haskell很好地绑定在一起。

Bling UI工具包- 链接

从其首页的描述:

Bling是基于C#的库,可轻松在Microsoft的WPF / .NET上对图像,动画,交互和可视化进行编程。Bling面向设计技术人员,即有时会编程的设计师,以帮助快速设计丰富的UI设计思想。学生,艺术家,研究人员和业余爱好者还将发现Bling作为快速表达想法或可视化效果的工具很有用。Bling的API和构造经过优化,可以快速编写扔掉的代码,而不是仔细地对生产代码进行编程。

免费的LtU文章

我已经对此进行了测试,但未在客户项目中使用它。它看起来很棒,具有不错的C#运算符重载,可形成值之间的绑定。它使用WPF / SL /(WinRT)中的依赖项属性作为事件源。它的3D动画在合理的硬件上运行良好。如果我最终完成一个需要可视化的项目,我将使用它。可能将其移植到Windows 8。

ReactiveUI- 链接

之前在MSFT任职,现在在Github的Paul Betts编写了该框架。我已经很广泛地使用它,并且喜欢模型。它比Blink更加解耦(从本质上来说,它不使用Rx及其抽象)-使其更易于对代码进行单元测试。Windows的github git客户端是用这个编写的。

注释

对于大多数性能要求较高的应用程序,反应性模型都具有足够的性能。如果您正在考虑实时性,我敢打赌大多数GC语言都有问题。Rx,ReactiveUI创建了一些需要进行GC处理的小对象,因为这是创建/处置订阅以及在响应的“ monad”回调中处理中间值的方式。通常,在.Net上,我更喜欢反应式编程而不是基于任务的编程,因为回调是静态的(在编译时已知,没有分配),而任务是动态分配的(未知,所有调用都需要实例,创建了垃圾),并且lambdas可以编译成编译器生成的类。

显然,对C#和F#进行了严格的评估,因此时间泄漏在这里不是问题。JS也一样。但是,可重播或缓存的可观察对象可能会成为问题。


感谢您的出色回答。我喜欢Haskell FRP实现的一件事是,它们似乎使我能够清楚地将控制的计算u(t)与仿真的解耦f(t)。F#实现就是这种情况吗?
mnish 2012年

我猜您可以说这两个功能在时间上是分离的,是的。但是,它们在逻辑上可能没有分离。;)
Henrik 2012年

据我所知,Reactive Extensions和其他更加精致的UI(针对UI的程序包)(实际上,以及Haskell以外的所有程序)仅使用事件语义-也就是说,它们具有可以打开的事件概念,但不是可以按方程式进行交互的连续时间信号的概念。我认为,对于构建GUI,这很好。但是,对于构建仿真和模型,这可能是不幸的。
sclv 2012年

您是在暗示所有功能性反应式编程库实现都需要对时间进行连续建模,而不是对时间进行离散建模吗?我发现了一篇名为“具有定时的处理代数:实时和离散时间”的论文-这是了解您在说什么的一个很好的起点吗?
亨里克(Henrik)2012年

我并不是说所有需要-有些需要,有些不需要。但是那些确实更适合某些任务的东西,而那些却不更适合其他任务的……
sclv 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.