技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

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 で処理すれば終了。