下面的理解如何工作?

How does below for comprehension work?

我正在尝试解决 https://github.com/dehun/learn-fp/blob/master/src/test/scala/learnfp/monad/WriterTest.scala 中的练习。目前我无法理解下面的代码是如何工作的,尤其是第 20、22 和 24 行。WriterString 没有 map 方法。另外,_有什么用?

"writer monad" should {
    "work" in {
      val s : Int = 3
      type WriterString[A] = Writer[List[String], A];
      {
        for {
          x <- 1.pure[WriterString]
          _ <- tell(List("een"))
          y <- 2.pure[WriterString]
          _ <- tell(List("twee"))
          z <- 3.pure[WriterString]
          _ <- tell(List("drie"))
      } yield (x, y, z) }.run() shouldBe (List("een", "twee", "drie"), (1, 2, 3))
    }

如果您为了理解而脱糖(例如使用 intellij,或手动) 你会得到

  {
    1.pure[WriterString]
      .flatMap(
        x =>
          tell(List("een")).flatMap {
            case _ =>
              2.pure[WriterString]
                .flatMap(
                  y =>
                    tell(List("twee")).flatMap {
                      case _ =>
                        3.pure[WriterString]
                          .flatMap(z => tell(List("drie")).map { case _ => (x, y, z) })
                  }
                )
        }
      )
  }.run()

注意 _(下划线)在 case 子句中,它们基本上意味着我们不关心值。特别是这里我们不在乎,因为 tell returns 具有 Unit 类型值的 Writer。

def tell[W](m:W)(implicit monoid:Monoid[W]):Writer[W, Unit] = ???

tell来自进口import learnfp.functor.Writer._

WriterStringWriter 的类型别名,可以转换为 FunctorOps (可能有 map 方法)- https://github.com/dehun/learn-fp/blob/master/src/main/scala/learnfp/functor/Writer.scala#L16

for {
  a <- A
  b <- B
  c <- C
} yield (a,b,c)

翻译成

A.flatMap { a =>
  B.flatMap { b =>
     C.map { c => (a,b,c) }
  }
}

最后一个操作转换为 map(如果您没有 yield 结果,则为 foreach),它之前的所有操作 - 转换为 flatMap。操作是嵌套的(next <- 表示下一个嵌套操作)。

同样 ifs 转换为 withFilter

_ 表示您忽略了该值(您必须将 flatMap/map 的参数分配给某些东西,但您可能决定不使用它)。