简体   繁体   English

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

[英]Haskell >> operator with two lists

For a college assignment I am learning Haskell and when reading about the do-notation and sequencing with >>= and >> I came across this behaviour that I did not expect.对于一项大学作业,我正在学习 Haskell,在阅读有关使用>>=>>的做符号和排序时,我遇到了这种我没有预料到的行为。

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

Can anyone explain why every element of the first array is replaced by the elements of the second array?谁能解释为什么第一个数组的每个元素都被第二个数组的元素替换? It seems like the list is concatenated in some way, while I expected the result of the first expression to be completely ignored, thus I would expect [1] as the result.似乎列表以某种方式连接在一起,而我希望第一个表达式的结果被完全忽略,因此我希望[1]作为结果。

Thanks a lot in advance.非常感谢。

The “result” is in this case the values contained in [1,2,3] , which are indeed ignored.在这种情况下,“结果”是[1,2,3]中包含的值,它们确实被忽略了。 What >> does not ignore is the context , which for the list monad is the shape (ie length) of the list. >>没有忽略的是context ,对于列表 monad 来说,它是列表的形状(即长度)。 This can't be ignored, because we must have x >>= pure ≡ x , ie这不能忽略,因为我们必须有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]

An example with length>1 on the RHS: 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]

There are several equivalent ways of writing [1,2,3] >> [1] : [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])

It replaces every element of [1..3] with [1] and then collapses it:它用 [ [1] ] 替换[1..3]的每个元素,然后折叠它:

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

It completely ignores the elements of [1,2,3] , just using the shape (length).它完全忽略[1,2,3]的元素,只使用形状(长度)。 Look what happens if we replace them with undefined :看看如果我们用undefined替换它们会发生什么:

> do [undefined, undefined, undefined]; return 1
[1,1,1]

The results of the first computation are indeed ignored.第一次计算的结果确实被忽略了。

Monads can be seen as generalized nested loops . Monad 可以看作是广义的嵌套循环 What you have can be written in pseudocode as你所拥有的可以用伪代码写成

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

Both y and x are in scope at the innermost level. yx都在最内层的 scope 中。 y 's value is indeed ignored. y的值确实被忽略了。

Still for each y in [1,2,3] each x in [1] is produced, thus defining the overall computation.对于[1,2,3]中的每个y ,都会生成[1]中的每个x ,从而定义整体计算。 For lists this means the results produced one by one by the combined computation as a whole are the results produced one by one at the innermost level.对于列表来说,这意味着组合计算作为一个整体逐一产生的结果是最内层逐一产生的结果。 Sounds trivial, isn't it.听起来微不足道,不是吗?

How exactly this is implemented is an implementational detail.这是如何实现的是一个实现细节。 Seeing the lists as data this means splicing the results of the inner computations in place , flattening the list of lists into a one-level list, appending the inner lists together.将列表视为数据意味着将内部计算的结果就地拼接,将列表列表展平为一级列表,将内部列表附加在一起。 concatMap is widely known as flatMap in other languages: concatMap在其他语言中被广泛称为flatMap

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

Related answers: Why >> duplicates right-hand side operand , Map and flatMap , How does Monad on list work?相关答案:为什么>>复制右侧操作数Map 和 flatMapMonad on list 是如何工作的? , Why list monad combines in that order? 为什么要按那个顺序列出 monad 组合? , mapM with const functions in Haskell , under the hood reason we can use nested loops in list comprehensions , Generalizing prime pairs in SICP . , mapM中带有 const 函数的 mapM ,在幕后原因是我们可以在列表推导中使用嵌套循环,在 SICP 中泛化素数对

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM