在 Haskell 中,种类可以是星星序列以外的任何东西吗?
In Haskell, Can Kinds Be Anything Other Than a Sequence of Stars?
如果这个问题很愚蠢,请原谅我。
在阅读 Haskell 种时,我注意到一个主题:
*
* -> *
* -> * -> *
我的印象是 Haskell 中的种类最终归结为星号的数量。你可能会说类型的种类实际上只是在它变成 * 之前你需要应用到它的类型的数量。换句话说,您可以计算除最后一个以外的所有 *,并通过整数定义类型的种类。说 0、1、2 等
这是我的问题:
这是对 Haskell 类型系统的正确观察吗?或者它是否允许除 * 之外的其他内容到达您通常看到 * 的地方?例如:
* -> a -> *
我想有人可能想这样做来限制类型变量具有类型实例 class,例如。
Functor a, Applicative b => * -> a -> b -> *
是这样吗?
这种语言的最基本形式仅包含 *
(或更现代的 Type
Haskell;我怀疑我们最终会远离 *
) 和 ->
.
但是你可以用这种语言构建的东西比你仅仅通过“计算 *
的数量”所能表达的要多。重要的不仅仅是 *
或 ->
的数量,还有它们的嵌套方式。例如 * -> * -> *
是那种采用两个类型参数来生成类型的东西,但是 (* -> *) -> *
是那种采用单个参数来生成类型的东西,其中该参数本身必须是一个东西它需要一个类型参数来产生一个类型。 data ThreeStars a b = Cons a b
使用种类 * -> * -> *
创建类型构造器,而 data AlsoThreeStars f = AlsoCons (f Integer)
使用种类 (* -> *) -> *
.
创建类型构造器
有几种语言扩展可以为这种语言添加更多功能。
PolyKinds
添加种类 variables ,其工作方式与类型变量的工作方式完全相同。现在我们可以有类似 forall k. (* -> k) -> k
.
的种类
ConstraintKinds
使约束(类型签名中 =>
左侧的内容,如 Eq a
)成为新类型中的普通 type-level 实体:Constraint
。 =>
剩下的东西不是与语言的其余部分相当分离的特殊用途语法,现在可以接受的是 Constraint
类型的任何东西。 类 像 Eq
一样成为类型构造函数 * -> Constraint
;您将它应用于 Eq Bool
之类的类型以生成 Constraint
。优点是现在我们可以使用所有语言功能来操纵 type-level 实体来操纵约束(包括 PolyKinds
!)。
DataKinds
添加了创建包含新 type-level 事物的新 user-defined 种类的能力,与在原版 Haskell 中我们可以创建新 user-defined 类型包含新的 term-level 事物。 (与 完全相同;DataKinds
实际工作的方式是它允许您正常使用 data
声明,然后您可以使用生成的类型构造函数类型或种类级别)
还有用于 unboxed/unlifted 类型的种类,它们不能与“普通”Haskell 类型混合使用,因为它们具有不同的内存布局;它们不能包含 thunk 来实现惰性求值,因此运行时必须知道永远不要尝试将它们作为代码指针“输入”,或寻找额外的 header 位等。它们需要分开保存在kind 级别,这样 kind *
的普通类型变量不能用这些 unlifted/unboxed 类型实例化(这将允许您将这些需要特殊处理的类型传递给不知道提供特殊处理)。我隐约知道这些东西,但从来没有真正使用过它,所以我不会再添加任何东西,以免我弄错了。 (任何知道他们在说什么的人都可以在这里写一个简短的摘要段落,请随时编辑答案)
可能还有一些我忘记了。但肯定的是,这种语言比 OP 想象的更丰富,只有基本的 Haskell 功能,而且一旦你打开一些(相当广泛使用的)扩展,它还有更多。
如果这个问题很愚蠢,请原谅我。
在阅读 Haskell 种时,我注意到一个主题:
*
* -> *
* -> * -> *
我的印象是 Haskell 中的种类最终归结为星号的数量。你可能会说类型的种类实际上只是在它变成 * 之前你需要应用到它的类型的数量。换句话说,您可以计算除最后一个以外的所有 *,并通过整数定义类型的种类。说 0、1、2 等
这是我的问题:
这是对 Haskell 类型系统的正确观察吗?或者它是否允许除 * 之外的其他内容到达您通常看到 * 的地方?例如:
* -> a -> *
我想有人可能想这样做来限制类型变量具有类型实例 class,例如。
Functor a, Applicative b => * -> a -> b -> *
是这样吗?
这种语言的最基本形式仅包含 *
(或更现代的 Type
Haskell;我怀疑我们最终会远离 *
) 和 ->
.
但是你可以用这种语言构建的东西比你仅仅通过“计算 *
的数量”所能表达的要多。重要的不仅仅是 *
或 ->
的数量,还有它们的嵌套方式。例如 * -> * -> *
是那种采用两个类型参数来生成类型的东西,但是 (* -> *) -> *
是那种采用单个参数来生成类型的东西,其中该参数本身必须是一个东西它需要一个类型参数来产生一个类型。 data ThreeStars a b = Cons a b
使用种类 * -> * -> *
创建类型构造器,而 data AlsoThreeStars f = AlsoCons (f Integer)
使用种类 (* -> *) -> *
.
有几种语言扩展可以为这种语言添加更多功能。
PolyKinds
添加种类 variables ,其工作方式与类型变量的工作方式完全相同。现在我们可以有类似 forall k. (* -> k) -> k
.
ConstraintKinds
使约束(类型签名中 =>
左侧的内容,如 Eq a
)成为新类型中的普通 type-level 实体:Constraint
。 =>
剩下的东西不是与语言的其余部分相当分离的特殊用途语法,现在可以接受的是 Constraint
类型的任何东西。 类 像 Eq
一样成为类型构造函数 * -> Constraint
;您将它应用于 Eq Bool
之类的类型以生成 Constraint
。优点是现在我们可以使用所有语言功能来操纵 type-level 实体来操纵约束(包括 PolyKinds
!)。
DataKinds
添加了创建包含新 type-level 事物的新 user-defined 种类的能力,与在原版 Haskell 中我们可以创建新 user-defined 类型包含新的 term-level 事物。 (与 完全相同;DataKinds
实际工作的方式是它允许您正常使用 data
声明,然后您可以使用生成的类型构造函数类型或种类级别)
还有用于 unboxed/unlifted 类型的种类,它们不能与“普通”Haskell 类型混合使用,因为它们具有不同的内存布局;它们不能包含 thunk 来实现惰性求值,因此运行时必须知道永远不要尝试将它们作为代码指针“输入”,或寻找额外的 header 位等。它们需要分开保存在kind 级别,这样 kind *
的普通类型变量不能用这些 unlifted/unboxed 类型实例化(这将允许您将这些需要特殊处理的类型传递给不知道提供特殊处理)。我隐约知道这些东西,但从来没有真正使用过它,所以我不会再添加任何东西,以免我弄错了。 (任何知道他们在说什么的人都可以在这里写一个简短的摘要段落,请随时编辑答案)
可能还有一些我忘记了。但肯定的是,这种语言比 OP 想象的更丰富,只有基本的 Haskell 功能,而且一旦你打开一些(相当广泛使用的)扩展,它还有更多。