6

I have read in Learn you a Haskell, that list comprehensions in Haskell could be rewritten as monadic joins or (which is practically the same) do-notation.

However, when I try to rewrite the following code (produce all possible lists having each element from one of given lists):

c :: [[a]] -> [[a]]
c []     = [[]]
c (x:xs) = [a:b | a <- x, b <- c xs]

in such a manner:

d :: [[a]] -> [[a]]
d []     = [[]]
d (x:xs) = do
              a <- x
              b <- d xs
              return a:b

I get the following error:

Couldn't match type `a' with [a]
    `a' is a rigid type variable bound by
        the type signature for d :: [[a]] -> [[a]] 
Expected type: [[a]]
  Actual type: [a] 
In the second argument of `(:)', namely `b' 
In a stmt of a 'do' block: return a : b

if I change the last line of do to this: return a:[b], I don't get errors, but the result is obviously incorrect:

ghci> c [[1, 2], [3, 4]] 
[[1,3],[1,4],[2,3],[2,4]]

ghci> d [[1, 2], [3, 4]]
[[1],[3],[1],[],[1],[4],[1],[],[2],[3],[2],[],[2],[4],[2],[]]

So the questions are:

  1. How can I rewrite this list comprehension?
  2. Are list comprehension and do-notation interchangeable, how replacement can be done generically?
4

2 回答 2

10

仔细查看错误信息:

无法将类型“a”与 [a] 匹配
    `a' 是一个刚性类型变量,由
        d :: [[a]] -> [[a]] 的类型签名
预期类型:[[a]]
  实际类型:[a]

在 `(:)' 的第二个参数中,即`b' 在 'do' 块的 stmt 中: return a : b

这意味着它被解析为

(return a) : b

因此b成为(:)那里的第二个论据;但你打算这样做

return (a : b)
于 2014-02-24T18:47:43.897 回答
6

你需要括号。

return (a:b)
于 2014-02-24T18:37:46.493 回答