简体   繁体   English

是否存在Haskell无法验证的类型签名?

[英]Are there type signatures which Haskell can't verify?

This paper establishes that type inference (called "typability" in the paper) in System F is undecidable. 本文确定系统F中的类型推断(在本文中称为“可打字性”)是不可判定的。 What I've never heard mentioned elsewhere is the second result of the paper, namely that "type checking" in F is also undecidable. 我在其他地方从未听过的是该论文的第二个结果,即F中的“类型检查”也是不可判定的。 Here the "type checking" question means: given a term t , type T and typing environment A , is the judgment A ⊢ t : T derivable? 这里的“类型检查”问题意味着:给定一个术语t ,输入T和输入环境A ,判断A ⊢ t : T可推导? That this question is undecidable (and that it's equivalent to the question of typability) is surprising to me, because it seems intuitively like it should be an easier question to answer. 这个问题是不可判定的(并且它相当于可打字性的问题)对我来说是令人惊讶的,因为它似乎直觉上应该是一个更容易回答的问题。

But in any case, given that Haskell is based on System F (or F-omega, even), the result about type checking would seem to suggest that there is a Haskell term t and type T such that the compiler would be unable to decide whether t :: T is valid. 但无论如何,鉴于Haskell基于System F(或F-omega,偶数),关于类型检查的结果似乎表明存在Haskell项t和类型T ,因此编译器将无法决定t :: T是否有效。 If that's the case, I'm curious what such a term and type are... if it's not the case, what am I misunderstanding? 如果是这样的话,我很好奇这样的术语和类型是什么......如果不是这样的话,我有什么误解?

Presumably comprehending the paper would lead to a constructive answer, but I'm a little out of my depth :) 据推测,理解这篇论文会得到一个建设性的答案,但我有点超出我的深度:)

Type checking can be made decidable by enriching the syntax appropriately. 通过适当地丰富语法,可以使类型检查成为可判定的。 For example, in the paper, we have lambdas written as \\x -> e ; 例如,在论文中,我们将lambdas写为\\x -> e ; to type-check this, you must guess the type of x . 要键入检查,你必须猜测 x的类型。 However, with a suitably enriched syntax, this can be written as \\x :: t -> e instead, which takes the guess-work out of the process. 但是,使用适当丰富的语法,可以将其写为\\x :: t -> e ,它将猜测工作从流程中取出。 Similarly, in the paper, they allow type-level lambdas to be implicit; 同样,在论文中,它们允许类型级lambda是隐含的; that is, if e :: t , then also e :: forall a. t 也就是说,如果e :: t ,那么e :: forall a. t e :: forall a. t . e :: forall a. t To do typechecking, you have to guess when and how many forall 's to add, and when to eliminate them. 做类型检查,你必须在猜测多少forall的增加,以及何时消除它们。 As before, you can make this more deterministic by adding syntax: we add two new expression forms /\\a. e 和以前一样,您可以通过添加语法使其更具确定性:我们添加两个新的表达式/\\a. e /\\a. e and e [t] and two new typing rule that says if e :: t , then /\\a. e :: forall a. t /\\a. ee [t]以及两个新的输入规则,如果e :: t ,那么/\\a. e :: forall a. t /\\a. e :: forall a. t /\\a. e :: forall a. t , and if e :: forall a. t /\\a. e :: forall a. t ,如果e :: forall a. t e :: forall a. t , then e [t'] :: t [t' / a] (where the brackets in t [t' / a] are substitution brackets). e :: forall a. t ,然后e [t'] :: t [t' / a] (其中t [t' / a]中的括号是替换括号)。 Then the syntax tells us when and how many foralls to add, and when to eliminate them as well. 然后语法告诉我们何时以及添加多少个foralls,以及何时消除它们。

So the question is: can we go from Haskell to sufficiently-annotated System F terms? 所以问题是:我们可以从Haskell转到充分注释的System F术语吗? And the answer is yes, thanks to a few critical restrictions placed by the Haskell type system. 答案是肯定的,这要归功于Haskell类型系统的一些关键限制。 The most critical is that all types are rank one*. 最关键的是所有类型都排名第一*。 Without going into too much detail, "rank" is related to how many times you have to go to the left of an -> constructor to find a forall . 没有太多细节,“排名”与你必须在->构造函数的左边找到一个forall

Int -> Bool -- rank 0?
forall a. (a -> a) -- rank 1
(forall a. a -> a) -> (forall a. a -> a) -- rank 2

In particular, this restricts polymorphism a bit. 特别是,这有点限制了多态性。 We can't type something like this with rank one types: 我们不能用一级类型输入这样的东西:

foo :: (forall a. a -> a) -> (String, Bool) -- a rank-2 type
foo polymorphicId = (polymorphicId "hey", polymorphicId True)

The next most critical restriction is that type variables can only be replaced by monomorphic types. 下一个最关键的限制是类型变量只能被单形类型替换。 (This includes other type variables, like a , but not polymorphic types like forall a. a .) This ensures in part that type substitution preserves rank-one-ness. (这包括其他类型变量,如a ,但不是像forall a. a这样的多态类型。)这确保了部分类型替换保留了一等级。

It turns out that if you make these two restrictions, then not only is type-inference decidable, but you also get minimal types. 事实证明,如果你做出这两个限制,那么不仅类型推断是可判定的,而且你也得到最小的类型。

If we turn from Haskell to GHC, then we can talk not only about what is typable, but how the inference algorithm looks. 如果我们从Haskell转向GHC,那么我们不仅可以讨论什么是可打字的,而且可以讨论推理算法的外观。 In particular, in GHC, there are extensions that relax the above two restrictions; 特别是在GHC中,有一些扩展可以放宽上述两个限制; how does GHC do inference in that setting? GHC如何在该环境中进行推理? Well, the answer is that it simply doesn't even try. 嗯,答案是它根本就没有尝试过。 If you want to write terms using those features, then you must add the typing annotations we talked about all the way back in paragraph one: you must explicitly annotate where forall s get introduced and eliminated. 如果您想使用这些功能编写术语,那么您必须在第一段中添加我们所讨论的键入注释:您必须明确注释引入和消除forall的位置。 So, can we write a term that GHC's type-checker rejects? 那么,我们可以写一个GHC的类型检查器拒绝的术语吗? Yes, it's easy: simply use un-annotated rank-two (or higher) types or impredicativity. 是的,这很简单:只需使用未注释的二级(或更高级)类型或不可预测性。 For example, the following doesn't type-check, even though it has an explicit type annotation and is typable with rank-two types: 例如,以下内容不进行类型检查,即使它具有显式类型注释并且可以使用rank-two类型:

{-# LANGUAGE Rank2Types #-}
foo :: (String, Bool)
foo = (\f -> (f "hey", f True)) id

* Actually, restricting to rank two is enough to make it decidable, but the algorithm for rank one types can be more efficient. *实际上,限制为二级足以使其可判定,但是一级类型的算法可以更有效。 Rank three types already give the programmer enough rope to make the inference problem undecidable. 排名三种类型已经给程序员足够的绳索使推理问题变得不可判定。 I'm not sure whether these facts were known at the time that the committee chose to restrict Haskell to rank-one types. 我不确定这些事实是否在委员会选择将Haskell限制为一级类型时已知。

Here is an example for a type level implementation of the SKI calculus in Scala: http://michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/ 以下是Scala中SKI演算的类型级实现的示例: http//michid.wordpress.com/2010/01/29/scala-type-level-encoding-of-the-ski-calculus/

The last example shows an unbounded iteration. 最后一个示例显示了无界迭代。 If you do the same in Haskell (and I'm pretty sure you can), you have an example for an "untypeable expression". 如果你在Haskell中做同样的事情(我很确定你可以),你有一个“不可表达的表达式”的例子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM