## 动力学知识库

在前面的几篇讨论里我们初步对FP有了些少了解：FP嘛，不就是F[A]吗？也是，FP就是在F[]壳子（context）内对程序的状态进行更改，也就是在F壳子（context）内施用一些函数。再直白一点就是在F壳子内进行OOP惯用的行令编程（imperative programming）。当然，既然是在壳子（context）内进行编程这种新的模式，那么总需要些新的函数施用方法吧。我们再次审视一下以前了解过的FP函数施用方法：

`1 1 // Functor : map[A,B] (F[A])(f: A => B): F[B]2 2 // Applicative: ap[A,B] (F[A])(f: F[A => B]): F[B] 3 3 // Monad : flatMap[A,B](F[A])(f: A => F[B]): F[B]`

`1 def ap[A,B](ma: F[A])(mf: F[A => B]): F[B] = mf.flatMap(f => ma.flatMap(a => point(f(a)))2 def flatMapByJoin[A,B](ma: M[A])(f: A => M[B]): M[B] = join(map(ma)(a => f(a)))3 def join[A](mma: M[M[A]]): M[A]`

` 1 trait KeyLog[K] { 2  def value: K 3  def log: String 4 override def toString = "["+value+","+log+"]" 5 } 6 object KeyLog { 7 def apply[K](k: K, msg: String): KeyLog[K] = new KeyLog[K] { 8 def value = k 9 def log = msg10  }11 }1213 KeyLog(3,"Entered Number 3") //> res0: Exercises.keylog.KeyLog[Int] = [3,Entered Number 3]14 KeyLog("Hello", "Entered String 'Hello'") //> res1: Exercises.keylog.KeyLog[String] = [Hello,Entered String 'Hello']`

`1 trait KeyLog[K] {2  def value: K3  def log: String4 override def toString = "["+value+","+log+"]"5 def mapLog(preLog: String): KeyLog[K] = KeyLog(value,preLog +";"+log)6 }`

`1 trait KeyLog[K] {2  def value: K3  def log: String4 override def toString = "["+value+","+log+"]"5 def mapLog(preLog: String): KeyLog[K] = KeyLog(value,preLog +";"+log)6 def flatMap[I](f: K => KeyLog[I]): KeyLog[I] =7  f(value).mapLog(log)8 }`

`1 KeyLog(3,"Entered Number 3").flatMap(a => KeyLog("Hello", "Entered String 'Hello'"))2 //> res2: Exercises.keylog.KeyLog[String] = [Hello,Entered Number 3;Entered Stri3 //| ng 'Hello']`

` 1 object KeyLog { 2 def apply[K](k: K, msg: String): KeyLog[K] = new KeyLog[K] { 3 def value = k 4 def log = msg 5  } 6 import scalaz._ 7 import Scalaz._ 8 implicit object keylogMonad extends Monad[KeyLog] { 9 def point[K](k: => K): KeyLog[K] = KeyLog(k,"")10 def bind[K,I](kk: KeyLog[K])(f: K => KeyLog[I]): KeyLog[I] = kk flatMap f11  }12 }`

`def enterInt(k: Int): KeyLog[Int] = KeyLog(k, "Number:"+k.toString)//> enterInt: (k: Int)Exercises.keylog.KeyLog[Int]def enterStr(k: String): KeyLog[String] = KeyLog(k,"String:"+k)//> enterStr: (k: String)Exercises.keylog.KeyLog[String]enterInt(3) >>= {a => enterInt(4) >>= {b => enterStr("Result:") map {c => c + (a * b).toString} }}//> res3: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String://| Result:;]for {a <- enterInt(3)b <- enterInt(4)c <- enterStr("Result:")} yield c + (a * b).toString //> res4: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String//| :Result:;]`

value和log都按照要求实现了转变。

`1 for {2 a <- enterInt(3)3 b <- enterInt(4) if b > 04 c <- enterStr("Result:")5 } yield c + (a * b).toString`

