为什么Haskell列表中包含多个生成器的理解将最右边的生成器视为最紧密的循环?

为什么Haskell列表中包含多个生成器的理解将最右边的生成器视为最紧密的循环?,haskell,conventions,Haskell,Conventions,我正在通读,想知道为什么在一个包含两个生成器的列表理解中,最右边的生成器被迭代得“最快”(即编译到最里面的循环,我猜)。观察以下GHCi输出: *Main>concat[[(x,y)| x,使事物以一种理智的方式运行 [(x, y) | x <- [1..10], y <- [1..x]] 这就没什么意义了 此外,这种方式与domonad语法一致: do x <- [1..10] y <- [1..x] return (x, y) 实际上,Python使用

我正在通读,想知道为什么在一个包含两个生成器的列表理解中,最右边的生成器被迭代得“最快”(即编译到最里面的循环,我猜)。观察以下GHCi输出:


*Main>concat[[(x,y)| x,使事物以一种理智的方式运行

[(x, y) | x <- [1..10], y <- [1..x]]
这就没什么意义了

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

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

实际上,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)]

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

[ (x,y) | x <- [1,2,3], y <- [x+1,x+2] ]
这清楚地表明,
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] ]

[(x,y)| y对于新手来说,使用
do
monad语法展示同一代码的外观可能是一个好主意。作为初学者,我真的看不出作用域如何比生成器的顺序更随意。再次使用我的嵌套示例,
[(x,y)| x嵌套是(并且是应该是)与链式理解语法完全不同。在任何情况下,
do
符号都有一个明确的顺序,列表理解符合该顺序。响应您的编辑添加单子语法(正如@dflemstr猜测的那样,我还不熟悉:),这不是同一顺序,因为
返回(x,y)
已经走到了最后!但我明白你的意思。我想在这里,与理解的命令式解释相对应的顺序被认为比嵌套列表更自然。因此,本质上,Haskell对此的解释与我在问题中链接的Python解释相同,毕竟,它是嗯。哦,你已经知道了。无论如何,我会把这个放在这里进行比较。呃,是的,这就是我的意思:)我会编辑我的问题以澄清。是的,我认为你的观点与路易斯·沃瑟曼的答案相似。但如果推理真的与范围顺序一致,即从左到右以适应(说英语的人)人类从左到右阅读,那么为什么表达式(
(x,y)
)位于变量量化的左侧?真的,为什么不一直遵循指令的一元顺序,这样
[1,2,3]>=\x->[x+1,x+2]>=\y->return(x,y)
就被糖化为,比如说,
[x换言之,当你扫描
y时,这是一个正确的点。我怀疑这样写的原因是它与数学平行(记住Haskell有很多数学的影响)。如果它能帮你解决问题,我总是把竖线
|
读为“where”(我以前读它时是“That”)在我认为自己更像一个数学家而不是一个程序员的日子里……)所以基本上我猜这种语法显示了一种古老的认知不协调,即在黑板上画一个
g
箭头,然后再画一个
f
箭头,然后将图表命名为“
f\circ g
”…选一个,坚持下去!作为一名数学系学生,我总是希望我们写
(x)f
,而不是
f(x)
来解决这个问题。现在它也跟着我来到了Haskell world!:P谢谢你的洞察力。这怎么会更自然呢?你也想要11,21,31,41而不是11,12,13,14吗?我想使用
(y,x)
作为原型表达式——或者将y生成器放在x生成器的左边——如果最左边的生成器是最紧的循环,则更有意义。然后它将是我的GHCi输出中的第二行,在您看来很奇怪(11、21、31、41),而不是第一个,但它们仍然会彼此不同,这是我的观点。抱歉,我想我应该在回复你时称呼你,@Ingo。(对Stack Overflow来说有点陌生。)我不认为这有什么深层次的技术原因,所以如果你想找的东西不仅仅是“因为这对那些创造这种语言的人来说是正确的”“嗯,你可能运气不好。”@DanielWagner是的,所以我从人们的回答中收集。。。
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+1,x+2] >>= \y ->
[1,2,3] >>= \x ->
return (x,y)
[ (x,y) | y <- [x+1,x+2], x <- [1,2,3] ]