任何人都可以解释或提供链接解释* - > *以下代码的一部分?
data BinaryTree t :: * -> * where
Leaf :: BinaryTree Empty a
Branch :: a -> BinaryTree isempty a -> BinaryTree isempty' a -> BinaryTree NonEmpty a
非常感谢。
答案 0 :(得分:5)
Kind signatures。它们可用于显式定义类型构造函数的arity。 *
表示“任何类型”,其余类似 kind 的正常函数类型。在这种情况下,我们甚至有一个部分应用程序:
BinaryTree t :: * -> *
表示“BinaryTree t
是一个从类型到类型的函数”,这是有道理的,因为您可以将它应用于另一种类型:
f :: (BinaryTree t) a -> (BinaryTree t) b
* -> * * * -> * *
BinaryTree t
部分应用于a
类型,为您提供BinaryTree t a :: *
类型。仅(BinaryTree t)
尚未完全应用,因此具有类型* -> *
,您仍然需要应用它来获得简单类型。 (这与f 1
时<{1}}仍然具有Int -> Int
类型f :: Int -> Int -> Int
的方式相同。
请注意,您可以混合正常的“arity声明”,提及类型的参数,这些是隐式的,以及类型签名,就像在此处所做的那样。我们也可以编写BinaryTree
如下:
data BinaryTree t a -- normal variant
或者像这样:
data BinaryTree :: * -> * -> * -- fully "kinded"
在这两种情况下,编译器都知道BinaryTree
将采用两种类型参数。
它的用途是什么?首先,在链接中描述了类似,有时您需要或想要明确声明您的类型应该采用多少类型参数。当你使用 diffent kind 而不是*
(又名DataKinds)时,会发生另一个更有趣的情况。看看这个:
data Empty = Empty | NonEmpty
data BinaryTree (t :: Empty) (a :: *) :: * where
-- ...
哦,如果您不确定,ghci可以让您查看种类。它的工作方式与:t
的工作方式相同:
Prelude> :k Either
Either :: * -> * -> *
答案 1 :(得分:4)
* -> *
是一种亲切签名的示例。种类可以被认为是“类型的类型”。也就是说,正如值具有类型一样,类型也有类型。
如果我们忽略了一些语言扩展,那么只使用两个构造函数构建类型:
*
表示正确类型的类型,即那些由值居住的类型,例如Int
,Char
,{{1} },Maybe Int
。[Char]
(其中k1 -> k2
和k1
本身就是种类)指定类型构造函数,即需要完成的类型表达式一个或多个类型参数以形成正确的类型。例如:类型构造函数k2
需要类型为Maybe
的参数才能生成正确的类型,因此它具有类*
;对列表的类型构造函数* -> *
保持相同,因此也有类[]
;类型构造函数* -> *
采用类型Either
的两个参数来形成正确的类型(例如*
或Either Int Char
),因此它具有类Either (Maybe Int) [Char]
。 请注意,类型构造函数* -> * -> *
与右侧相关联。也就是说,->
与* -> * -> *
相同。对于所谓的高阶类型的示例(即,作为类型构造函数而不是作为其参数的正确类型的类型),首先考虑玫瑰树的类型* -> (* -> *)
:
Rose
这是第一类data Rose a = Branch a [Rose a]
类型。但是如果我们通过抽象使用列表的类型构造函数来概括,我们就得到了
* -> *
具有种类data GRose f a = Branch a (f a)
,因此是二阶类型。
二阶类型的另一个例子是类型级定点运算符(* -> *) -> * -> *
:
Fix
实践中高于2的订单类型几乎不会发生。我见过的少数几个例子之一就是newtype Fix f = In {out :: f (Fix f)}
的一个版本“被提升为Fix
:
* -> *
确实,data HFix h a = HIn {hOut :: h (HFix h) a}
属于HFix
。
GHC的交互式环境(ghci)提供了命令((* -> *) -> * -> *) -> * -> *
(通常缩写为:kind
),用于查询类型表达式的类型。例如:
:k
只是程序可以包含类型错误,可能会引入类错误。例如:
> :k Either
Either :: * -> * -> *
> :k Either Int
Either Int :: * -> *
> :k Either Int Char
Either Int Char :: *
在这里,我们根据需要向> :k Either Int Maybe
<interactive>:1:12:
Expecting one more argument to `Maybe'
In a type in a GHCi command: Either Int Maybe
提供了Either
类型表达式而非* -> *
的第二个参数。
如果将非函数类型的表达式(即类型*
)应用于另一个类型表达式,这也是一种错误:
*
答案 2 :(得分:1)
此表示法用于表示kinds,类似于函数可以包含Int -> String
或a -> a
基本上*
表示任何具体类型,如Int
。然后,像BinaryTree
这样的类型构造函数采用具体类型来生成类似BinaryTree Int
或BinaryTree Double
的具体类型。这由BinaryTree
的类型表示,即* -> *
。
你可以在ghci中找到它:
ghci> :k Int
Int :: *
ghci> :k Maybe
Maybe :: * -> *
ghci> :k Maybe Int
Maybe Int :: *