为什么:k [False]导致GHCI出错?

时间:2015-11-05 20:56:38

标签: haskell data-kinds

我对下面会话结束时收到的错误感到困惑:

$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Ok, modules loaded: Main.
*Main> :set -XDataKinds

*Main> :t [False, True]
[False, True] :: [Bool]

*Main> :t [False]
[False] :: [Bool]

*Main> :k [False, True]
[False, True] :: [Bool]

*Main> :k [False]

<interactive>:1:2:
    Expected kind ‘*’, but ‘False’ has kind ‘Bool’
    In a type in a GHCi command: [False]

为什么会出错?

未来的实验揭示:

*Main> :k [Int]
[Int] :: *

*Main> :k [Int, Int]
[Int, Int] :: [*]

[Int]可以有无人居住的值,因此它是*种类,但它也是[*]种。

更多数据点:

*Main> :k []
[] :: * -> *

*Main> :k [Bool]
[Bool] :: *

2 个答案:

答案 0 :(得分:11)

如果您的类型级别列表只包含一个元素,GHC认为它不是一个提升列表,而是一个应用于某种类型*的常规列表类型构造函数。

您应该在列表前加上撇号,以明确选择提升列表:

> :k '[False]
'[False] :: [Bool]

与空列表类似:

> :k '[]
'[] :: [k]

答案 1 :(得分:3)

正如您所说:

  

[Int]可以有人居住的值,因此它是*种类,但它也是有意义的[*]

你发现的是,如果只是允许将值表达式提升到类型级别,那么DataKinds在某些类型表达式中存在歧义。由于列表文字和列表类型都使用方括号,因此经常会出现这样的列表,但它并不完全特定于列表。

基本上,源代码文本[False]可以引用三个不同的东西:

  1. 列出值级别列表的文字语法,包含值为False的单个元素
  2. 应用于类型 False
  3. 的列表类型构造函数
  4. 列出类型级别列表的文字语法,包含单个元素类型 False
  5. 如果没有DataKinds,则第三个含义不存在,因此编译器始终可以使用其上下文知识来确定源代码文本[False]是在类型表达式还是值表达式中发生的。但是案例2和3都出现在类型表达式中,所以这没有帮助。

    在这种情况下,我们可以看到[False]作为类型“False类型的事物列表”没有任何意义,因为[]类型构造函数只能应用亲切的事*。但是编译器必须知道你在尝试之前说什么才能输入/检查事物以确定它是否一致;我们真的不希望它尝试几种可能的解释和类型/种类检查它们,默默地接受它们中的一种是否有效。无论如何只需要一点努力(沿着定义合适的类型名称和/或使用PolyKinds来制作接受多种类型的类型构造函数),你就可以想出一种源文本具有所有3种类型的情况。我在上面概述的含义,并且所有3个都可以编译而没有错误。

    因此,为了解决歧义(不会破坏现有语法,如[Int]为“Int类型的事物列表”,GHC采用普通非提升类型构造函数优先的规则。所以[False]实际上意味着类型级别的单例列表;它只表示(无意义)“False类型的事物列表”类型,这会导致您看到的类型错误。

    但是DataKinds还引入了语法来明确请求其他含义;如果你在任何类型的构造函数之前加上一个撇号,那么GHC就知道你指的是值构造函数的提升版本,而不是任何同名的非提升类型构造函数。例如:

    Prelude> :k 'False
    'False :: Bool
    

    同样地,在列表文字语法的前面添加撇号明确表示你正在编写类型级列表文字,编写列表类型,即使列表只有一个项目。所以:

    Prelude> :k '[False]
    '[False] :: [Bool]
    
    Prelude> :k '[Int]
    '[Int] :: [*]
    

    您可以类似地使用它来区分类型* -> *的列表类型构造函数和空类型级别列表:

    Prelude> :k []
    [] :: * -> *
    Prelude> :k '[]
    '[] :: [k]