Haskell中的刚性类型变量错误
为什么会出现Haskell中的刚性类型变量错误,haskell,Haskell,为什么会出现刚性类型变量错误: 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)) =
刚性类型变量
错误:
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
错误中真正告诉您发生了什么的部分是: 因此,您提供给
map
的函数类型是错误的。但为什么会这样呢<代码>地图具有以下类型:
map :: (a -> b) -> [a] -> [b]
list
是mytreea->[a]
,因此:
map list :: (MyTree a -> [a]) -> [MyTree a] -> [[a]]
这意味着映射列表xs
将具有类型[[a]]
。您是这样使用它的:
list x ++ map list xs -- omitting unnecessary parentheses.
(++)
是列表连接;它需要两个相同类型的列表<但是,代码>列表x是[a]
而不是[[a]]
,这会导致类型错误。由于[a]
是[[a]]
的元素类型,您可以尝试使用(:)
,而不是(++)
,将列表x
预先添加到列表的其余部分
list (Branch _ (x:xs)) = list x : map list xs
但是,这是多余的:您正在对x
和xs
的元素应用相同的list
函数。这意味着您可以将其简化为:
list (Branch _ xs) = map list xs
我们仍然没有完成,因为映射列表xs
的类型为[[a]]
,而您需要[a]
。不过,这很容易解决:只需使用concatMap
,它映射函数并展平结果列表。然后,完整的定义将变成:
list :: MyTree a -> [a]
list (Leaf m) = m
list (Branch _ xs) = concatMap list xs
我已删除多余的(Leaf[])
案例。请注意,您的函数没有涵盖(
分支机构[])
案例;这不是一个问题,因为我们没有只匹配(x:xs)
。映射(列表)xs的类型是[[a]]
,您需要[a]
类型的东西。我们可以使用一个函数concat
:concat(映射列表xs)
,但是我们可以用concatMap
更惯用地编写它:concatMap列表xs
hmm,在列表(节点x:xs)的代码中还有另一个错误
由于您没有将节点定义为MyTree类型的值构造函数,即您只提供了Leaf和BranchHmm,因此代码仍然被分解为什么是索引树
?您从未在此代码段中定义过它。代码仍然被破坏,因为您的分支
值构造函数接受两个参数,但在模式匹配中,您只给分支
(应该是分支
)一个参数,即(x:xs)
占用了(字符串,a),但即使代码是错误的,因为(x:xs)不是用于元组,而是用于列表,其中x是列表的第一个元素。感谢您的详细解释。
list :: MyTree a -> [a]
list (Leaf m) = m
list (Branch _ xs) = concatMap list xs