Skip to content

dragisak/modeling-with-free

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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)

Releases

No releases published

Packages

No packages published

Languages