Haskell中的刚性类型变量错误

时间:2014-05-05 00:31:41

标签: haskell

为什么会出现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

2 个答案:

答案 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]

listMyTree 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函数应用于xxs的元素。这意味着您可以将其简化为:

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}}