cats.data.WriterT 的 for-comprehension 中忽略的参数
Ignored parameter in for-comprehension for cats.data.WriterT
我正在和猫一起经历 scala。在 Writer
($4.7.2, p. 111) 的示例中,使用了以下 for-comprehension:
import cats.data.Writer
import cats.syntax.writer._
import cats.syntax.applicative._
import cats.instances.vector._
type Logged[A] = Writer[Vector[String], A]
val writer1 = for {
a <- 10.pure[Logged]
_ <- Vector("a", "b", "c").tell
b <- 32.writer(Vector("x", "y", "z"))
} yield a + b
// writer1: cats.data.WriterT[cats.Id,Vector[String],Int] = WriterT((
Vector(a, b, c, x, y, z),42))
据我所知,下划线 (_
) 用于忽略的参数,它从不在 yield
关键字之后使用。仍然将值 "a"
、"b"
和 "c"
写入日志。这是成语还是有其他解释?
Writer
monad 可以被认为是一个元组,其中第一个元素表示日志值,而第二个元素表示主要业务值。关键要明白
中的下划线_
for {
a <- 10.pure[Logged]
_ <- Vector("a", "b", "c").tell
b <- 32.writer(Vector("x", "y", "z"))
} yield a + b
代表“业务价值”,即元组的第二个 ._2
元素,而不是整个元组,因此在组合中此时只忽略业务价值。如果我们对 for-comprehension
进行去糖处理,也许会有帮助
WriterT[Id, Vector[String], Int](Vector(), 10).flatMap { (a: Int) =>
WriterT[Id, Vector[String], Unit](Vector("a", "b", "c"), ()).flatMap { (_: Unit) =>
WriterT[Id, Vector[String], Int](Vector("x", "y", "z"), 32).map { (b: Int) =>
a + b
}
}
}
这样我们就看不到任何不寻常的事情发生;参数 (_: Unit)
根本没有在 (_: Unit) => body
的正文中使用。现在让我们也看看 flatMap
def flatMap[U](
f: V => WriterT[F, L, U]
)(implicit flatMapF: FlatMap[F], semigroupL: Semigroup[L]): WriterT[F, L, U] =
WriterT {
flatMapF.flatMap(run) { lv =>
flatMapF.map(f(lv._2).run) { lv2 =>
(semigroupL.combine(lv._1, lv2._1), lv2._2)
}
}
}
很少有东西会立即弹出
- 元组表示法
._1
和 ._2
semigroupL.combine(lv._1, lv2._1)
f(lv._2)
我们看到了如何使用半群来组合日志,日志是元组的第一个元素。在我们的例子中分析 f(lv._2)
,我们有 lv._2 = ()
和 f
是函数 (_: Unit) => body
,其中参数 (_: Unit)
根本没有在 body
中使用。
一般来说,flatMap
的特殊定义赋予了 monad 特有的力量。在 Writer
的情况下,这种能力允许它在我们沿着计算链前进时透明地组合日志。
作为旁注,正如 Luis 所说,这里没有 side 效应发生。在下面的句子
中考虑术语效果的函数式编程意义
- Identity monad encodes the effect of having no effect
- IO monad encodes the effect of having a side-effect
- Option monad encodes the effect of having optionality
effect 的语义由 flatMap
的实现编码。
我正在和猫一起经历 scala。在 Writer
($4.7.2, p. 111) 的示例中,使用了以下 for-comprehension:
import cats.data.Writer
import cats.syntax.writer._
import cats.syntax.applicative._
import cats.instances.vector._
type Logged[A] = Writer[Vector[String], A]
val writer1 = for {
a <- 10.pure[Logged]
_ <- Vector("a", "b", "c").tell
b <- 32.writer(Vector("x", "y", "z"))
} yield a + b
// writer1: cats.data.WriterT[cats.Id,Vector[String],Int] = WriterT((
Vector(a, b, c, x, y, z),42))
据我所知,下划线 (_
) 用于忽略的参数,它从不在 yield
关键字之后使用。仍然将值 "a"
、"b"
和 "c"
写入日志。这是成语还是有其他解释?
Writer
monad 可以被认为是一个元组,其中第一个元素表示日志值,而第二个元素表示主要业务值。关键要明白
_
for {
a <- 10.pure[Logged]
_ <- Vector("a", "b", "c").tell
b <- 32.writer(Vector("x", "y", "z"))
} yield a + b
代表“业务价值”,即元组的第二个 ._2
元素,而不是整个元组,因此在组合中此时只忽略业务价值。如果我们对 for-comprehension
WriterT[Id, Vector[String], Int](Vector(), 10).flatMap { (a: Int) =>
WriterT[Id, Vector[String], Unit](Vector("a", "b", "c"), ()).flatMap { (_: Unit) =>
WriterT[Id, Vector[String], Int](Vector("x", "y", "z"), 32).map { (b: Int) =>
a + b
}
}
}
这样我们就看不到任何不寻常的事情发生;参数 (_: Unit)
根本没有在 (_: Unit) => body
的正文中使用。现在让我们也看看 flatMap
def flatMap[U](
f: V => WriterT[F, L, U]
)(implicit flatMapF: FlatMap[F], semigroupL: Semigroup[L]): WriterT[F, L, U] =
WriterT {
flatMapF.flatMap(run) { lv =>
flatMapF.map(f(lv._2).run) { lv2 =>
(semigroupL.combine(lv._1, lv2._1), lv2._2)
}
}
}
很少有东西会立即弹出
- 元组表示法
._1
和._2
semigroupL.combine(lv._1, lv2._1)
f(lv._2)
我们看到了如何使用半群来组合日志,日志是元组的第一个元素。在我们的例子中分析 f(lv._2)
,我们有 lv._2 = ()
和 f
是函数 (_: Unit) => body
,其中参数 (_: Unit)
根本没有在 body
中使用。
一般来说,flatMap
的特殊定义赋予了 monad 特有的力量。在 Writer
的情况下,这种能力允许它在我们沿着计算链前进时透明地组合日志。
作为旁注,正如 Luis 所说,这里没有 side 效应发生。在下面的句子
中考虑术语效果的函数式编程意义 - Identity monad encodes the effect of having no effect
- IO monad encodes the effect of having a side-effect
- Option monad encodes the effect of having optionality
effect 的语义由 flatMap
的实现编码。