混合使用Erlang和Haskell

55
如果您已经接受了函数式编程范例,那么您很可能喜欢Erlang和Haskell。两者都具有纯函数核心和其他优点,例如轻量级线程,使它们非常适合多核世界。但也存在一些差异。
Erlang是一种商业上成熟的容错语言,具有成熟的分布式模型。它似乎具有一项独特的功能,即通过热代码加载在运行时升级其版本。(太酷了!)
另一方面,Haskell拥有任何主流语言中最复杂的类型系统。(我将“主流”定义为任何具有O'Reilly出版书的语言,因此Haskell也算。)其直线单线程性能看起来优于Erlang,并且其轻量级线程看起来更轻盈。
我正在尝试组建一个开发平台,以用于我的余生编码,并想知道是否可以混合使用Erlang和Haskell来实现最佳平台。这个问题有两个部分:
  1. 我希望使用Erlang作为一种容错MPI将GHC运行时实例粘合在一起。每个GHC运行时将有一个Erlang进程。如果“不可能发生的事情”发生了,GHC运行时就会死亡,然后Erlang进程会以某种方式检测到并死亡。Erlang的热代码加载和分发功能将继续工作。可以配置GHC运行时仅使用一个核,或者使用本地计算机上的所有核心,或者两者之间的任何组合。一旦编写了Erlang库,Erlang级别的其余代码应该是纯样板文件,并且应根据每个应用程序自动生成。(例如,通过Haskell DSL)如何实现至少其中一些内容?
  2. 我希望Erlang和Haskell能够共享相同的垃圾收集器。(这比1要远得多。)在JVM和CLR上运行的语言通过共享运行时实现更大的规模。我了解在JVM或CLR上运行Erlang(热代码加载)和Haskell(高阶多态性)存在技术限制。但是仅取消捆绑垃圾收集器怎么样呢?(有点像函数式语言的运行时的开始。)分配显然仍然需要非常快,因此可能需要将其静态链接。并且应该有一些机制来区分可变堆和不可变堆(包括惰性写入一次内存),因为GHC需要这样做。是否可以修改HIPE和GHC,使垃圾收集器可以共享堆?

请回答任何经验(积极或消极)、想法或建议。实际上,任何反馈(除了直接的虐待!)都受到欢迎。

更新

感谢迄今为止的4个回复 - 每一个都教给了我至少一个有用的东西,我之前不知道。

关于编程生涯的其他事情 - 我略带调侃地提出这个问题以激发讨论,但实际上是真的。我有一个想法,打算一直工作到死亡,并且它需要一个稳定的平台。

在我提出的平台中,我只会写Haskell,因为Erlang的样板代码将会被自动生成。那么Haskell还能持续多久呢?嗯,Lisp仍然存在,并且看起来它不会很快消失。Haskell是BSD3开源的,并且已经实现了临界质量。如果编程本身在50年后仍然存在,我希望Haskell或者Haskell的某种连续演变仍然会存在。

更新2 回应rvirding的帖子

同意 - 实现完整的"Erskell/Haslang"通用虚拟机可能不是绝对不可能的,但肯定非常困难。仅共享垃圾收集器级别作为类似VM的东西,尽管仍然很难,但对我来说难度要小一个数量级。在垃圾收集模型方面,函数式语言必须具有很多共同点 - 不可变数据(包括thunks)的普及性以及需要非常快速的分配。因此,常见性与单片VM紧密捆绑似乎有点奇怪。

VM可以帮助实现关键的质量,只需看看像F#和Scala这样的“轻量级”函数语言如何起飞。 Scala可能没有Erlang的绝对容错能力,但它为许多被绑定到JVM的人提供了一条出路。
虽然具有单个堆使消息传递非常快,但它引入了许多其他问题,主要是由于它必须是交互式的和全局不可中断的,因此进行GC变得更加困难,因此无法使用与每个进程堆模型相同的简单算法。
当然,这对我来说很有道理。 GHC开发团队中非常聪明的人似乎正在尝试使用并行“停止世界”GC解决部分问题。

http://research.microsoft.com/en-us/um/people/simonpj/papers/parallel-gc/par-gc-ismm08.pdf

显然,“stop the world”对于一般的Erlang并不适用,因为其主要用例。但即使在“stop the world”可行的用例中,它们的加速效果似乎也不是普遍的。所以我同意你的观点,没有普适最佳GC,这也是我在问题第一部分中指定原因的原因。
GHC运行时可以配置为仅使用一个核心,或者使用本地计算机上的所有核心,或者介于两者之间的任何组合。因此,在给定的用例中,经过基准测试后,我可以选择走Erlang的路线,每个核心运行一个GHC运行时(带有单线程GC)加上一个Erlang进程,并让Erlang在核心之间复制内存以获得良好的局部性。
另外,在具有良好处理器内存带宽的双处理器机器上,基准测试可能表明我应该在每个处理器上运行一个GHC运行时(带有并行GC),加上一个Erlang进程。
在两种情况下,如果Erlang和GHC可以共享堆,则共享可能会绑定到以某种方式在单个核心上运行的单个OS线程。(我已经超出了我的能力范围,这就是我问问题的原因。)
我还有另一个议程-独立于GC对功能语言进行基准测试。通常我会阅读OCaml v GHC v Erlang v ...的基准测试结果,并想知道这些结果被不同的GC所混淆了多少。如果GC的选择与功能语言的选择是正交的,那么GC有多昂贵?请参见这篇魔鬼倡导者的博客文章。

http://john.freml.in/garbage-collection-harmful

这篇文章是我的Lisp朋友约翰·弗莱姆林写的,他很巧妙地将其标题定为“自动垃圾回收是垃圾”。当约翰声称垃圾回收很慢并且没有真正加快太多时,我希望能够用一些数字来反驳。


出于类似的动机,我得出了下一个十年左右“完美语言组合”的结论,其中包括 Rust。可能是因为我的嵌入式系统背景。因此,我的梦幻团队组合将是:Erlang|值得替代 + Haskell + Rust。 - BitTickler
1
Pony的ORCA和Azul的C4 JVM是无暂停、并行和并发GC。Erlang的GC要容易得多,因为每个Erlang进程都有自己的堆。 - user246672
6个回答

33

很多Haskell和Erlang的人对一种模式感兴趣,即Erlang监督分布,而Haskell并行运行共享内存节点进行所有的数字计算/逻辑。

这方面的一个开端是haskell-erlang库: http://hackage.haskell.org/package/erlang

在Ruby领域中,我们通过Hubris进行了类似的努力: http://github.com/mwotton/Hubris/tree/master

现在的问题是找到有人真正推动Erlang/Haskell互操作性以找出其中的棘手问题。


谢谢!这似乎是目前为止最有见地的答案。所以听起来,至少在1中我所要求的基本上就是许多其他人已经想要的。这表明这是一个明智的方向,这很好知道。我既不知道haskell-erlang也不知道Hubris...去看看它们吧。 - Paul Delhanty
2
Haskell-Erlang 看起来很有技术含量,但它是 GPL 的。我对 GPL 没有任何偏见 - 实际上我将来可能会在自己的一些项目中使用它,所以这里存在一定程度的虚伪。但是,如果我要将其用于像 Erlang-Haskell 桥接这样的对我平台至关重要的事情上,我不会使用其他人的 GPL 代码,因为这将极大地限制我将来许可我的代码库的方式。 - Paul Delhanty
Hubris似乎是MIT许可证。这更接近,但可能无法重新许可为BSD3。(考虑到从MIT到MIT/LGPL/GPL的Mozilla三重许可证事件。)实际上,我希望我的平台级Haskell代码是BSD3。 - Paul Delhanty
回复:需要有人真正推动Erlang/Haskell互操作性 - 我愿意参与其中,但我需要帮助,并且必须是BSD3许可证才能适合我。 - Paul Delhanty
请注意,您不能重新授权您不拥有的任何内容;只有所有者才能这样做。但是,如果您使用类似BSD3的许可证下的代码,则应该可以自由使用,而MIT许可证将不会比BSD3限制更多。 - cjs
显示剩余3条评论

5

虽然这是一个相当老的帖子,但如果读者仍然感兴趣,那么值得看一下Cloud Haskell,它将Erlang风格的并发和分布式引入了GHC稳定版。

即将推出的distributed-process-platform库添加了对类似OTP的构造的支持,如gen_servers、监督树以及从Erlang/OTP借鉴和启发的各种“Haskell风味”抽象。


5
你将在将Haskell和Erlang混合使用GC时度过有趣的时光。 Erlang使用每个进程堆栈,并在进程之间复制数据 - 由于Haskell甚至没有进程的概念,我不确定如何在两者之间映射这个“通用”GC。此外,为了获得最佳性能,Erlang使用多种分配器,每种分配器都具有略微调整的行为,这肯定会影响GC子系统。
像软件中的所有事物一样,抽象是有代价的。在这种情况下,我非常怀疑您是否需要引入许多层才能使两种语言克服阻抗不匹配,否则您最终可能会得到一个性能不太好(或无用)的共同VM。
底线 - 拥抱差异!不在同一个进程中运行所有内容有巨大的优势,特别是从可靠性的角度来看。此外,我认为期望一个语言/ VM在您的余生中持续存在有点天真(除非您打算a)短暂生活或b)成为某种仅在单个项目上工作的代码僧侣)。软件开发完全取决于思维敏捷性和愿意使用最好的可用工具来构建快速,可靠的代码。

