[关闭]
@MiloXia 2015-07-03T08:28:46.000000Z 字数 19710 阅读 2610

Scala FP 扫盲

scala 函数式编程


fold

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); 尾递归

  1. def foldRight[A, B](l :List[A], z: B)(op: (A, B) => B): B = l match {
  2. case Nil => z
  3. case h :: t => op(h, foldRight(t, z)(op))
  4. }
  5. def foldLeft[A, B](l :List[A], z: B)(op: (A, B) => B): B = l match {
  6. case Nil => z
  7. case h :: t => foldLeft(t, op(h, z))(op)
  8. }
  9. println(foldRight(List(1,2,3,4,5), 0)((a, b) => {println(a, b); b + a}))
  10. println(foldLeft(List(1,2,3,4,5), 0)((a, b) => {println(a, b); b + a}))
  1. (5,0)
  2. (4,5)
  3. (3,9)
  4. (2,12)
  5. (1,14)
  6. 15
  7. (1,0)
  8. (2,1)
  9. (3,3)
  10. (4,6)
  11. (5,10)
  12. 15

Either

  1. trait Either[+E, +A]

E代表异常类型,A代表计算类型
Left代表无法完成计算, Right 代表计算正常完成

  1. case class Employee(name: String, age: Int, salary: Double)
  2. def getAge(msg: String, v: Int): Either[String, Int] = if(v <= 18) Left(msg) else Right(v)
  3. def getName(msg: String, v: String): Either[String, String] = if(v.isEmpty) Left(msg) else Right(v)
  4. def getSalary(msg: String, v: Double): Either[String, Double] = if(v < 0.0) Left(msg) else Right(v)
  5. var e1 = for {
  6. age <- getAge("invalid age", 26).right
  7. name <- getName("invalid name", "").right
  8. salary <- getSalary("invalid salary", 10000.0).right
  9. } yield Employee(name, age, salary)
  10. println(e1)
  11. //用map2_s合并错误 monad貌似不行
  12. def map2_s[A,B,C](a: Either[String, A],b: Either[String, B])(f: (A, B) => C): Either[String, C] = (a, b) match {
  13. case (Left(e), Left(ee)) => Left(e + "," + ee)
  14. case (_, Left(e)) => Left(e)
  15. case (Left(e), _) => Left(e)
  16. case (Right(a), Right(b)) => Right(f(a, b))
  17. }
  18. // 编译不过
  19. // 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] =
  20. // map2_s(a, b)((a, b) => map2_s(c, Right(a,b))((ax, bx) => f(bx._1, bx._2, ax)))
  21. 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] =
  22. map2_s(a, map2_s(b, c){(bx, cx) =>
  23. (bx, cx)
  24. }){(ax, bcx) => f(ax, bcx._1, bcx._2)}
  25. 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)))
  26. val e3 = map3_s(getName("invalid name", ""), getAge("invalid age", 17), getSalary("invalid salary", 10000.0))((a, b, c) => Employee(a, b, c))
  27. println(e2)
  28. println(e3)
  1. Left(invalid name)
  2. Left(invalid age,invalid name)
  3. Left(invalid name,invalid age)

lazy evaluation

  1. def pair(x: => Int):(Int, Int) = (x, x)
  2. println(pair({println("hello");1}))
  1. hello
  2. hello
  3. (1,1)

参数x的类型是 => Int, 代表x参数是non-strict的。(call-by-name)
non-strict参数每次使用时都会重新计算一次。
从 内部实现机制来解释:这是因为编译器(compiler)遇到non-strict参数时会把一个指针放到调用堆栈里,而不 是惯常的把参数的值放入。
所以每次使用non-strict参数时都会重新计算一下

lazy声明可以解决non- strict参数多次运算问题

  1. def pair2(x: => Int):(Int, Int) = {
  2. lazy val lx = x
  3. (lx, lx)
  4. }
  5. println(pair2({println("hello");1}))
  1. hello
  2. (1,1)
  1. def inc(i :Int) = i + 1
  2. def lazyInc(x: => Int) = 1
  3. def pair3(x: => Int) = inc(x) //x被计算
  4. def pair4(x: => Int) = lazyInc(inc(x)) //inc(x)不被计算
  5. println(pair3({println("hello3");1}))
  6. println(pair4({println("hello4");1}))
  1. hello3
  2. 2
  3. 1

