为什么使用多个生成器的Haskell列表推导将最右边的生成器视为最紧密的循环?

时间:2012-05-01 15:00:38

标签: haskell conventions

我正在阅读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世界the word似乎是选择了排序“因为这是你编写for循环的顺序“但我认为,就for循环来说,思考并不是大多数Haskell程序员所做的......

思想?


从我对路易斯·沃瑟曼的回答如下:

  

我猜这里对应于强制性命令式解释的顺序被认为比嵌套列表更自然。所以从本质上讲,Haskell对此的解释与我在问题中链接的Python解释相同,毕竟,似乎。

3 个答案:

答案 0 :(得分:22)

因此事情的范围是理智的。

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

有道理 - x符合y的理解范围 - 但

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

有点不太有意义。

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

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

答案 1 :(得分:6)

如果将列表推导首先扩展为do符号然后再扩展为monadic绑定,则可能更有意义。假设我们想写一个理解,我们引用已经绑定的名称:

[ (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是什么。你必须向后阅读理解才能找到答案。

所以它没有需要是最右边的绑定被展开到“内循环”的情况,但是当你考虑到人类将不得不这样做时它是有意义的阅读结果代码。

答案 2 :(得分: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)]
>>>