我正在学习Scala中的免费monad,并且我已经汇总了一个代数的简单例子,我可以使用猫将其升级为免费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效果?
答案 0 :(得分:3)
我在这些情况下看到的常见方法是使用 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 ()
其中,imho比monad变压器更清洁。
请注意,您可能需要一些其他import
并略微修改代码,我没有尝试过,但概念是:使用遍历。