` 1 trait MonadPlus[F[_]] extends Monad[F] with ApplicativePlus[F] { self => 2 //// 3 4 /** Remove `f`-failing `A`s in `fa`, by which we mean: in the 5  * expression `filter(filter(fa)(f))(g)`, `g` will never be invoked 6  * for any `a` where `f(a)` returns false. 7 */ 8 def filter[A](fa: F[A])(f: A => Boolean) = 9 bind(fa)(a => if (f(a)) point(a) else empty[A])10 ...`

`1 trait ApplicativePlus[F[_]] extends Applicative[F] with PlusEmpty[F] { self =>`

ApplicativePlus又继承了PlusEmpty: scalaz/PlusEmpty.scala

`1 trait PlusEmpty[F[_]] extends Plus[F] { self =>2 ////3  def empty[A]: F[A]4 ...`

PlusEmpty定义了抽象成员empty[A]，又继承了Plus: scalar/Plus.scala

` 1 trait Plus[F[_]] { self => 2 //// 3 4 /**The composition of Plus `F` and `G`, `[x]F[G[x]]`, is a Plus */ 5 def compose[G[_]](implicit G0: Plus[G]): Plus[({type λ[α] = F[G[α]]})#λ] = new CompositionPlus[F, G] { 6 implicit def F = self 7 8 implicit def G = G0 9  }1011 /**The product of Plus `F` and `G`, `[x](F[x], G[x]])`, is a Plus */12 def product[G[_]](implicit G0: Plus[G]): Plus[({type λ[α] = (F[α], G[α])})#λ] = new ProductPlus[F, G] {13 implicit def F = self1415 implicit def G = G016  }1718 def plus[A](a: F[A], b: => F[A]): F[A]1920 def semigroup[A]: Semigroup[F[A]] = new Semigroup[F[A]] {21 def append(f1: F[A], f2: => F[A]): F[A] = plus(f1, f2)22  }23 ...`

`1 for {2 a <- enterInt(3)3 b <- enterInt(4) if b > 04 c <- enterStr("Result:")5 } yield c + (a * b).toString`

` 1 for { //list 2 a <- 1 |-> 50 if a.shows contains '7' 3 } yield a //> res5: List[Int] = List(7, 17, 27, 37, 47) 4 for { //option 5 a <- Some(3) 6 b <- Some(4) if a < b 7 } yield b //> res6: Option[Int] = Some(4) 8 for { //option 9 a <- Some(3)10 b <- Some(4) if a > b11 } yield b //> res7: Option[Int] = None`

List和Option的empty分别是：Nil和None，这个很容易理解。那么plus呢？把 plus(list1,list2):list3 = list1 ++ list2这个倒是容易理解，但plus(option1,option2):option3这个又应该怎么理解呢？我们还是看看在scalaz里是怎么定义plus的吧：scalaz.std/List.scala

`1 implicit val listInstance = new Traverse[List] with MonadPlus[List] with Each[List] with Index[List] with Length[List] with Zip[List] with Unzip[List] with Align[List] with IsEmpty[List] with Cobind[List] {2 ...3 def empty[A] = Nil4 def plus[A](a: List[A], b: => List[A]) = a ++ b5 ...`

List的plus就是把两个List接起来（concat）

scalaz.std/Option.scala

`1 implicit val optionInstance = new Traverse[Option] with MonadPlus[Option] with Each[Option] with Index[Option] with Length[Option] with Cozip[Option] with Zip[Option] with Unzip[Option] with Align[Option] with IsEmpty[Option] with Cobind[Option] with Optional[Option] {2 ...3 def empty[A]: Option[A] = None4 def plus[A](a: Option[A], b: => Option[A]) = a orElse b5 ...`

`1 List(1,2,3) <+> List(4,5,6) //> res4: List[Int] = List(1, 2, 3, 4, 5, 6)2 Nil <+> List(1,2,3) //> res5: List[Int] = List(1, 2, 3)3 List(1,2,3) <+> Nil //> res6: List[Int] = List(1, 2, 3)4 none <+> 2.some //> res7: Option[Int] = Some(2)5 2.some <+> 3.some //> res8: Option[Int] = Some(2)6 2.some <+> none //> res9: Option[Int] = Some(2)7 none <+> none //> res10: Option[Nothing] = None`