call-by-name
求职:在使用的地方就会被求职
class构造函数参数不可以是non-strict,所以要lazy必须传函数() => ???

  1. case class Pair(x : => Int, y : => Int) //编译不过
  2. case class Pair(x : () => Int, y : () => Int) {
  3. def pairF = (x, y)
  4. def pair = (x(), y())
  5. }
  6. println(Pair(() => 1, () => 2))
  7. println(Pair(() => 1, () => 2).pairF)
  8. println(Pair(() => 1, () => 2).pair)
  1. Pair(<function0>,<function0>)
  2. (<function0>,<function0>)
  3. (1,2)

Stream

  1. trait Stream[+A]
  2. case object Empty extends Stream[Nothing]
  3. case class Cons[+A](head: () => A, tail: () => Stream[A]) extends Stream[A]

由于Cons不是普通函数而是一个类,不容许延后计算类参数,所以传入的是一个函数 () => ???

  1. trait Stream[+A] {
  2. def uncons: Option[(A, Stream[A])]
  3. def isEmpty: Boolean = uncons.isEmpty
  4. //other
  5. def toList: List[A] = {
  6. @annotation.tailrec
  7. def go(s: Stream[A], acc: List[A]): List[A] = {
  8. s.uncons match {
  9. case None => acc
  10. case Some((h,t)) => go(t,h :: acc)
  11. }
  12. }
  13. go(this, Nil).reverse
  14. }
  15. import Stream._
  16. def take(n: Int): Stream[A] = {
  17. if ( n == 0 ) empty
  18. else
  19. uncons match {
  20. case None => empty
  21. case Some((h,t)) => cons({println("take"+h);h},t.take(n-1)) //lazy的 并没真的take 执行uncons时才计算
  22. }
  23. }
  24. def drop(n: Int): Stream[A] = {
  25. if (n == 0) this
  26. else {
  27. uncons match {
  28. case Some((h,t)) => t.drop(n-1)
  29. case _ => this
  30. }
  31. }
  32. }
  33. // lazy的foldRight
  34. def foldRight[B](z: B)(op: (A, => B) => B): B = { //op第二个参数是=> B,所以t.foldRight(z)(op)就是延迟计算的
  35. uncons match {
  36. case None => z
  37. case Some((h,t)) => op({println("fold"+h);h},t.foldRight(z)(op)) //只要不在op里使用b fold就会结束
  38. }
  39. }
  40. // lazy的exists 满足条件p(a) = true 就结束foldRight
  41. def exists(p: A => Boolean): Boolean = {
  42. foldRight(false){(a,b) => p(a) || b } //op = (a,b) => p(a) || b ,当p(a) = true时 b不再传给foldRight
  43. }
  44. def forAll(p: A => Boolean): Boolean = {
  45. foldRight(true){(a,b) => p(a) && b}
  46. }
  47. def filter(p: A => Boolean): Stream[A] = {
  48. foldRight(empty[A]){(h,t) => {println("filter"+h);if(p(h)) cons(h,t) else t}} //该表达式,foldRight会执行到底
  49. }
  50. def map[B](p: A => B): Stream[B] = {
  51. foldRight(empty[B]){(h,t) => cons({println("map"+h);p(h)}, t)}
  52. }
  53. def flatMap_1[B](f: A => Stream[B]): Stream[B] = {
  54. foldRight(empty[B]){(h,t) => f(h) #++ t}
  55. }
  56. def append[B >: A](b: Stream[B]): Stream[B] = {
  57. uncons match {
  58. case None => b
  59. case Some((h,t)) => cons(h, t.append(b))
  60. }
  61. }
  62. //append简写
  63. def #++[B >: A](b: Stream[B]): Stream[B] = append(b)
  64. // override def toString = s"Stream(${toList.mkString(",")})" //会导致全部计算一遍,这可不好
  65. override def toString = "Stream(lazy...)"
  66. }
  67. object Stream {
  68. def empty[A]: Stream[A] = new Stream[A] { def uncons = None }
  69. //采用call-by-name比较好,Cons case class的构造参数会比较难看
  70. def cons[A](h: => A, t: => Stream[A]): Stream[A] = new Stream[A] {
  71. def uncons = Some((h, t)) /*!!!!!!此时计算*/
  72. }
  73. def apply[A](as: A*): Stream[A] = {
  74. if (as.isEmpty) empty
  75. else cons(as.head, apply(as.tail: _*))
  76. }
  77. }
  78. def get1 = {println("hello1");1}
  79. def get2 = {println("hello2");2}
  80. def get3 = {println("hello3");3}
  81. println(Stream(1,2,3) take 2)
  82. println(Stream(get1,get2,get3) take 2) //打印hello是因为apply 所以Stream只能作为产生器
  83. println((Stream(1,2,3) take 2).toList)
  84. println("------")
  85. println(Stream(1,2,3).foldRight(0)(_+_))
  86. println(Stream(1,2,3).foldRight(0)((a, b) => a )) //foldRight 是否lazy和op有关 只要不使用b fold就会结束 在第一层a=1时 op(1, b不计算)=>1
  87. println("------")
  88. println(Stream(1,2,3).take(2).foldRight(0)(_+_)) //每次foldRight执行uncons时会计算lazy的take
  89. println(Stream(1,2,3).exists(_ == 2))
  90. println("------")
  91. println(Stream(1,2,3).map(_+1).filter(_ % 2 == 0).toList) //只遍历一次
  1. Stream(lazy...)
  2. hello1
  3. hello2
  4. hello3
  5. Stream(lazy...)
  6. take1
  7. take2
  8. List(1, 2)
  9. ------
  10. fold1
  11. fold2
  12. fold3
  13. 6
  14. fold1
  15. 1
  16. ------
  17. take1
  18. fold1
  19. take2
  20. fold2
  21. 3
  22. fold1
  23. fold2
  24. true
  25. ------
  26. fold1
  27. map1
  28. fold2
  29. fold2
  30. filter2
  31. map2
  32. fold3
  33. fold3
  34. filter3
  35. map3
  36. fold4
  37. filter4
  38. List(2, 4)

Infinite Stream 无穷数据流

  1. object Stream {
  2. ...
  3. def constant[A](a: A): Stream[A] = cons(a, constant(a))
  4. def from(n: Int): Stream[Int] = cons(n, from(n+1))
  5. def fibs: Stream[Int] = {
  6. def go (prev: Int, cur: Int): Stream[Int] = {
  7. cons(prev,go(cur,prev + cur))
  8. }
  9. go(0,1)
  10. }
  11. //我们不断重复的在cons。而cons的参数则是算法的实现结果
  12. //A为前一个值,S为下一个值
  13. def unfold[A,S](z: S)(f: S => Option[(A, S)]): Stream[A] = {
  14. f(z) match {
  15. case None => empty
  16. case Some((a,s)) => cons(a, unfold(s)(f))
  17. }
  18. }
  19. def constantByUnfold[A](a: A): Stream[A] = unfold(a)(_ => Some((a,a)))
  20. def fromByUnfold(s: Int): Stream[Int] = unfold(s)(s => Some(s,s+1))
  21. def fibsByUnfold: Stream[Int] = unfold((0,1)){ case (a1,a2) => Some((a1, (a2, a1+a2))) }
  22. }
  23. println(Stream.constant(1).take(5).toList)
  24. println(Stream.from(5).take(5).toList)
  25. println(Stream.fibs.take(5).toList)
  26. println(Stream.constantByUnfold(1).take(5).toList)
  27. println(Stream.fromByUnfold(5).take(5).toList)
  28. println(Stream.fibsByUnfold.take(5).toList)
  1. List(1, 1, 1, 1, 1)
  2. List(5, 6, 7, 8, 9)
  3. List(0, 1, 1, 2, 3)
  4. List(1, 1, 1, 1, 1)
  5. List(5, 6, 7, 8, 9)
  6. List(0, 1, 1, 2, 3)

unfold的工作原理模仿了一种状态流转过程:z是一个起始状态,代表的是一个类型的值。然后用户(caller)再提供一个操作函数f。f的款式是:S => Option[(A,S)],意思是接受一个状态,然后把它转换成一对新的A值和新的状态S,再把它们放入一个Option。如果Option是None的话,这给了用户一个机会去终止运算,让unfold停止递归。

用unfold实现getMore

  1. def getData(s:Int, l:Int) = Option(s"sql...skip=$s limit=$l")
  2. def getMore(skip: Int, limit: Int) = Stream.unfold(skip){
  3. s => Some(getData(s, limit), s+limit)
  4. }
  5. println(Stream.getMore(0,10).take(3).toList)
  1. List(Some(sql...skip=0 limit=10), Some(sql...skip=10 limit=10), Some(sql...skip=20 limit=10))

State

  1. case class State[S,+A](run: S => (A, S)) {
  2. import State._
  3. def flatMap[B](f: A => State[S,B]): State[S,B] = State[S,B] {
  4. s => {
  5. val (a, s1) = run(s)
  6. f(a).run(s1)
  7. }
  8. }
  9. def map[B](f: A => B): State[S,B] = {
  10. flatMap { a => unit(f(a)) }
  11. // s => {
  12. // val (a, s1) = run(s)
  13. // (f(a),s1)
  14. // }
  15. }
  16. def map2[B,C](sb: State[S,B])(f: (A,B) => C): State[S,C] = {
  17. //flatMap {a => sb.map { b => f(a,b) }}
  18. for {
  19. a <- this
  20. b <- sb
  21. } yield f(a,b)
  22. }
  23. def map3[B,C,D](sb: State[S,B], sc: State[S,C])(f: (A,B,C) => D): State[S,D] ={
  24. for {
  25. a <- this
  26. b <- sb
  27. c <- sc
  28. } yield f(a,b,c)
  29. }
  30. }
  31. object State {
  32. def unit[S,A](a: A) = State[S,A](s => (a, s))
  33. }
  34. type Stack = List[Int]
  35. def pop = State[Stack, Int]{ case x :: xs => (x, xs) }
  36. def push(i: Int) = State[Stack, Unit]{ case xs => ((), i :: xs ) }
  37. def stackRun: State[Stack, Int] = {
  38. for {
  39. _ <- push(13)
  40. a <- pop
  41. b <- pop
  42. } yield a + b
  43. }
  44. val (a, s) = stackRun.run(List(10,11,12))
  45. println(a,s)
  46. case class Acc(bar: Int)
  47. object Acc {
  48. def inc(i : Int) = State[Acc, Int]{s => (s.bar, new Acc(s.bar + i))}
  49. def cut(i : Int) = State[Acc, Int]{s => (s.bar, new Acc(s.bar - i))}
  50. }
  51. println(Acc.inc(2).run(Acc(1)))
  52. println((for {
  53. i <- Acc.inc(2)
  54. j <- Acc.cut(1)
  55. } yield {println(i,j); i + j}) run Acc(0))
  56. //这样更好
  57. implicit class AccOp(acc :Acc) {
  58. def inc(i: Int) = Acc.inc(i).run(acc)._2
  59. def cut(i: Int) = Acc.cut(i).run(acc)._2
  60. }
  61. println(Acc(0).inc(2).cut(1))
  1. (23,List(11, 12))
  2. (1,Acc(3))
  3. (0,2)
  4. (2,Acc(1))
  5. Acc(1)

Par

  1. object Par {
  2. import java.util.concurrent._
  3. type Par[A] = ExecutorService => Future[A]
  4. def run[A](pa: Par[A])(implicit es: ExecutorService): Future[A] = pa(es)
  5. def unit[A](a: A): Par[A] = es => {
  6. new Future[A] {
  7. def get: A = a
  8. def isDone = true
  9. def isCancelled = false
  10. def get(timeOut: Long, timeUnit: TimeUnit): A = get
  11. def cancel(evenIfRunning: Boolean): Boolean = false
  12. }
  13. }
  14. def fork[A](pa: => Par[A]): Par[A] = es => {
  15. es.submit[A](new Callable[A] {
  16. def call: A = run(pa)(es).get
  17. })
  18. }
  19. def async[A](a: => A): Par[A] = fork(unit(a)) //不被计算
  20. //applicative
  21. def map2[A,B,C](pa: Par[A], pb: Par[B])(f: (A,B) => C): Par[C] = {
  22. import TimeUnit.NANOSECONDS
  23. es => new Future[C] {
  24. val fa = run(pa)(es) //在这里按pa的定义来确定在那个线程运行。如果pa是fork Par则在非主线程中运行
  25. val fb = run(pb)(es)
  26. def get = f(fa.get, fb.get)
  27. def get(timeOut: Long, timeUnit: TimeUnit) = {
  28. val start = System.nanoTime
  29. val a = fa.get
  30. val end = System.nanoTime
  31. //fa.get用去了一些时间。剩下给fb.get的timeout值要减去
  32. val b = fb.get(timeOut - timeUnit.convert(end - start, NANOSECONDS) , timeUnit)
  33. f(a,b)
  34. }
  35. def isDone = fa.isDone && fb.isDone
  36. def isCancelled = fa.isCancelled && fb.isCancelled
  37. def cancel(evenIsRunning: Boolean) = fa.cancel(evenIsRunning) || fb.cancel(evenIsRunning)
  38. }
  39. }
  40. //map2 >> map3 时用右结合 map3(a,b,c)(f) = map2(a, map2(b,c)(f))(f)
  41. def map3[A,B,C,D](pa: Par[A], pb: Par[B], pc: Par[C])(f: (A,B,C) => D): Par[D] = {
  42. map2(pa,map2(pb,pc){(b,c) => (b,c)}){(a,bc) => {
  43. val (b,c) = bc
  44. f(a,b,c)
  45. }}
  46. }
  47. //monad
  48. def flatMap[A,B](pa: Par[A])(f: A => Par[B]): Par[B] = {
  49. es => {
  50. run(f(run(pa)(es).get))(es)
  51. }
  52. }
  53. }
  54. import java.util.concurrent._
  55. implicit val es = Executors.newCachedThreadPool()
  56. val a = Par.unit({println("a "+Thread.currentThread.getName);4+7})
  57. val b = Par.async({println("b "+Thread.currentThread.getName);2+1})
  58. println(Par.run(a).get)
  59. println(Par.run(b).get)
  60. import Par._
  61. val r = Par.map2(async({println(Thread.currentThread.getName); 41+2}),
  62. async({println(Thread.currentThread.getName); 33+4}))
  63. {(a,b) => {println(Thread.currentThread.getName); a+b}}(es).get
  64. println(r)
  65. val r1 = fork { map2(async({println(Thread.currentThread.getName); 41+2}),
  66. async({println(Thread.currentThread.getName); 33+4}))
  67. {(a,b) => {println(Thread.currentThread.getName); a+b}}}(es).get
  68. println(r1)
  69. es.shutdown()
  1. a main
  2. 11
  3. b pool-1-thread-1
  4. 3
  5. pool-1-thread-1
  6. pool-1-thread-2
  7. main
  8. 80
  9. pool-1-thread-1
  10. pool-1-thread-3
  11. pool-1-thread-2
  12. 80

Monad

1、可以使用for-comprehension

2、支持泛函式的循序命令执行流程,即:在高阶类结构内部执行操作流程。flatMap在这里起了关键作用,它确保了流程环节间一个环节的输出值成为另一个环境的输入值

那么我们可不可以说:Monad就是泛函编程中支持泛函方式流程式命令执行的特别编程模式。

Monad是一个高度概括的抽象模型。好像创造Monad的目的是为了抽取各种数据类型的共性组件函数汇集成一套组件库从而避免重复编码。

  1. //Functor
  2. trait Functor[F[_]] {
  3. def map[A,B](a: F[A])(f: A => B): F[B]
  4. }
  5. object ListFunctor extends Functor[List] {
  6. def map[A,B](la: List[A])(f: A => B): List[B] = la map f
  7. }
  8. object OptionFunctor extends Functor[Option] {
  9. def map[A,B](oa: Option[A])(f: A => B): Option[B] = oa map f
  10. }
  11. println(ListFunctor.map(List(1,2,3)){_ + 10})
  12. println(OptionFunctor.map(Some(1)){_ + 10})
  13. //monad
  14. trait Monad[M[_]] extends Functor[M] {
  15. def unit[A](a: A): M[A]
  16. def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B]
  17. def map[A,B](ma: M[A])(f: A => B): M[B] = {
  18. flatMap(ma){a => unit(f(a))}
  19. }
  20. //Applicative
  21. // def map2[A,B,C](ma: M[A], mb: M[B])(f: (A,B) => C): M[C] = {
  22. // flatMap(ma) { a => map(mb){ b => f(a,b) }}
  23. // }
  24. // def map2[A,B,C](ma: M[A], mb: M[B])(f: (A,B) => C): M[C] = {
  25. // flatMap(ma) { a => map(mb){ b => f(a,b) }}
  26. // }
  27. // def map3[A,B,C,D](ma: M[A], mb: M[B], mc: M[C])(f: (A,B,C) => D): M[D] = {
  28. // map2(ma,
  29. // map2(mb,mc){(b,c) => (b,c)}
  30. // ){(a,bc) => {
  31. // val (b,c) = bc
  32. // f(a,b,c)
  33. // }}
  34. // }
  35. // 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] = {
  36. // map2(ma,
  37. // map2(mb,
  38. // map2(mc,md){(c,d) => (c,d)}
  39. // ){(b,cd) => (b,cd)}
  40. // ){(a,bcd) => {
  41. // val (b,(c,d)) = bcd
  42. // f(a,b,c,d)
  43. // }}
  44. // }
  45. }
  46. val listMonad = new Monad[List] {
  47. def unit[A](a: A) = List(a)
  48. def flatMap[A,B](la: List[A])(f: A => List[B]): List[B] = {
  49. la flatMap f
  50. }
  51. }
  52. val optionMonad = new Monad[Option] {
  53. def unit[A](a: A) = Some(a)
  54. def flatMap[A,B](oa: Option[A])(f: A => Option[B]): Option[B] = {
  55. oa flatMap f
  56. }
  57. }

