快捷搜索:
您的位置:AG真人平台下注 > 科学资讯 > cats.Free的类型款式如下,但有多少项目是会选择

cats.Free的类型款式如下,但有多少项目是会选择

2019-12-01 05:39

Free as in freedom

 

Free不论是译作“自由”依然“无偿”对于使用者来说就像是都有益处,但当自身处于开拓者或支付厂家的角度,大概正是“双重规范”了,终究非常少人能像Linus那样Just For Fun,也平昔不人能像Richard Matthew Stallman那样发明“Copyleft”;我们要吃饭。

 1 import cats.free._
 2 import cats.Functor
 3 object catsFree {
 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       
10       def ask(prompt: String): Free[Interact,String] = Free.liftF(Ask(prompt))
11       def tell(msg: String): Free[Interact,Unit] = Free.liftF(Tell(msg))
12 
13 
14       implicit object interactFunctor extends Functor[Interact]  {
15         def map[A,B](ia: Interact[A])(f: A => B): Interact[B] = ???
16       /*   ia match {
17            case Ask(p) => ???
18            case Tell(m) => ???
19         } */
20       }  
21     }
22   }
23   object DSLs {
24     import ADTs._
25     import Interact._
26     val prg: Free[Interact,Unit] = for {
27       first <- ask("What's your first name?")
28       last <- ask("What's your last name?")
29       _ <- tell(s"Hello $first $last")
30     } yield()
31   }

但有多少项目是会选用以开源方式公布呢?强行开源无疑不科学。

测量试验运算:

Licence的拈轻怕重在软件以开源方式透露时显得很关键。如今本国好些个“开源”软件基本秉承的是开源不免费的大旨,从小编的角度这自然未有什么能够指责,只是对于众多的中型Mini团队以来,总是希望能在少年老成款开源免费的软件幼功上做开荒,减弱项目运转阶段的时光。

得出对ADT类型供给结论后,大家随后示范cats的Free编制程序。上面是Free程序的机能实现interpret部分(implementation):

 1  object DSLs {
 2     import ADTs._
 3     import KVStoreA._
 4     def prg: KVStore[Option[Int]] =
 5     for {
 6       _ <- put[Int]("wild-cats", 2)
 7       _ <- mod[Int]("wild-cats", (_   12))
 8       _ <- put[Int]("tame-cats", 5)
 9       n <- get[Int]("wild-cats")
10       _ <- del("tame-cats")
11     } yield n
12   }

  cats是scala的三个新的函数式编制程序工具库,其设计原理基本继承了scalaz:我们都以haskell typeclass的scala版达成。当然,cats在scalaz的根底上从贯彻细节、库协会结商谈调用形式上拓宽了一些优化,所以对客户来讲:cats的根基数据类型、数据布局在职能上与scalaz是大概相同的,大概有局地语法上的改变。与scalaz闻明抽象、复杂的语法表现情势相比较,cats的语法可能更形象、简单直白。在scalaz的学习进度中,大家明白到所谓函数式编程正是monadic Programming:即用monad那样的数据类型来营造程序。而实际上可行的monadic programming正是用Free-Monad编制程序了。因为Free-Monad程序是真的可运转的,也许说是能够实现安全运会转的,因为它能够确定保证在一直的仓库内实现Infiniti运算。大家领略:函数式编制程序方式的运营方式以递归算法为主,flatMap函数本身便是生龙活虎种递归算法。那就预示着monadic programming相当轻巧形成仓库溢出标题(StackOverflowError)。当大家把经常的泛函类型F[A]进级成Free-Monad后就能够丰盛利用Free-Monad安全运会算能力来营造实际可运维的次第了。由于大家在前方已经详细的领会了scalaz的超越46%typeclass,饱含Free,对cats的商量就从Free带头,集中在cats.Free编制程序形式方面。同期,我们得以在应用cats.Free的长河中对cats的其余数据类型实行增加补充领悟。

S是个高阶类,正是风姿浪漫种函数式运算。值得注意的是:以往S不需若是个Functor了。因为Free的二个实例Suspend类型是如此的:

