Created
December 16, 2016 22:45
-
-
Save mandubian/4365085d947d609b18af95df39ea569b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package papersplease2 | |
import freek._ | |
import cats.free.Free | |
import cats.{~>, Id} | |
import cats.data.Xor | |
case class Person(name: String) | |
case class Picture(person: Person) | |
case class Passedport(person: Person) | |
case class FingerPrint(person: Person) | |
sealed trait Log[A] | |
object Log { | |
final case class Info(msg: String) extends Log[Unit] | |
final case class Error(msg: String) extends Log[Unit] | |
} | |
sealed trait PictureError | |
sealed trait PictureService[A] | |
object PictureService { | |
final case class Shoot(dude: Person) extends PictureService[Xor[PictureError, Picture]] | |
} | |
sealed trait PersonService[A] | |
object PersonService { | |
final case class AskPassedport(dude: Person) extends PersonService[Option[Passedport]] | |
final case class AskFingerPrint(dude: Person) extends PersonService[Option[FingerPrint]] | |
} | |
sealed trait PoliceService[A] | |
object PoliceService { | |
final case class Eject(dude: Person) extends PoliceService[Unit] | |
} | |
sealed trait IDResult | |
case object OK extends IDResult | |
case object KO extends IDResult | |
sealed trait IDError | |
sealed trait IDService[A] | |
object IDService { | |
final case class Check(pic: Picture, passedport: Passedport, fingers: FingerPrint) extends IDService[Xor[IDError, IDResult]] | |
} | |
sealed trait PPResult | |
final case object Passed extends PPResult | |
final case object Rejected extends PPResult | |
sealed trait Logic[A] | |
object Logic { | |
final case class Dystopian(person: Person) extends Logic[PPResult] | |
} | |
object PapersPlease { | |
import cats.instances.option._ | |
// import cats.instances.list._ | |
// import cats.syntax.traverse._ | |
type PRG = Log :|: PictureService :|: PersonService :|: PoliceService :|: IDService :|: Logic :|: NilDSL | |
val PRG = DSL.Make[PRG] | |
type O = Xor[IDError, ?] :&: Xor[PictureError, ?] :&: Option :&: Bulb | |
def logic(dude: Person): Free[PRG.Cop, O#Layers[PPResult]] = (for { | |
pic <- PictureService.Shoot(dude) .freek[PRG].onionT[O] | |
passedport <- PersonService.AskPassedport(dude) .freek[PRG].onionT[O] | |
fingers <- PersonService.AskFingerPrint(dude) .freek[PRG].onionT[O] | |
status <- IDService.Check(pic, passedport, fingers) .freek[PRG].onionT[O] | |
res <- status match { | |
case OK => for { | |
_ <- Log.Info(s"$dude OK") .freek[PRG].onionT[O] | |
} yield (Passed:PPResult) | |
case KO => for { | |
_ <- Log.Error(s"$dude KO") .freek[PRG].onionT[O] | |
res <- Logic.Dystopian(dude) .freek[PRG].onionT[O] | |
_ <- PoliceService.Eject(dude) .freek[PRG].onionT[O] | |
} yield (res) | |
} | |
} yield (res)).value | |
} | |
sealed trait SecretPoliceService[A] | |
object SecretPoliceService { | |
case object Deny extends SecretPoliceService[PPResult] | |
case object Abduct extends SecretPoliceService[PPResult] | |
} | |
object ErrorManager { | |
type PRG = Log :|: SecretPoliceService :|: NilDSL | |
val PRG = DSL.Make[PRG] | |
def apply(dude: Person, res: PapersPlease.O#Layers[PPResult]): Free[PRG.Cop, PPResult] = | |
res match { | |
case Xor.Left(idError) => SecretPoliceService.Deny.freek[PRG] | |
case Xor.Right(Xor.Left(picError)) => SecretPoliceService.Deny.freek[PRG] | |
case Xor.Right(Xor.Right(res)) => res match { | |
case Some(res) => Free.pure[PRG.Cop, PPResult](Passed) | |
case None => SecretPoliceService.Abduct.freek[PRG] | |
} | |
} | |
} | |
object PapersPleaseWithErrorManager { | |
type PRG = PapersPlease.PRG :||: ErrorManager.PRG | |
val PRG = DSL.Make[PRG] | |
def logic(dude: Person): Free[PRG.Cop, PPResult] = for { | |
res0 <- PapersPlease.logic(dude).expand[PRG] | |
res1 <- ErrorManager(dude, res0).expand[PRG] | |
} yield (res1) | |
} | |
sealed trait Foo3[A] | |
final case class Bar31(s: String) extends Foo3[Float] | |
object Interpreters { | |
val Log2Id = new (Log ~> Id) { | |
def apply[A](l: Log[A]): Id[A] = l match { | |
case Log.Info(msg) => println(s"[info] $msg") | |
case Log.Error(msg) => println(s"[error] $msg") | |
} | |
} | |
val PictureService2Id = new (PictureService ~> Id) { | |
def apply[A](l: PictureService[A]): Id[A] = l match { | |
case PictureService.Shoot(p) => Xor.Right(Picture(p)) | |
} | |
} | |
import fs2.Task | |
val Log2Task0 = new (Log ~> Task) { | |
def apply[A](l: Log[A]): Task[A] = l match { | |
case Log.Info(msg) => Task.now(println(s"[info] $msg")) | |
case Log.Error(msg) => Task.now(println(s"[error] $msg")) | |
} | |
} | |
class Camera { | |
def shoot: Task[Picture] = ??? | |
} | |
class PictureService2Task( | |
camera: Camera | |
) extends (PictureService ~> Task) { | |
def apply[A](l: PictureService[A]): Task[A] = l match { | |
case PictureService.Shoot(p) => camera.shoot.map(Xor.Right(_)) | |
} | |
} | |
val Log2Task: Log ~> Task = ??? | |
val PictureService2Task: PictureService ~> Task = ??? | |
val PersonService2Task: PersonService ~> Task = ??? | |
val PoliceService2Task: PoliceService ~> Task = ??? | |
val IDService2Task: IDService ~> Task = ??? | |
val Logic2Task: Logic ~> Task = ??? | |
val SecretPoliceService2Task: SecretPoliceService ~> Task = ??? | |
val interpreter = Log2Task :&: PictureService2Task :&: PersonService2Task :&: PoliceService2Task :&: IDService2Task :&: Logic2Task :&: SecretPoliceService2Task | |
val interpreter2 = SecretPoliceService2Task :&: interpreter | |
val dude: Person = ??? | |
val program: Free[PapersPleaseWithErrorManager.PRG.Cop, PPResult] = PapersPleaseWithErrorManager.logic(dude) | |
implicit val monad: cats.Monad[Task] = ??? | |
val res: Task[PPResult] = program.interpret(interpreter) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the example.
I have this example:
I'm getting
could not find implicit value for parameter lifter2: freek.Lifter2.Aux[List[Test.Hobby],Test.O,Test.Hobby]
compile error.Any idea what i'm missing here?