欢迎来到类型种类的世界!
您必须提供要显示的项目的完整类型。Tree
不是类型 (kind *
),而是需要类型参数才能成为类型 (kind ) 的东西* -> *
。
尝试
derive Show (Tree a)
请注意,这是
derive Show (Show a => Tree a)
这类似于这样一个事实,要显示一棵树,您还需要知道如何显示树中的值(至少,derive 生成的代码需要知道这一点 - 当然,可以手动编写一个实例来打印只是树的形状,所以不需要它)。
通常,每个类型类的实例中所需的种类是固定的。错误消息告诉您需要 kind *
for Show
。
编辑:消除另一个可能的误解
请注意,这与您的递归类型无关。我们以可选值的定义为例:
data Maybe a = Nothing | Just a
这种类型不是递归的,但我们仍然不能说:
derive Show Maybe -- same kind error as above!!
但是,给定以下类型类:
class ListSource c -- things we can make a list from
toList :: c a -> [a]
我们需要说:
instance ListSource Maybe where
toList (Just x) = [x]
toList Nothing = []
(instance
并且derive
为了讨论而等效,两者都创建实例,不同之处在于derive
为某些类型类自动生成实例函数。)
诚然,不清楚为什么在一种情况下是这样,而在另一种情况下却不同。关键是,在每种情况下,我们要使用的类操作的类型。例如,在课堂上Show
我们有:
class Show s where
show :: s -> String
现在,我们看到所谓的类类型变量s
(代表任何未来实例化的类型表达式)单独出现在函数数组的左侧。当然,这表明它s
必须是一个普通类型(kind *
),因为我们将一个值传递给show
并且每个值都有一个 kind 类型*
。我们可以有类型Int
or的值,但没有值有类型Maybe Int
or 。Tree String
Maybe
Tree
另一方面,在 的定义中ListSource
,类类型变量c
被应用于a
的类型中的一些其他类型变量toList
,它也显示为列表元素类型。从后者,我们可以得出结论,它a
有种类*
(因为列表元素是值)。我们知道,函数箭头左边和右边的类型*
也必须有 kind,因为函数接受和返回值。所以,c a
有种*
。因此,c
当应用于一种类型时,单独的东西会*
产生一种类型*
。这是写的* -> *
。
这意味着,用简单的英语来说,当我们想要创建一个实例时,ListSource
我们需要一些“容器”类型的类型构造函数,该类型构造函数用另一种类型参数化。在这里是可能的,但Tree
不是。Maybe
Int