非常感谢您提供有关Erlang每个进程堆的信息。我想我会将1个Erlang进程的堆与1个GHC运行时实例共享。然后对于我的问题1,我可以在Erlang和Haskell之间传递不可变数据而无需复制它。 - Paul Delhanty
同意,在多个进程中运行有巨大的优势。通常情况下,这是正确的选择,但并非总是如此。我希望能够根据实证数据做出选择。事实上,我最想共享 Haskell(GHC)堆栈底部的调用栈,以避免 FFI 的编组成本。 - Paul Delhanty
a) 我计划尽可能地长寿,但我已经45岁了,所以我不再把它视为理所当然的事情。这意味着我很着急。 b) 是的,我正在进行一个代码僧项目,需要一个稳定的平台。我可能需要在某个时候更改语言,但我不想改变设计。 - Paul Delhanty
我对拆分垃圾收集器感兴趣的另一个原因是计算机语言 shootout 基准测试。使用相同的 GC 来比较 Erlang 和 Haskell 将是很好的。 - Paul Delhanty
谢谢你对消息何时被复制和何时被分享的回复。已经记下以备将来参考。 - Paul Delhanty
显示剩余3条评论

4
  1. 您可以使用OTP gen_supervisor进程来监视使用open_port()生成的Haskell实例。根据“端口”退出的方式,您将能够重新启动它或决定它停止是有意为之,并让相应的Erlang进程也死亡。

  2. 算了吧。即使是这些与语言无关的虚拟机有时也会出现传递数据的问题。您应该以某种方式在两者之间序列化数据:数据库、XML-RPC等。

