` 1  trait Monad[M[_]] { 2  def unit[A](a: A): M[A] 3 def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B] 4 def compose[A,B,C](f: A => M[B], g: B => M[C]): A => M[C] = { 5 a => { flatMap(f(a))(g)} 6  } 7 def flatMapByCompose[A,B](ma: M[A])(f: A => M[B]): M[B] = { 8 compose(((_):Unit) => ma,f)(()) 9  }10 def join[A](mma: M[M[A]]): M[A] = {11 flatMap(mma)(ma => ma)12  }13 def map[A,B](ma: M[A])(f: A => B): M[B] = {14 flatMap(ma)(a => unit(f(a)))15  }16 def flatMapByJoin[A,B](ma: M[A])(f: A => M[B]): M[B] = {17 join(map(ma)(a => f(a)))18  }19 def composeByJoin[A,B,C](f: A => M[B], g: B => M[C]): A => M[C] = {20 a => { join(map(f(a))(g)) }21  }22 }`

`1  trait Functor[F[_]] {2 def map[A,B](fa: 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 }`

`1 def map2[A,B,C](ma: M[A], mb: M[B])(f: (A,B) => C): M[C] = {2 flatMap(ma)(a => map(mb)(b => f(a,b)))3 }`

`1 def sequence[A](lma: List[M[A]]): M[List[A]] = {2 lma.foldRight(unit(List[A]()))((a,ma) => map2(a,ma)(_ :: _))3  }4 def traverse[A,B](la: List[A])(f: A => M[B]): M[List[B]] = {5 la.foldRight(unit(List[B]()))((a,mb) => map2(f(a),mb)(_ :: _))6 }`

`1 def Map2[A,B,C](ma: Option[A], mb: Option[B])(f: (A,B) => C): Option[C] = {2  (ma,mb) match {3 case (Some(a),Some(b)) => Some(f(a,b))4 case _ => None5  }6 }`

`1 def map[A,B] (ma: M[A]) (f: A => B) : M[B]2 def map2[A,B,C](ma: M[A], mb: M[B])(f: (A,B) => C): M[C]3 def flatMap[A,B] (ma: M[A]) (f: A => M[B]) : M[B]`

map和map2都是正宗的在高阶数据类型结构内的函数施用，但flatMap的函数是 A=>M[B]，会破坏结果的结构。例如：我们对一个有3个元素的List进行map操作，结果仍然是一个3个元素的List。但如果flatMap的话就可能会产生不同长度的List：

`1 def apply[A,B](fab: F[A => B])(fa: F[A]): F[B]`

` 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  map2(fab,fa)(_(_)) 9  }10 def map[A,B](fa: F[A])(f: A => B): F[B] = {11 // map2(unit(f),fa)((f,a) => f(a))12  map2(unit(f),fa)(_(_))13  }14 def mapByApply[A,B](fa: F[A])(f: A => B): F[B] = {15  apply(fa)(unit(f))16  }17 }`

` 1 def Map2[A,B,C](ma: Option[A], mb: Option[B])(f: (A,B) => C): Option[C] = { 2  (ma,mb) match { 3 case (Some(a),Some(b)) => Some(f(a,b)) 4 case _ => None 5  } 6  } 7 def apply[A,B](ma: Option[A])(f: Option[A => B]): Option[B] = { 8  (ma,f) match { 9 case (Some(a),Some(f)) => Some(f(a))10 case _ => None11  }12  }13 def flatMap[A,B](ma: Option[A])(f: A => Option[B]): Option[B] = {14  ma match {15 case Some(a) => f(a)16 case _ => None17  }18 }`

` 1 def map3[A,B,C,D](ma: M[A], mb: M[B], mc: M[C])(f: (A,B,C) => D): M[D] = { 2  map2(ma, 3 map2(mb,mc){(b,c) => (b,c)} 4 ){(a,bc) => { 5 val (b,c) = bc 6  f(a,b,c) 7  }} 8  } 9 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] = {10  map2(ma,11  map2(mb,12 map2(mc,md){(c,d) => (c,d)}13 ){(b,cd) => (b,cd)}14 ){(a,bcd) => {15 val (b,(c,d)) = bcd16  f(a,b,c,d)17  }}18  }19 def map5[A,B,C,D,E,F](ma: M[A], mb: M[B], mc: M[C], md: M[D], me: M[E])(f: (A,B,C,D,E) => F): M[F] = {20  map2(ma,21  map2(mb,22  map2(mc,23 map2(md,me){(d,e) => (d,e)}24 ){(c,de) => (c,de)}25 ){(b,cde) => (b,cde)}26 ){(a,bcde) => {27 val (b,(c,(d,e))) = bcde28  f(a,b,c,d,e)29  }}30 }`

unit(f.curried) = M[A=>B=>C]。apply(M[A])(M[A=>B]):M[B]。我们可以针对每个M值分步施用apply：A=>B=>C >>> A=>BC >>> BC=B=>C,apply(M[A])(unit(f.curried))=M[B=>C],那么可以用apply来实现map3,map4,map5:

` 1 def map3[A,B,C,D](ma: F[A], mb: F[B], mc: F[C])(f: (A,B,C) => D): F[D] = { 2  apply(mc)(apply(mb) 3  (apply(ma)(unit(f.curried)))) 4  } 5 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] = { 6  apply(md)(apply(mc) 7  (apply(mb) 8  (apply(ma)(unit(f.curried))))) 9  }10 def map5[A,B,C,D,E,G](ma: F[A], mb: F[B], mc: F[C],md: F[D], me: F[E])(f: (A,B,C,D,E) => G): F[G] = {11  apply(me)(apply(md)12  (apply(mc)13  (apply(mb)14  (apply(ma)(unit(f.curried))))))15 }`

` 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 }  `

` 1 implicit def eitherMonad[E] = new Monad[({type l[V] = Either[E,V]})#l] { 2 def unit[A](a: A) = Right(a) 3 def flatMap[A,B](ea: Either[E,A])(f: A => Either[E,B]): Either[E,B] = { 4  ea match { 5 case Right(a) => f(a) 6 case Left(e) => Left(e) 7  } 8  } 9  }10  def validateName(name: String): Either[String,String]11  def validatebirthdate(birthdate: Date): Either[String,Date]12 def validatePhone(phone: String): Either[String,String]`

`1 validateName(field1) flatMap (f1 =>2 validateBirthdate(field2) flatMap (f2 =>3 validatePhone(field3) map (WebForm(_, _, _))`

WebForm是个构建函数（constructor）: case class WebForm(name: String, birthdate: Date, phone: String)。如果我们像上面那样逐个flatMap验证函数结果的话，从flatMap的具体实现代码可以看出：如果validName返回错误的话，下面的validateBirthdate, validatePhone都不会运行。系统直接将错误返回用户，用户要先改正了第一个错误再提交后系统继续下一个字段的验证。如果需要填写多个字段的信息表格什么的就更凸显麻烦了。如果我们用Applicative风格：

`1 apply(apply(apply((WebForm(_, _, _)).curried)(2  validateName(field1)))(3  validateBirthdate(field2)))(4 validatePhone(field3))`

`1 trait Validation[+E,+A]2 case class Failure[E](head: E, tail: Vector[E]) extends Validation[E,Nothing]3 case class success[A](a: A) extends Validation[Nothing,A]`

Validation类型的Failure可以容纳多条数据。注意 +E,+A使我们可以代入Nothing: Validate[E,Nothing],Validation[Nothing,A]。

` 1 implicit def validationApplicative[E] = new Applicative[({type l[A] = Validation[E,A]})#l] { 2 def unit[A](a: A) = Success(a) 3 def map2[A,B,C](fa: Validation[E,A], fb: Validation[E,B])(f: (A,B) => C): Validation[E,C] = { 4  (fa,fb) match { 5 case (Success(a),Success(b)) => Success(f(a,b)) 6 case (Failure(h1,t1),Failure(h2,t2)) => Failure(h1, t1 ++ Vector(h2) ++ t2) 7 case ([email protected](_,_),_) => e 8 case (_,[email protected](_,_)) => e 9  }10  }11 }`

map2+unit是Applicative的最基本组件函数。我们只要实现这两个函数就行了。

` 1 trait Validation[+E,+A] 2 case class Failure[E](head: E, tail: Vector[E]) extends Validation[E,Nothing] 3 case class Success[A](a: A) extends Validation[Nothing,A] 4 implicit def validationApplicative[E] = new Applicative[({type l[A] = Validation[E,A]})#l] { 5 def unit[A](a: A) = Success(a) 6 def map2[A,B,C](fa: Validation[E,A], fb: Validation[E,B])(f: (A,B) => C): Validation[E,C] = { 7  (fa,fb) match { 8 case (Success(a),Success(b)) => Success(f(a,b)) 9 case (Failure(h1,t1),Failure(h2,t2)) => Failure(h1, t1 ++ Vector(h2) ++ t2)10 case ([email protected](_,_),_) => e11 case (_,[email protected](_,_)) => e12  }13  }14 }15 import java.util.Date16 case class WebForm(name: String, birthdate: Date, phone: String)1718 def validateName(name: String): Validation[String, String] = {19 if (name != "")20  Success(name)21 else Failure("Name cannot be empty", Vector())22 }2324 def validateBirthdate(birthdate: String): Validation[String, Date] = {25 try {26 import java.text._27 Success((new SimpleDateFormat("yyyy-MM-dd")).parse(birthdate))28 } catch {29 case e => Failure("Birthdate must be in the form yyyy-MM-dd", Vector())30  }31 }32 def validatePhone(phoneNumber: String): Validation[String, String] = {33 if (phoneNumber.matches("[0-9]{10}"))34  Success(phoneNumber)35 else Failure("Phone number must be 10 digits", Vector())36 }37 def validateWebForm(name: String, birthdate: String, phone: String): Validation[String, WebForm] = {38  apply(validateName(name))39  (apply(validateBirthdate(birthdate))40  (apply(validatePhone(phone))((WebForm(_,_,_)).curried)))))41 }`

Top