我对Elm并不是很熟悉,但我稍微了解了一下,对Reason比较熟悉,所以我会试着帮忙。我相信这里会有一些不准确的地方,请不要将我所说的作为事实,而应该将其作为指向你自己更详细了解的提示。
Elm和Reason都是具有非常相似编程模型的类ML语言,因此我将重点介绍它们之间的区别。
语法:
Elm使用Haskell风格的语法,它被设计(或者演化)用于Elm和Reason所使用的编程模型,因此一旦你熟悉它,阅读和编写惯用代码时应该非常顺畅,但对大多数程序员来说,它看起来非常不同和陌生。
Reason试图通过尽可能模拟JavaScript的语法来使其更易接近,这对于大多数程序员来说都很熟悉。然而,它也旨在支持底层OCaml语言的整个功能集,这使得某些函数式模式相当笨拙。
其中一个例子是函数应用语法,在Elm中强调了函数的柯里化性质(f a b
),非常适合组合函数并构建可读的DSL。 Reason使用括号语法(f(a, b)
)隐藏了这种复杂性,这使得它更容易进入(直到你意外地被绊倒,因为它当然仍然不同),但是会让大量使用函数组合的语句需要用大量的括号。
可变性:
Elm是一种纯函数语言,理论上很好,但在实践中挑战很大,因为周围的世界对Elm追求纯粹性的努力不太关心。我认为,Elm首选的解决方案是通过在JavaScript中编写有问题的代码来隔离不纯性,然后通过Web组件或端口在Elm中访问它。这意味着您可能需要在一个单独且非常不安全的语言中维护大量的代码,并连接它们所需的大量样板文件,同时还需要弄清楚如何将圆形物体适配到端口等方面。
另一方面,Reason则更加“实用主义”,我喜欢称之为这样。您会为了增加生产力和短期利益而牺牲一些安全性、理想和长期利益。在Reason中隔离不纯性仍然是一个好的实践,但您不可避免地会走捷径来完成事情,这会在以后给您带来麻烦。
但即使您设法足够自律地隔离所有不纯性,您仍然需要付出代价才能在语言中进行突变。其中一部分代价就是所谓的
值限制,您迟早会遇到它,并且它会让您感到困惑和愤怒,因为编译器无法证明在某个时刻不可能涉及可变引用而拒绝直观上应该工作的代码。
JavaScript互操作性:
如上所述,Elm通过端口和Web组件提供了与JavaScript互操作的能力,这些功能是故意限制的。以前可以使用本地模块,它们提供了更多的灵活性(和可能导致问题的能力),但这种可能性正在消失(至少对于普通人来说),这一举措在哲学上并不令人惊讶,但也引起了争议。
在此处阅读更多关于此变化的信息
Reason或者说BuckleScript提供了丰富的基元,可以直接绑定到JavaScript,并且很常见地生成符合惯用法的Reason接口,而无需编写任何粘合代码。虽然不是非常直观,但一旦理解就很容易做到。但是,如果做错了,稍后某个随机点可能会出现问题。您必须编写一些粘合代码才能提供良好的惯用API,可以使用所有安全保证的Reason来编写,而不必编写不安全的JavaScript。
生态系统:
由于Elm的JavaScript互操作性有限,因此生态系统相当小。没有太多优质的第三方JavaScript库可提供Web组件,自己实现需要大量的工作。因此,您将看到库直接在Elm本身中实现,这当然需要更多的努力,但通常会产生更高的质量,因为它们是专门为Elm设计的。
工具链:
Elm因其出色的错误信息而闻名。尽管Reason也在努力,但在很大程度上并不如此。至少部分原因是因为Reason本身并不是编译器,而是建立在OCaml编译器之上,因此可用信息有限,可能出现的错误面积非常大。但它们也没有经过深思熟虑。
Elm还拥有一个伟大的打包工具,可以为您设置一切,并检查您发布的软件包的接口是否已更改以及版本号是否符合语义化版本控制。Resaon/BuckleScript只使用npm,并要求您手动管理所有Reason/BuckleScript特定的内容,例如使用新依赖项更新bsconfig.json。
Reason、BuckleScript、它的构建系统和OCaml都非常快。我还没有遇到任何项目需要超过3秒才能从头开始编译,包括所有依赖项,增量编译通常只需要几毫秒(尽管这并不完全没有成本)。据我所知,Elm的性能不如此高。
Elm和Reason都有格式化工具,但Reason格式化的代码质量显着较差(尽管正在缓慢改善)。我认为这主要是因为它必须处理的语法复杂得多。
成熟和衰败:
Reason是基于OCaml构建的,具有20多年的历史,因此拥有经过实战检验和长时间证明有效的坚实基础。此外,它是由学术界大力发展的语言,这意味着某个功能可能需要一段时间才能得到实现,但是一旦实现了,它就非常可靠,因为它基于理论甚至可能已被正式证明。不足之处在于,它的年龄和实验性质也意味着它积累了一些难以摆脱的过时内容。
另一方面,Elm相对较新,管理不那么繁琐,可以更快地移动,并且不害怕与过去决裂。这使其更加简洁连贯,但类型系统也不那么强大。
可移植性:
Elm编译成JavaScript,本身就非常便携,但目前仅限于浏览器,特别是Elm架构。这是一个选择,而且将其定位于node或平台也不会太困难。但反对这种做法的论点是,它会分散注意力,从而使其在其专业领域的表现不佳。
Reason基于OCaml,实际上首先目标是本机机器代码和字节码,但也有JavaScript编译器(或两个),使其能够针对浏览器、node、electron、react native,甚至能够
编译成unikernel。不过据说Windows支持有点靠不住。作为一个生态系统,Reason首要目标是React,但也
有一些库可以很自然地使用Elm架构。
治理:
Elm由一名单独的开发者设计和开发,他能够清晰地传达他的目标和推理,并且全职工作。这使得最终产品具有连贯性和良好的设计,但是开发速度较慢,而巴士因素可能会使投资变得困难。
Reason的故事稍微复杂一些,因为它更像是一个项目集合的伞头名称。
OCaml是在公开管理、设计和开发的,主要由学者和各种基金会和商业支持者赞助的开发者开发。
BuckleScript是一种JavaScript编译器,源自于OCaml编译器,由一名开发者开发,他的目标和就业情况不明确,并且不费心解释他的推理或决策。虽然PR被接受,但缺乏解释和晦涩的代码库使其实际上是封闭式开发。不幸的是,这也不会导致特别连贯的设计,而巴士因素可能也会使投资变得困难。
Reason本身和ReasonReact由Facebook管理。PR受到欢迎,大量的Reason开发由外部驱动,但大多数决策似乎是在某个后房间做出的。除了微不足道的错别字修正等之外,对ReasonReact的PR经常被拒绝,可能有很好的理由,但通常没有太多解释。然后,更好的设计通常会在后房间中随着时间的推移得以出现。
javascript
,它肯定会被关闭。但是我注意到广泛的elm
问题通常保持开放状态,甚至得到很好的答案(比如@glennsl的回答)。 - Sidneyjavascript
。如何询问“在什么情况下应该使用哪种语言?”(涉及任何两种语言),却不引发很多意见呢? - Onorio Catenacci