Scala 関数型デザイン&プログラミング:Exercize3.16-3.23
Scala 関数型デザイン&プログラミング:Exercize3.2 - 3.13 - 謎言語使いの徒然 の続き。
Exercise 3.16
各要素に +1 したリストを返す関数を作れ。
なんか仕様的に map 関数に似てるなーと思った。
とりあえず フォイ
def map[A, B](as: List[A], func: A => B): List[B] = foldRight(as, Nil:List[B])((a, b) => Cons(func(a), b)) def increment(as: List[Int]): List[Int] = map[Int, Int](as, v => v + 1) /* printRec(List.increment(List(1, 2, 3, 4))) */
Exercise 3.17
List[Double] を List[String] にする関数を作りなさい。
はいはい mapmap
def toStringList[A](as: List[A]): List[String] = map[A, String](as, _.toString)
しかしこの map 型指定しないとコンパイルコケるのはダサいな。
Exercise 3.18
下記シグネチャで map 作れ
def map[A, B](as: List[A], func: A => B): List[B]
上記 map のシグネチャだけ変更。
何か型推論がいい仕事始めて、「map[A, String](as, _.toString)
」が「map(as)( _.toString)
」になった。
引数が一つであることを(curry にでもして)保証すると精度でも上がるのかね?
Exercise 3.19
与えられた条件を満たされるまでリストから要素を削除する filter 関数を記述せよ。
def filter[A](as: List[A])(f: A => Boolean): List[A]
まぁ foldRight あれば余裕な
def filter[A](as: List[A])(f: A => Boolean): List[A] = foldRight(as, Nil: List[A])((a, b) => if (f(a)) Cons(a, b) else b) /* printRec(List.filter(List(1,2,3,4,5,6,7,8,9))(_ % 2 == 0)) */
Exercise3.20
map と似た動きをする関数、flatMap を作れ。シグネチャは下記の通り。
def flatMap[A,B](as: List[A])(f: A => List[B]): List[B]
flatMap(List(1, 2, 3))(i => List(i, i))
と書いたら、List(1, 1, 2, 2, 3, 3)
を返せ。
Scala 標準の flatMap ほど高機能ではないか…?
def flatMap[A,B](as: List[A])(f: A => List[B]): List[B] = concat(map(as)(f)) /* printRec(List.flatMap(List(1, 2, 3))(a => List(a, a))) */
Exercise3.21
flatMap を使って filter を実装せよ。
何だ? f(x)==false
の時 Nil にでもするのか?
def filterViaFlatMap[A](as: List[A])(f: A => Boolean): List[A] = flatMap(as)(a => if(f(a)) List(a) else Nil: List[A]) /* printRec(List.filterViaFlatMap(List(1,2,3,4,5))(_ % 2 == 0)) */
何だろう…効率的な実装に見えない。
Exercise3.22
同数二つの List[Int] を受け取って、対応する要素同士で足し算する関数を作れ。
def addPairwise(list: List[Int], list1: List[Int]): List[Int] = { def addPairwise(a: List[Int], b: List[Int], sum: List[Int]): List[Int] = { (a, b) match { case (Nil, _) => sum case (_, Nil) => sum case (Cons(ah, at), Cons(bh, bt)) => addPairwise(at, bt, Cons(ah + bh, sum)) } } reverse(addPairwise(list, list1, Nil: List[Int])) } /* printRec(List.addPairwise(List(1,2,3), List(1,2,3))) */
こうですか?わかりません。
Exercise3.23
Exercise3.22 の処理を、加算、減算にとらわれずに実行できるようにせよ。
def zipWith[A, B, C](al: List[A], bl: List[B])(f: (A, B) => C): List[C] = { def zipWith(a: List[A], b: List[B], r: List[C]): List[C] = { (a, b) match { case (Nil, _) => r case (_, Nil) => r case (Cons(ah, at), Cons(bh, bt)) => zipWith(at, bt, Cons(f(ah, bh), r)) } } reverse(zipWith(al, bl, Nil)) }
addPairwise を zipWith で処理すれば終了。