在Scala中的免费Monad中堆叠monadic效果

Gab*_*lla 20 scala free-monad scala-cats

我正在学习Scala中的Free monad,我已经汇总了一个代数的简单例子,我可以使用猫将其升级为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]]
}
Run Code Online (Sandbox Code Playgroud)

我可以像使用它一样

def app = for {
  c <- consultation.Create(Consultation("123", "A consultation"))
  _ <- consultation.Get(c._id)
} yield ()

def interpreters = ConsultationInterpreter or UserInterpreter
app.foldMap(interpreters)
Run Code Online (Sandbox Code Playgroud)

当从提升ConsultationOpFree隐式执行.

(缺少很多细节,完整的工作实现在这里: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 ()
Run Code Online (Sandbox Code Playgroud)

但它看起来很丑,而且感觉不对.

使用免费monad时,如果有的话,有什么美化方式可以叠加monadic效果?

lam*_*sta 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 ()
Run Code Online (Sandbox Code Playgroud)

恕我直言,这比 monad 变压器替代方案干净得多。请注意,您可能需要一些其他的import并稍微修改代码,我没有尝试,但概念是:使用遍历。