用do-notation重写haskell列表理解

时间:2014-02-24 18:19:04

标签: haskell list-comprehension do-notation

我在Learn you a Haskell中读过,Haskell中的列表推导可以改写为monadic join或(实际上是相同的)do-notation。

但是,当我尝试重写以下代码时(生成所有可能的列表,其中包含给定列表中的每个元素):

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

以这种方式:

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

我收到以下错误:

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

如果我将do的最后一行更改为:return a:[b],我不会收到错误,但结果显然不正确:

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

所以问题是:

  1. 如何重写此列表理解?
  2. 列表理解和标记是否可以互换,如何更换一般?

2 个答案:

答案 0 :(得分:10)

仔细查看错误消息:

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

这意味着它被解析为

(return a) : b

因此b成为(:)的第二个参数;但你打算把它作为

return (a : b)

答案 1 :(得分:6)

你需要括号。

return (a:b)