Applicative

  1. trait Applicative[F[_]] extends Functor[F] {
  2. def unit[A](a: A): F[A]
  3. def map2[A,B,C](fa: F[A], fb: F[B])(f: (A,B) => C): F[C] = {
  4. apply(fb)(map(fa)(f.curried)) //map(fa)(a => (b => c)) >>> F[A=>B]
  5. }
  6. def apply[A,B](fa: F[A])(fab: F[A =>B]): F[B] = { //<*>
  7. map2(fab,fa)((f,a) => f(a))
  8. }
  9. def map[A,B](fa: F[A])(f: A => B): F[B] = {
  10. map2(unit(f),fa)((f,a) => f(a))
  11. }
  12. // def map[A,B](fa: F[A])(f: A => B): F[B] = {
  13. // apply(fa)(unit(f))
  14. // }
  15. //map3(ma,mb,mc)(f) = apply(mc)(apply(mb)(apply(mc)(unit(f.curried))))
  16. def map3[A,B,C,D](ma: F[A], mb: F[B], mc: F[C])(f: (A,B,C) => D): F[D] = {
  17. apply(mc)(apply(mb)
  18. (apply(ma)(unit(f.curried))))
  19. }
  20. 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] = {
  21. apply(md)(apply(mc)
  22. (apply(mb)
  23. (apply(ma)(unit(f.curried)))))
  24. }
  25. }
  26. val optionApplicative = new Applicative[Option] {
  27. def unit[A](a: A) = Option(a)
  28. override def map2[A,B,C](ma: Option[A], mb: Option[B])(f: (A,B) => C): Option[C] = (ma, mb) match {
  29. case (Some(a), Some(b)) => Some(f(a, b))
  30. case _ => None
  31. }
  32. }
  33. val s = optionApplicative.apply(Some(1))(Some[Int => Int](_ + 1))
  34. println(s)
  35. implicit class OptionApplicativeOp[A](opt1: Option[A]) {
  36. def apply[B,C](opt2: Option[A => B]): Option[B] =
  37. optionApplicative.map2(opt1, opt2)((opt1x, opt2f) => opt2f(opt1x))
  38. def apply2[B,C](opt2: Option[(A, B) => C]): Option[B => C] =
  39. optionApplicative.map2(opt1, opt2)((opt1x, opt2f) => opt2f(opt1x, _))
  40. }
  41. def inc(x :Int) = x + 1
  42. def add2(x: Int, y: Int) = x + y
  43. def add3(x: Int, y: Int, z: Int) = x + y + z
  44. val s2 = Some(1) apply Some(inc _)
  45. println(s2)
  46. val s3 = optionApplicative.map3(Some(1), Some(2), Some(3))(add3)
  47. println(s3)
  48. val s4 = Some(1) apply (Some(2) apply2 Some(add2 _))
  49. println(s4)
  1. Some(2)
  2. Some(2)
  3. Some(6)
  4. Some(3)