/** Suspend the computation with the given suspension. */
  private final case class Suspend[S[_], A](a: S[A]) extends Free[S, A]
 1     type Prompt = String
 2     type Reply = String
 3     type Message = String
 4     type Tester[A] = Map[Prompt,Reply] => (List[Message],A)
 5     object tester extends (Interact ~> Tester) {
 6       def apply[A](ia: Interact[A]): Tester[A] = ia match {
 7         case Ask(p) => { m => (List(), m(p)) }
 8         case Tell(m) => { _ => (List(m), ()) }
 9       }
10     }
11     import cats.Monad
12     implicit val testerMonad = new Monad[Tester] {
13       override def pure[A](a: A): Tester[A] = _ => (List(),a)
14       override def flatMap[A,B](ta: Tester[A])(f: A => Tester[B]): Tester[B] = m => {
15         val (o1,a1) = ta(m)
16         val (o2,a2) = f(a1)(m)
17         (o1    o2, a2)
18       }
19       override def tailRecM[A,B](a: A)(f: A => Tester[Either[A,B]]): Tester[B] =
20          defaultTailRecM(a)(f)
21     }
22   }

 

/**
   * Same as foldMap but without a guarantee of stack safety. If the recursion is shallow
   * enough, this will work
   */
  final def foldMapUnsafe[M[_]](f: FunctionK[S, M])(implicit M: Monad[M]): M[A] =
    foldMap[M](f)(M, RecursiveTailRecM.create)

那就是说只要运算testWriter呢?我们先得到WriterT的Monad实例: 

1   object ADTs {
2     sealed trait KVStoreA[ A]
3     case class Put[T](key: String, value: T) extends KVStoreA[Unit]
4     case class Get[T](key: String) extends KVStoreA[Option[T]]
5     case class Del(key: String) extends KVStoreA[Unit]
6   }
 1    import cats.data.WriterT
 2     type WF[A] = Map[Prompt,Reply] => A
 3     type WriterTester[A] = WriterT[WF,List[Message],A]
 4     def testerToWriter[A](f: Map[Prompt,Reply] => (List[Message],A)) =
 5     WriterT[WF,List[Message],A](f)
 6     object testWriter extends (Interact ~> WriterTester) {
 7       import Interact._
 8       def apply[A](ia: Interact[A]): WriterTester[A] = ia match {
 9         case Ask(p) => testerToWriter(m => (List(),m(p)))
10         case Tell(m) => testerToWriter(_ => (List(m),()))
11       }
12     }

在此个事例里Interact并非三个Functor,因为咱们鞭长不比得到Interact Functor实例的map函数。先让大家剖判一下Functor的map:

下一场大家制作一些测验数据:

 

 1  object IMPLs {
 2     import ADTs._
 3     import cats.{~>}
 4     import cats.data.State
 5    
 6     type KVStoreState[A] = State[Map[String, Any], A]
 7     val kvsToState: KVStoreA ~> KVStoreState = new (KVStoreA ~> KVStoreState) {
 8       def apply[A](fa: KVStoreA[A]): KVStoreState[A] =
 9         fa match {
10           case Put(key, value) => State { (s:Map[String, Any]) =>
11              (s.updated(key, value),()) }
12           case Get(key) => State { (s:Map[String, Any]) =>
13             (s,s.get(key).asInstanceOf[A]) }
14           case Del(key) => State { (s:Map[String, Any]) =>
15               (s - key, (())) }
16         }
17     }
18   }
 1 import cats.free._
 2 import cats.instances.all._
 3 object catsFreeKVS {
 4   object ADTs {
 5     sealed trait KVStoreA[ A]
 6     case class Put[T](key: String, value: T) extends KVStoreA[Unit]
 7     case class Get[T](key: String) extends KVStoreA[Option[T]]
 8     case class Del(key: String) extends KVStoreA[Unit]
 9     type KVStore[A] = Free[KVStoreA,A]
10     object KVStoreA {
11       def put[T](key: String, value: T): KVStore[Unit] =
12         Free.liftF[KVStoreA,Unit](Put[T](key,value))
13       def get[T](key: String): KVStore[Option[T]] =
14         Free.liftF[KVStoreA,Option[T]](Get[T](key))
15       def del(key: String): KVStore[Unit] =
16         Free.liftF[KVStoreA,Unit](Del(key))
17       def mod[T](key: String, f: T => T): KVStore[Unit] =
18         for {
19           opt <- get[T](key)
20           _ <- opt.map {t => put[T](key,f(t))}.getOrElse(Free.pure(()))
21         } yield()
22     }
23   }
24   object DSLs {
25     import ADTs._
26     import KVStoreA._
27     def prg: KVStore[Option[Int]] =
28     for {
29       _ <- put[Int]("wild-cats", 2)
30       _ <- mod[Int]("wild-cats", (_   12))
31       _ <- put[Int]("tame-cats", 5)
32       n <- get[Int]("wild-cats")
33       _ <- del("tame-cats")
34     } yield n
35   }
36   object IMPLs {
37     import ADTs._
38     import cats.{~>}
39     import cats.data.State
40    
41     type KVStoreState[A] = State[Map[String, Any], A]
42     val kvsToState: KVStoreA ~> KVStoreState = new (KVStoreA ~> KVStoreState) {
43       def apply[A](fa: KVStoreA[A]): KVStoreState[A] =
44         fa match {
45           case Put(key, value) => State { (s:Map[String, Any]) =>
46              (s.updated(key, value),()) }
47           case Get(key) => State { (s:Map[String, Any]) =>
48             (s,s.get(key).asInstanceOf[A]) }
49           case Del(key) => State { (s:Map[String, Any]) =>
50               (s - key, (())) }
51         }
52     }
53   }
54   import ADTs._,DSLs._,IMPLs._
55   val prgRunner = prg.foldMap(kvsToState)
56   prgRunner.run(Map.empty).value
57   
58   import cats.{Monad,RecursiveTailRecM}
59   implicitly[Monad[KVStoreState]]
60   implicitly[RecursiveTailRecM[KVStoreState]]
61 }

 

Interact:

1      implicit object interactFunctor extends Functor[Interact]  {
2         def map[A,B](ia: Interact[A])(f: A => B): Interact[B] = ia match {
3            case Ask(p) => ???
4            case Tell(m) => ???
5         }
6       }

假诺大家用Writer来实现Interact,实际上正是把Ask和Tell都进步成Writer类型。

 

 

当今大家得以用这些DSL来编排KVS程序了: 

DSL程序的效率完毕便是把ADT F[A]对应到实际的命令集G[A],在Free编制程序里用NaturalTransformation ~>来贯彻。注意G[A]必得是个Monad。在上边包车型地铁事例里对应提到是:Interact~>Id,代表直接对应到运算指令println和readLine。大家也能够兑现另三个本子: 

1   import cats.{Monad,RecursiveTailRecM}
2   implicitly[Monad[KVStoreState]]      //> res1: cats.Monad[demo.ws.catsFreeKVS.IMPLs.KVStoreState] = cats.data.StateT Instances$$anon$2@71bbf57e
3   implicitly[RecursiveTailRecM[KVStoreState]]     //> res2: cats.RecursiveTailRecM[demo.ws.catsFreeKVS.IMPLs.KVStoreState] = cats.RecursiveTailRecM$$anon$1@7f13d6e

咱俩再示范一下cats官方文书里关于free monad例子:模拟一个KVStore的put,get,delete成效。ADT设计如下:

 

/**
   * Catamorphism for `Free`.
   *
   * Run to completion, mapping the suspension with the given
   * transformation at each step and accumulating into the monad `M`.
   *
   * This method uses `tailRecM` to provide stack-safety.
   */
  final def foldMap[M[_]](f: FunctionK[S, M])(implicit M: Monad[M], r: RecursiveTailRecM[M]): M[A] =
    r.sameType(M).tailRecM(this)(_.step match {
      case Pure(a) => M.pure(Right(a))
      case Suspend(sa) => M.map(f(sa))(Right(_))
      case FlatMapped(c, g) => M.map(c.foldMap(f))(cc => Left(g(cc)))
    })

 

