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)