1 sealed trait Auth[+A]
2 object Auth {
3 case class Authorize(uid: String) extends Auth[Boolean]
4 }
1 object Dependencies { 2 trait PasswordControl { 3 val mapPasswords: Map[String,String] 4 def matchUserPassword(uid: String, pswd: String): Boolean 5 } 6 trait AccessControl { 7 val mapAccesses: Map[String, Boolean] 8 def grandAccess(uid: String): Boolean 9 } 10 trait Authenticator extends PasswordControl with AccessControl 11 }
1 import Dependencies._ 2 type ReaderContext[A] = Reader[Authenticator,A]
1 import Auth._ 2 type PRG3 = Auth :|: PRG //Interact :|: Login :|: NilDSL
3 val PRG3 = DSL.Make[PRG3] 4 val authorizeDSL: Free[PRG3.Cop, Unit] =
5 for { 6 uid <- Ask("Enter your User ID:").freek[PRG3] 7 pwd <- Ask("Enter your Password:").freek[PRG3] 8 auth <- Authenticate(uid,pwd).freek[PRG3] 9 perm <- if (auth) Authorize(uid).freek[PRG3] 10 else Free.pure[PRG3.Cop,Boolean](false) 11 _ <- if (perm) Tell(s"Hello $uid, access granted!").freek[PRG3] 12 else Tell(s"Sorry $uid, access denied!").freek[PRG3] 13 } yield()
1 val readerAuth = new (Auth ~> ReaderContext) { 2 def apply[A](aa: Auth[A]): ReaderContext[A] = aa match { 3 case Authorize(u) => Reader {ac => ac.grandAccess(u)} 4 } 5 } 6 val userAuth = readerAuth :&: userInteractLogin
1 import Dependencies._ 2 object AuthControl extends Authenticator { 3 override val mapPasswords = Map( 4 "Tiger" -> "1234", 5 "John" -> "0000"
6 ) 7 override def matchUserPassword(uid: String, pswd: String) =
8 mapPasswords.getOrElse(uid, pswd+"!") == pswd 9
10 override val mapAccesses = Map ( 11 "Tiger" -> true, 12 "John" -> false
13 ) 14 override def grandAccess(uid: String) =
15 mapAccesses.getOrElse(uid, false) 16 } 17
18 // interactLoginDSL.interpret(userInteractLogin).run(AuthControl)
19 authorizeDSL.interpret(userAuth).run(AuthControl)
1 Enter your User ID: 2 Tiger 3 Enter your Password: 4 1234
5 Hello Tiger, access granted!
6
7 Process finished with exit code 0
8 ... 9 Enter your User ID: 10 John 11 Enter your Password: 12 0000
13 Sorry John, access denied!
14
15 Process finished with exit code 0
1 import cats.free.Free 2 import cats.{Id, ~>} 3 import cats.data.Reader 4 import demo.app.FreeKModules.ADTs.Auth.Authorize 5 import freek._ 6 object FreeKModules { 7 object ADTs { 8 sealed trait Interact[+A] 9 object Interact { 10 case class Ask(