为什么不进行编译?
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)
失败并出现此错误:
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]]
Actual type: [a]
In the first argument of `comb', namely `xs'
In the second argument of `map', namely `(comb xs)'
xs是列表的尾部,因此它是梳子的有效参数? 谢谢David Kramf
答案 0 :(得分:9)
您的方法comb xs
会返回[[a]]
类型。传入map (traverse x)
时,会调用traverse x
[[a]]
的每个元素,即[a]
类型的元素。但是,traverse x
的类型为[[a]] -> [[a]]
,因此此处的不匹配traverse
期待[[a]]
,但您给它[a]
。
答案 1 :(得分:5)
一些指示:
++
comb
您可能需要的案例多于必要的案例 - 您真的需要的不仅仅是comb []
和comb (x:xs)
吗?traverse
与包含多个列表的第二个参数我自己没有通过Haskell运行,但我认为最后一点可能是你的主要问题。
编辑:@Kevin Ballard的答案当然是正确的,为什么你会得到特定的类型错误。但是,我认为更大的问题是,在某些时候,你需要concat
- enate(即,flatten)一系列组合列表(实际上是排列,如果我理解你现有的代码),我在这里看不到。
作为这个硬币的另一面,也许遍历的类型签名应该是a -> [a] -> [[a]]
?
答案 2 :(得分:3)
我的建议是保持具体。类型变量a可以匹配Int,[Int],[[Int]]等,这可能导致在开发的早期阶段出现混淆。一旦程序适用于具体类型,通常不会很难概括为任意类型。
以下是您之前(错误)计划的混乱版本:
append :: [a] -> [a] -> [a]
append xs ys = foldr (:) ys xs
traverse :: Int -> [Int] -> [[Int]]
traverse x [] = [[x]]
traverse x (y:ys) = append [(x:y:ys)] (map (y:) (traverse x ys))
comb :: [Int] -> [[Int]]
comb [] = [[]]
comb (x:[]) = [[x]]
comb (x:y:[]) = [[x,y],[y,x]]
comb (x:xs) = map (traverse x) (comb xs)
ghci会抱怨最后一行:
Couldn't match expected type `Int' with actual type `[Int]'
Expected type: [Int] -> [Int]
Actual type: [Int] -> [[Int]]
In the return type of a call of `traverse'
In the first argument of `map', namely `(traverse x)'
看起来比你遇到的更容易理解。虽然[a]可以表示来自[Int],[[Int]]等的任何内容,[Int]可以表示..嗯,[Int]。
正如你在上一个问题中所说,遍历函数很好:
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]]]
类型:
Main> :type map (traverse 3) [[1,2],[2,1]]
map (traverse 3) [[1,2],[2,1]] :: [[[Int]]]
现在,回想一下梳子功能的类型:
comb :: [Int] -> [[Int]]
类型错误的原因应该足够清楚。您需要做的就是在最后一行“合并”地图的结果,如下所示:
comb (x:xs) = concat $ map (traverse x) (comb xs)
这是(固定)程序的输出:
Main> comb [1,2,3]
[[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]]
现在你可以尝试推广到任意类型。