` 1 import scalaz._ 2 import Scalaz._ 3 object keylog { 4 trait KeyLog[+K] { 5 override def toString = this match { 6 case KeyIn(value,log) => "["+value+","+log+"]" 7 case _ => "[Keypad Locked]" 8  } 9 def mapLog(preLog: String): KeyLog[K] = this match {10 case KeyIn(value,log) => KeyIn(value,preLog +";"+log)11 case _ => KeyLock12  }13 def flatMap[I](f: K => KeyLog[I]): KeyLog[I] = this match {14 case KeyIn(value,log) => f(value).mapLog(log)15 case _ => KeyLock16  }17 }18 case class KeyIn[K](value: K, log: String) extends KeyLog[K]19 case object KeyLock extends KeyLog[Nothing]20 object KeyLog {21 /* def apply[K](k: K, msg: String): KeyLog[K] = new KeyLog[K] {22  def value = k23  def log = msg24  } */25 implicit object keylogMonad extends Monad[KeyLog] {26 def point[K](k: => K): KeyLog[K] = KeyIn(k,"")27 def bind[K,I](kk: KeyLog[K])(f: K => KeyLog[I]): KeyLog[I] = kk flatMap f28  }29 }`

` 1 def enterInt(k: Int): KeyLog[Int] = KeyIn(k, "Number:"+k.toString) 2 //> enterInt: (k: Int)Exercises.keylog.KeyLog[Int] 3 def enterStr(k: String): KeyLog[String] = KeyIn(k,"String:"+k) 4 //> enterStr: (k: String)Exercises.keylog.KeyLog[String] 5 enterInt(3) >>= {a => enterInt(4) >>= {b => enterStr("Result:") map {c => c + (a * b).toString} }} 6 //> res0: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String 7 //| :Result:;] 8 for { 9 a <- enterInt(3)10 b <- enterInt(4)11 c <- enterStr("Result:")12 } yield c + (a * b).toString //> res1: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String13 //| :Result:;]`

现在把KeyLock效果加进去：

`1 enterInt(3) >>= {a => (KeyLock: KeyLog[Int]) >>= {b => enterStr("Result:") map {c => c + (a * b).toString} }}2 //> res2: Exercises.keylog.KeyLog[String] = [Keypad Locked]3 for {4 a <- enterInt(3)5 b <- enterInt(4)6 x <- (KeyLock: KeyLog[String])7 c <- enterStr("Result:")8 } yield c + (a * b).toString //> res3: Exercises.keylog.KeyLog[String] = [Keypad Locked]`

` 1 implicit object keylogMonad extends Monad[KeyLog] with MonadPlus[KeyLog] { 2 def point[K](k: => K): KeyLog[K] = KeyIn(k,"") 3 def bind[K,I](kk: KeyLog[K])(f: K => KeyLog[I]): KeyLog[I] = kk flatMap f 4 5 def empty[K]: KeyLog[K] = KeyLock 6 def plus[K](a: KeyLog[K], b: => KeyLog[K]): KeyLog[K] = a match { 7 case KeyIn(value,log) => KeyIn(value,log) 8 case KeyLock => b 9  }10 }`

` 1 for { 2 a <- enterInt(3) 3 b <- enterInt(4) 4 c <- enterStr("Result:") 5 } yield c + (a * b).toString //> res3: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String 6 //| :Result:;] 7 for { 8 a <- enterInt(3) 9 b <- enterInt(4) if b > 010 c <- enterStr("Result:")11 } yield c + (a * b).toString //> res4: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;;Strin12 //| g:Result:;]13 for {14 a <- enterInt(3)15 b <- enterInt(4) if b > 516 c <- enterStr("Result:")17 } yield c + (a * b).toString //> res5: Exercises.keylog.KeyLog[String] = [Keypad Locked]`