功能编程和类型系统

时间:2010-07-01 19:40:34

标签: clojure functional-programming programming-languages type-systems

我一直在学习各种函数式语言,包括Haskell,Scala和Clojure。 Haskell有一个非常严格且定义良好的静态类型系统。 Scala也是静态类型的。另一方面,Clojure是动态类型的。

所以我的问题是

  1. 类型系统在函数式语言中扮演什么角色?
  2. 语言是否有必要使用类型系统才能正常运行?
  3. 语言的“功能”级别与语言类型系统的类型有何关系?

4 个答案:

答案 0 :(得分:39)

语言不需要输入功能 - 函数式编程的核心是lambda calculus,它有无类型和typed变体。

类型系统扮演两个角色:

  • 它在编译时提供了一种保证,即在运行时不会发生一类错误。错误类通常包括尝试将两个字符串添加到一起,或者尝试将整数应用为函数。
  • 它具有一些效率优势,因为运行时的对象不需要携带它们的类型,因为类型已经在编译时建立。这称为type erasure

在像Haskell这样的高级类型系统中,类型系统可以提供更多好处:

  • 重载:使用一个标识符来引用不同类型的操作
  • 它允许库根据其使用的类型自动选择优化的实现(使用Type Families
  • 它允许在编译时证明强大的不变量,例如红黑树中的不变量(使用Generalised Algebraic Datatypes

答案 1 :(得分:13)

  

类型系统在函数式语言中扮演什么角色?

对于Simon Marlow的优秀答案,我想补充说一个类型系统,特别是包含代数数据类型的系统,可以更容易地编写程序:

  • 面向对象语言中的软件设计有时使用UML图表示,使用类型可以非常清楚地表达。这种清晰度尤其表现在不仅 values 具有类型,而且 modules 具有类型,如在Objective Caml或Standard ML中。

  • 当一个人编写代码时,一些简单的启发式方法可以很容易地根据类型编写纯函数:

    • 始终可以使用lambda创建函数类型的值。
    • 应用函数类型的值总是可以消耗。
    • 可以通过应用任何类型的构造函数来创建代数数据类型的值。
    • 通过使用case表达式仔细检查代数数据类型的值,可以消耗它。

    基于这些观察,以及简单的规则,除非有充分的理由,函数应该使用它的每个参数,否则很容易减少可能写入极少数候选者的可能代码的空间。例如,没有那么多合理的类型函数(使用Haskell表示法)

    forall a . (a -> Bool) -> [a] -> Bool
    

    使用类型创建代码的艺术被称为类型导向编程。当它运行良好时,你会听到函数式程序员说出类似的东西,一旦我们得到了类型,代码实际上是自己写的。“因为这些类型通常要小得多 代码,这是一个很大的胜利。

答案 2 :(得分:2)

  1. 与任何编程语言相同:它可以帮助您避免/查找代码中的错误。在静态类型的情况下,良好类型系统会阻止编译具有某些类型错误的程序。
  2. 否。 untyped lambda calculus是你可以称之为函数式编程语言的原型,顾名思义,它完全是无类型的。
  3. 在函数式语言(以及函数可用作值的任何其他语言)中,类型系统需要知道函数的类型。除此之外,功能语言的类型系统没有什么特别之处。

    在纯函数式语言中,您需要抽象副作用,因此您希望类型系统能够以某种方式支持它。例如,如果您想要一个类似于Clean的世界类型,您希望类型系统支持唯一性类型以确保正确使用。

    如果你想在haskell中有一个IO monad,你需要一个IO类型(虽然像haskell这样的monad类型类不需要有一个IO monad,所以你不需要一个类型系统,支持那个)。

答案 3 :(得分:1)

1:与其他任何一个相同,它会阻止你进行不明确的操作,或者对人类造成“无意义”的操作。就像在整数上添加浮点数一样 2:Nope是世界上最古老的编程语言,(无类型)lambda演算,既有功能也有无类型。
3:很难,功能只是意味着没有副作用,没有突变,参考透明等等。

请记住最古老的函数式语言,无类型的lambda演算没有类型系统。