Scalaz(32)- Free :lift - Monad生产线 企
来源:互联网 发布:多益网络用户中心 编辑:程序博客网 时间:2024/05/16 05:44
在前面的讨论里我们提到自由数据结构就是产生某种类型的最简化结构,www.njtw123.com比如:free monoid, free monad, free category等等。我们也证明了List[A]是个free monoid。我们再看看free monad结构Free的定义:scalaz/Free.scala
/** A free operational monad for some functor `S`. Binding is done using the heap instead of the stack, * allowing tail-call elimination. */www.njtw123.comsealed abstract class Free[S[_], A] {... /** Return from the computation with the given value. */ private[scalaz] case class Return[S[_], A](a: A) extends Free[S, A] /** Suspend the computation with the given suspension. */www.njtw123.com private[scalaz] case class Suspend[S[_], A](a: S[Free[S, A]]) extends Free[S, A]...
我们在上一篇里证明过Free就是free monad,因为Free是个Monad而且它的结构是最简单的了:
1、Free[S[_],A]可以代表一个运算
2、case class Return是一个数据结构。Return(a:A)代表运算结束,运算结果a存放在结构中。www.njtw123.com另一个意义就是Monad.point(a:A),把一个任意A值a升格成Free
3、case class Suspend也是另一个数据结构。Suspend(a: S[Free[S,A]])代表把下一个运算存放在结构中。如果用Monad.join(a: F[F[A]])表示,那么里面的F[A]应该是个Free[S,A],这样我们才可能把运算结束结构Return[S,A](a:A)存放到Suspend中来代表下一步结束运算。
注意,Suspend(a: S[Free[S,A]])是个递归类型,S必须是个Functor,但不是任何Functor,而是map over Free[S,A]的Functor,也就是运算另一个Free[S,A]值。如果这个Free是Return则返回运算结果,如果是Suspend则继续递归运算。
简单来说Free是一个把Functor S[_]升格成Monad的产生器。我们可以用Free.liftF函数来把任何一个Functor升格成Monad。看看Free.liftF的函数款式就知道了:
/** Suspends a value within a functor in a single step. Monadic unit for a higher-order monad. */ def liftF[S[_], A](value: => S[A])(implicit S: Functor[S]): Free[S, A] = Suspend(S.map(value)(Return[S, A]))
liftF可以把一个S[A]升格成Free[S,A]。我们用个例子来证明:
1 package Exercises 2 import scalaz._ 3 import Scalaz._ 4 import scala.language.higherKinds 5 import scala.language.implicitConversions 6 object freelift { 7 trait Config[+A] { 8 def get: A 9 }10 object Config {11 def apply[A](a: A): Config[A] = new Config[A] { def get = a}12 implicit val configFunctor = new Functor[Config] {13 def map[A,B](ca: Config[A])(f: A => B) = Config[B](f(ca.get))14 }15 }16 17 val freeConfig = Free.liftF(Config("hi config")) //> freeConfig : scalaz.Free[Exercises.freelift.Config,String] = Suspend(Exercises.freelift$Config$$anon$2@d70c109)www.njtw123.com
在上面的例子里Config是个运算A值的Functor。我们可以用Free.liftF把Config(String)升格成Free[Config,String]。实际上我们可以把这个必须是Functor的门槛取消,因为用Coyoneda就可以把任何F[A]拆解成Coyoneda[F,A],而Coyoneda天生是个Functor。我们先看个无法实现map函数的F[A]:
1 trait Interact[+A] //Console交互www.njtw123.com2 //println(prompt: String) then readLine 返回String3 case class Ask(prompt: String) extends Interact[String]4 //println(msg: String) 不反回任何值5 case class Tell(msg: String) extends Interact[Unit]
由于Ask和Tell都不会返回泛类值,所以无需或者无法实现map函数,Interact[A]是个不是Functor的高阶类。我们必须把它转成Coyoneda提供给Free产生Monad:
1 Free.liftFC(Tell("hello")) //> res0: scalaz.Free.FreeC[Exercises.freelift.Interact,Unit] = Suspend(scalaz.Coyoneda$$anon$22@71423665)2 Free.liftFC(Ask("how are you")) //> res1: scalaz.Free.FreeC[Exercises.freelift.Interact,String] = Suspend(scalaz.Coyoneda$$anon$22@20398b7c)
我们看看liftFC函数定义:
/** A version of `liftF` that infers the nested type constructor. */ def liftFU[MA](value: => MA)(implicit MA: Unapply[Functor, MA]): Free[MA.M, MA.A] = liftF(MA(value))(MA.TC) /** A free monad over a free functor of `S`. */ def liftFC[S[_], A](s: S[A]): FreeC[S, A] = liftFU(Coyoneda lift s)
Coyoneda lift s 返回结果Coyoneda[S,A], liftFU用Unapply可以把Coyoneda[S,A]转化成S[A]并提供给liftF。www.njtw123.com看看Unapply这段:
/**Unpack a value of type `M0[A0, B0]` into types `[a]M0[a, B0]` and `A`, given an instance of `TC` */ implicit def unapplyMAB1[TC[_[_]], M0[_, _], A0, B0](implicit TC0: TC[({type λ[α] = M0[α, B0]})#λ]): Unapply[TC, M0[A0, B0]] { type M[X] = M0[X, B0] type A = A0 } = new Unapply[TC, M0[A0, B0]] { type M[X] = M0[X, B0] type A = A0 def TC = TC0 def leibniz = refl } /**Unpack a value of type `M0[A0, B0]` into types `[b]M0[A0, b]` and `B`, given an instance of `TC` */ implicit def unapplyMAB2[TC[_[_]], M0[_, _], A0, B0](implicit TC0: TC[({type λ[α] = M0[A0, α]})#λ]): Unapply[TC, M0[A0, B0]] { type M[X] = M0[A0, X] type A = B0 } = new Unapply[TC, M0[A0, B0]] { type M[X] = M0[A0, X] type A = B0 def TC = TC0 def leibniz = refl }
好了。但是又想了想,一个是Functor的Interact又是怎样的呢?那Ask必须返回一个值,www.njtw123.com而这个值应该是个Free,实际上是代表下一个运算:
1 package Exercises 2 import scalaz._ 3 import Scalaz._ 4 import scala.language.higherKinds 5 object interact { 6 trait Interact[+A] 7 case class Ask[Next](prompt: String, n: String => Next) extends Interact[Next] 8 case class Tell[Next](msg: String, n: Next) extends Interact[Next] 9 10 object interFunctor extends Functor[Interact] {11 def map[A,B](ia: Interact[A])(f: A => B): Interact[B] = ia match {12 case Tell(m,n) => Tell(m, f(n))13 case g: Ask[A] => Ask[B](g.prompt, g.n andThen f)14 }15 }
所以Ask返回Next类型值,应该是个Free,代表下一个运算。
- Scalaz(32)- Free :lift - Monad生产线 企
- Scalaz(32)- Free :lift - Monad生产线
- 泛函编程(30)-泛函IO:Free Monad-Monad生产线
- Scalaz(25)- Monad: Monad Transformer-叠加Monad效果
- Scalaz(41)- Free :IO Monad-Free特定版本的FP语法
- Scalaz(19)- Monad: \/ - Monad 版本的 Either
- Scalaz(11)- Monad:你存在的意义
- Scalaz(12)- Monad:再述述flatMap,顺便了解MonadPlus
- Scalaz(13)- Monad:Writer - some kind of logger
- Scalaz(28)- ST Monad :FP方式适用变量
- Scalaz(16)- Monad:依赖注入-Dependency Injection By Reader Monad
- Scalaz(17)- Monad:泛函状态类型-State Monad
- Scalaz(29)- Free :Coyoneda - Functor for free
- Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern
- Scalaz(14)- Monad:函数组合-Kleisli to Reader
- Scalaz(15)- Monad:依赖注入-Reader besides Cake
- Scalaz(20)-Monad: Validation-Applicative版本的Either
- Scalaz(18)- Monad: ReaderWriterState-可以是一种简单的编程语言
- php quickSort_快速排序
- IOS 中控件相对坐标
- Android LayoutInflater源码分析及使用(一)
- Spring源码解析之初始化
- 例题9-5 UVA 12563 Jin Ge Jin Qu [h]ao (01 背包)
- Scalaz(32)- Free :lift - Monad生产线 企
- 解密module_init
- Hadoop 系统的存储引擎和在线事务处理
- MPU6050的深度解析请看:
- Oracle linux 安装 Oracle 11G 报错解决 error: "net.bridge.bridge-nf-call-ip6tables" is an unknown key
- Android Volley完全解析(一),初识Volley的基本用法
- GitHub 上排名前 100 的 IOS 开源库简介
- Android 实现不同样式风格的CharSequence
- HTTP