【发布时间】:2012-04-21 04:18:18
【问题描述】:
许多静态类型语言都具有参数多态性。例如在 C# 中可以定义:
T Foo<T>(T x){ return x; }
在调用站点中你可以这样做:
int y = Foo<int>(3);
这些类型有时也写成这样:
Foo :: forall T. T -> T
我听说有人说“forall 就像类型级别的 lambda 抽象”。所以 Foo 是一个函数,它接受一个类型(例如 int)并产生一个值(例如一个 int -> int 类型的函数)。很多语言都会推断类型参数,所以你可以写Foo(3)而不是Foo<int>(3)。
假设我们有一个类型为forall T. T -> T 的对象f。我们可以对这个对象做的首先是通过编写f<Q> 将类型Q 传递给它。然后我们返回一个类型为Q -> Q 的值。但是,某些f 是无效的。比如这个f:
f<int> = (x => x+1)
f<T> = (x => x)
所以如果我们“调用”f<int>,那么我们会返回一个类型为 int -> int 的值,通常如果我们“调用”f<Q>,那么我们会返回一个类型为 Q -> Q 的值,这很好.但是,一般认为这个f 不是forall T. T -> T 类型的有效事物,因为它根据您传递的类型而不同。 forall 的想法是明确不允许允许这样做。另外,如果 forall 是类型级别的 lambda,那么存在什么? (即存在量化)。由于这些原因,似乎 forall 和 exists 并不是真正的“类型级别的 lambda”。但那它们是什么?我意识到这个问题相当模糊,但是有人可以帮我解决这个问题吗?
可能的解释如下:
如果我们看逻辑,量词和 lambda 是两个不同的东西。一个量化表达式的例子是:
forall n in Integers: P(n)所以有两部分需要考虑:一个用于量化的集合(例如整数)和一个谓词(例如 P)。 Forall 可以看作是一个高阶函数:
forall n in Integers: P(n) == forall(Integers,P)有类型:
forall :: Set<T> -> (T -> bool) -> boolExists 具有相同的类型。 Forall 就像一个无限合取,其中 S[n] 是集合 S 的第 n 个元素:
forall(S,P) = P(S[0]) ∧ P(S[1]) ∧ P(S[2]) ...Exists 就像一个无限的析取:
exists(S,P) = P(S[0]) ∨ P(S[1]) ∨ P(S[2]) ...如果我们对类型进行类比,我们可以说∧的类型类比是计算交集类型∩,∨的类比类型是计算并集类型∪。然后我们可以定义 forall 和存在于类型如下:
forall(S,P) = P(S[0]) ∩ P(S[1]) ∩ P(S[2]) ... exists(S,P) = P(S[0]) ∪ P(S[1]) ∪ P(S[2]) ...所以 forall 是一个无限的交集,exists 是一个无限的并集。他们的类型是:
forall, exists :: Set<T> -> (T -> Type) -> Type例如多态恒等函数的类型。这里
Types是所有类型的集合,->是函数的类型构造函数,=>是lambda抽象:forall(Types, t => (t -> t))现在
forall T:Type. T -> T类型的东西是一个值,而不是从类型到值的函数。它是一个值,其类型是所有类型 T -> T 的交集,其中 T 涵盖所有类型。当我们使用这样一个值时,我们不必将它应用到一个类型上。相反,我们使用子类型判断:id :: forall T:Type. T -> T id = (x => x) id2 = id :: int -> int这会将
id向下转换为int -> int类型。这是有效的,因为int -> int也出现在无限交叉点中。我认为这很有效,它清楚地解释了 forall 是什么以及它与 lambda 有何不同,但这个模型与我在 ML、F#、C# 等语言中看到的不兼容。例如在 F#您使用
id<int>来获取整数上的标识函数,这在此模型中没有意义:id 是值上的函数,而不是返回值上的函数的类型上的函数。
有类型理论知识的人能解释一下究竟什么是 forall 和存在吗? “forall 是类型级别的 lambda”在多大程度上是真的?
【问题讨论】:
-
如果你喜欢这类东西,你应该非常对Types and Programming Languages感兴趣。
标签: haskell types ocaml existential-type parametric-polymorphism