Haskell >> 有两个列表的运算符

Haskell >> operator with two lists

为了大学作业,我正在学习 Haskell,在阅读有关 >>=>> 的符号和排序时,我遇到了这种我没有预料到的行为。

[1,2,3] >> [1] -- returns [1,1,1]

谁能解释为什么第一个数组的每个元素都被第二个数组的元素替换?似乎列表以某种方式连接在一起,而我希望第一个表达式的结果被完全忽略,因此我希望结果为 [1]

非常感谢。

在这种情况下,“结果”是 [1,2,3] 中包含的值,它们确实被忽略了。 >> 没有忽略的是 context,对于列表 monad 来说,它是列表的 shape(即长度)。这不能忽略,因为我们必须有x >>= pure ≡ x,即

Prelude> [1,2,3] >>= pure
[1,2,3]
Prelude> [1,2,3] >>= \n -> [n]
[1,2,3]
Prelude> [1,2,3] >>= \n -> [1]
[1,1,1]
Prelude> [1,2,3] >>= \_ -> [1]
[1,1,1]
Prelude> [1,2,3] >> [1]
[1,1,1]

RHS 上长度>1 的示例:

[1,2,3] >>= \n -> [n, n+10]
[1,11,2,12,3,13]
Prelude> [1,2,3] >>= \n -> [100, 10]
[100,10,100,10,100,10]
Prelude> [1,2,3] >> [100, 10]
[100,10,100,10,100,10]

有几种等价的写法[1,2,3] >> [1]:

do [1,2,3]
   return 1

[ x | _ <- [1,2,3], x <- [1] ]

[ 1 | _ <- [1,2,3] ]

[1,2,3] >>= \_ -> [1]

concatMap (const [1]) [1,2,3]

concat (map (const [1]) [1,2,3])

concat ([1,2,3] $> [1])

它将 [1..3] 的每个元素替换为 [1] 然后折叠它:

  concatMap (\_ -> [1]) [1,2,3]
= concat (map (\_ -> [1]) [1,2,3])
= concat [[1],[1],[1]]
= [1,1,1]

它完全忽略了[1,2,3]的元素,只使用形状(长度)。看看如果我们将它们替换为 undefined:

会发生什么
> do [undefined, undefined, undefined]; return 1
[1,1,1]

第一个计算的结果确实被忽略了。

Monad 可以看作是广义的 nested loops。你所拥有的可以用伪代码写成

  for y in [1,2,3]:
    for x in [1]:     -- for x in ((\_ -> [1]) y):
      yield x

yx 都在最内层的范围内。 y的值确实被忽略了。

仍然为 [1,2,3] 中的每个 y 生成 [1] 中的每个 x,从而定义整体计算。对于列表来说,这意味着组合计算作为一个整体逐一产生的结果是最内层逐一产生的结果。听起来微不足道,不是吗。

具体如何实现是一个实现细节。将列表视为数据,这意味着拼接内部计算的结果 就地 ,将列表列表展平为 one-level 列表,将内部列表附加在一起。 concatMap 在其他语言中被广泛称为 flatMap

   [  1,   2,   3  ]
     [1]  [1]  [1]
  -------------------
  [   1,   1,   1  ]

相关回答: , , , , mapM with const functions in Haskell , , .