用do-notation重写haskell列表理解

suk*_*mel 6 haskell list-comprehension do-notation

我读过" 了解你一个Haskell",Haskell中的列表理解可以改写为monadic join或(实际上是相同的)do-notation.

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

c :: [[a]] -> [[a]]
c []     = [[]]
c (x:xs) = [a:b | a <- x, b <- c xs]
Run Code Online (Sandbox Code Playgroud)

以这种方式:

d :: [[a]] -> [[a]]
d []     = [[]]
d (x:xs) = do
              a <- x
              b <- d xs
              return a:b
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

如果我改变了最后一行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],[]]
Run Code Online (Sandbox Code Playgroud)

所以问题是:

  1. 我怎样才能重写这个列表理解?
  2. 列表理解和标记是否可以互换,如何更换一般?

Wil*_*ess 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
Run Code Online (Sandbox Code Playgroud)

从而b成为(:)那里的第二个论点; 但你打算这样做

return (a : b)
Run Code Online (Sandbox Code Playgroud)

  • 是的,Haskell的错误是众所周知的难以理解的.:)但是在你习惯了这种风格后你会停止注意它. (2认同)