欢迎来到类型种类的世界!
您必须提供要显示的项目的完整类型。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 类型*。我们可以有类型Intor的值,但没有值有类型Maybe Intor 。Tree StringMaybeTree
另一方面,在 的定义中ListSource,类类型变量c被应用于a的类型中的一些其他类型变量toList,它也显示为列表元素类型。从后者,我们可以得出结论,它a有种类*(因为列表元素是值)。我们知道,函数箭头左边和右边的类型*也必须有 kind,因为函数接受和返回值。所以,c a 有种*。因此,c当应用于一种类型时,单独的东西会*产生一种类型*。这是写的* -> *。
这意味着,用简单的英语来说,当我们想要创建一个实例时,ListSource我们需要一些“容器”类型的类型构造函数,该类型构造函数用另一种类型参数化。在这里是可能的,但Tree不是。MaybeInt