@MiloXia
2015-07-03T08:28:46.000000Z
字数 19710
阅读 3058
scala 函数式编程
List(a, b, c, d)
foldRight: 尾元素d 先于 z 施用op; op(a,op(b,op(c,op(d,z)))); 非尾递归
foldLeft: 头元素a 先于 z 施用op; op(op(op(op(z,a),b),c),d); 尾递归
def foldRight[A, B](l :List[A], z: B)(op: (A, B) => B): B = l match {case Nil => zcase h :: t => op(h, foldRight(t, z)(op))}def foldLeft[A, B](l :List[A], z: B)(op: (A, B) => B): B = l match {case Nil => zcase h :: t => foldLeft(t, op(h, z))(op)}println(foldRight(List(1,2,3,4,5), 0)((a, b) => {println(a, b); b + a}))println(foldLeft(List(1,2,3,4,5), 0)((a, b) => {println(a, b); b + a}))
(5,0)(4,5)(3,9)(2,12)(1,14)15(1,0)(2,1)(3,3)(4,6)(5,10)15
trait Either[+E, +A]
E代表异常类型,A代表计算类型
Left代表无法完成计算, Right 代表计算正常完成
case class Employee(name: String, age: Int, salary: Double)def getAge(msg: String, v: Int): Either[String, Int] = if(v <= 18) Left(msg) else Right(v)def getName(msg: String, v: String): Either[String, String] = if(v.isEmpty) Left(msg) else Right(v)def getSalary(msg: String, v: Double): Either[String, Double] = if(v < 0.0) Left(msg) else Right(v)var e1 = for {age <- getAge("invalid age", 26).rightname <- getName("invalid name", "").rightsalary <- getSalary("invalid salary", 10000.0).right} yield Employee(name, age, salary)println(e1)//用map2_s合并错误 monad貌似不行def map2_s[A,B,C](a: Either[String, A],b: Either[String, B])(f: (A, B) => C): Either[String, C] = (a, b) match {case (Left(e), Left(ee)) => Left(e + "," + ee)case (_, Left(e)) => Left(e)case (Left(e), _) => Left(e)case (Right(a), Right(b)) => Right(f(a, b))}// 编译不过// def map3_s[A,B,C,D](a: Either[String, A],b: Either[String, B],c: Either[String, C])(f: (A, B, C) => D): Either[String, D] =// map2_s(a, b)((a, b) => map2_s(c, Right(a,b))((ax, bx) => f(bx._1, bx._2, ax)))def map3_s[A,B,C,D](a: Either[String, A],b: Either[String, B],c: Either[String, C])(f: (A, B, C) => D): Either[String, D] =map2_s(a, map2_s(b, c){(bx, cx) =>(bx, cx)}){(ax, bcx) => f(ax, bcx._1, bcx._2)}val e2 = map2_s(getAge("invalid age", 17), getName("invalid name", ""))((a, b) => map2_s(getSalary("invalid salary", 10000.0), Right(a,b))((ax, bx) => Employee(bx._2, bx._1, ax)))val e3 = map3_s(getName("invalid name", ""), getAge("invalid age", 17), getSalary("invalid salary", 10000.0))((a, b, c) => Employee(a, b, c))println(e2)println(e3)
Left(invalid name)Left(invalid age,invalid name)Left(invalid name,invalid age)
def pair(x: => Int):(Int, Int) = (x, x)println(pair({println("hello");1}))
hellohello(1,1)
参数x的类型是 => Int, 代表x参数是non-strict的。(call-by-name)
non-strict参数每次使用时都会重新计算一次。
从 内部实现机制来解释:这是因为编译器(compiler)遇到non-strict参数时会把一个指针放到调用堆栈里,而不 是惯常的把参数的值放入。
所以每次使用non-strict参数时都会重新计算一下
lazy声明可以解决non- strict参数多次运算问题
def pair2(x: => Int):(Int, Int) = {lazy val lx = x(lx, lx)}println(pair2({println("hello");1}))
hello(1,1)
def inc(i :Int) = i + 1def lazyInc(x: => Int) = 1def pair3(x: => Int) = inc(x) //x被计算def pair4(x: => Int) = lazyInc(inc(x)) //inc(x)不被计算println(pair3({println("hello3");1}))println(pair4({println("hello4");1}))
hello321
call-by-name
求职:在使用的地方就会被求职
class构造函数参数不可以是non-strict,所以要lazy必须传函数() => ???
case class Pair(x : => Int, y : => Int) //编译不过case class Pair(x : () => Int, y : () => Int) {def pairF = (x, y)def pair = (x(), y())}println(Pair(() => 1, () => 2))println(Pair(() => 1, () => 2).pairF)println(Pair(() => 1, () => 2).pair)
Pair(<function0>,<function0>)(<function0>,<function0>)(1,2)
trait Stream[+A]case object Empty extends Stream[Nothing]case class Cons[+A](head: () => A, tail: () => Stream[A]) extends Stream[A]
由于Cons不是普通函数而是一个类,不容许延后计算类参数,所以传入的是一个函数 () => ???
trait Stream[+A] {def uncons: Option[(A, Stream[A])]def isEmpty: Boolean = uncons.isEmpty//otherdef toList: List[A] = {@annotation.tailrecdef go(s: Stream[A], acc: List[A]): List[A] = {s.uncons match {case None => acccase Some((h,t)) => go(t,h :: acc)}}go(this, Nil).reverse}import Stream._def take(n: Int): Stream[A] = {if ( n == 0 ) emptyelseuncons match {case None => emptycase Some((h,t)) => cons({println("take"+h);h},t.take(n-1)) //lazy的 并没真的take 执行uncons时才计算}}def drop(n: Int): Stream[A] = {if (n == 0) thiselse {uncons match {case Some((h,t)) => t.drop(n-1)case _ => this}}}// lazy的foldRightdef foldRight[B](z: B)(op: (A, => B) => B): B = { //op第二个参数是=> B,所以t.foldRight(z)(op)就是延迟计算的uncons match {case None => zcase Some((h,t)) => op({println("fold"+h);h},t.foldRight(z)(op)) //只要不在op里使用b fold就会结束}}// lazy的exists 满足条件p(a) = true 就结束foldRightdef exists(p: A => Boolean): Boolean = {foldRight(false){(a,b) => p(a) || b } //op = (a,b) => p(a) || b ,当p(a) = true时 b不再传给foldRight}def forAll(p: A => Boolean): Boolean = {foldRight(true){(a,b) => p(a) && b}}def filter(p: A => Boolean): Stream[A] = {foldRight(empty[A]){(h,t) => {println("filter"+h);if(p(h)) cons(h,t) else t}} //该表达式,foldRight会执行到底}def map[B](p: A => B): Stream[B] = {foldRight(empty[B]){(h,t) => cons({println("map"+h);p(h)}, t)}}def flatMap_1[B](f: A => Stream[B]): Stream[B] = {foldRight(empty[B]){(h,t) => f(h) #++ t}}def append[B >: A](b: Stream[B]): Stream[B] = {uncons match {case None => bcase Some((h,t)) => cons(h, t.append(b))}}//append简写def #++[B >: A](b: Stream[B]): Stream[B] = append(b)// override def toString = s"Stream(${toList.mkString(",")})" //会导致全部计算一遍,这可不好override def toString = "Stream(lazy...)"}object Stream {def empty[A]: Stream[A] = new Stream[A] { def uncons = None }//采用call-by-name比较好,Cons case class的构造参数会比较难看def cons[A](h: => A, t: => Stream[A]): Stream[A] = new Stream[A] {def uncons = Some((h, t)) /*!!!!!!此时计算*/}def apply[A](as: A*): Stream[A] = {if (as.isEmpty) emptyelse cons(as.head, apply(as.tail: _*))}}def get1 = {println("hello1");1}def get2 = {println("hello2");2}def get3 = {println("hello3");3}println(Stream(1,2,3) take 2)println(Stream(get1,get2,get3) take 2) //打印hello是因为apply 所以Stream只能作为产生器println((Stream(1,2,3) take 2).toList)println("------")println(Stream(1,2,3).foldRight(0)(_+_))println(Stream(1,2,3).foldRight(0)((a, b) => a )) //foldRight 是否lazy和op有关 只要不使用b fold就会结束 在第一层a=1时 op(1, b不计算)=>1println("------")println(Stream(1,2,3).take(2).foldRight(0)(_+_)) //每次foldRight执行uncons时会计算lazy的takeprintln(Stream(1,2,3).exists(_ == 2))println("------")println(Stream(1,2,3).map(_+1).filter(_ % 2 == 0).toList) //只遍历一次
Stream(lazy...)hello1hello2hello3Stream(lazy...)take1take2List(1, 2)------fold1fold2fold36fold11------take1fold1take2fold23fold1fold2true------fold1map1fold2fold2filter2map2fold3fold3filter3map3fold4filter4List(2, 4)
object Stream {...def constant[A](a: A): Stream[A] = cons(a, constant(a))def from(n: Int): Stream[Int] = cons(n, from(n+1))def fibs: Stream[Int] = {def go (prev: Int, cur: Int): Stream[Int] = {cons(prev,go(cur,prev + cur))}go(0,1)}//我们不断重复的在cons。而cons的参数则是算法的实现结果//A为前一个值,S为下一个值def unfold[A,S](z: S)(f: S => Option[(A, S)]): Stream[A] = {f(z) match {case None => emptycase Some((a,s)) => cons(a, unfold(s)(f))}}def constantByUnfold[A](a: A): Stream[A] = unfold(a)(_ => Some((a,a)))def fromByUnfold(s: Int): Stream[Int] = unfold(s)(s => Some(s,s+1))def fibsByUnfold: Stream[Int] = unfold((0,1)){ case (a1,a2) => Some((a1, (a2, a1+a2))) }}println(Stream.constant(1).take(5).toList)println(Stream.from(5).take(5).toList)println(Stream.fibs.take(5).toList)println(Stream.constantByUnfold(1).take(5).toList)println(Stream.fromByUnfold(5).take(5).toList)println(Stream.fibsByUnfold.take(5).toList)
List(1, 1, 1, 1, 1)List(5, 6, 7, 8, 9)List(0, 1, 1, 2, 3)List(1, 1, 1, 1, 1)List(5, 6, 7, 8, 9)List(0, 1, 1, 2, 3)
unfold的工作原理模仿了一种状态流转过程:z是一个起始状态,代表的是一个类型的值。然后用户(caller)再提供一个操作函数f。f的款式是:S => Option[(A,S)],意思是接受一个状态,然后把它转换成一对新的A值和新的状态S,再把它们放入一个Option。如果Option是None的话,这给了用户一个机会去终止运算,让unfold停止递归。
def getData(s:Int, l:Int) = Option(s"sql...skip=$s limit=$l")def getMore(skip: Int, limit: Int) = Stream.unfold(skip){s => Some(getData(s, limit), s+limit)}println(Stream.getMore(0,10).take(3).toList)
List(Some(sql...skip=0 limit=10), Some(sql...skip=10 limit=10), Some(sql...skip=20 limit=10))
case class State[S,+A](run: S => (A, S)) {import State._def flatMap[B](f: A => State[S,B]): State[S,B] = State[S,B] {s => {val (a, s1) = run(s)f(a).run(s1)}}def map[B](f: A => B): State[S,B] = {flatMap { a => unit(f(a)) }// s => {// val (a, s1) = run(s)// (f(a),s1)// }}def map2[B,C](sb: State[S,B])(f: (A,B) => C): State[S,C] = {//flatMap {a => sb.map { b => f(a,b) }}for {a <- thisb <- sb} yield f(a,b)}def map3[B,C,D](sb: State[S,B], sc: State[S,C])(f: (A,B,C) => D): State[S,D] ={for {a <- thisb <- sbc <- sc} yield f(a,b,c)}}object State {def unit[S,A](a: A) = State[S,A](s => (a, s))}type Stack = List[Int]def pop = State[Stack, Int]{ case x :: xs => (x, xs) }def push(i: Int) = State[Stack, Unit]{ case xs => ((), i :: xs ) }def stackRun: State[Stack, Int] = {for {_ <- push(13)a <- popb <- pop} yield a + b}val (a, s) = stackRun.run(List(10,11,12))println(a,s)case class Acc(bar: Int)object Acc {def inc(i : Int) = State[Acc, Int]{s => (s.bar, new Acc(s.bar + i))}def cut(i : Int) = State[Acc, Int]{s => (s.bar, new Acc(s.bar - i))}}println(Acc.inc(2).run(Acc(1)))println((for {i <- Acc.inc(2)j <- Acc.cut(1)} yield {println(i,j); i + j}) run Acc(0))//这样更好implicit class AccOp(acc :Acc) {def inc(i: Int) = Acc.inc(i).run(acc)._2def cut(i: Int) = Acc.cut(i).run(acc)._2}println(Acc(0).inc(2).cut(1))
(23,List(11, 12))(1,Acc(3))(0,2)(2,Acc(1))Acc(1)
object Par {import java.util.concurrent._type Par[A] = ExecutorService => Future[A]def run[A](pa: Par[A])(implicit es: ExecutorService): Future[A] = pa(es)def unit[A](a: A): Par[A] = es => {new Future[A] {def get: A = adef isDone = truedef isCancelled = falsedef get(timeOut: Long, timeUnit: TimeUnit): A = getdef cancel(evenIfRunning: Boolean): Boolean = false}}def fork[A](pa: => Par[A]): Par[A] = es => {es.submit[A](new Callable[A] {def call: A = run(pa)(es).get})}def async[A](a: => A): Par[A] = fork(unit(a)) //不被计算//applicativedef map2[A,B,C](pa: Par[A], pb: Par[B])(f: (A,B) => C): Par[C] = {import TimeUnit.NANOSECONDSes => new Future[C] {val fa = run(pa)(es) //在这里按pa的定义来确定在那个线程运行。如果pa是fork Par则在非主线程中运行val fb = run(pb)(es)def get = f(fa.get, fb.get)def get(timeOut: Long, timeUnit: TimeUnit) = {val start = System.nanoTimeval a = fa.getval end = System.nanoTime//fa.get用去了一些时间。剩下给fb.get的timeout值要减去val b = fb.get(timeOut - timeUnit.convert(end - start, NANOSECONDS) , timeUnit)f(a,b)}def isDone = fa.isDone && fb.isDonedef isCancelled = fa.isCancelled && fb.isCancelleddef cancel(evenIsRunning: Boolean) = fa.cancel(evenIsRunning) || fb.cancel(evenIsRunning)}}//map2 >> map3 时用右结合 map3(a,b,c)(f) = map2(a, map2(b,c)(f))(f)def map3[A,B,C,D](pa: Par[A], pb: Par[B], pc: Par[C])(f: (A,B,C) => D): Par[D] = {map2(pa,map2(pb,pc){(b,c) => (b,c)}){(a,bc) => {val (b,c) = bcf(a,b,c)}}}//monaddef flatMap[A,B](pa: Par[A])(f: A => Par[B]): Par[B] = {es => {run(f(run(pa)(es).get))(es)}}}import java.util.concurrent._implicit val es = Executors.newCachedThreadPool()val a = Par.unit({println("a "+Thread.currentThread.getName);4+7})val b = Par.async({println("b "+Thread.currentThread.getName);2+1})println(Par.run(a).get)println(Par.run(b).get)import Par._val r = Par.map2(async({println(Thread.currentThread.getName); 41+2}),async({println(Thread.currentThread.getName); 33+4})){(a,b) => {println(Thread.currentThread.getName); a+b}}(es).getprintln(r)val r1 = fork { map2(async({println(Thread.currentThread.getName); 41+2}),async({println(Thread.currentThread.getName); 33+4})){(a,b) => {println(Thread.currentThread.getName); a+b}}}(es).getprintln(r1)es.shutdown()
a main11b pool-1-thread-13pool-1-thread-1pool-1-thread-2main80pool-1-thread-1pool-1-thread-3pool-1-thread-280
1、可以使用for-comprehension
2、支持泛函式的循序命令执行流程,即:在高阶类结构内部执行操作流程。flatMap在这里起了关键作用,它确保了流程环节间一个环节的输出值成为另一个环境的输入值
那么我们可不可以说:Monad就是泛函编程中支持泛函方式流程式命令执行的特别编程模式。
Monad是一个高度概括的抽象模型。好像创造Monad的目的是为了抽取各种数据类型的共性组件函数汇集成一套组件库从而避免重复编码。
//Functortrait Functor[F[_]] {def map[A,B](a: F[A])(f: A => B): F[B]}object ListFunctor extends Functor[List] {def map[A,B](la: List[A])(f: A => B): List[B] = la map f}object OptionFunctor extends Functor[Option] {def map[A,B](oa: Option[A])(f: A => B): Option[B] = oa map f}println(ListFunctor.map(List(1,2,3)){_ + 10})println(OptionFunctor.map(Some(1)){_ + 10})//monadtrait Monad[M[_]] extends Functor[M] {def unit[A](a: A): M[A]def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B]def map[A,B](ma: M[A])(f: A => B): M[B] = {flatMap(ma){a => unit(f(a))}}//Applicative// def map2[A,B,C](ma: M[A], mb: M[B])(f: (A,B) => C): M[C] = {// flatMap(ma) { a => map(mb){ b => f(a,b) }}// }// def map2[A,B,C](ma: M[A], mb: M[B])(f: (A,B) => C): M[C] = {// flatMap(ma) { a => map(mb){ b => f(a,b) }}// }// def map3[A,B,C,D](ma: M[A], mb: M[B], mc: M[C])(f: (A,B,C) => D): M[D] = {// map2(ma,// map2(mb,mc){(b,c) => (b,c)}// ){(a,bc) => {// val (b,c) = bc// f(a,b,c)// }}// }// def map4[A,B,C,D,E](ma: M[A], mb: M[B], mc: M[C], md: M[D])(f: (A,B,C,D) => E): M[E] = {// map2(ma,// map2(mb,// map2(mc,md){(c,d) => (c,d)}// ){(b,cd) => (b,cd)}// ){(a,bcd) => {// val (b,(c,d)) = bcd// f(a,b,c,d)// }}// }}val listMonad = new Monad[List] {def unit[A](a: A) = List(a)def flatMap[A,B](la: List[A])(f: A => List[B]): List[B] = {la flatMap f}}val optionMonad = new Monad[Option] {def unit[A](a: A) = Some(a)def flatMap[A,B](oa: Option[A])(f: A => Option[B]): Option[B] = {oa flatMap f}}
trait Applicative[F[_]] extends Functor[F] {def unit[A](a: A): F[A]def map2[A,B,C](fa: F[A], fb: F[B])(f: (A,B) => C): F[C] = {apply(fb)(map(fa)(f.curried)) //map(fa)(a => (b => c)) >>> F[A=>B]}def apply[A,B](fa: F[A])(fab: F[A =>B]): F[B] = { //<*>map2(fab,fa)((f,a) => f(a))}def map[A,B](fa: F[A])(f: A => B): F[B] = {map2(unit(f),fa)((f,a) => f(a))}// def map[A,B](fa: F[A])(f: A => B): F[B] = {// apply(fa)(unit(f))// }//map3(ma,mb,mc)(f) = apply(mc)(apply(mb)(apply(mc)(unit(f.curried))))def map3[A,B,C,D](ma: F[A], mb: F[B], mc: F[C])(f: (A,B,C) => D): F[D] = {apply(mc)(apply(mb)(apply(ma)(unit(f.curried))))}def map4[A,B,C,D,E](ma: F[A], mb: F[B], mc: F[C],md: F[D])(f: (A,B,C,D) => E): F[E] = {apply(md)(apply(mc)(apply(mb)(apply(ma)(unit(f.curried)))))}}val optionApplicative = new Applicative[Option] {def unit[A](a: A) = Option(a)override def map2[A,B,C](ma: Option[A], mb: Option[B])(f: (A,B) => C): Option[C] = (ma, mb) match {case (Some(a), Some(b)) => Some(f(a, b))case _ => None}}val s = optionApplicative.apply(Some(1))(Some[Int => Int](_ + 1))println(s)implicit class OptionApplicativeOp[A](opt1: Option[A]) {def apply[B,C](opt2: Option[A => B]): Option[B] =optionApplicative.map2(opt1, opt2)((opt1x, opt2f) => opt2f(opt1x))def apply2[B,C](opt2: Option[(A, B) => C]): Option[B => C] =optionApplicative.map2(opt1, opt2)((opt1x, opt2f) => opt2f(opt1x, _))}def inc(x :Int) = x + 1def add2(x: Int, y: Int) = x + ydef add3(x: Int, y: Int, z: Int) = x + y + zval s2 = Some(1) apply Some(inc _)println(s2)val s3 = optionApplicative.map3(Some(1), Some(2), Some(3))(add3)println(s3)val s4 = Some(1) apply (Some(2) apply2 Some(add2 _))println(s4)
Some(2)Some(2)Some(6)Some(3)
更像Haskell的方式
implicit class OptionApplicativeOp1[A,B](opt1: Option[A => B]) {def apply(opt2: Option[A]): Option[B] =optionApplicative.map2(opt2, opt1)((opt2x, opt1f) => opt1f(opt2x))}implicit class OptionApplicativeOp2[A,B,C](opt1: Option[(A, B) => C]) {def apply(opt2: Option[A]): Option[B => C] =optionApplicative.map2(opt2, opt1)((opt2x, opt1f) => opt1f(opt2x, _))}val s5 = Some(add2 _) apply Some(2) apply Some(1)
flatMap和map2的差别,这也代表着Monad和Applicative在行为上的区别
def apply[A,B](ma: Option[A])(f: Option[A => B]): Option[B] = {(ma,f) match {case (Some(a),Some(f)) => Some(f(a))case _ => None}}def flatMap[A,B](ma: Option[A])(f: A => Option[B]): Option[B] = {ma match {case Some(a) => f(a)case _ => None}
apply和map的运算都依赖于两个传入参数的状态:只有两个参数都是Some时才会在Some结构内部进行运算。而flatMap的传入函数A=>Option[B]是否运行则依赖于ma状态是否Some,而传入函数运行的结果又依赖于ma内元素A的值。
所以Applicative可以保持运算结果的结构不变,而Monad有可能会造成运算结果的结构变化。
trait Monad[M[_]] extends Applicative[M]{def unit[A](a: A): M[A]def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B] = {join(map(ma)(f))}def compose[A,B,C](f: A => M[B], g: B => M[C]): A => M[C] = {a => { flatMap(f(a))(g)}}def join[A](mma: M[M[A]]): M[A] = {flatMap(mma)(ma => ma)}override def apply[A,B](ma: M[A])(fab: M[A => B]): M[B] = {flatMap(fab)(f => flatMap(ma)(a => unit(f(a))))}}
apply和map2一样可由flatMap实现
这样所有Monad都可以是Applicative。但是,有些Applicative未必是Monad,因为我们可能无法用某些类型Applicative实例的map2或apply来实现flatMap、join、compose。
不同的Functor是可以组合得到F[G[A]]的
def compose[F[_],G[_]](m: Functor[F], n: Functor[G]) =new Functor[({type l[x] = F[G[x]]})#l] { //呵呵override def map[A,B](fga: F[G[A]])(f: A => B) = {m.map(fga)(ga => n.map(ga)(f))}}val fg = compose(listFunctor,optionFunctor)fg.map(List(Option("abc"),Option("xy"),Option("ryuiyty"))){ _.length }
但是Monad不可以
Monad Transformer可以实现多个Monad效果的累加(stacking effect)
trait Functor[F[_]] {def map[A,B](a: F[A])(f: A => B): F[B]}trait Monad[M[_]] extends Functor[M] {def unit[A](a: A): M[A]def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]def map[A, B](ma: M[A])(f: A => B): M[B] = {flatMap(ma) { a => unit(f(a))}}}implicit val listMonad = new Monad[List] {def unit[A](a: A) = List(a)def flatMap[A,B](la: List[A])(f: A => List[B]): List[B] = {la flatMap f}}case class OptionT[M[_] : Monad,A](run: M[Option[A]]) {def map[B](f: A => B): OptionT[M,B] = {val m = implicitly[Functor[M]]OptionT[M,B](m.map(run)(a => a.map(f)))}def flatMap[B](f: A => OptionT[M,B]): OptionT[M,B] = {val m = implicitly[Monad[M]]OptionT[M,B](m.flatMap(run) {case Some(a) => f(a).runcase None => m.unit(None)})}}// 编译不过的 Some[List[]] 无法组合// val c = for {// a <- Some(1)// b <- List(1,2,3)// } yield a + b// println(c)val c = for {a <- OptionT[List, Int](List(Some(1)))b <- OptionT[List, Int](List(Some(1), Some(2), Some(3)))} yield a + bprintln(c)
OptionT(List(Some(2), Some(3), Some(4)))
OptineT的签名OptionT[M[ _ ] : Monad, A] 和Option[A]比多了个M[ _ ] 的Monad 代表Option主导的Monad栈
StateT的签名为StateT[M[ _ ] : Monad, S, A] 比State[S,A]也是多了个M
这是Monad Transformer的通用模式
1. 类型变为Monad[A] >>> MonadT[M[ _ ] : Monad, A]
2. map则改为先调用M[ _ ] : Monad的map和faltMap再调用Monad[A]自己的map(Functor的组合)
3. flatMap则调用M[ _ ] : Monad的flatMap,然后自己解Monad[A]得到a后执行f(a).run返回M[Monad[A]],千万不要调用Monad自己的flatMap,因为这样两个Monad是组合不起来的(flatMap套flatMap)其实就是只保留M的flatMap调用,自己解Monad[A]得A再返回M[Monad[A]]
4. MonadT也是个Monad可继续组合下去
//XMonad的Monad Transformer 通用模式case class XMonadT[M[_] : Monad,A](run: M[XMonad[A]]) {def map[B](f: A => B): XMonadT[M,B] = {val m = implicitly[Functor[M]]XMonadT[M,B](m.map(run)(a => a.map(f))) //map再map是functor组合,返回M[XMonad[A]]}def flatMap[B](f: A => XMonadT[M,B]): OptionT[M,B] = {val m = implicitly[Monad[M]]XMonadT[M,B](m.flatMap(run) { a =>f(a.get).run //解开a 返回M[XMonad[A]] 这里是关键})}}
trait Trampoline[+A] {final def runT: A = resume match {case Right(a) => acase Left(k) => k().runT}def flatMap[B](f: A => Trampoline[B]): Trampoline[B] = {this match {// case Done(a) => f(a)// case More(k) => f(runT)case FlatMap(a,g) => FlatMap(a, (x: Any) => g(x) flatMap f)case x => FlatMap(x, f)}}def map[B](f: A => B) = flatMap(a => Done(f(a)))def resume: Either[() => Trampoline[A], A] = this match {case Done(a) => Right(a)case More(k) => Left(k)case FlatMap(a,f) => a match {case Done(v) => f(v).resumecase More(k) => Left(() => k() flatMap f)case FlatMap(b,g) => FlatMap(b, (x: Any) => g(x) flatMap f).resume}}}case class Done[+A](a: A) extends Trampoline[A]case class More[+A](k: () => Trampoline[A]) extends Trampoline[A]case class FlatMap[A,B](sub: Trampoline[A], k: A => Trampoline[B]) extends Trampoline[B]def foldRight[A, B](l :List[A], z: B)(op: (A, B) => B): B = l match {case Nil => zcase h :: t => op(h, foldRight(t, z)(op))}// println(foldRight((1 to 10000).toList, 0)(_+_)) //stackoverflowdef foldRight2[A, B](l :List[A], z: B)(op: (A, B) => B): Trampoline[B] = l match {case Nil => Done(z)case h :: t => More(() => {foldRight2(t, z)(op) flatMap {a => More(() => Done(op(h, a)))}})}println(foldRight2((1 to 10000).toList, 0)((a,b) => {println(a,b);a+b}).runT)
trait Interact[A] //交互数据类型//提问,等待返回String类型答案case class Ask(prompt: String) extends Interact[String]//告知,有没有返回结果case class Tell(msg: String) extends Interact[Unit]//Tell依赖Ask的结果 这么写编译不过 不是monad// for {// x <- Ask("What's your first name?")// y <- Ask("What's your last name?")// _ <- Tell(s"Hello $y $x!")// } yield ()trait Free[F[_],A] {//Monaddef unit(a: A) = Return(a)def flatMap[B](f: A => Free[F,B]): Free[F,B] = this match {case Return(a) => f(a)case Bind(fa,g) => Bind(fa, (x: Any) => g(x) flatMap f)//case Bind(fa,g) => Bind(fa, g andThen (_ flatMap f))}def map[B](f: A => B): Free[F,B] = flatMap(a => Return(f(a)))//Interpreter//可以用折叠算法来实现F[_]结构中表达式的转换def foldMap[G[_]: Monad](f: F ~> G): G[A] = this match {case Return(a) => implicitly[Monad[G]].unit(a)case Bind(b,g) => implicitly[Monad[G]].flatMap(f(b))(a => g(a).foldMap(f))}}case class Return[F[_],A](a: A) extends Free[F,A] //表示计算结束case class Bind[F[_],I,A](a: F[I], f: I => Free[F,A]) extends Free[F,A] //表示依赖计算 或者延续计算implicit def lift[F[_],A](fa: F[A]): Free[F,A] = Bind(fa, (a: A) => Return(a))val prg = for {x <- Ask("What's your first name?")y <- Ask("What's your last name?")_ <- Tell(s"Hello $y $x!")} yield ()println(prg) //返回Monad 紧紧描述算法而已// Bind(Ask("What's your first name?"), (a: String) => Return(a)) //fa , g// _ => Bind(Ask("What's your last name?"), (a: String) => Return(a))// Bind(Ask("What's your first name?"), (a: Any) => Bind(Ask("What's your last name?"), (a: String) => Return(a)))// _ => Bind(Tell(s"Hello $y $x!"), (a: Unit) => Return(a))//// Bind(Ask("What's your first name?"), (a: Any) => Bind(Ask("What's your last name?"), (a: String) => Return(a)))//Free Monad 分为Monad和Interpreter 是算法和运算分离的//Interpreter解译程序形成针对特定运行环境的可运行代码//Interpreter程序运算是通过一个转换函数实现的。这个函数把F[_]这样一个算法解译成G[_]这样一个针对可运行环境的Monad运行代码。这种转换就是自然转换(Natural Transformation)trait ~>[F[_],G[_]] {def apply[A](fa: F[A]): G[A]}type Id[A] = Aimplicit val idMonad: Monad[Id] = new Monad[Id] {def unit[A](a: A) = adef flatMap[A,B](fa: A)(f: A => B): B = f(fa)}object Console extends (Interact ~> Id) { //Interact ~> Id的实现def apply[A](i: Interact[A]): A = i match {case Ask(prompt) => {println(prompt)readLine}case Tell(msg) => println(msg)}}prg.foldMap(Console)