为什么用函数式语言编写一个编译器更简单?
我一直在想这个问题很长,但真的无法find答案在谷歌以及在Stackoverflow类似的问题。 如果有重复,我很抱歉。
很多人似乎都认为用OCaml和Haskell等函数式语言编写编译器和其他语言工具要用命令式语言编写它们会更加高效和容易。
这是真的? 如果是这样的话 – 为什么使用函数式语言而不是像C这样的命令式语言来编写它们是如此高效和容易呢? 另外 – function语言中的语言工具是否比C语言中的低级语言要慢?
很多时候,编译器在树上工作很多。 源代码被parsing成一个语法树。 那个树可能会被转换成另外一个带有types注解的树来执行types检查。 现在,您可以将该树转换为仅包含核心语言元素的树(将句法糖类符号转换为非加糖forms)。 现在你可以执行各种基本上是树上转换的优化。 之后,你可能会创build一个正常forms的树,然后遍历树来创build目标(汇编)代码。
函数式语言具有模式匹配和有效recursion的良好支持等特性,这使得使用树很容易,所以这就是为什么它们通常被认为是编写编译器的好语言。
很多编译任务是树结构上的模式匹配。
OCaml和Haskell都具有强大而简洁的模式匹配function。
将模式匹配添加到命令式语言是困难的,因为无论正在评估或提取哪个值以匹配模式,都必须是无副作用的。
要考虑的一个重要因素是,任何编译器项目的很大一部分是你可以自己托pipe编译器并“自己吃狗粮”。 因为这个原因,当你查看像OCaml这样的语言研究devise语言时,他们倾向于编译器types的问题。
在我最后的编译器工作中,我们使用OCaml来处理C代码,正是这个原因,它只是这个任务的最佳工具。 如果INRIA的人们build立了不同优先级的OCaml,它可能不是那么适合。
也就是说,函数式语言是解决任何问题的最佳工具,因此从逻辑上说,它们是解决这个特定问题的最佳工具。 QED。
/ me:不太喜欢爬回我的Java任务
也可以看看
F#devise模式
FP通过操作对事物进行分组,而OO按照types对事物进行分组,对于编译器/解释器来说,更为自然。
基本上,编译器是从一组代码到另一组代码的转换 – 从源代码到IR,从IR到优化的IR,从IR到组装等等。这正是function语言所devise的function – 纯function是只是从一个到另一个的转变。 重要的function没有这个质量。 虽然可以用命令式语言编写这种代码,但是函数式语言却是专门为此编写的。
一种可能是编译器往往不得不非常小心地处理大量的案例。 通过使用devise模式来实现代码的正确性通常变得更加容易,这些devise模式以与实现的规则相似的方式来构build实现。 通常,这最终会成为声明式(模式匹配,“where”)而不是命令式(sorting,“什么时候”)devise,因此更容易以声明性语言实现(并且大部分是function性的)。
似乎每个人都错过了另一个重要的原因。 为parsing器编写一个embedded式域特定语言(EDSL)是很容易的,这个parsing器看起来很像普通代码中的(E)BNF。 像Parsec这样的parsing器组合器在使用高级函数和函数组合的函数式语言中很容易编写。 不仅更容易,而且非常优雅。
基本上,您将最简单的genericsparsing器表示为函数,并且您有特殊的操作(通常是高阶函数),可以将这些原语parsing器组合成更复杂,更具体的语法分析器。
当然,这不是唯一的方法。