15

我正在阅读Gentle Introduction并且想知道为什么在具有两个生成器的列表理解中,最右边的生成器被迭代“最快”(即编译到最内层循环,我猜)。观察以下 GHCi 输出:

*Main> concat [[(x,y) | x <- [0..2]] | y <- [0..2]]
[(0,0),(1,0),(2,0),(0,1),(1,1),(2,1),(0,2),(1,2),(2,2)]
*Main> [(x,y) | x <- [0..2], y <- [0..2]]
[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]

如果最左边的生成器迭代得最快,那么上述两个表达式将具有相同的值,我认为这使得选择这个约定更自然。

那么有谁知道为什么选择了相反的约定?我注意到 Python 具有与 Haskell 相同的约定(甚至可能是从 Haskell 借来的?),在 Python 世界中,这个词似乎是选择了排序“因为这是你编写 for 循环的顺序”,但是我认为从 for 循环的角度思考并不是大多数 Haskell 程序员所做的......

想法?


根据我对 Louis Wasserman 回答的评论如下:

我想在这里,与理解的命令式解释相对应的顺序被认为比与嵌套列表相对应更自然。因此,本质上,Haskell 对此的解释与我在问题中链接的 Python 解释相同,毕竟,看起来。

4

3 回答 3

23

所以事情的范围是理智的。

[(x, y) | x <- [1..10], y <- [1..x]]

有道理——x在理解范围内y——但是

[(x, y) | y <- [1..x], x <- [1..10]]

意义不大。

此外,这种方式与domonad 语法一致:

do x <- [1..10]
   y <- [1..x]
   return (x, y)
于 2012-05-01T15:03:44.433 回答
6

do如果您先将列表推导式扩展为符号,然后再扩展为单子绑定,则可能更有意义。假设我们要编写一个推导式,在其中引用已经绑定的名称:

[ (x,y) | x <- [1,2,3], y <- [x+1,x+2] ]

这扩展到

do x <- [1,2,3]
   y <- [x+1,x+2]
   return (x,y)

扩展到

[1,2,3] >>= \x ->
[x+1,x+2] >>= \y -> 
return (x,y)

这清楚地表明,x它恰好在需要的时候在范围内。

如果扩展为do符号是从右到左而不是从左到右,那么我们的原始表达式将扩展为

[x+1,x+2] >>= \y ->
[1,2,3] >>= \x ->
return (x,y)

这显然是荒谬的 - 它指的是尚未绑定x的范围内的值。x所以我们必须把我们原来的理解写成

[ (x,y) | y <- [x+1,x+2], x <- [1,2,3] ]

为了得到我们想要的结果,这似乎不自然——当你的眼睛扫描y <- [x+1,x+2]你实际上并不知道是什么的短语时x。您必须向后阅读理解才能找出答案。

因此,不需要将最右边的绑定展开到“内循环”中,但是当您考虑到人类将不得不阅读生成的代码时,这是有道理的。

于 2012-05-01T16:00:08.130 回答
0

实际上 Python 使用与 Haskell 相同的范围结构来进行列表推导。

比较你的 Haskell:

*Main> concat [[(x,y) | x <- [0..2]] | y <- [0..2]]
[(0,0),(1,0),(2,0),(0,1),(1,1),(2,1),(0,2),(1,2),(2,2)]
*Main> [(x,y) | x <- [0..2], y <- [0..2]]
[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]

使用这个 Python:

>>> from itertools import chain
>>> list(chain(*[[(x,y) for x in range(3)] for y in range(3)]))
[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)]
>>> [(x,y) for x in range(3) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
>>> 
于 2012-05-01T15:09:43.340 回答