关于Haskell GADT

时间:2013-05-06 07:20:21

标签: haskell

任何人都可以解释或提供链接解释* - > *以下代码的一部分?

data BinaryTree t :: * -> * where
   Leaf :: BinaryTree Empty a
   Branch :: a -> BinaryTree isempty a -> BinaryTree isempty' a -> BinaryTree NonEmpty a

非常感谢。

3 个答案:

答案 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)

* -> *是一种亲切签名的示例。种类可以被认为是“类型的类型”。也就是说,正如值具有类型一样,类型也有类型。

如果我们忽略了一些语言扩展,那么只使用两个构造函数构建类型:

  • *表示正确类型的类型,即那些由值居住的类型,例如IntChar,{{1} },Maybe Int
  • 表单的种类[Char](其中k1 -> k2k1本身就是种类)指定类型构造函数,即需要完成的类型表达式一个或多个类型参数以形成正确的类型。例如:类型构造函数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

GHCI

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 -> Stringa -> a

等类型的表达方式

基本上*表示任何具体类型,如Int。然后,像BinaryTree这样的类型构造函数采用具体类型来生成类似BinaryTree IntBinaryTree Double的具体类型。这由BinaryTree的类型表示,即* -> *

你可以在ghci中找到它:

ghci> :k Int
Int :: *

ghci> :k Maybe
Maybe :: * -> *

ghci> :k Maybe Int
Maybe Int :: *