更像Haskell的方式

  1. implicit class OptionApplicativeOp1[A,B](opt1: Option[A => B]) {
  2. def apply(opt2: Option[A]): Option[B] =
  3. optionApplicative.map2(opt2, opt1)((opt2x, opt1f) => opt1f(opt2x))
  4. }
  5. implicit class OptionApplicativeOp2[A,B,C](opt1: Option[(A, B) => C]) {
  6. def apply(opt2: Option[A]): Option[B => C] =
  7. optionApplicative.map2(opt2, opt1)((opt2x, opt1f) => opt1f(opt2x, _))
  8. }
  9. val s5 = Some(add2 _) apply Some(2) apply Some(1)

Applicative与Monad差别

flatMap和map2的差别,这也代表着Monad和Applicative在行为上的区别

  1. def apply[A,B](ma: Option[A])(f: Option[A => B]): Option[B] = {
  2. (ma,f) match {
  3. case (Some(a),Some(f)) => Some(f(a))
  4. case _ => None
  5. }
  6. }
  7. def flatMap[A,B](ma: Option[A])(f: A => Option[B]): Option[B] = {
  8. ma match {
  9. case Some(a) => f(a)
  10. case _ => None
  11. }

apply和map的运算都依赖于两个传入参数的状态:只有两个参数都是Some时才会在Some结构内部进行运算。而flatMap的传入函数A=>Option[B]是否运行则依赖于ma状态是否Some,而传入函数运行的结果又依赖于ma内元素A的值。

所以Applicative可以保持运算结果的结构不变,而Monad有可能会造成运算结果的结构变化。

Monad extends Applicative

  1. trait Monad[M[_]] extends Applicative[M]{
  2. def unit[A](a: A): M[A]
  3. def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B] = {
  4. join(map(ma)(f))
  5. }
  6. def compose[A,B,C](f: A => M[B], g: B => M[C]): A => M[C] = {
  7. a => { flatMap(f(a))(g)}
  8. }
  9. def join[A](mma: M[M[A]]): M[A] = {
  10. flatMap(mma)(ma => ma)
  11. }
  12. override def apply[A,B](ma: M[A])(fab: M[A => B]): M[B] = {
  13. flatMap(fab)(f => flatMap(ma)(a => unit(f(a))))
  14. }
  15. }

