Haskell:列表理解谓词顺序

时间:2016-01-08 13:22:21

标签: haskell list-comprehension

在线阅读了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]

通常情况下,我会将此作为一个提示,即订单并不重要,并且完成了它。然而,这是一个来自旧考试的问题,问题的答案是,虽然结果可能相同,但计算它们的方式可能不同。

我假设这是真的,但我无法在网上找到有关它的任何信息。 所以我的问题是:两个列表推导之间的计算有何不同?为什么?列表理解是否是我不知道的某种形式的句法糖?

2 个答案:

答案 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时生成 - 所以你可以说它更好 /更高性能