设为首页 加入收藏

TOP

Cats(2)- Free语法组合,Coproduct-ADT composition(二)
2017-10-10 12:11:55 】 浏览:2052
Tags:Cats Free 语法 组合 Coproduct-ADT composition
无须构建Coproduct

2、catsFreeLeftInjectInstance:Inject[F,Coproduct[F,G,?]]:构建Coproduct结构并将F放在左边

3、catsFreeRightInjectInstance:Inject[F,Coproduct[H,G,?]]:把F注入到已经包含H,G的Coproduct[H,G,?]

有了这三种实例后我们可以根据解析到的隐式实例类型使用inj函数通过Coproduct构建更大的语法集了。我们可以通过implicitly来验证一下Interact和Login语法的Inject隐式实例:

1     val selfInj = implicitly[Inject[Interact,Interact]] 2     type LeftInterLogin[A] = Coproduct[Interact,Login,A] 3     val leftInj = implicitly[Inject[Interact,LeftInterLogin]] 4     type RightInterLogin[A] = Coproduct[Login,LeftInterLogin,A] 5     val rightInj = implicitly[Inject[Interact,RightInterLogin]]

现在我们可以用Inject.inj和Free.liftF把Interact和Login升格成Free[G,A]。G是个类型变量,Interact和Login在Coproduct的最终左右位置由当前Inject隐式实例类型决定:

 1   object ADTs {  2     sealed trait Interact[+A]  3     object Interact {  4       case class Ask(prompt: String) extends Interact[String]  5       case class Tell(msg: String) extends Interact[Unit]  6       type FreeInteract[A] = Free[Interact,A]  7       //def ask(prompt: String): FreeInteract[String] = Free.liftF(Ask(prompt))  8       //def tell(msg: String): FreeInteract[Unit] = Free.liftF(Tell(msg))
 9       def ask[G[_]](prompt: String)(implicit I: Inject[Interact,G]): Free[G,String] =
10  Free.liftF(I.inj(Ask(prompt))) 11       def tell[G[_]](msg: String)(implicit I: Inject[Interact,G]): Free[G,Unit] =
12  Free.liftF(I.inj(Tell(msg))) 13  } 14 
15     sealed trait Login[+A] 16     object Login { 17       type FreeLogin[A] = Free[Login,A] 18       case class Authenticate(user: String, pswd: String) extends Login[Boolean] 19       //def authenticate(user: String, pswd: String): FreeLogin[Boolean] = 20       // Free.liftF(Authenticate(user,pswd))
21       def authenticate[G[_]](user: String, pswd: String)(implicit I: Inject[Login,G]): Free[G,Boolean] =
22  Free.liftF(I.inj(Authenticate(user,pswd))) 23     }

现在我们可以用混合语法的DSL来编程了:

 1   object DSLs {  2  import ADTs._  3  import Interact._  4  import Login._  5     val interactDSL: FreeInteract[Unit] = for {  6       first <- ask("What's your first name?")  7       last <- ask("What's your last name?")  8       _ <- tell(s"Hello, $first $last!")  9     } yield() 10 
11     val loginDSL: FreeLogin[Boolean] = for { 12       login <- authenticate("Tiger","123") 13     } yield login 14 
15     type InteractLogin[A] = Coproduct[Interact,Login,A] 16     val interactLoginDSL: Free[InteractLogin,Boolean] = for { 17       uid <- ask[InteractLogin]("Enter your User ID:") 18       pwd <- ask[InteractLogin]("Enter your Password:") 19       aut <- authenticate[InteractLogin](uid,pwd) 20     } yield aut 21   }

在interactLoginDSL里所有ADT通过Inject隐式实例都被自动升格成统一的Free[Coproduct[Interact,Login,A]]。

interactLogin的功能实现方式之一示范如下:

 1   object IMPLs {  2     import cats.{Id,~>}  3  import ADTs._,Interact._,Login._  4  import DSLs._  5     object InteractConsole extends (Interact ~> Id) {  6       def apply[A](ia: Interact[A]): Id[A] = ia match {  7         case Ask(p) => {println(p); readLine}  8         case Tell(m) => println(m)  9  } 10  } 11     object LoginMock extends (Login ~> Id) { 12       def apply[A](la: Login[A]): Id[A] = la match { 13         case Authenticate(u,p) => if (u == "Tiger" && p == "123") true else false
14  } 15  } 16     val interactLoginMock: (InteractLogin ~> Id) = InteractConsole.or(LoginMock) 17   }

这个interactLoginMock就是一个Interact,Login混合语法程序的功能实现。不过我们还是应该赋予Login一个比较实在点的实现:我们可以用一种依赖注入方式通过Reader数据类型把外部系统的用户密码验证的方法传入:

 1  import Dependenc
首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇scala数据库工具类 下一篇Scala--高阶函数

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目