apply和map2一样可由flatMap实现
这样所有Monad都可以是Applicative。但是,有些Applicative未必是Monad,因为我们可能无法用某些类型Applicative实例的map2或apply来实现flatMap、join、compose。

Monad Transformer

不同的Functor是可以组合得到F[G[A]]的

  1. def compose[F[_],G[_]](m: Functor[F], n: Functor[G]) =
  2. new Functor[({type l[x] = F[G[x]]})#l] { //呵呵
  3. override def map[A,B](fga: F[G[A]])(f: A => B) = {
  4. m.map(fga)(ga => n.map(ga)(f))
  5. }
  6. }
  7. val fg = compose(listFunctor,optionFunctor)
  8. fg.map(List(Option("abc"),Option("xy"),Option("ryuiyty"))){ _.length }

但是Monad不可以
Monad Transformer可以实现多个Monad效果的累加(stacking effect)

  1. trait Functor[F[_]] {
  2. def map[A,B](a: F[A])(f: A => B): F[B]
  3. }
  4. trait Monad[M[_]] extends Functor[M] {
  5. def unit[A](a: A): M[A]
  6. def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B]
  7. def map[A, B](ma: M[A])(f: A => B): M[B] = {
  8. flatMap(ma) { a => unit(f(a))}
  9. }
  10. }
  11. implicit val listMonad = new Monad[List] {
  12. def unit[A](a: A) = List(a)
  13. def flatMap[A,B](la: List[A])(f: A => List[B]): List[B] = {
  14. la flatMap f
  15. }
  16. }
  17. case class OptionT[M[_] : Monad,A](run: M[Option[A]]) {
  18. def map[B](f: A => B): OptionT[M,B] = {
  19. val m = implicitly[Functor[M]]
  20. OptionT[M,B](m.map(run)(a => a.map(f)))
  21. }
  22. def flatMap[B](f: A => OptionT[M,B]): OptionT[M,B] = {
  23. val m = implicitly[Monad[M]]
  24. OptionT[M,B](m.flatMap(run) {
  25. case Some(a) => f(a).run
  26. case None => m.unit(None)
  27. })
  28. }
  29. }
  30. // 编译不过的 Some[List[]] 无法组合
  31. // val c = for {
  32. // a <- Some(1)
  33. // b <- List(1,2,3)
  34. // } yield a + b
  35. // println(c)
  36. val c = for {
  37. a <- OptionT[List, Int](List(Some(1)))
  38. b <- OptionT[List, Int](List(Some(1), Some(2), Some(3)))
  39. } yield a + b
  40. println(c)
  1. 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可继续组合下去

  1. //XMonad的Monad Transformer 通用模式
  2. case class XMonadT[M[_] : Monad,A](run: M[XMonad[A]]) {
  3. def map[B](f: A => B): XMonadT[M,B] = {
  4. val m = implicitly[Functor[M]]
  5. XMonadT[M,B](m.map(run)(a => a.map(f))) //map再map是functor组合,返回M[XMonad[A]]
  6. }
  7. def flatMap[B](f: A => XMonadT[M,B]): OptionT[M,B] = {
  8. val m = implicitly[Monad[M]]
  9. XMonadT[M,B](m.flatMap(run) { a =>
  10. f(a.get).run //解开a 返回M[XMonad[A]] 这里是关键
  11. })
  12. }
  13. }

Trampoline (Stackless Scala)

  1. trait Trampoline[+A] {
  2. final def runT: A = resume match {
  3. case Right(a) => a
  4. case Left(k) => k().runT
  5. }
  6. def flatMap[B](f: A => Trampoline[B]): Trampoline[B] = {
  7. this match {
  8. // case Done(a) => f(a)
  9. // case More(k) => f(runT)
  10. case FlatMap(a,g) => FlatMap(a, (x: Any) => g(x) flatMap f)
  11. case x => FlatMap(x, f)
  12. }
  13. }
  14. def map[B](f: A => B) = flatMap(a => Done(f(a)))
  15. def resume: Either[() => Trampoline[A], A] = this match {
  16. case Done(a) => Right(a)
  17. case More(k) => Left(k)
  18. case FlatMap(a,f) => a match {
  19. case Done(v) => f(v).resume
  20. case More(k) => Left(() => k() flatMap f)
  21. case FlatMap(b,g) => FlatMap(b, (x: Any) => g(x) flatMap f).resume
  22. }
  23. }
  24. }
  25. case class Done[+A](a: A) extends Trampoline[A]
  26. case class More[+A](k: () => Trampoline[A]) extends Trampoline[A]
  27. case class FlatMap[A,B](sub: Trampoline[A], k: A => Trampoline[B]) extends Trampoline[B]
  28. def foldRight[A, B](l :List[A], z: B)(op: (A, B) => B): B = l match {
  29. case Nil => z
  30. case h :: t => op(h, foldRight(t, z)(op))
  31. }
  32. // println(foldRight((1 to 10000).toList, 0)(_+_)) //stackoverflow
  33. def foldRight2[A, B](l :List[A], z: B)(op: (A, B) => B): Trampoline[B] = l match {
  34. case Nil => Done(z)
  35. case h :: t => More(() => {
  36. foldRight2(t, z)(op) flatMap {
  37. a => More(() => Done(op(h, a)))
  38. }
  39. })
  40. }
  41. println(foldRight2((1 to 10000).toList, 0)((a,b) => {println(a,b);a+b}).runT)

Free Monad

  1. trait Interact[A] //交互数据类型
  2. //提问,等待返回String类型答案
  3. case class Ask(prompt: String) extends Interact[String]
  4. //告知,有没有返回结果
  5. case class Tell(msg: String) extends Interact[Unit]
  6. //Tell依赖Ask的结果 这么写编译不过 不是monad
  7. // for {
  8. // x <- Ask("What's your first name?")
  9. // y <- Ask("What's your last name?")
  10. // _ <- Tell(s"Hello $y $x!")
  11. // } yield ()
  12. trait Free[F[_],A] {
  13. //Monad
  14. def unit(a: A) = Return(a)
  15. def flatMap[B](f: A => Free[F,B]): Free[F,B] = this match {
  16. case Return(a) => f(a)
  17. case Bind(fa,g) => Bind(fa, (x: Any) => g(x) flatMap f)
  18. //case Bind(fa,g) => Bind(fa, g andThen (_ flatMap f))
  19. }
  20. def map[B](f: A => B): Free[F,B] = flatMap(a => Return(f(a)))
  21. //Interpreter
  22. //可以用折叠算法来实现F[_]结构中表达式的转换
  23. def foldMap[G[_]: Monad](f: F ~> G): G[A] = this match {
  24. case Return(a) => implicitly[Monad[G]].unit(a)
  25. case Bind(b,g) => implicitly[Monad[G]].flatMap(f(b))(a => g(a).foldMap(f))
  26. }
  27. }
  28. case class Return[F[_],A](a: A) extends Free[F,A] //表示计算结束
  29. case class Bind[F[_],I,A](a: F[I], f: I => Free[F,A]) extends Free[F,A] //表示依赖计算 或者延续计算
  30. implicit def lift[F[_],A](fa: F[A]): Free[F,A] = Bind(fa, (a: A) => Return(a))
  31. val prg = for {
  32. x <- Ask("What's your first name?")
  33. y <- Ask("What's your last name?")
  34. _ <- Tell(s"Hello $y $x!")
  35. } yield ()
  36. println(prg) //返回Monad 紧紧描述算法而已
  37. // Bind(Ask("What's your first name?"), (a: String) => Return(a)) //fa , g
  38. // _ => Bind(Ask("What's your last name?"), (a: String) => Return(a))
  39. // Bind(Ask("What's your first name?"), (a: Any) => Bind(Ask("What's your last name?"), (a: String) => Return(a)))
  40. // _ => Bind(Tell(s"Hello $y $x!"), (a: Unit) => Return(a))
  41. //
  42. // Bind(Ask("What's your first name?"), (a: Any) => Bind(Ask("What's your last name?"), (a: String) => Return(a)))
  43. //Free Monad 分为Monad和Interpreter 是算法和运算分离的
  44. //Interpreter解译程序形成针对特定运行环境的可运行代码
  45. //Interpreter程序运算是通过一个转换函数实现的。这个函数把F[_]这样一个算法解译成G[_]这样一个针对可运行环境的Monad运行代码。这种转换就是自然转换(Natural Transformation)
  46. trait ~>[F[_],G[_]] {
  47. def apply[A](fa: F[A]): G[A]
  48. }
  49. type Id[A] = A
  50. implicit val idMonad: Monad[Id] = new Monad[Id] {
  51. def unit[A](a: A) = a
  52. def flatMap[A,B](fa: A)(f: A => B): B = f(fa)
  53. }
  54. object Console extends (Interact ~> Id) { //Interact ~> Id的实现
  55. def apply[A](i: Interact[A]): A = i match {
  56. case Ask(prompt) => {
  57. println(prompt)
  58. readLine
  59. }
  60. case Tell(msg) => println(msg)
  61. }
  62. }
  63. prg.foldMap(Console)
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注