顺便说一句,仅使用一个平台终身可能也是不切实际的。计算技术和时尚变化太快,期望您可以永远只使用一种语言是不可能的。您的问题本身就说明了这一点:即使是今天,也没有一种语言可以做到我们希望的一切。


感谢回复,特别是在第1个问题中的技术细节。你对第2个问题的回答正是我认为大多数人会说的 - 它比第1个问题更远期。关于编码生活平台的其余部分 - 我已经45岁了,所以可能比StackOverlow上的一些人更短。但是你的观点很好。时尚确实会改变 - 但是像函数式编程和消息传递这样的东西通常是长寿的想法。因此,我真正在寻找一个可以发展的平台。 - Paul Delhanty
1
据我估计,你还有两个时尚时代才能退休。 :) - Warren Young
关于你对问题2的回答,我不需要分享数据——只需分享堆 ;-) - Paul Delhanty

4
正如 dizzyd 在他的评论中提到的,消息中的并非所有数据都被复制,大型二进制存在于进程堆之外,因此不会被复制。
使用不同的内存结构以避免拥有单独的进程堆是可行的,并且在许多早期实现中已经完成。虽然单个堆使消息传递非常快,但它引入了其他一些问题,主要是进行垃圾回收变得更加困难,因为它必须是交互式和全局非中断的,因此无法使用与每个进程堆模型相同的简单算法。
只要我们使用不可变数据结构,就不存在健壮性和安全性问题。决定使用哪种内存和GC模型是一个巨大的权衡,不幸的是没有普遍最佳模型。
虽然 Haskell 和 Erlang 都是函数式语言,但在许多方面它们是非常不同的语言,具有非常不同的实现。很难想象出一台“Erskell”(或 Haslang)机器,可以高效地处理这两种语言。我个人认为最好将它们分开,并确保它们之间有一个非常好的接口。

谢谢回复。我可能没有表达清楚,但我同意你写的大部分内容,特别是关于没有普遍最佳的GC模型这一点。如果我在这个评论中进一步回应,它会变得有点冗长和杂乱无章,所以我将在我的问题中添加一个“更新2”。 - Paul Delhanty

2
CLR支持使用显式的tail操作码(如F#中所用)进行尾递归优化,而JVM目前尚无相应功能,这限制了此类语言风格的实现。使用单独的AppDomain允许CLR热交换代码(例如,参见此博客文章展示了如何完成此操作)。
由于Simon Peyton Jones就在微软研究院的Don Syme和F#团队旁边工作,如果我们最终没有看到一种具有某种官方地位的IronHaskell,那将是一个巨大的遗憾。开发IronErlang将是一个有趣的项目——最大的工作量可能是将绿色线程调度程序移植过来,而不会像Windows Workflow引擎那样变得过重,或者必须在CLR上运行BEAM VM。

感谢对CLR/JVM的技术反馈。如果我没记错的话,SPJ曾在一次采访中表示,与JVM相比,CLR对函数式编程的支持略微更多,但我不知道原因。现在我知道了,这是由于尾操作码的存在。 - Paul Delhanty
关于与AppDomains的链接,这确实很有趣,可能允许我们模拟Erlang的某些功能。然而,要达到Erlang所具有的可靠性水平是很困难的。 - Paul Delhanty
关于IronHaskell,未来可能在技术上实现。但是,鉴于F#的存在,我不认为MSRC会投入太多精力。 (SPJ在一次采访中表示,F#的存在使他不必再努力让Haskell在CLR上运行。)对我来说,MSR资助Haskell开发的原因是为了拥有一个非常纯净的函数式平台,以开发诸如软件事务内存之类的想法,这些想法可能在以后迁移到更主流的语言。 - Paul Delhanty
我猜,如果 F# 真的火起来了,它可能会推动 CLR 的需求。比如 Don Syme 决定将类型类放入 F# 中,这样 CLR 就可以获得高阶多态性,我听说这是类型类所需要的,然后 IronHaskell 就有可能实现... - Paul Delhanty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接