gpt4 book ai didi

haskell - 为什么生成器会覆盖 Haskell 列表理解中的变量值?

转载 作者:行者123 更新时间:2023-12-02 13:44:04 24 4
gpt4 key购买 nike

假设我们有一个预定义列表 pairs ,它是所有 (x,y) 对的列表,使得 x,y ∈ {1..9} 且 2x=y。在 Haskell 中,它看起来像:

pairs = [ (x,y) | x <- [1..9], y <- [1..9], 2 * x == y ]

现在,我想使用pairs定义一个新列表 triplets ,它是所有三元组 (x,y,z) 的列表,使得 x,y,z∈{1..9}、2x=y 和 2y=z。最明显的写法是:

triplets = [ (x,y,z) | (x,y) <- pairs, (y,z) <- pairs ]

奇怪的是,这不起作用。

现在,我知道它不这样做的技术原因: (y,z) <- pairs生成器循环比 (x,y) <- pairs 更紧密,以及它分配给 y 的值覆盖任何y在进入该循环之前。但为什么要设计一种语言来做到这一点呢?让生成器“看到”左侧并重用预先分配的值,以便每个变量在每次迭代中都有一个值,这不是更直观(并且符合数学约定)吗?我认为这种设计选择背后一定有一个务实的理由,但我不确定它是什么。

最佳答案

问题在于列表理解只是为列表单子(monad)编写 do 表示法的另一种方式:

triplets = do
(x, y) <- pairs
(y, z) <- pairs
return (x, y, z)

因此,您会看到您正在单子(monad)操作中重新绑定(bind)名称。虽然这是允许的,但如果您打开 -Wall ,您会收到警告

Warning: Defined by not used: `y'
Warning:
The binding for `y' shadows the existing binding bound at module:line:column

相反,首选方法是这样做

triplets = do
(x, y1) <- pairs
(y2, z) <- pairs
guard $ y1 == y2
return (x, y1, z)

或者作为理解

triplets = [(x, y1, z) | (x, y1) <- pairs, (y2, z) <- pairs, y1 == y2]

记住这句格言:“显式优于隐式”。你不会因为能够做你想做的事情而获得任何效率加成,这清楚地表达了你的意图,而 [(x, y, z) | (x, y) <- pairs, (y, z) <- pairs]比较难理解。

关于haskell - 为什么生成器会覆盖 Haskell 列表理解中的变量值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22509238/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com