在 Scala 的 Free Monad 中堆叠 monadic 效果
Stacking monadic effects in a Free Monad in Scala
我正在学习 Scala 中的 Free monad,我整理了一个简单的代数示例,我可以使用 cats 将其提升到 Free monad。
这是我的代数
sealed trait ConsultationOp[A]
object consultation {
case class Create(c: Consultation) extends ConsultationOp[Unit]
case class Get(s: ConsultationId) extends ConsultationOp[Option[Consultation]]
}
而且我可以像这样使用它
def app = for {
c <- consultation.Create(Consultation("123", "A consultation"))
_ <- consultation.Get(c._id)
} yield ()
def interpreters = ConsultationInterpreter or UserInterpreter
app.foldMap(interpreters)
从 ConsultationOp
到 Free
的提升是隐式执行的。
(缺少很多细节,完整的工作实现在这里:https://github.com/gabro/free-api)
到目前为止一切顺利,但如果我需要提取 consultation.Get
返回的可选值怎么办。
首先想到的是 monad 转换器,即类似
def app = for {
c <- consultation.Create(Consultation("123", "A consultation")).liftM[OptionT]
d <- OptionT(consultation.Get(c._id))
_ <- doSomethingAConsultation(d)
} yield ()
但是长得丑,感觉也不对
使用免费 monad 时堆叠 monadic 效果的最佳方式是什么?
我看到在这些情况下反复出现的常见方法是使用 traverse,因此您可以按照以下行更改代码:
import cats.syntax.traverse._
import cats.instances.option._
// ...
def app = for {
c <- consultation.Create(Consultation("123", "A consultation"))
d <- consultation.Get(c._id)
_ <- d.traverseU(doSomethingAConsultation(_))
} yield ()
恕我直言,这比 monad transformer 替代方案要干净得多。
请注意,您可能需要一些其他 import
并稍微修改代码,我没有尝试过,但概念是:使用 traverse.
我正在学习 Scala 中的 Free monad,我整理了一个简单的代数示例,我可以使用 cats 将其提升到 Free monad。
这是我的代数
sealed trait ConsultationOp[A]
object consultation {
case class Create(c: Consultation) extends ConsultationOp[Unit]
case class Get(s: ConsultationId) extends ConsultationOp[Option[Consultation]]
}
而且我可以像这样使用它
def app = for {
c <- consultation.Create(Consultation("123", "A consultation"))
_ <- consultation.Get(c._id)
} yield ()
def interpreters = ConsultationInterpreter or UserInterpreter
app.foldMap(interpreters)
从 ConsultationOp
到 Free
的提升是隐式执行的。
(缺少很多细节,完整的工作实现在这里:https://github.com/gabro/free-api)
到目前为止一切顺利,但如果我需要提取 consultation.Get
返回的可选值怎么办。
首先想到的是 monad 转换器,即类似
def app = for {
c <- consultation.Create(Consultation("123", "A consultation")).liftM[OptionT]
d <- OptionT(consultation.Get(c._id))
_ <- doSomethingAConsultation(d)
} yield ()
但是长得丑,感觉也不对
使用免费 monad 时堆叠 monadic 效果的最佳方式是什么?
我看到在这些情况下反复出现的常见方法是使用 traverse,因此您可以按照以下行更改代码:
import cats.syntax.traverse._
import cats.instances.option._
// ...
def app = for {
c <- consultation.Create(Consultation("123", "A consultation"))
d <- consultation.Get(c._id)
_ <- d.traverseU(doSomethingAConsultation(_))
} yield ()
恕我直言,这比 monad transformer 替代方案要干净得多。
请注意,您可能需要一些其他 import
并稍微修改代码,我没有尝试过,但概念是:使用 traverse.