我试图找到一个对DataKinds扩展的解释,这对我来说只有阅读Learn You a Haskell才有意义。是否有一个标准的来源,对我来说只有我学到的东西才有意义?
编辑:例如documentation说
使用-XDataKinds,GHC会自动提升每种合适的数据类型 成为一种,它的(值)构造函数是类型构造函数。 以下类型
并给出了示例
data Nat = Ze | Su Nat
产生以下种类和类型构造函数:
Nat :: BOX
Ze :: Nat
Su :: Nat -> Nat
我没有明白这一点。虽然我不明白BOX
的含义,但Ze :: Nat
和Su :: Nat -> Nat
语句似乎表明Ze和Su通常就是正常数据构造函数的情况,正如您所期望的那样看看ghci
Prelude> :t Su
Su :: Nat -> Nat
答案 0 :(得分:56)
好吧,让我们从基础开始
种类是类型*,例如
Int :: *
Bool :: *
Maybe :: * -> *
请注意,->
在类型级别上被重载为“函数”。所以*
是一种普通的Haskell类型。
我们可以要求GHCi使用:k
打印某种内容。
现在这不是很有用,因为我们无法自己制作!使用DataKinds
时,我们写
data Nat = S Nat | Z
GHC将促进此操作以创建相应类型Nat
和
S :: Nat -> Nat
Z :: Nat
所以DataKind
使得类型系统可扩展。
让我们使用GADTs来做原型种类的例子
data Vec :: Nat -> * where
Nil :: Vec Z
Cons :: Int -> Vec n -> Vec (S n)
现在我们看到我们的Vec
类型按长度编制索引。
这是10k英尺的基本概述。
**这实际上还在继续,Values : Types : Kinds : Sorts ...
有些语言(Coq,Agda ..)支持这个无限的宇宙堆栈,但是Haskell将所有东西都归为一类。
答案 1 :(得分:37)
这是我的看法:
考虑长度索引的Vector类型:
data Vec n a where
Vnil :: Vec Zero a
Vcons :: a -> Vec n a -> Vec (Succ n) a
data Zero
data Succ a
我们有一个Vec :: * -> * -> *
种。因为您可以通过以下方式表示Int的零长度Vector:
Vect Zero Int
您还可以声明无意义的类型:
Vect Bool Int
这意味着我们可以在类型级别进行无类型的函数式编程。因此,我们通过引入数据类型来消除这种模糊性,并且可以具有这样的类型:
Vec :: Nat -> * -> *
现在我们的Vec
获取一个名为Nat
的DataKind,我们可以将其声明为:
datakind Nat = Zero | Succ Nat
通过引入新的数据种类,没有人可以声明无意义的类型,因为Vec
现在具有更受约束的种类签名。