在线阅读了List Comprehensions的Haskell语法后,我感觉谓词总是最后的。例如:
[(x,y) | x <- [1..10000], y <- [1..100], x==2000, odd y]
但是以下行完成了相同的结果:
[(x,y) | x <- [1..10000], x==2000, y <- [1..100], odd y]
通常情况下,我会将此作为一个提示,即订单并不重要,并且完成了它。然而,这是一个来自旧考试的问题,问题的答案是,虽然结果可能相同,但计算它们的方式可能不同。
我假设这是真的,但我无法在网上找到有关它的任何信息。 所以我的问题是:两个列表推导之间的计算有何不同?为什么?列表理解是否是我不知道的某种形式的句法糖?
答案 0 :(得分:2)
你可以想到像
这样的列表理解[(x,y) | x <- [1..10000], y <- [1..100], x==2000, odd y]
对应于命令式伪代码
for x in [1..10000]:
for y in [1..100];
if x == 2000:
if odd y:
yield (x,y)
和
[(x,y) | x <- [1..10000], x==2000, y <- [1..100], odd y]
与
对应for x in [1..10000]:
if x == 2000;
for y in [1..100]:
if odd y:
yield (x,y)
具体而言,将列表理解传递给mapM_ print
之类的操作与在命令式版本中用yield
替换print
的操作相同。
显然,“#&#34;漂浮&#34;在可能的情况下,使用生成器/ if
的警卫/ for
。 (罕见的例外是当生成器实际上是一个空列表时,保护条件的计算成本很高。)
答案 1 :(得分:1)
它们在生成多少中间结果/列表的方式上有所不同。
你可以用一些trace
来形象化这一点 - 请注意我对此进行了一些修改以得到合理的结果 - 我也用()
替换了返回值以使其更清晰:
comprehension1 = [ () | x <- [1..3], trace' 'x' x, y <- [1..3], trace' 'y' y, x==2, odd y]
comprehension2 = [ () | x <- [1..3], trace' 'x' x, x==2, y <- [1..3], trace' 'y' y, odd y]
trace' :: Show a => Char -> a -> Bool
trace' c x = trace (c : '=' : show x) True
这是评价:
λ> comprehension1
x=1
y=1
y=2
y=3
x=2
y=1
[()y=2
y=3
,()x=3
y=1
y=2
y=3
]
λ> comprehension2
x=1
x=2
y=1
[()y=2
y=3
,()x=3
]
现在你注意到了什么?
显然,在第一个示例中,(x,y)
和x=1,2,3
的每个y=1,2,3
对都会在应用过滤器之前生成。
但是在第二个例子中,y
仅在x=2
时生成 - 所以你可以说它更好 /更高性能