设为首页 加入收藏

TOP

Cats(2)- Free语法组合,Coproduct-ADT composition(三)
2017-10-10 12:11:55 】 浏览:2049
Tags:Cats Free 语法 组合 Coproduct-ADT composition
ies._
2 import cats.data.Reader 3 type ReaderPass[A] = Reader[PasswordControl,A] 4 object LoginToReader extends (Login ~> ReaderPass) { 5 def apply[A](la: Login[A]): ReaderPass[A] = la match { 6 case Authenticate(u,p) => Reader{pc => pc.matchUserPassword(u,p)} 7 } 8 } 9 object InteractToReader extends (Interact ~> ReaderPass) { 10 def apply[A](ia: Interact[A]): ReaderPass[A] = ia match { 11 case Ask(p) => {println(p); Reader(pc => readLine)} 12 case Tell(m) => {println(m); Reader(pc => ())} 13 } 14 } 15 val userLogin: (InteractLogin ~> ReaderPass) = InteractToReader or LoginToReader

假设用户密码验证由外部另一个系统负责,PasswordControl是与这个外部系统的界面(interface):

1 object Dependencies { 2  trait PasswordControl { 3  val mapPasswords: Map[String,String] 4  def matchUserPassword(uid: String, pwd: String): Boolean 5  } 6 }

我们用Reader来注入PasswordControl这个外部依赖(dependency injection IOC)。因为Interact和Login结合形成的是一个统一的语句集,所以我们必须进行Interact与?ReaderPass对应。下面我们先构建一个PasswordControl对象作为模拟数据,然后试运行:

 1 object catsComposeFree extends App {  2  import Dependencies._  3  import FreeModules._  4  import DSLs._  5  import IMPLs._  6   object UserPasswords extends PasswordControl {  7     override val mapPasswords: Map[String, String] = Map(  8       "Tiger" -> "123",  9       "John" -> "456"
10  ) 11     override def matchUserPassword(uid: String, pwd: String): Boolean =
12       mapPasswords.getOrElse(uid,pwd+"!") == pwd 13  } 14 
15   val r = interactLoginDSL.foldMap(userLogin).run(UserPasswords) 16  println(r) 17 
18 }

运算结果:

 1 Enter your User ID:  2 Tiger  3 Enter your Password:  4 123
 5 true
 6 ...  7 Enter your User ID:  8 Chan  9 Enter your Password: 10 123
11 false

我们再用这个混合的DSL编个稍微完整点的程序:

1     val userLoginDSL: Free[InteractLogin,Unit] = for { 2       uid <- ask[InteractLogin]("Enter your User ID:") 3       pwd <- ask[InteractLogin]("Enter your Password:") 4       aut <- authenticate[InteractLogin](uid,pwd) 5       _ <- if (aut) tell[InteractLogin](s"Hello $uid") 6            else tell[InteractLogin]("Sorry, who are you?") 7     } yield()

运算这个程序不需要任何修改:

1   //val r = interactLoginDSL.foldMap(userLogin).run(UserPasswords) 2   //println(r)
3   userLoginDSL.foldMap(userLogin).run(UserPasswords)

现在结果变成了:

 1 Enter your User ID:  2 Tiger  3 Enter your Password:  4 123
 5 Hello Tiger  6 ...  7 Enter your User ID:  8 CHAN  9 Enter your Password: 10 123
11 Sorry, who are you?

如果我们在这两个语法的基础上再增加一个模拟权限管理的语法,ADT设计如下:

1     sealed trait Auth[+A] 2     object Auth { 3       case class Authorize(uid: String) extends Auth[Boolean] 4       def authorize[G[_]](uid:String)(implicit I: Inject[Auth,G]): Free[G,Boolean] =
5  Free.liftF(I.inj(Authorize(uid))) 6     }

假设实际的权限管理依赖外部系统,我们先定义它的界面:

 1 object Dependencies {  2  trait PasswordControl {  3  val mapPasswords: Map[String,String]  4  def matchUserPassword(uid: String, pwd: String): Boolean  5  }  6  trait PermControl {  7  val mapAuthorized: Map[String,Boolean]  8  def authorized(uid: String): Boolean  9  } 10 }

再用三种语法合成的DSL来编一段程序:

 1  import Auth._  2     type Permit[A] = Coproduct[Auth,InteractLogin,A]  3     val userPermitDSL: Free[Permit,Unit] = for {  4       uid <- ask[Permit]("Enter your User ID:")  5       pwd <- ask[Permit]("Enter your Password:")  6       auth <- authenticate[Permit](uid,pwd)  7       perm <- if(auth) authorize[Permit](uid)  8               else Free.pure[Permit,Boolean](false)  9       _ <- if (perm) tell[Permit](s"Hell
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇scala数据库工具类 下一篇Scala--高阶函数

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目