1 import cats.data.Coproduct 2 import cats.free.{Free, Inject} 3 object FreeModules { 4 object ADTs { 5 sealed trait Interact[+A] 6 object Interact { 7 case class Ask(prompt: String) extends Interact[String] 8 case class Tell(msg: String) extends Interact[Unit] 9 type FreeInteract[A] = Free[Interact,A] 10 //def ask(prompt: String): FreeInteract[String] = Free.liftF(Ask(prompt)) 11 //def tell(msg: String): FreeInteract[Unit] = Free.liftF(Tell(msg))
12 def ask[G[_]](prompt: String)(implicit I: Inject[Interact,G]): Free[G,String] =
13 Free.liftF(I.inj(Ask(prompt))) 14 def tell[G[_]](msg: String)(implicit I: Inject[Interact,G]): Free[G,Unit] =
15 Free.liftF(I.inj(Tell(msg))) 16 } 17
18 sealed trait Login[+A] 19 object Login { 20 type FreeLogin[A] = Free[Login,A] 21 case class Authenticate(user: String, pswd: String) extends Login[Boolean] 22 //def authenticate(user: String, pswd: String): FreeLogin[Boolean] = 23 // Free.liftF(Authenticate(user,pswd))
24 def authenticate[G[_]](user: String, pswd: String)(implicit I: Inject[Login,G]): Free[G,Boolean] =
25 Free.liftF(I.inj(Authenticate(user,pswd))) 26 } 27
28 sealed trait Auth[+A] 29 object Auth { 30 case class Authorize(uid: String) extends Auth[Boolean] 31 def authorize[G[_]](uid:String)(implicit I: Inject[Auth,G]): Free[G,Boolean] =
32 Free.liftF(I.inj(Authorize(uid))) 33 } 34 val selfInj = implicitly[Inject[Interact,Interact]] 35 type LeftInterLogin[A] = Coproduct[Interact,Login,A] 36 val leftInj = implicitly[Inject[Interact,LeftInterLogin]] 37 type RightInterLogin[A] = Coproduct[Login,LeftInterLogin,A] 38 val rightInj = implicitly[Inject[Interact,RightInterLogin]] 39 } 40
41 object DSLs { 42 import ADTs._ 43 import Interact._ 44 import Login._ 45 val interactDSL: FreeInteract[Unit] = for { 46 first <- ask("What's your first name?") 47 last <- ask("What's your last name?") 48 _ <- tell(s"Hello, $first $last!") 49 } yield() 50
51 val loginDSL: FreeLogin[Boolean] = for { 52 login <- authenticate("Tiger","123") 53 } yield login 54
55 type InteractLogin[A] = Coproduct[Interact,Login,A] 56 val interactLoginDSL: Free[InteractLogin,Boolean] = for { 57 uid <- ask[InteractLogin]("Enter your User ID:") 58 pwd <- ask[InteractLogin]("Enter your Password:") 59 aut <- authenticate[InteractLogin](uid,pwd) 60 } yield aut 61 val userLoginDSL: Free[InteractLogin,Unit] = for { 62 uid <- ask[InteractLogin]("Enter your User ID:") 63 pwd <- ask[InteractLogin]("Enter your Password:") 64 aut <- authenticate[InteractLogin](uid,pwd) 65 _ <- if (aut) tell[InteractLogin](s"Hello $uid") 66 else tell[InteractLogin]("Sorry, who are you?") 67 } yield() 68 /* import Auth._ 69 type Permit[A] = Coproduct[Auth,InteractLogin,A] 70 val userPermitDSL: Free[Permit,Unit] = for { 71 uid <- ask[Permit](&qu