SML:可推广与非通用类型变量

时间:2015-08-18 18:25:00

标签: functional-programming sml

我刚刚在Ch中遇到过这些。 Ullman的 ML编程元素中的5个。他说:

'a等类型变量有两个不同的含义。它可以表示”对于每个类型T,此类对象的实例都使用类型T代替'a。此类型变量称为可推广。“

然后他说:

'a也可以表示我们选择的任何一种类型。但是,在选择了一种类型之后,即使我们重复使用原始类型变量{{ 1}}。这种类型变量称为非泛化。“

有人能给出每种类型的例子吗?我很难绕过这个并理解这种区别似乎很重要(他建立在这些定义的基础上)。

谢谢!

1 个答案:

答案 0 :(得分:4)

这是SML中value restriction的结果。

当语言推断出程序的类型时,它可以找到适用于任何类型的表达式,它用类型变量表示。 map函数就是一个很好的例子。 (我的语法可能有点偏,因为我从未使用过SML。)

fun map f nil     = nil
  | map f (x::xs) = f x :: map f xs

由于此函数适用于任何类型的列表,因此它获取一个类型变量:

('a -> 'b) -> 'a list -> 'b list

我们可以对mapint list使用相同的string list函数 - 这是可推广的类型变量。值得注意的一点是nil案例:nil可以很容易地将int的空列表作为string的空列表。它的类型为'a list

在一个完美的世界里,这就是我们所拥有的一切。然而,存在一个问题:可变引用。遵循与上面相同的逻辑,以下ref也将在其类型中具有类型变量:

val x = ref nil

我们希望x('a list) ref。就像nil本身一样,它可以很容易地成为(int list) ref(string list) ref - 或者可以吗?问题是我们可以设置引用。如果我们可以使用x ,就像它具有更具体的类型(int list) ref,我们可以将其设置为[1,2,3]。然后,如果我们可以在其他地方将其用作(string list) ref,我们可以将[1,2,3]读出来预期字符串列表!这是一个问题。

为了解决这个问题,SML具有值限制。粗略地说,这意味着那些看起来不那么重要的东西。类似函数不能完全多态 - 它们不具有可推广的类型变量。相反,x的类型将基于我们使用它的第一个具体类型(即(int list) ref)。如果我们继续尝试使用具有不同具体类型的x,我们将得到关于非泛化类型变量的错误。,

从某种意义上说,非泛化类型变量只是一个占位符,直到我们使用x并给它一个具体类型。它有点令人困惑,因为它仍然看起来像普通的类型变量('a)但如果我们以多种方式使用它会给我们一个错误。我认为OCaml在区分二者方面做得更好。 OCaml会将x的类型推断为'_a,它在语法上与普通类型变量不同,并清楚地表明它只是一个占位符,而不是正常的多态值。

这有点像语言中的疣,但如果你想要有类似的可变引用,那么基本上是不可避免的。