Haskell 另一类错误

Haskell 另一类错误,haskell,Haskell,为什么不编译 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 (

为什么不编译

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是列表的尾部,因此它是comb的有效参数?? 谢谢David Kramf一些建议:

尽管它可能很有教育意义,但您不需要自己的附加函数-您可以使用++ 您可能有比comb更多的案例-您真的需要比comb[]和comb x:xs更多的案例吗? 如前所述,遍历将不匹配包含多个列表的第二个参数 我自己并没有通过Haskell来阐述这一点,但我认为最后一点可能是您的主要问题

编辑:@Kevin Ballard的答案当然是正确的,关于为什么会出现特定的类型错误。但是,我相信更大的问题是,在某一点上,如果我理解您现有的代码,您将需要concat enate,也就是说,展平一个组合列表,实际上是排列,而我在这里看不到这一点


与此相反,traverse的类型签名可能应该是a->[a]->[[a]]?

您的方法comb xs返回类型[[a]]。当传递到map traverse x中时,将调用traverse x,每个元素为[[a]],即类型为[a]的元素。但是,traverse x的类型为[[a]]->[[a]],因此这里的不匹配是traverse期望的是[[a]],而您给的是[a].

我的建议是保持具体。类型变量a可以匹配Int、[Int]、[Int]]等等,这可能会在开发的早期阶段导致混淆。一旦程序对具体类型起作用,就不难对任意类型进行泛化

以下是您以前的buggy程序的conrete版本:

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]]
类型错误的原因应该足够清楚。您只需在最后一行中组合map的结果,如下所示:

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

现在,您可以尝试推广到任意类型。

认为FPLs中没有方法,只有函数。我们基本上把它们当作同义词来使用。@JFritsch:严格地说,你可能是对的,但Haskell似乎确实像Louis Wasserman所说的那样把它们当作同义词来对待。我以为TypeClass有方法。你试图用错误的方式来修复它。您不应该向遍历第二个参数添加[]层,而应该从comb的最后一个等式的结果中删除一个。请参阅我对您的另一个问题的评论。列表符号[x]也可用于模式中。[x] 与x:[]的功能完全匹配。所以comb x:[]≡ 梳[x]和梳x:y:[]≡ comb[x,y]。为什么不在上一个问题中保留这一点,或者至少将该问题标记为已回答?traverse也不会将空列表作为其第二个参数进行匹配。