【问题标题】:Rewrite haskell list comprehension in do-notation用do-notation重写haskell列表理解
【发布时间】:2014-03-26 14:08:52
【问题描述】:

我在Learn you a Haskell 中读到,Haskell 中的列表推导可以重写为单子连接或(实际上是相同的)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. 列表理解和 do-notation 是否可以互换,一般如何替换?

【问题讨论】:

    标签: haskell list-comprehension do-notation


    【解决方案1】:

    仔细查看错误信息:

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

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

    这意味着它被解析为

    (return a) : b
    

    因此b 成为(:) 的第二个参数;但你的本意是

    return (a : b)
    

    【讨论】:

    • 我现在明白了,我无法正确解析错误文本 :-) +1 以获得详尽的解释。
    • 是的,Haskell 的错误是出了名的不可读。 :) 但是习惯了这种风格之后就不会注意到了。
    【解决方案2】:

    你需要括号。

    return (a:b)
    

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 2018-09-05
      • 2013-05-19
      • 1970-01-01
      • 2012-05-13
      • 2019-12-04
      • 2011-11-20
      • 2015-08-22
      • 2021-08-14
      相关资源
      最近更新 更多