scala - cat.data.WriterT 的理解中忽略的参数
问题描述
我正在和猫一起经历scala。在Writer
($4.7.2, p. 111) 的示例中,使用了以下助于理解:
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
元素,而不是整个元组,所以在组合中此时只忽略业务价值。如果我们对理解不加糖,也许会有所帮助
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)
我们看到 semigroup 如何用于组合作为元组的第一个元素的日志。在我们的例子中分析f(lv._2)
我们有lv._2 = ()
并且f
是函数(_: Unit) => body
,其中参数(_: Unit)
根本没有在body
.
一般来说,特定的定义flatMap
是赋予 monad 特有的力量的原因。在这种情况下,Writer
它允许它在我们沿着计算链进行时透明地组合日志。
作为旁注,正如路易斯所说,这里没有副作用发生。考虑以下句子中术语效果的函数式编程意义
- 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
效果的语义由flatMap
.
推荐阅读
- r - 在 material_modal 中渲染 R/Shiny glide 组件
- python - 在不使用python循环的情况下在目录中查找第一个文件
- python - 问题创建 Django 模型
- variables - 是否可以从共享库/dll 外部修改静态变量?
- generics - VHDL:在通用映射中使用类型“时间”
- javascript - 我正在尝试使用带有本地存储的 JavaScript 制作待办事项列表,但是在重新加载任务时不会保存在本地存储中,
- python - auto-py-to-exe, 可执行文件没有在好的终端启动
- vue.js - 如何发送 v-file-input 的内容?
- flutter - 如何在颤动中创建时间线,例如制作插槽或帐户注册
- reactjs - 来自 url 地址的 React、filepond 和默认文件