功能语言的独特特征

时间:2009-01-27 21:42:51

标签: haskell f# functional-programming erlang clojure

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

其他功能语言(Clojure,F#,Arc,还是其他)之间有哪些独特的基本差异?从根本上说,我的意思是影响你在这种语言中发展的方式,而不是,例如,它是否与某种广泛的运行时集成。

7 个答案:

答案 0 :(得分:25)

脱离我的头顶:

  • lazy vs. eager(又名非严格严格按需拨打致电 - by-value ):是在函数应用程序之前或之后评估的函数参数,还是从不?
  • pure vs. impure:语言是否允许函数产生副作用?它有可变引用吗?
  • static vs. dynamic:语言在编译时或运行时检查类型吗?
  • algebraic datatypes:语言是否支持模式匹配变体类型?
  • metaprogramming:该语言是否提供了强大的代码生成系统?
  • concurrencyparallelism:线程/进程是一流的抽象吗?该语言是否可以轻松地同时运行多个计算?
  • “异国情调”类型:静态类型系统的表现力如何? GADTs?依赖类型?线性类型?系统F?

只有前两个项目对于函数式语言来说才是真正独特的(即,几乎所有命令式语言都是渴望和不纯的)。

答案 1 :(得分:14)

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

就特定语言的功能而言,我会选择 F# 来调出许多其他FPL中没有的功能:

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

就一般分类而言,F#是

  • 渴望(严格,按值调用;但'lazy'是一个关键字&库,使用seq / IEnumerable进行一些懒惰是一种常见的策略)
  • 不纯(虽然语法会使您偏向纯粹的默认样式)
  • 静态(使用类型推断,因此F#经常'感觉就像脚本',只有类型安全)

你的问题的表达方式明显偏向某些语言外语用语(例如它与运行时集成的内容),但你也会问“影响你的发展方式”,这些事情会影响到:< / p>

  • Visual Studio集成意味着出色的编辑体验(例如Intellisense)
  • Visual Studio集成意味着出色的调试体验(例如断点/跟踪点,本地人,即时窗口......)
  • 用于编写脚本或即时UI的
  • REPL 是热门的(fsi.exe命令行或VS中集成的“F#Interactive”)
  • .NET集成意味着大多数'X'已经有了一个库来做
  • 像FsLex / FsYacc这样的辅助工具,以及与MSBuild的集成,使“构建系统”变得简单

(我认为尝试将语言与其运行时和工具分开是一项主要的学术练习。)

所以我对一个特定语言的许多独特特征进行了描述。我希望其他人可能会发布类似的答案,这些答案可以说出其他语言的独特特征。

答案 2 :(得分: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和(vanilla)OCaml中的模式匹配非常快,但由于Mathematica中的活动模式甚至未知的渐近复杂性,在F#中具有未知的性能。

  8. 即时编译到本机 码。 F#,Lisp和Scheme允许代码 生成,编译和 在运行时有效执行。

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

  10. 标准化与专有。 SML,Haskell 2010,Common Lisp和Scheme是标准化语言,而OCaml,Erlang,F#和Mathematica是专有的。

答案 3 :(得分:5)

存在许多差异,但只有两个差异我将其归类为基本,因为它们会对您的开发产生重大影响:

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

答案 4 :(得分:3)

功能编程是一种风格,而不是语言结构

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

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

但最重要的原则是他们通常会强迫你以功能性的方式写作。您可以使用大多数语言编写功能样式。如果您像其他语言一样编写代码,C#可被视为“功能性”。

答案 5 :(得分:2)

基本属性?

  • 功能纯度(缺乏副作用)
  • 作为上述搭配,缺乏国家。
  • 功能中的模式匹配

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

对于缺乏国家的现实补偿是我发现功能语言之间最大的区别。

这几件事给了很多免费赠品。大多数情况下,语言处理memoization。

答案 6 :(得分:2)

当您将代码称为数据时,您指的是代码在数据结构中表示的语言。这被称为Homoiconicity,它通常仅适用于lisp方言或接近它的语言。 Haskell,Erlang和Scala不是Homoiconic,Clojure是。

Clojure的基本区别是:

  1. 它有一个软件事务内存系统,可以简化共享状态并发编程

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

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

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