19

众所周知,所有函数式语言都共享一些基本属性,例如将函数用作程序的基本构建块,并具有所有后果,例如使用递归而不是迭代。但是,也存在一些根本性差异。Lisp 对 Lisp 代码和数据使用单一表示,而 ML 没有 ML 代码的标准表示。Erlang 有一个内置的基于actor的并发。Haskell 有单子。Haskell 在静态类型系统中区分了纯函数和不纯函数;机器学习没有。

其他函数式语言(Clojure、F#、Arc 等)之间有哪些显着的根本区别?基本我的意思是影响你用这种语言开发的方式,而不是例如它是否与一些广泛传播的运行时集成。

4

7 回答 7

26

在我的头顶上:

  • 懒惰急切(又名非严格严格按需调用与按值调用):函数参数是在函数应用之前评估,还是之后评估,还是从不评估?
  • 不纯:语言是否允许函数具有副作用?它有可变引用吗?
  • 静态动态:语言是否在编译时或运行时检查类型?
  • 代数数据类型:语言是否支持变体类型的模式匹配?
  • 元编程:该语言是否提供强大的代码生成系统?
  • 并发性并行性:线程/进程是一流的抽象吗?该语言是否可以轻松地同时运行多个计算?
  • “异国情调”类型:静态类型系统的表现力如何?GADT?依赖类型?线性类型?F系统?

只有前两项是函数式语言真正独有的(即,几乎所有命令式语言都是急切的和不纯的)。

于 2009-01-28T01:54:45.800 回答
14

我喜欢 Chris Conway 的回答,它陈述了一些有助于对不同功能语言进行分类的重要轴。

在特定语言的特性方面,我将选择F#来调出许多其他 FPL 中没有的一些特性:

  • 活动模式:许多 FPL 具有代数数据类型和模式匹配,但称为“活动模式”的 F# 功能允许您定义允许您对任意数据使用模式匹配语法的新模式。
  • 计算表达式:F# 有一些用于编写单子代码的漂亮语法糖;虽然类型系统不能表达更高种类的多态性(没有对类型构造函数的抽象)所以你不能为任意的 monad M 编写代码,你可以为固定的 monad 编写的代码非常酷,人们在seq{} 或 async{} 单子。
  • 引用:通常的“代码作为元编程的数据”位,尽管 F# 具有富有表现力的静态类型系统和丰富的语法,但我不确定有多少非 lisps 可以做到这一点。

在一般分类方面,F# 是

  • 急切(严格,按值调用;但 'lazy' 是一个关键字和库,使用 seq/IEnumerable 来处理一些惰性是一种常见的策略)
  • 不纯的(尽管语法使您偏向于更纯的默认样式)
  • 静态的(带有类型推断,所以 F# 经常“感觉像脚本”,只有类型安全)

你的问题的措辞明显偏向于一些额外的语言语用学(例如它与什么运行时集成),但你也问什么“影响你的开发方式”,这些事情确实会影响:

  • Visual Studio 集成意味着出色的编辑体验(例如 Intellisense)
  • Visual Studio 集成意味着出色的调试体验(例如断点/跟踪点、本地变量、即时窗口……)
  • 用于脚本或 UI-on-the-fly 的REPL是热门(fsi.exe 命令行,或集成在 VS 中的“F# Interactive”)
  • .NET 集成意味着对于大多数“X”来说,已经有一个库可以做到这一点
  • FsLex/FsYacc 等辅助工具,以及与 MSBuild 的集成,这使得“构建系统”变得容易

(我认为尝试将一种语言与其运行时和工具分开是一项学术活动。)

因此,我对一种特定语言的许多独特特征进行了描述,我是该语言的粉丝。我希望其他人可能会发布类似的答案,以突出其他个别语言的独特特征。

于 2009-01-28T13:43:48.867 回答
9
  1. 非严格与严格评估。

  2. 静态与动态类型。

  3. 结构与名义静态类型。OCaml 是我能想到的唯一一种结构类型(在对象和多态变体中)的语言,它通过消除定义许多类型(例如变体类型)的需要来缩小与动态类型的差距。

  4. Hindley-Milner 导数与其他静态类型推理算法。SML、OCaml、Haskell 和 F# 使用基于 Hindley-Milner 的类型推断算法,而 Scala 只有本地类型推断(如 C# 3)并且需要更多注释才能编译。(Haskell 代码通常在函数级别上充满了类型注释,但大多数都是不必要的,并且添加用于文档并在出现错误时帮助编译器)。

  5. 模式匹配与手动解构。SML、OCaml、F#、Haskell、Mathematica 和 Scheme 自动解构值。

  6. 封闭总和类型与仅开放总和类型。SML、OCaml、F# 和 Haskell 允许定义封闭/密封代数类型,以通过隐式传递更具体的约束来加强静态类型。OCaml 和 F# 也允许开放求和类型,而 SML 不允许,Haskell 需要精心设计的解决方法(由 Oleg Kiselyov 描述)。

  7. 限时模式。模式匹配在 SML 和(普通)OCaml 中非常快,但在 F# 中由于活动模式甚至 Mathematica 中未知的渐近复杂性而具有未知的性能。

  8. 即时编译为本机代码。F#、Lisp 和 Scheme 允许在运行时高效地生成、编译和执行代码。

  9. 宏。OCaml、Mathematica、Lisp 和 Scheme 是可扩展的语言。

  10. Standardized vs proprietary. SML, Haskell 2010, Common Lisp and Scheme are standardized languages whereas OCaml, Erlang, F# and Mathematica are proprietary.

于 2009-05-06T03:05:18.067 回答
5

有很多差异,但我认为只有两个差异是基本的,因为它们对您的发展有很大的影响:

  1. 具有代数数据类型和类型推断的动态类型与静态、多态类型系统。静态类型系统在一定程度上限制了代码,但有很多优点:
    • 类型是编译器检查的文档。
    • 类型系统可帮助您选择接下来要编写的代码,当您不确定要编写什么代码时,类型系统可帮助您轻松快速地排除许多替代方案。
    • 一个强大的、现代的、多态的类型系统非常擅长检测小的、愚蠢的、浪费时间的错误。
  2. 延迟评估作为默认值无处不在,而延迟评估仅限于仔细控制的构造。
    • 懒惰与渴望对您预测和理解程序的时间和空间成本的能力有巨大的影响。
    • 在一种完全惰性的语言中,您可以将数据的生成与关于如何处理生成的数据的决策完全分离。这对于搜索问题尤其重要,因为模块化和重用代码变得更加容易。
于 2009-01-30T03:10:23.753 回答
3

函数式编程是一种风格,而不是一种语言结构

大多数函数式语言都有一些共同的原则:

  • 不可变对象
  • 闭包和匿名函数
  • 通用算法
  • 继续

但最重要的原则是,它们通常会迫使你以功能性风格写作。您可以使用几乎任何语言以功能样式进行编程。如果您编写这样的代码,C# 可以被认为是“功能性的”,就像任何其他语言一样。

于 2009-01-27T21:47:45.143 回答
2

基本属性?

  • 功能纯度(无副作用)
  • 作为上述的搭配,缺乏状态。
  • 函数中的模式匹配

第一个是美丽的,第二个是前者的丑陋副作用(双关语)。

我发现对状态缺失的现实补偿是函数式语言之间最大的区别。

这几样东西给了很多免费赠品。大多数时候,语言处理记忆。

于 2009-01-27T21:47:57.670 回答
2

当您说代码作为数据时,您指的是一种以数据结构表示代码的语言。这被称为Homoiconicity,它通常只适用于 lisp 方言或接近它的语言。Haskell、Erlang 和 Scala 不是 Homoiconic,Clojure 是。

Clojure 的基本区别在于:

  1. 它有一个软件事务内存系统,这使得共享状态并发编程更容易

  2. 它是一个 Lisp,与 Haskell 或 Erlang 不同,因此所有代码都是数据,它允许您通过宏系统在运行时对语言本身进行看起来像的更改

  3. 它在 JVM 上运行,这意味着您可以直接访问所有 J​​ava 库

  4. Clojure 数据结构在适当的地方实现了 Java 接口,例如 Collection、List、Map、Runnable 和 Callable。字符串只是 Java 字符串,数字是 Java 整数和双精度数。这意味着 Clojure 数据结构可以直接传递给 Java 库,无需任何桥接或翻译

于 2009-01-28T01:12:52.297 回答