简体   繁体   English

另一个类型错误

[英]another type error

Why doesn't this compile? 为什么不编译?

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)

It fails with this error: 失败并显示以下错误:

 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 is a tail of list and so it is a valid argument for comb?? xs是列表的尾部,因此它是comb的有效参数? Thanks , David Kramf 谢谢大卫·克拉姆夫

Your method comb xs returns a type [[a]] . 您的方法comb xs返回类型[[a]] When passed into map (traverse x) , this calls traverse x with each element of [[a]] , ie elements of type [a] . 当传递到map (traverse x)traverse x使用[[a]]每个元素(即[a]类型的元素map (traverse x)调用traverse x However, traverse x has the type [[a]] -> [[a]] , so the mismatch here is traverse is expecting a [[a]] but you're giving it a [a] . 但是, traverse x的类型为[[a]] -> [[a]] ,因此此处的traverse不匹配是traverse [[a]]期望值,但您给了它[a]

Some pointers: 一些指针:

  • educational though it may be, you don't need your own append function -- you can use ++ 尽管可能具有教育意义,但您不需要自己的附加函数-您可以使用++
  • you probably have more cases than necessary for comb -- do you really need more than comb [] and comb (x:xs) ? 您可能拥有的comb数量比comb []需要的要多-您真的需要的不仅仅是comb []comb (x:xs)吗?
  • as written, traverse will not match a second argument containing more than one list 如所写, traverse将不匹配包含多个列表的第二个参数

I have not run this through Haskell myself, but I think that last point may be your main problem. 我自己还没有通过Haskell来解决这个问题,但是我认为最后一点可能是您的主要问题。


Edit: @Kevin Ballard's answer is of course correct with respect to why you get the particular type error. 编辑:@Kevin Ballard的答案对于您为什么会收到特定类型错误当然是正确的。 But, I believe the larger problem is that, at some point, you will need to concat -enate (ie, flatten) a list of lists of combinations (actually permutations, if I understand your existing code), and I don't see that here. 但是,我认为,更大的问题是,在某些时候,你需要concat -enate(即压平)组合的列表的列表(实际上排列,如果我理解你的现有代码),我没有看到在这里。

As the flip side of this coin, perhaps the type signature of traverse should be a -> [a] -> [[a]] ? 作为硬币的反面,也许导线的类型签名应该是a -> [a] -> [[a]]

My advice would be to stay concrete. 我的建议是保持具体。 The type variable a can match Int, [ Int ], [[ Int ]] and so on, which can lead to confusion at the early stages of development. 类型变量a可以匹配Int,[Int],[[Int]]等,这可能会导致开发初期的混乱。 Once the program works for concrete types, it is often not very difficult to generalize over arbitrary types. 一旦程序适用于具体类型,通常就很难对任意类型进行概括。

Here is the conrete version of your previous (buggy) program: 这是您以前的(越野车)程序的具体版本:

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 would complain about the last line: 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)'

which looks more understandable than the one you encountered. 看起来比您遇到的更容易理解。 Whereas [a] can mean anything from [ Int ], [[ Int ]], etc., [ Int ] can mean .. well, [ Int ]. [a]可以表示[Int],[[Int]]等中的任何内容,而[Int]可以表示..好,[Int]。
As you said in your last question, the traverse function is fine: 正如您在上一个问题中所说的那样,遍历功能很好:

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

with type: 类型:

Main> :type map (traverse 3) [[1,2],[2,1]]
map (traverse 3) [[1,2],[2,1]] :: [[[Int]]]

Now, recall the type of comb function: 现在,回想一下梳子功能的类型:

comb :: [Int] -> [[Int]]

The reason of the type error should be clear enough. 类型错误的原因应该很清楚。 All you need to do is to "combine" the results of map in the last line, like so: 您需要做的就是在最后一行“组合” map的结果,如下所示:

comb (x:xs) = concat $ map (traverse x) (comb xs)

Here is the output of the (fixed) program: 这是(固定)程序的输出:

Main>  comb [1,2,3]
[[1,2,3],[2,1,3],[2,3,1],[1,3,2],[3,1,2],[3,2,1]] 

Now you can try generalizing to arbitrary types. 现在,您可以尝试泛化为任意类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM