我对列表理解的理解很少。我理解表达式:
[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]]
我无法自行解决,请帮助我
答案 0 :(得分:7)
Haskell Report告诉我们如何翻译列表推导:
[ 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]
我们终于处于一个没有列表推导的版本。
如果你对monad很满意,那么你也可以通过观察concatMap
是列表的(>>=)
函数的翻转版本来深入了解这个表达式的行为。此外,[e]
与列表的return e
类似。所以,用monad运算符重写:
= [1..10] >>= \x ->
[1..x] >>= \y ->
[1..y] >>= \z ->
return (x,y+z)
答案 1 :(得分: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
答案 2 :(得分:3)
您可以将其转换为do
- 符号:
foo = do x <- [1..10]
y <- [1..x]
z <- [1..y]
return (x, y+z)
这是有效的,因为list是monad。 do
- 符号本身只是monadic计算的语法糖。遵循这些令人畏惧的规则(在“去除障碍物”下描述here),你最终会得到:
[1..10] >>= (\x -> [1..x] >>= (\y -> [1..y] >>= (\z -> [(x,y+z)])))
运算符>>=
在Control.Monad
中定义,相当于带有列表翻转参数的concatMap
。在列表的情况下,return t
只是[t]
。