我不明白为什么以下代码无法编译:
append :: [a] -> [a] -> [a]
append xs ys = foldr (:) ys xs
traverse :: a -> [a] -> [[a]]
traverse x [] = [[x]]
traverse x (y:ys) = append [(x:y:ys)] (map (y:) (traverse x ys))
comb :: [a] -> [[a]]
comb [] = [[]]
comb (x:[]) = [[x]]
comb (x:y:[]) = [[x,y],[y,x]]
comb (x:xs) = map (traverse x) (comb xs)
它会产生以下错误:
pr27.hs:13:20:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for comb :: [a] -> [[a]] at pr27.hs:10:1
Expected type: [a] -> [a]
Actual type: [a] -> [[a]]
In the return type of a call of `traverse'
In the first argument of `map', namely `(traverse x)'
Failed, modules loaded: none
但是当我只加载traverse
并在类似于上面的表达式中使用它时,我得到了所需的结果。发生了什么事?
Main> map (traverse 3) [[1,2],[2,1]]
[[[3,1,2],[1,3,2],[1,2,3]],[[3,2,1],[2,3,1],[2,1,3]]]
答案 0 :(得分:4)
问题是comb
必须返回[[a]]
类型的值。 traverse
返回类型[[a]]
的值,因此将其映射到另一个列表会产生[[[a]]]
,其嵌套级别太高。
让我们看看map
。它的类型为map :: (x -> y) -> [x] -> [y]
。 traverse x
的类型为[a] -> [[a]]
。现在我们需要将两者结合起来。为此,我们将x
替换为[a]
,将y
替换为[[a]]
,获取([a] -> [[a]]) -> [[a]] -> [[[a]]]
。这清楚地表明映射traverse
的结果必须至少有三个嵌套级别。
如果你看一下你的例子,这就是你实际得到的。对于comb
,您只需要两个级别。
你的例子在GHCi中工作的原因是因为一个表达式可以有任何类型。您的map (traverse 3) [[1,2], [2,1]]
表达完全合法;但是,它具有类型Num a => [[[a]]]
,它是一系列数字列表。 (试试看::t map (traverse 3) [[1,2], [2,3]]
。)但是,comb
的类型为[a] -> [[a]]
。这意味着结果必须是列表列表,而不是列表列表。所以问题是map (traverse 3)
与comb
不兼容,而不是它本身就是非法的。