【问题标题】:How to properly combine List[M[List[A]]] into M[List[A]] if M is a monad?如果 M 是单子,如何将 List[M[List[A]]] 正确组合成 M[List[A]]?
【发布时间】:2018-12-11 19:18:33
【问题描述】:

我有包装列表的单子。我想将这些 monad 组合成一个 monad,将所有列表串联起来。

M[List[A]] + M[List[A]] ==> M[List[A]]

为了实现这一点,我做了以下(伪代码)

(1 to 10).foldLeft(Option(List(0)))((accumulator, i) => {
  for {
    prev <- accumulator
    more <- Option(List(i))
  } yield prev ++ more
})

这似乎可以编译,但我觉得它应该比这更简单和更短。有什么改进的想法吗?

【问题讨论】:

  • 您要合并多少个列表?您的示例看起来好像只是 Monad[M].unit((1 to 10)),所以我根本不明白您想要在那里组合什么。
  • 对不起,我不明白你在问什么。我想合并 11 个列表。
  • 我在问您是否要将(M[List[A]], M[List[A]])List[M[List[A]]] 合并到M[List[A]] 中。您的第一个代码 sn-p 建议您要组合一对单子 (map2),第二个 sn-p 建议您要组合一系列单子 (sequence + map)。是哪一个?
  • 有什么区别?自然变换也是一样的。
  • 不同之处在于(M[List[A]], M[List[A]]) 可以转换为任何monad 的M[List[A]],而更一般的Foo[M[List[A]]] 可以转换为M[List[A]],只有Foo 是可遍历的。 M 是一个 monad 的事实并不能自动保证您可以将任意 Foo[M[...]] 交换为 M[Foo[...]],并且任何 Foo[List[A]] 也不能折叠为 List[A]

标签: scala functional-programming monads applicative scala-cats


【解决方案1】:

有一个Traverse[List] 的实例。 每个Monad[M] 都是Applicative[M] 的特例。因此,如果你有一个

List[M[List[A]]]

您应该能够使用Traverse[List] 中的sequenceApplicative[M] 首先将其转换为

M[List[List[A]]]

然后用mapFunctor[M]改成flatten

M[List[A]]

类似

val lists: List[Option[List[A]]] = ???
val optLists: Option[List[List[A]]] = Traverse[List].sequence(lists)
val optList: Option[List[A]] = optLists.map(_.flatten)

Option的情况下。

【讨论】:

  • 当您不想依赖隐式解析时,实际上使用后缀是一件好事!
【解决方案2】:

我认为 semigroup(或 SemigroupK)可能是您正在寻找的抽象

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-10-15
  • 2015-01-31
  • 2016-11-14
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 2015-12-19
相关资源
最近更新 更多