Scalaリスト遊び3(Scala関数型デザインより)
まだまだリストで遊ぶぞ。
def concat[A](l: List[List[A]]): List[A] =
foldRight(l)(Nil:List[A])(append)
- リストのリストを平らにする。やはりfoldRightで、右から、リストをappendしていく
def map[A, B](as: List[A])(f: A => B): List[B] = foldRight(as)(Nil:List[B])((h,t) => Cons(f(h),t)) def filter[A](as: List[A])(f: A => Boolean): List[A] = foldRight(as)(Nil:List[A])((h,t) => if (f(h)) Cons(h,t) else t) def flatMap[A, B](as: List[A])(f: A => List[B]): List[B] = concat(map(as)(f)) def filter2[A](as: List[A])(f: A => Boolean): List[A] = flatMap(as)(a => if (f(a)) List(a) else Nil)
- map関数。foldRightで、Nil:List[B]に対して、fを適用したあとに、Consでつなげる
- filter。Consの前のif (f(h))がミソ。else tも。
- flatMap。mapして、concatするだけ。mapの結果がList[List[A]]になるため。
- filter2。filterのflatMap実装。さっきは、Consでつなげていたが、List(a)かNilで返して、flatにする。
def addPairwise(a: List[Int], b: List[Int]): List[Int] = (a,b) match { case (Nil, _) => Nil case (_, Nil) => Nil case (Cons(h1,t1), Cons(h2,t2)) => Cons(h1+h2, addPairwise(t1,t2)) } def zipWith[A,B,C](a: List[A], b: List[B])(f: (A,B) => C): List[C] = (a,b) match { case (Nil, _) => Nil case (_, Nil) => Nil case (Cons(h1,t1), Cons(h2,t2)) => Cons(f(h1,h2), zipWith(t1,t2)(f)) }
- addPairwise zipWithのInt型版。match文がイディオム。
- addPairwiseを抽象化して、zipWithにすると、「+」メソッドの抽象化が必要になり、関数パラメータとしてもらう必要がある。