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にすると、「+」メソッドの抽象化が必要になり、関数パラメータとしてもらう必要がある。