0

我对列表理解有一些了解。我理解这样的表达:

[x * x | x <- [1..10]]
should output [1,4,9,16,25,36,49,64,81,100]

并且该表达式的效果与以下内容相同:

map power [1..10]
power x = x * x

现在,我必须为以下功能找出另一种方法(就像上面一样):

[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]

我自己无法弄清楚没有错误,请帮助我

4

3 回答 3

8

Haskell 报告告诉我们如何翻译列表推导:

[ e | True ]         = [e]
[ e | q ]            = [ e | q, True ]
[ e | b, Q ]         = if b then [ e | Q ] else []
[ e | p <- l, Q ]    = let ok p = [ e | Q ]
                           ok _ = []
                       in concatMap ok l
[ e | let decls, Q ] = let decls in [ e | Q ]

由于您的列表理解仅使用无可辩驳的模式(即永不失败的模式),因此上面的第四个子句在某种程度上简化了:

[ e | p <- l, Q ]    = concatMap (\p -> [ e | Q ]) l

为了简洁起见,我将使用此版本,但真正的推导应该使用报告中的定义。(作业:尝试真正的翻译,并检查最后是否得到“相同的东西”。)让我们试一试,好吗?

  [(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]
= concatMap (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]] [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y]]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y], True]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z) | True]) [1..y]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z)]) [1..y]) [1..x]) [1..10]

我们终于来到了一个没有列表推导的版本。

concatMap如果您对 monad 感到满意,那么您还可以通过观察它是列表函数的翻转版本来深入了解这个表达式的行为(>>=);而且,[e]就像列表中的return e. 因此,用 monad 运算符重写:

= [1..10] >>= \x ->
  [1..x]  >>= \y ->
  [1..y]  >>= \z ->
  return (x,y+z)
于 2011-10-19T13:12:41.437 回答
5
[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]

是相同的

concatMap
    (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]])
    [1..10]

您可以类似地从列表推导中提取y和变量。z(但是你必须按照从左到右的顺序来做:所以y下一个和z最后一个。)

concatMap是 Prelude 中定义的函数:

concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = concat . map f
于 2011-10-19T10:28:25.897 回答
3

您可以将其转换为do-notation:

foo = do x <- [1..10]
         y <- [1..x]
         z <- [1..y]
         return (x, y+z)

这是有效的,因为 list 是一个单子。do-notation 本身只是一元计算的语法糖。遵循脱糖规则(此处在“do 块的脱糖”下描述),您最终会得到:

[1..10] >>= (\x -> [1..x] >>= (\y -> [1..y] >>= (\z -> [(x,y+z)])))

运算符>>=在 , 中定义Control.Monad,等效于concatMap带有翻转参数的列表。return t只是[t]在列表的情况下。

于 2011-10-19T10:48:24.680 回答