当前的F#编译器是用F#编写的,是开源的,并在.Net和Mono上运行,使其可以在许多平台上执行,包括Windows、Mac和Linux。 F#的代码引用机制已被用于在项目中将F#编译为JavaScript,例如WebSharper、Pit和FunScript。 还有一些人对在JVM上运行F#代码很感兴趣。
如果有人想构建一个在JVM上运行的F#编译器,那么哪种方式更容易:
当前的F#编译器是用F#编写的,是开源的,并在.Net和Mono上运行,使其可以在许多平台上执行,包括Windows、Mac和Linux。 F#的代码引用机制已被用于在项目中将F#编译为JavaScript,例如WebSharper、Pit和FunScript。 还有一些人对在JVM上运行F#代码很感兴趣。
如果有人想构建一个在JVM上运行的F#编译器,那么哪种方式更容易:
另一个可能需要考虑的选项是将.NET CLR字节码转换为JVM字节码,就像http://www.ikvm.net使用JVM>CLR字节码一样。尽管fjord的所有者曾经考虑过并予以否决。
选择1)中从高层获得支持,并让F#编译器团队具有可插拔的后端,可以发出Java字节码,在理论上似乎会产生最完美的解决方案。
但如果你看看其他被移植到不同平台的语言,情况很少如此。大多数时候都要从头开始重写。但这也可能是由于原始语言团队本身没有兴趣支持另类平台,原始主机实现可能无法支持多个后端,而且它已经过慢,不能作为可行的开始选项。
我的直觉是结合从头开始重写和能够尽可能地在原始实现中共享代码和自动化。例如,如果测试套件可以用于两种实现,那么这将极大地减轻JVM端的负担,并在确保语言平等性方面产生很大作用。
如果我真的不得不这样做,我可能会从第一种方法开始 - 给现有编译器添加JVM后端。但我也会尝试争取一个不同的目标虚拟机。
引用并不是很相关 - 作为WebSharper的作者,我可以向您保证,虽然引用可以给您一个类似F#的漂亮语言进行编程,但它们是有限制的且不被优化。我想象对于潜在的JVM F#用户来说,门槛会更高 - 完全语言兼容性和可比性的性能。这非常困难。
以尾调用为例。在WebSharper中,我们应用启发式算法将某些本地尾调用优化为JavaScript中的循环,但这还不够 - 您无法像通用的F#库一样依赖TCO。对于WebSharper而言,这是可以接受的,因为我们的用户不希望完全拥有F#,但对于JVM F#移植而言,则不可行。我相信大多数JVM实现都不会执行TCO,因此必须通过一些间接方式来实现,这会引入性能损失。
@mythz提到的字节码重新编译方法非常吸引人,因为它不仅允许移植F#,而且理想情况下还允许将更多.NET软件移植到JVM。我在一个内部的WebSharper 3.0项目中使用了很多.NET字节码分析 - 我们正在探索编译.NET字节码而不是F#引用到JavaScript的选项。但那里面存在巨大的挑战:
很多BCL中的代码是不透明的(本地)- 您无法反汇编它
泛型模型相当复杂。我已经实现了一个JavaScript运行时,可以准确地模拟类和方法的泛型、实例化、类型生成和基本反射,并具有合理的性能。这在具有闭包的动态JavaScript中已经很困难了,而在JVM上以高性能完成可能也相当困难 - 但我可能只是没有看到简单的解决方案。
值类型在字节码中创建了重大的复杂性。我尚未为WebSharper 3.0解决这个问题。它们也不能被忽略,因为它们被许多您想要移植的库广泛使用。
同样,基本反射在许多实际的.NET库中被使用,但在跨编译方面却是个噩梦,需要大量的本机代码以及对泛型和值类型的适当支持。
此外,字节码方法并没有解决如何实现尾调用的问题。据我所知,Scala并没有实现尾调用。他们肯定有天赋和资金来做到这一点-他们不这样做,这告诉我JVM上实现TCO的实用性。对于我们的.NET->JavaScript端口,我可能会采用类似的方法-除非你专门要求跳板调用,否则不保证TCO的性能,这将导致性能损失一个或两个数量级。
有一个将OCaml编译成JVM的项目,OCaml-Java:它非常完整,特别是可以编译OCaml编写的编译器源代码。我不确定您对F#语言的哪些方面感兴趣,但如果您主要想获得一个成熟的严格类型的函数式语言,那么这可能是一个不错的选择。
我认为无论哪种方法都需要付出大量的工作,但我认为你的第一个建议是唯一一个能避免引入许多附加的不兼容和错误的方法。编译器非常复杂,且在重载解析等方面存在许多特殊情况(规范可能也存在缺陷),因此新实现具有一致兼容的语义似乎非常不可能。
我在寻找类似的东西,尽管更像是一个 F# 到 Akka 的翻译器/编译器。就 F# -> JVM 而言,我发现了两个不太成熟的选择:
1. F# -> [Fjord][1] -> JVM.
2. F# -> [Funscript][2] -> [Vert.X][3] -> JVM