简体   繁体   English

Haskell:列表理解谓词顺序

[英]Haskell: List comprehension predicate order

After reading about the Haskell syntax for List Comprehensions online, I got the feeling that predicates always come last. 在线阅读了List Comprehensions的Haskell语法之后,我感觉谓词总是最后的。 Eg: 例如:

[(x,y) | x <- [1..10000], y <- [1..100], x==2000, odd y]

But the following line accomplishes the same result: 但是以下行完成了相同的结果:

[(x,y) | x <- [1..10000], x==2000, y <- [1..100], odd y]

Normally I would just take this as a hint that the order doesn't matter and be done with it. 通常情况下,我只是将此作为一个提示,即订单无关紧要并完成。 However this is a problem that comes from an old exam, and the answer to the problem says that while the results may be the same, the way in which they are computed may differ. 然而,这是来自旧考试的问题,并且问题的答案表明虽然结果可能相同,但计算它们的方式可能不同。

I'm assuming this is true but I can't find any information about it on the web. 我假设这是真的,但我在网上找不到任何关于它的信息。 So my question is : How could the computations differ between the two list comprehensions and why? 所以我的问题是 :两个列表推导之间的计算有何不同?为什么? Are list comprehensions some form of syntactic sugar that I don't know about? 列表理解是否是我不知道的某种形式的句法糖?

You can think of a list comprehension like 你可以想到列表理解就像

[(x,y) | x <- [1..10000], y <- [1..100], x==2000, odd y]

as corresponding to the imperative pseudo-code 对应于命令式伪代码

for x in [1..10000]:
    for y in [1..100];
        if x == 2000:
            if odd y:
                yield (x,y)

and

[(x,y) | x <- [1..10000], x==2000, y <- [1..100], odd y]

as corresponding to 对应于

for x in [1..10000]:
    if x == 2000;
        for y in [1..100]:
            if odd y:
                yield (x,y)

Specifically, passing the list comprehension to something like mapM_ print is the same operationally as replacing yield by print in the imperative version. 具体来说,将列表理解传递给mapM_ print之类的操作与在命令式版本中通过print替换yield相同。

Obviously, it's almost always better to "float" a guard/ if out of a generator/ for when possible. 显然,这是几乎总是更好地“漂浮”保护/ if出了发电机/ for在可能的情况。 (The rare exception is when the generator is actually an empty list, and the guard condition is expensive to compute.) (罕见的例外是当生成器实际上是一个空列表时,保护条件的计算成本很高。)

They differ in the way of how many intermediary results/lists are generated. 它们在生成多少中间结果/列表的方式上有所不同。

You can visualize this with some trace - note that I modified this a bit to give reasonable results - also I replaced the return values by () to make it clearer: 你可以用一些想象这个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

here is the evaluation: 这是评价:

λ> 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
]

now do you notice something? 现在你注意到了什么?

Obviously in the first example every (x,y) pair for x=1,2,3 and y=1,2,3 is generated before the filters are applied. 显然,在第一个例子中(x,y)在应用滤波器之前,生成x=1,2,3y=1,2,3每个(x,y)对。

But in the second example the y s are only generated when x=2 - so you could say it's better /more performant 但是在第二个例子中,只有当x=2时才生成y s - 所以你可以说它更好 /更高效

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM