命令性语言与功能性语言之间的区别是什么?


17

我正在阅读西蒙·佩顿·琼斯(Simon Peyton Jones)的《函数式编程语言的实现》,有一个说法让我有些惊讶(第39页):

与命令式语言相比,功能语言在很大程度上是彼此的语法变体,语义上的差异相对较小。

现在,它写于1987年,我对此主题的想法可能会受到当时不流行或不流行的现代编程语言的影响。但是,我发现这有点难以置信。例如,我认为所描述的Miranda编程语言(Haskell的较早版本)与严格的语言(如ML)相比,语义要多得多,而不是说C必须进行Pascal甚至C进行小规模的交谈(尽管我承认C ++对他的观点提供了一些验证:-)。

但是话又说回来,我是基于我的直觉理解。西蒙·佩顿·琼斯(Simon Peyton Jones)的说法是否正确,还是有争议的观点?

Answers:


19

从扩展的角度来看,西蒙基本上是正确的。我们非常了解现代功能语言的语义,它们实际上是彼此的相对较小的变体-它们各自代表一种单语成语的翻译形式。甚至像Scheme这样的语言(具有一流控制的动态类型的高阶命令式语言)也具有与ML和Haskell的语义非常接近的语义。

从一个指称点,您可以通过给一个非常简单的域方程方案的语义开始-称之为。人们可以并且确实在70年代末80年代初就解决了这样的方程式,所以这还不错。同样,Scheme也有相对简单的操作语义。(请注意,当我说“方案”时,我的意思是未类型化的lambda演算加上连续性加上状态,而不是像所有真实语言一样具有一些疣的实际Scheme。)V

但是要进入适合于解释现代类型功能语言的类别,事情就变得很恐怖。基本上,您最终在该域上构造了一个超等效的部分等价关系类别。(例如,请参阅Birkedal,Stovring和Thamsborg的“参数多态性,通用参考和递归类型的可实现性语义”。)偏爱操作语义的人们将这些东西称为逐步索引逻辑关系。(例如,参见艾哈迈德(Ahmed),德雷尔(Dreyer)和罗斯伯格(Rossberg)的“状态依赖表示独立性”。)无论哪种方式,使用的技术都是相对较新的技术。

a -> b一种Ťb一种bŤ一种一种a

因此,就等式理论而言,由于这些语言都可以通过翻译成同一语言的稍有不同的子集来描述,因此将它们彼此称为语法变体是完全公平的。

ML和Haskell之间的感觉差异实际上是由两种语言的内涵特性引起的,即执行时间和内存消耗。ML具有组成性能模型(即程序的时间/空间成本可以从其子术语的时间/空间成本计算得出),就像真正的按名称调用语言一样。实际的Haskell是通过按需调用(一种回忆)来实现的,因此其性能不是基于组合的-与变量绑定的表达式需要花多长时间来评估,取决于它是否曾被使用过。我上面提到的语义没有对此进行建模。

如果您想更认真地对待内涵特性,那么ML和Haskell确实会表现出更大的差异。仍然有可能为它们设计一个通用的元语言,但是类型的解释将以更加系统的方式有所不同,这与聚焦的证明理论有关。了解这一点的一个好地方是Noam Zeilberger的博士学位论文。


10

我的感觉是SPJ指的是纯粹的功能语言-即参照透明的语言。例如,这包括Haskell,Miranda,Clean,但不包括ML。通常,一旦有了一种纯粹的功能性语言,就可以为其提供一种相当干净且定义明确的指称语义。通常,这种语义看起来像是lambda演算的语义,在这里和那里都有一些调整。通常,您将拥有一个类型系统,其类型类似于System F的变体-在某些方面可能更强大,而在其他方面则更受限制。这就是为什么从复杂的依赖类型的证明助手(例如Agda)相对简单地提取代码到Haskell,O'Caml等的代码,或者将其编译到该代码。

在此框架内,还有很多游戏空间。当然,非严格语言和严格语言之间仍然存在差异。但是,在没有副作用的情况下,唯一的区别是,非严格语言包含更多表示底数的表达方式-他们同意,只要这两种评估策略都不会产生底线。

西蒙的声明也符合非常重要的历史背景。在Haskell(1987)诞生之时,出现了一大堆非严格的功能语言-不仅是Miranda,而且还有Lazy ML,Orwell,Clean等。除了某些句法变体以外,它们都几乎是同一语言。这正是Haskell委员会成立的动机。有关更多信息,请参见“ Haskell的历史:对类懒惰”:http : //research.microsoft.com/zh-cn/um/people/simonpj/papers/history-of-haskell/


5

我认为SPJ对于核心语义来说是正确的。

尽管您可以指出许多高级的细微之处,例如默认为严格评估或惰性评估,但是类型系统的细节或更大的代码单元(模块,结构)的组织方式,程序的思维模式是跨功能语言非常相似。

选择一些特定的指定函数并将其用您比较的所有语言编写,您可能会发现不同实现的结构和语义对于所有这些实现都非常相似,包括抽象级别,选择的数据结构,所有这些都假设是垃圾回收,等等。

相反,说相同功能的C实现与Smalltalk实现可能具有不同的结构(函数和低级数据结构与对象),专注于不同级别的细节(例如,手动内存管理与垃圾回收) ),并在不同的抽象级别上运行。

功能语言设计空间的世界观比“命令式编程”空间的世界观更加统一和连贯,后者将汇编语言,C语言,Smalltalk语言,Forth语言以及其他数十种根本不同的语言归为一类。


4

我认为Simon PJ的报价实际上只是一时的说法。

语言之间的相似性取决于研究人员和语言设计者社区所达成的共识。毫无疑问,功能性编程社区中的共识程度要比命令式编程社区中更高。但是也存在这样的情况,函数式编程语言主要是由研究人员而不是从业人员设计的。因此,达成这种共识是很自然的。

几乎所有功能语言都使用垃圾回收内存管理和递归数据结构(由Lisp发起),其中大多数使用“代数”数据类型和模式匹配(由Hope发起),其中许多使用高阶函数和多态函数(由ML发起)。除此之外,共识消失了。它们在所使用的模块系统,如何处理状态更改操作和其他计算效果以及评估顺序(按名称致电与按值致电)等方面有所不同。

命令式编程语言通常使用嵌套的控制结构(由Algol 60发起)和类型系统(由Algol 60发起,但由Algol 68合并)。它们通常具有繁琐的表面语法(再次回到Algol 60),全心全意地尝试处理高阶函数和多态类型,并且在对块结构和模块系统的支持上也有所不同。评估顺序可能更统一,因为在60年代以后,按命令呼叫实质上已经从命令性语言中消失了。

因此,我不清楚这两种语言在语言统一性上的差异是否很大。

将功能性编程的更简洁统一的符号引入命令式编程语言中确实是值得的。我看到Scala在这个方向上已经开始。这种趋势是否会持续下去还有待观察。


我不知道您为什么在“代数”数据类型中使用吓人的引号?
史蒂文·肖
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.