相应的模仿功用函数设计如下:

 

Free程序的性状是算式(description)/算法(implementation)关怀分离(separation of concern):大家用风姿洒脱组数据类型来模拟少年老成种编制程序语句ADT(algebraic data type),那少年老成组ADT就产生了风度翩翩种定制的编制程序语言DSL(domain specific language)。Free的编制程序部分就是用DSL来叙述程序功效(description of purpose),即算式了。算法即用DSL描述的功用的有板有眼落到实处,能够有八种的功力完结方式。大家先看个简易的DSL:

运算结果意气风发致。

 1       sealed trait FunInteract[NS]
 2       object FunInteract {
 3         case class FunAsk[NS](prompt: String, onInput: String =>  NS) extends FunInteract[NS]
 4         case class FunTell[NS](msg: String, ns: NS) extends FunInteract[NS]
 5         
 6         def funAsk(prompt: String): Free[FunInteract,String] = Free.liftF(FunAsk(prompt,identity))
 7         def funAskInt(prompt: String): Free[FunInteract,Int] = Free.liftF(FunAsk(prompt,_.toInt))
 8         def funTell(msg: String): Free[FunInteract,Unit] = Free.liftF(FunTell(msg,()))
 9         
10         implicit object funInteract extends Functor[FunInteract] {
11            def map[A,NS](fa: FunInteract[A])(f: A => NS) = fa match {
12               case FunAsk(prompt,input) => FunAsk(prompt,input andThen f)
13               case FunTell(msg,ns) => FunTell(msg,f(ns))
14            }
15         }
16       }

cats.Free的项目款式如下:

我们把KVStoreA ADT模拟成对State构造的S调换(mutation),重回State{S=>(S,A卡塔尔(قطر‎}。KVStoreState[A]类型的S参数为immutable.Map[String, Any],所以我们在S调换操作时用immutable map的操作函数来构建新的map重返,标准的pure code。大家来运算一下KVStoreA程序:

1     import ADTs._
2     object iconsole extends (Interact ~> Id) {
3       def apply[A](ia: Interact[A]): Id[A] = ia match {
4          case Ask(p) => {println(p); readLine}
5          case Tell(m) => println(m)
6       }
7     }
8   }

 

今后那八个ADT是有品种参数NS的了:FunAsk[NS],FunTell[NS]。NS代表了ADT当前项目,如FunAsk[Int]、FunTell[String]...,现在那五个ADT都经过项目参数NS产生了可map的靶子了,如FunAsk[String] >>> FunAsk[String], FunAsk[String] >>> FunAsk[Int]...。所以大家能够很流畅的落到实处object funInteract的map函数。可是,一个风趣的场所是:为了实现这种地方调换,要是ADT要求回到操作结果,就非得具有叁个引领状态调换的机制,如FunAsk类型里的onInput: String => NS:它表示funAsk函数重回的结果能够本着下叁个状态。新添函数funAskInt是个很好的自己要作为模范遵守规则:通过再次来到的String结果将气象调换成FunAsk[Int]意况。函数funTell不回来结果,所以FunTell没有动静转变机制。scalaz旧版本Free.Suspend的品类款式是:Suspend[F[Free,A]],那是三个递归类型,内部的Free代表下多个景观。由于大家必需用F.map技能抽出下三个情形,所以F必需是个Functor。大家应当专心到若是ADT是Functor的话会变成Free程序的冗余代码。既然cats.Free对F[A]尚无设置Functor门槛,那么大家理应尽量防止使用Functor。

除了这几个之外必要M是个Monad之外,cats还要求M的RecursiveTailRecM隐式实例。那么如何是RecursiveTailRecM呢:

private[data] sealed trait StateTInstances2 {
  implicit def catsDataMonadForStateT[F[_], S](implicit F0: Monad[F]): Monad[StateT[F, S, ?]] =
    new StateTMonad[F, S] { implicit def F = F0 }

  implicit def catsDataRecursiveTailRecMForStateT[F[_]: RecursiveTailRecM, S]: RecursiveTailRecM[StateT[F, S, ?]] = RecursiveTailRecM.create[StateT[F, S, ?]]

  implicit def catsDataSemigroupKForStateT[F[_], S](implicit F0: Monad[F], G0: SemigroupK[F]): SemigroupK[StateT[F, S, ?]] =
    new StateTSemigroupK[F, S] { implicit def F = F0; implicit def G = G0 }
}

 

 

 

1    implicit val testWriterMonad =  WriterT.catsDataMonadWriterForWriterT[WF,List[Message]]

本条函数无需RecursiveTailRecM。上面我们接收能承保运算安全的艺术来运算tester:首先大家需求Tester类型的Monad和RecursiveTailRecM实例:

sealed abstract class Free[S[_], A] extends Product with Serializable {...}
1  implicit val testWriterRecT = new RecursiveTailRecM[WriterTester]{}
2            //> testWriterRecT  : cats.RecursiveTailRecM[demo.ws.catsFree.IMPLs.WriterTester] = demo.ws.catsFree$$anonfun$main$1$$anon$2@6093dd95
3   val prgRunner = prg.foldMap(testWriter)         //> prgRunner  : demo.ws.catsFree.IMPLs.WriterTester[Unit] = WriterT(<function1>)
4   prgRunner.run(testData)._1.map(println)         //> Hello Tiger Chan
5                                                   //| res0: List[Unit] = List(())
/**
   * Suspend a value within a functor lifting it to a Free.
   */
  def liftF[F[_], A](value: F[A]): Free[F, A] = Suspend(value)

 

接下来创设四个RecursiveTailRecM实例后再用同风华正茂的测量检验数据来运算:

 1     type KVStore[A] = Free[KVStoreA,A]
 2     object KVStoreA {
 3       def put[T](key: String, value: T): KVStore[Unit] =
 4         Free.liftF[KVStoreA,Unit](Put[T](key,value))
 5       def get[T](key: String): KVStore[Option[T]] =
 6         Free.liftF[KVStoreA,Option[T]](Get[T](key))
 7       def del(key: String): KVStore[Unit] =
 8         Free.liftF[KVStoreA,Unit](Del(key))
 9       def mod[T](key: String, f: T => T): KVStore[Unit] =
10         for {
11           opt <- get[T](key)
12           _ <- opt.map {t => put[T](key,f(t))}.getOrElse(Free.pure(()))
13         } yield()
14     }
  1 import cats.free._
  2 import cats.{Functor, RecursiveTailRecM}
  3 object catsFree {
  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 
 10       def ask(prompt: String): Free[Interact,String] = Free.liftF(Ask(prompt))
 11       def tell(msg: String): Free[Interact,Unit] = Free.liftF(Tell(msg))
 12 
 13 
 14       implicit object interactFunctor extends Functor[Interact]  {
 15         def map[A,B](ia: Interact[A])(f: A => B): Interact[B] = ???
 16         /*   ia match {
 17              case Ask(p) => ???
 18              case Tell(m) => ???
 19           } */
 20       }
 21 
 22       sealed trait FunInteract[NS]
 23       object FunInteract {
 24         case class FunAsk[NS](prompt: String, onInput: String =>  NS) extends FunInteract[NS]
 25         case class FunTell[NS](msg: String, ns: NS) extends FunInteract[NS]
 26 
 27         def funAsk(prompt: String): Free[FunInteract,String] = Free.liftF(FunAsk(prompt,identity))
 28         def funAskInt(prompt: String): Free[FunInteract,Int] = Free.liftF(FunAsk(prompt,_.toInt))
 29         def funTell(msg: String): Free[FunInteract,Unit] = Free.liftF(FunTell(msg,()))
 30 
 31         implicit object funInteract extends Functor[FunInteract] {
 32           def map[A,NS](fa: FunInteract[A])(f: A => NS) = fa match {
 33             case FunAsk(prompt,input) => FunAsk(prompt,input andThen f)
 34             case FunTell(msg,ns) => FunTell(msg,f(ns))
 35           }
 36         }
 37       }
 38     }
 39   }
 40   object DSLs {
 41     import ADTs._
 42     import Interact._
 43     val prg: Free[Interact,Unit] = for {
 44       first <- ask("What's your first name?")
 45       last <- ask("What's your last name?")
 46       _ <- tell(s"Hello $first $last")
 47     } yield()
 48   }
 49   object IMPLs {
 50     import cats.{Id,~>}
 51     import ADTs._
 52     import Interact._
 53     object iconsole extends (Interact ~> Id) {
 54       def apply[A](ia: Interact[A]): Id[A] = ia match {
 55         case Ask(p) => {println(p); readLine}
 56         case Tell(m) => println(m)
 57       }
 58     }
 59 
 60     type Prompt = String
 61     type Reply = String
 62     type Message = String
 63     type Tester[A] = Map[Prompt,Reply] => (List[Message],A)
 64     object tester extends (Interact ~> Tester) {
 65       def apply[A](ia: Interact[A]): Tester[A] = ia match {
 66         case Ask(p) => { m => (List(), m(p)) }
 67         case Tell(m) => { _ => (List(m), ()) }
 68       }
 69     }
 70     import cats.Monad
 71     implicit val testerMonad = new Monad[Tester] with RecursiveTailRecM[Tester]{
 72       override def pure[A](a: A): Tester[A] = _ => (List(),a)
 73       override def flatMap[A,B](ta: Tester[A])(f: A => Tester[B]): Tester[B] = m => {
 74         val (o1,a1) = ta(m)
 75         val (o2,a2) = f(a1)(m)
 76         (o1    o2, a2)
 77       }
 78       override def tailRecM[A,B](a: A)(f: A => Tester[Either[A,B]]): Tester[B] =
 79         defaultTailRecM(a)(f)
 80     }
 81     import cats.data.WriterT
 82     import cats.instances.all._
 83     type WF[A] = Map[Prompt,Reply] => A
 84     type WriterTester[A] = WriterT[WF,List[Message],A]
 85     def testerToWriter[A](f: Map[Prompt,Reply] => (List[Message],A)) =
 86       WriterT[WF,List[Message],A](f)
 87     implicit val testWriterMonad =  WriterT.catsDataMonadWriterForWriterT[WF,List[Message]]
 88     object testWriter extends (Interact ~> WriterTester) {
 89       import Interact._
 90       def apply[A](ia: Interact[A]): WriterTester[A] = ia match {
 91         case Ask(p) => testerToWriter(m => (List(),m(p)))
 92         case Tell(m) => testerToWriter(_ => (List(m),()))
 93       }
 94     }
 95   }
 96 
 97   import ADTs._,DSLs._,IMPLs._
 98    val testData = Map("What's your first name?" -> "Tiger",
 99   "What's your last name?" -> "Chan")
