Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Last active February 18, 2019 13:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuabe/9ec9cdb438c11ae26c8530c5ccb416b5 to your computer and use it in GitHub Desktop.
Save yasuabe/9ec9cdb438c11ae26c8530c5ccb416b5 to your computer and use it in GitHub Desktop.
minimal cake + free monad
import cats.free.Free
import cats.free.Free.liftF
import cats.~>
// domain layer -----------------------------------------------------------
case class Movie(id: Int, title: String)
sealed trait Query[A]
case class GetMovie(id: Int) extends Query[Option[Movie]]
type QueryF[T] = Free[Query, T]
trait MovieRepo {
def getMovie(id: Int): QueryF[Option[Movie]]
}
trait UsesMovieRepo {
val movieRepo: MovieRepo
}
trait MovieService extends UsesMovieRepo {
def getMovie(id: Int): QueryF[Option[Movie]] = movieRepo.getMovie(id)
}
object MovieRepoImpl extends MovieRepo {
def getMovie(id: Int): QueryF[Option[Movie]] = liftF(GetMovie(id))
}
trait MixInMovieRepo {
val movieRepo: MovieRepo = MovieRepoImpl
}
object MovieService extends MovieService with MixInMovieRepo
// application layer -------------------------------------------------
import monix.eval.Task
val db = Map[Int, Movie](42 -> Movie(42, "A Movie"))
def taskInterpreter: Query ~> Task = new (Query ~> Task) {
def apply[A](fa: Query[A]): Task[A] = fa match {
case GetMovie(id) => Task(db.get(id))
}
}
val program = MovieService.getMovie(42).foldMap(taskInterpreter)
// runtime ------------------------------------------------------
import scala.concurrent.duration._
import scala.concurrent.Await
import monix.execution.Scheduler.Implicits.global
Await.result(program.runToFuture, 1.second)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment