use*_*108 2 haskell list-comprehension
假设我们有一个预定义的列表pairs,它是所有对(x,y)的列表,使得x,y∈{1..9}和2x = y.在Haskell中它看起来像:
pairs = [ (x,y) | x <- [1..9], y <- [1..9], 2 * x == y ]
Run Code Online (Sandbox Code Playgroud)
现在,我想用来pairs定义一个新列表triplets,它是所有三元组(x,y,z)的列表,使得x,y,z∈{1..9},2x = y和2y = z.写它的显而易见的方法是:
triplets = [ (x,y,z) | (x,y) <- pairs, (y,z) <- pairs ]
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这不起作用.
现在,我知道它没有的技术原因:(y,z) <- pairs生成器循环比(x,y) <- pairs它更紧密,并且它指定的值会y覆盖y进入该循环之前的任何内容.但是你为什么要设计一种语言呢?是不是更直观(并且符合数学约定)让生成器"看到"它的左边并重用预先分配的值,以便每个变量在每次迭代中都有一个值?我认为这个设计选择背后一定有一个实用的理由,但我不确定它是什么.
问题是列表理解只是为列表monad编写符号的另一种方法:
triplets = do
(x, y) <- pairs
(y, z) <- pairs
return (x, y, z)
Run Code Online (Sandbox Code Playgroud)
所以相反,你会看到你在monadic动作中重新绑定一个名字.虽然这是允许的,但如果你打开-Wall,你会收到警告
Warning: Defined by not used: `y'
Warning:
The binding for `y' shadows the existing binding bound at module:line:column
Run Code Online (Sandbox Code Playgroud)
相反,首选方法是这样做
triplets = do
(x, y1) <- pairs
(y2, z) <- pairs
guard $ y1 == y2
return (x, y1, z)
Run Code Online (Sandbox Code Playgroud)
或者作为一种理解
triplets = [(x, y1, z) | (x, y1) <- pairs, (y2, z) <- pairs, y1 == y2]
Run Code Online (Sandbox Code Playgroud)
记住口头禅"明确胜过隐性".你不会因为能够做你想做的事而获得任何效率加成,这显然表达了你的意图,同时[(x, y, z) | (x, y) <- pairs, (y, z) <- pairs]更难理解.
| 归档时间: |
|
| 查看次数: |
282 次 |
| 最近记录: |