100   //val prgRunner = prg.foldMap(tester)
101   //prgRunner(testData)
102   implicit val testWriterRecT = new RecursiveTailRecM[WriterTester]{}
103   val prgRunner = prg.foldMap(testWriter)
104   prgRunner.run(testData)._1.map(println)
105 }

 

1 import ADTs._,DSLs._,IMPLs._
2    val testData = Map("What's your first name?" -> "Tiger",
3   "What's your last name?" -> "Chan")    //> testData  : scala.collection.immutable.Map[String,String] = Map(What's your first name? -> Tiger, What's your last name? -> Chan)
4   val prgRunner = prg.foldMap(tester)    //> prgRunner  : demo.ws.catsFree.IMPLs.Tester[Unit] = <function1>
5   prgRunner(testData)                    //> res0: (List[demo.ws.catsFree.IMPLs.Message], Unit) = (List(Hello Tiger Chan),())

上边是个模拟测量检验:大家用个Map[K,V]来效仿相互影响,K模拟问prompt,V模拟获取回答Input。测验办法是个Function1,输入测量试验数据Map,在List[Message]里重返全体Tell发生的音信。下边提到过Tester[A]必得是个Monad,所以大家兑现了Tester的Monad实例testMonad。实际上 m=>(List,a卡塔尔便是个writer函数。所谓的Writer正是包嵌三个对值pair(L,V卡塔尔(英语:State of Qatar)的Monad,L代表Log,V代表运算值。Writer的特色正是log全部V的演算进度。大家又能够用Writer来完毕那么些tester:

留意一下mod函数:它是由底蕴函数get和put组合而成。大家渴求具备在for内的花色为Free[KVStoreA,?],所以当f函数施用后若是opt造成None时就回来结果Free.pure((卡塔尔卡塔尔,它的类型是:Free[Nothing,Unit],Nothing是KVStoreA的子类。

在cats的StateT.scala里能够找到这段代码:

咱俩无需map就足以把F[A]升格成Free

/**
 * This is a marker type that promises that the method
 * .tailRecM for this type is stack-safe for arbitrary recursion.
 */
trait RecursiveTailRecM[F[_]] extends Serializable {
  /*
   * you can call RecursiveTailRecM[F].sameType(Monad[F]).tailRec
   * to have a static check that the types agree
   * for safer usage of tailRecM
   */
  final def sameType[M[_[_]]](m: M[F]): M[F] = m
}
1   import ADTs._,DSLs._,IMPLs._
2   val prgRunner = prg.foldMap(kvsToState)    //> prgRunner  : demo.ws.catsFreeKVS.IMPLs.KVStoreState[Option[Int]] = cats.data.StateT@2cfb4a64
3   prgRunner.run(Map.empty).value       //> res0: (Map[String,Any], Option[Int]) = (Map(wild-cats -> 14),Some(14))

KVStore:

然则难道无需Monad、RecursiveTailRecM实例了啊?实际上cats已经提供了State的Monad和RecursiveTailRecM实例:

 

 

咱俩再来看看在cats里是怎么样运算Free DSL程序的。相对scalaz来讲,cats的演算函数轻便的多,就四个foldMap,我们来探视它的概念:

自家把上边五个示范的源代码提供在底下:

 

我们用RecursiveTailRecM来作保这几个Monad类型与tailRecM是非常的,这是风流倜傥种运算安全措施,所以在foldMap函数里r.sameType(M).tailRecM保证了tailRecM不会导致StackOverflowError。cats.Free里还应该有生机勃勃种不需求类型安全核实的函数foldMapUnsafe:

 

 

 1     import cats.Monad
 2     implicit val testerMonad = new Monad[Tester] with RecursiveTailRecM[Tester]{
 3       override def pure[A](a: A): Tester[A] = _ => (List(),a)
 4       override def flatMap[A,B](ta: Tester[A])(f: A => Tester[B]): Tester[B] = m => {
 5         val (o1,a1) = ta(m)
 6         val (o2,a2) = f(a1)(m)
 7         (o1    o2, a2)
 8       }
 9       override def tailRecM[A,B](a: A)(f: A => Tester[Either[A,B]]): Tester[B] =
10         defaultTailRecM(a)(f)
11     }

 

咱俩得以通过State数据结纯代码(pure code)形式来贯彻用immutable map的KVStore:

 

map的机能是用四个函数A => B把F[A]转成F[B]。约等于把讲话状态从F[A]转成F[B],但在Interact的气象里F[B]现已然是显著的Interact[Unit]和Interact[String]二种景况,而map的f是A => B,在地点的演示里我们该怎么施用f来获取那个Interact[B]啊?从地点的亲自去做里大家观看能够得出Ask和Tell那多少个ADT纯粹是为了参照他事他说加以考察ask和tell那四个函数。ask和tell分别重回Free版本的String,Unit结果。能够说:Interact并未改动来下贰个情况的必要。那么只要大家把ADT调节成上面那样啊:

 

 

1   val testData = Map("What's your first name?" -> "Tiger",
2   "What's your last name?" -> "Chan")             //> testData  : scala.collection.immutable.Map[String,String] = Map(What's your first name? -> Tiger, What's your last name? -> Chan)

 大家在scalaz.Free的争辨中并未能详尽地解析在什么样动静下S[_]非得是个Functor。上边我们须求用一些篇幅来解析。

本文由AG真人平台下注发布于科学资讯,转载请注明出处:cats.Free的类型款式如下,但有多少项目是会选择

关键词: ag真人网站 4.1 Mind Cats Scala 编程