我正在尝试在frege中实现经典的树结构,只要我不使用“derive”就可以很好地工作:
data Tree a = Node a (Tree a) (Tree a)
| Empty
derive Show Tree
给了我
realworld/chapter3/E_Recursive_Types.fr:7: kind error,
type constructor `Tree` has kind *->*, expected was *
这是不支持还是我必须以不同方式声明它?
答案 0 :(得分:4)
欢迎来到各种类型的世界!
您必须提供要显示的完整类型的项目。 Tree
不是类型(种类*
),而是需要类型参数成为一种类型(种类* -> *
)。
尝试
derive Show (Tree a)
请注意,这是
的简写derive Show (Show a => Tree a)
类似于以下事实:要显示树,您还需要知道如何在树中显示值(至少,derive生成的代码需要知道这一点 - 当然,可以编写一个实例手动只打印树的形状,因此不需要它。)
通常,每个类型类的实例所需的类型是固定的。该错误消息告诉您*
需要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
必须是普通类型(种类*
),因为我们将值传递给show
,并且每个值都有一种类型{{1 }}。我们可以包含*
或Int
或Maybe Int
类型的值,但没有任何值具有Tree String
或Maybe
类型。
另一方面,在Tree
的定义中,类类型变量ListSource
应用于c
类型的其他类型变量a
,其中也显示为列表元素类型。从后者我们可以得出结论,toList
具有种类a
(因为列表元素是值)。我们知道,函数箭头左侧和右侧的类型也必须具有类型*
,因为函数接受并返回值。因此,*
有c a
种。因此,*
单独应用于某种类型c
时会产生类型*
。这是*
。
这意味着,用简单的英语,当我们想为* -> *
创建一个实例时,我们需要一些用另一种类型参数化的“容器”类型的类型构造函数。这里可以ListSource
和Tree
,但不能Maybe
。