为什么会出现rigid type variable
错误:
data MyTree a = Leaf [a]
| Branch (String, a) [MyTree a]
deriving (Show)
list :: MyTree a -> [a]
list (Leaf []) = []
list (Leaf m) = m
list (Branch _ (x:xs)) = list x ++ map (list) xs
-------------------------------------------------------------
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for list :: MyTree a -> [a]
at test.hs:6:15
Expected type: MyTree a -> a
Actual type: MyTree a -> [a]
In the first argument of `map', namely `(list)'
In the second argument of `(++)', namely `map (list) xs'
In the expression: list x ++ map (list) xs
答案 0 :(得分:5)
实际上告诉您发生了什么的错误部分是:
Expected type: MyTree a -> a Actual type: MyTree a -> [a] In the first argument of `map', namely `(list)'
因此,您为map
提供的函数类型是错误的。但为什么会这样呢? map
的类型为:
map :: (a -> b) -> [a] -> [b]
list
为MyTree a -> [a]
,因此:
map list :: (MyTree a -> [a]) -> [MyTree a] -> [[a]]
这意味着map list xs
将具有[[a]]
类型。你正在使用它:
list x ++ map list xs -- omitting unnecessary parentheses.
(++)
是列表连接;它期望两个相同类型的列表。但是,list x
是[a]
而不是[[a]]
,这会导致类型错误。由于[a]
是[[a]]
元素的类型,因此您可以尝试使用(:)
代替(++)
,将list x
添加到列表的其余部分-of-列表。
list (Branch _ (x:xs)) = list x : map list xs
然而,这是多余的:您正在将list
函数应用于x
和xs
的元素。这意味着您可以将其简化为:
list (Branch _ xs) = map list xs
我们仍未完成,因为map list xs
的类型为[[a]]
,您需要[a]
。但这很容易解决:只需使用concatMap
,它会映射函数并展平生成的列表列表。完整的定义将成为:
list :: MyTree a -> [a]
list (Leaf m) = m
list (Branch _ xs) = concatMap list xs
我删除了多余的(Leaf [])
案例。请注意,您的功能未涵盖(
Branch _ [])
案例;现在我们不匹配(x:xs)
,这不是问题。
答案 1 :(得分:3)
map (list) xs
的类型为[[a]]
,您需要[a]
类型的内容。我们可以使用concat
函数concat (map list xs)
,但我们可以使用concatMap
以{1}} concatMap list xs
更具惯用性地编写它:{{1}}