# 泛函编程（14）－try to map them all

虽然明白泛函编程风格中最重要的就是对一个管子里的元素进行操作。这个管子就是这么一个东西：F[A]，我们说F是一个针对元素A的高阶类型，其实F就是一个装载A类型元素的管子，A类型是相对低阶，或者说是基础的类型。泛函编程风格就是在F内部用对付A类的函数对里面的元素进行操作。但在之前现实编程中确总是没能真正体会这种编程模式畅顺的用法：到底应该在哪里用？怎么用？可能内心里还是没能摆脱OOP的思维方式吧。在前面Stream设计章节里，我们采用了封装形式的数据结构设计，把数据结构uncons放进了特质申明里：

` 1 trait Stream[+A] { 2  def uncons: Option[(A, Stream[A])] 3 def isEmpty: Boolean = uncons.isEmpty 4  } 5  object Stream { 6 def empty[A]: Stream[A] = new Stream[A] { 7 def uncons = None 8  } 9 def cons[A](h: => A, t: => Stream[A]): Stream[A] = new Stream[A] {10 def uncons = Some((h,t))11  }12 def apply[A](as: A*): Stream[A] = {13 if (as.isEmpty) empty14 else cons(as.head, apply(as.tail: _*))15  }1617 }`

`1 //戴着套子进行模式匹配2 def toList: List[A] = uncons match {3 case None => Nil4 case Some((h,t)) => h :: t.toList5  }6 //用map操作7 def toList: List[A] = uncons.map {8 case (h,t) => h :: t.toList9 } getOrElse(Nil)`

` 1 //戴着套子 2 def take(n: Int): Stream[A] = { 3 if ( n == 0 ) empty 4 else 5  uncons match { 6 case None => empty 7 case Some((h,t)) => cons(h,t.take(n-1)) 8  } 9  }10 //用map操作11 def take(n: Int): Stream[A] = {12 if ( n == 0 ) empty13 else14  uncons map {15 case (h,t) => cons(h,t.take(n-1))16  } getOrElse(empty)17  }18 //戴着套子19 def takeWhile(f: A => Boolean): Stream[A] = {20  uncons match {21 case None => empty22 case Some((h,t)) => if ( f(h) ) cons(h,t.takeWhile(f)) else empty23  }24  }25 //用map操作26 def takeWhile(f: A => Boolean): Stream[A] = {27  uncons map {28 case (h,t) => if ( f(h) ) cons(h,t.takeWhile(f)) else empty29  } getOrElse empty30  }31 //高阶类型操作32 def foldRight[B](z: B)(op: (A, => B) => B): B = {33  uncons match {34 case None => z35 case Some((h,t)) => op(h,t.foldRight(z)(op))36  }37  }38 //monadic style39 def foldRight[B](z: B)(op: (A, => B) => B): B = {40  uncons map {41 case (h,t) => op(h,t.foldRight(z)(op))42  } getOrElse z43 }`

` 1 //没用map方式 2 def unfold[A,S](z: S)(f: S => Option[(A,S)]): Stream[A] ={ 3  f(z) match { 4 case None => empty 5 case Some((a,s)) => cons(a,unfold(s)(f)) 6  } 7  } 8 def mapByUnfold[B](f: A => B): Stream[B] = { 9  unfold(uncons) {10 case Some((h,t)) => Some((f(h),Some((t.headOption.getOrElse(h), t.tail.tailOption.getOrElse(empty)))))11 case _ => None12  }13  }14 def zipWithByUnfold[B,C](b: Stream[B])(f: (A,B) => C): Stream[C] = {15  unfold((uncons,b.uncons)) {16 case (Some((ha,ta)),Some((hb,tb))) => Some(f(ha,hb),(Some((ta.head,ta.tail)),Some((tb.head,tb.tail))))17 case _ => None18  }19 }`

` 1 def unfoldWithMap[A,S](z: S)(f: S => Option[(A,S)]): Stream[A] ={ 2  f(z) map { 3 case (a,s) => cons(a,unfold(s)(f)) 4  } getOrElse empty 5  } 6 def mapByUnfoldWithMap[B](f: A => B): Stream[B] = { 7 unfold(this) { s => 8 this.uncons map { 9 case (h,t) => (f(h),t)10  }11  }12 }`

` 1 def zipWithByUnfoldWithMap[B,C](b: Stream[B])(f: (A,B) => C): Stream[C] = { 2 //起始状态是tuple(Stream[A],Stream[B])，状态转换函数>>> （s1,s2) => Option(a, (s1,s2)) 3 unfold((this,b)) { s => { 4 for { 5 a <- s._1.uncons //用flatMap从Option[(A,Stream[A])]取出元素 >>> (A,Stream[A]) 6 b <- s._2.uncons //用flatMap从Option[(B,Stream[B])]取出元素 >>> (B,Stream[B]) 7  } yield { 8 ( f(a._1, b._1), (a._2, b._2) ) //返回新的状态：C >>> (f(a,b),(ta,tb)) 9  }10  }11  }12 }`