Skip to content

Latest commit

 

History

History
64 lines (48 loc) · 2.47 KB

README.md

File metadata and controls

64 lines (48 loc) · 2.47 KB

Modeling Video Store with Free

Build Status Codacy Badge Codacy Badge

Using Freasy and cats Free Monads to model a domain.

Example

Freasy macro allows for very concise code:

  1. Define DSL:

    @free trait VideoRental {
      sealed trait DSL[A]
      type VideoRentalF[A] = Free[DSL, A]
      def addInventory(movie: Movie, qty: Int): VideoRentalF[Set[DVD]]
      def searchForDVD(movie: Movie): VideoRentalF[Option[DVD]]
      def rentDVD(dvd: DVD): VideoRentalF[Unit]
      def returnDVD(dvd: DVD): VideoRentalF[Unit]
    }
  2. Implement service:

    override def interpreter() = new VideoRental.Interp[ErrorOr] {
      override def addInventory(movie: Movie, qty: Int): ErrorOr[Set[DVD]] = ...
      override def searchForDVD(movie: Movie): ErrorOr[Option[DVD]] = ...
      override def rentDVD(dvd: DVD): ErrorOr[Unit] = ...
      override def returnDVD(dvd: DVD): ErrorOr[Unit] = ...
    }

Using Freek

Combine two different Free algebras (as long as they use same return type):

type PRG = Logging.DSL :|: VideoRental.DSL :|: NilDSL
val PRG = DSL.Make[PRG]

val VS = VideoRental.DSL
val LOG = Logging.DSL

// Create program
val program = for {
    _     <- LOG.Info(s"Adding $movie").freek[PRG]
    dvds  <- VS.AddInventory(movie, qty).freek[PRG]
    dvd   = dvds.head
    _     <- LOG.Info(s"Renting $dvd").freek[PRG]
    _     <- VS.RentDVD(dvd).freek[PRG]
    _     <- LOG.Info(s"Returning $dvd").freek[PRG]
    res   <- VS.ReturnDVD(dvd).freek[PRG]
} yield res

// Combine interpreters for VideoRental and Logging
val combinedInterpreter: Interpreter[PRG.Cop, ErrorOr] = StdoutLogging().interpreter :&: InMemory().interpreter

val result = program.interpret(combinedInterpreter)