我对Haskell相当新,并且正在尝试从我的课程中完成作业。 我正在尝试创建一个预订单函数,以下列格式遍历树对象
preorder :: (a -> c) -> (b -> c) -> Tree a b -> [c]
preorder f g Empty = []
preorder f g (Leaf x) = [x]
My Tree类如下
data Tree a b = Empty | Leaf b | Branch a (Tree a b) (Tree a b)
定义预订单功能时,我会收到如下所示的错误。
Couldn't match expected type 'c' with actual type 'b'
'c' is a rigid type variable bound by the type signature for preorder :: (a -> c) -> (b -> c) -> Tree a b -> [c].
'b' is a rigid type variable bound by the type signature for preorder :: (a -> c) -> (b -> c) -> Tree a b -> [c].
它们发生在最后一个预订函数定义
preorder f g (Leaf x) = [x]
答案 0 :(得分:4)
类型Tree a b
包含带有b
类型元素的树叶,除了空白树叶外,还包含类型为a
的元素。您希望按预先访问树的每个节点,收集在f :: a -> c
类型列表中应用函数g :: b -> c
和[c]
的结果。编译器抱怨您的preorder
函数的原因是x
的类型为b
;这会强制c
与b
统一。但这是一种不太通用的类型,而不是你向编译器指出的类型。作为练习,看看您是否可以为编译器接受的函数编写更具体的类型。提示:b
和c
不同类型?
但是,您将获得一个函数g :: b -> c
。将此函数应用于x
会生成c
类型的值,并且此值可以收集到类型[c]
的列表中。此列表可能或可能不包含a
或b
类型的元素。您可以按以下方式重写符合给定签名的前序遍历:
preorder :: (a -> c) -> (b -> c) -> Tree a b -> [c]
preorder f g Empty = []
preorder f g (Leaf b) = [g b]
preorder f g (Branch a l r) = f a : preorder f g l ++ preorder f g r