有一种全新的“函数式编程”范式,与过程式编程相比,它需要彻底改变思维模式。它使用高阶函数、纯度、monad 等,这些在命令式和面向对象的语言中通常看不到。
我的问题是这些语言的实现与命令式或面向对象的语言有何不同,例如,内存管理或指针等内部结构。
有一些函数式语言在 JVM 之上运行。这是否意味着这些语言在内部像 JVM 上的其他语言一样工作?
有一种全新的“函数式编程”范式,与过程式编程相比,它需要彻底改变思维模式。它使用高阶函数、纯度、monad 等,这些在命令式和面向对象的语言中通常看不到。
我的问题是这些语言的实现与命令式或面向对象的语言有何不同,例如,内存管理或指针等内部结构。
有一些函数式语言在 JVM 之上运行。这是否意味着这些语言在内部像 JVM 上的其他语言一样工作?
由函数式语言产生的代码使用了您在非函数式语言中不同程度地看到的许多特性。垃圾收集已成为一般用途。尾调用优化在 GCC 和 VC++中完成。
然而,闭包是函数式编程的标志。你看不到一个没有另一个。如果您将“函数式语言”定义为仅指纯函数式语言,那么两者并不是同义词,因为您会在支持函数式编程的命令式语言中找到闭包(例如 Javascript 和 Scheme(这在技术上是命令式的,尽管函数式范式主要是用过的))。闭包可以通过调用堆栈的意大利面条堆栈来实现,或者通过在退出堆栈帧时复制局部变量,或者通过在堆上分配局部变量并让垃圾收集来处理它们来实现。
一旦你有了闭包,匿名函数就相对容易了(使用解释器,它们真的很容易)。使用编译器,函数在编译时被转换为字节码,并且字节码(确切地说,入口点的地址)在运行时与当前环境相关联。
函数组合可以依赖匿名函数。当编译器遇到函数组合运算符f . g
时,它会创建一个匿名函数来调用两个参数f
和g
,并将一个的结果作为参数传递给另一个。
Monad 可以在 OO 语言中实现,它们只是不像在纯函数式语言中那样必要。I/O monad 并没有什么特别之处,它们只是依赖于底层平台允许副作用这一事实。
函数式编程语言的实现使用了广泛的实现技术。这本书是对 Scheme(一种 Lisp 方言)实现的出色介绍: Christian Queinnec 的Lisp in Small Pieces。
我想到的最大区别是函数式语言的设计倾向于将源代码脱糖为数学上简单而强大的中间语言。这种语言通常包含 lambda、函数调用、if/else、机器类型等let
,而不是更多。转换后的代码是深度嵌套的、冗长的,并且实际上不适合人类阅读。表面语法被丢弃。
像这样的语言的编译器必须进行一些内联和一些闭包优化才能生成体面的代码。(对我来说,这些基线闭包优化似乎很重要——逃逸分析等等——但它可能只是缺乏熟悉。)
我想有很多方面可以从函数式语言的特别关注中受益,我想到的一个是:
函数式语言大量使用递归。所以任何实现都应该尝试优化这种情况。例如,识别尾递归并在内部转换为循环(从而节省函数调用开销,如堆栈保存/恢复)。(http://en.wikipedia.org/wiki/Tail_recursion)
Haskell 等函数式编程语言的实现通常与命令式语言的实现非常不同。您可以在此处阅读有关执行此操作的一种方法。尽管这篇论文已有好几年的历史,但我相信这些想法仍在使用。
一切都在同一个处理器上运行(因此也运行在相同的汇编指令上),所以只要你走得足够深,内部一切都是一样的。
@outis:虽然语言可能支持它们,但闭包与函数的数学概念冲突,就像副作用一样:它们允许您从相同的参数中获得不同的结果。这使得闭包是程序性的,而不是功能性的。
也就是说,有一些效率参数支持闭包而不是全局变量(尤其是在编译器实现的上下文中)。[但我知道不直接提供闭包的函数式语言,即使可以实现“类似工作”。]
(然而,柯里化类似于闭包,不会受到这种冲突的影响,并且确实经常出现在函数式语言中。)
无论如何,在我看来,函数式编程语言是努力使计算像数学函数一样可表示的语言。这意味着优化倾向于优化功能。
假设,至少,函数式语言允许机器处理比纯过程方法有用的更深的抽象。