Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stacking monadic effects in a Free Monad in Scala

I'm learning about the Free monad in Scala, and I've put together a simple example of algebra that I can lift into a Free monad using cats.

Here's my algebra

sealed trait ConsultationOp[A]
object consultation {
  case class Create(c: Consultation) extends ConsultationOp[Unit]
  case class Get(s: ConsultationId) extends ConsultationOp[Option[Consultation]]
}

And I'm able to use it like

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

def interpreters = ConsultationInterpreter or UserInterpreter
app.foldMap(interpreters)

Where the lifting from ConsultationOp to Free is performed implicitly.

(there's a lot of details missing, the full working implementation is here: https://github.com/gabro/free-api)

So far so good, but what if I need to extract the optional value returned by consultation.Get.

The first thing that comes to mind is a monad transformer, i.e. something like

def app = for {
  c <- consultation.Create(Consultation("123", "A consultation")).liftM[OptionT]
  d <- OptionT(consultation.Get(c._id))
  _ <- doSomethingAConsultation(d)
} yield ()

but it looks ugly, and it doesn't feel right.

What's the glorified way - if any - of stacking monadic effects when using a Free monad?

like image 392
Gabriele Petronella Avatar asked Sep 24 '15 15:09

Gabriele Petronella


1 Answers

The common way I see recurring in these cases is to use traverse, so you could change your code along the lines of:

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 ()

Which, imho, is much cleaner than the monad transformer alternative. Note that you could need some other import and slightly modify the code, I didn't try it, but the concept is: use traverse.

like image 98
lambdista Avatar answered Oct 31 '22 22:10

lambdista