関数型っぽさが増してきます。純粋関数では副作用が無いわけですが、どうやってデータを更新するの?というのが主な章です。Listの定義が現れて面食らいますが、読み解くのはそこまで難しくありませんでした。単方向リストの説明も行われ、パターンマッチの説明があります。matchはやっぱり便利ですね。ここでパターンマッチの簡単なクイズがあります(略)。次に、データが変更されないことを利用して、データの共通化をして節約してるよ、という話が入ります。ここから怒涛の練習問題です。詰込型プログラミングです。エラー処理は各自考えよ。リストの定義などはgithubに上げられています。github.comエラー処理は色々と方法がありそうですが、とりあえずNilを返すことにしました。本家ScalaのListでは例外を吐いていましたが、とりあえず簡単に実装できることを優先します。}↓はテスト用のコードです。println(List.init(y))}dropだけネストしてて不格好だなぁ......。豆知識として、dropWhileの型推論を改善する方法が紹介されています。カリー化して2つ目の引数を推測できるようにしています。定義されていたsumとproductを一般化するため、foldRightが出てきました。Scalaを触り始めて最初にこいつを見た時は、全く意味がわからなかったことを覚えています。foldRightでのproductは0.0を検出した瞬間に、直ちに再帰を中止して0.0を返せるか?質問されてしまいました。いうパターンもあるのね。独自のproductであれば0.0の要素まで来た時に続く再帰をさせず0.0を返すことはできますが、そこまでの要素は展開されてしまい計算するしかありません。foldRightだとfの中でそのような処理を行えますが、fが評価されるのは全て展開された後です。いうわけで「直ちに0.0を返せるか」という問はNoだと言えます。Nil及びCons自体をfoldRightに渡すとどうなるか?データコンストラクタとの関係は?なんとも曖昧な質問ではありますが、畳み込みでListのコンストラクタができる、ということだと思います。2要素をくっつけるのも演算として捉えられ、それを繰り返すことで単方向リストも作れるよ、というまさに抽象的な考え方です。foldRightを使ってリストの長さを求めよ。1)foldRightは末尾再帰でないため、スタックセーフでない。末尾再帰なfoldLeftを実装せよ。}foldLeftがさっくり出てきましたね。末尾再帰でないから〜という方向から紹介するのは何となく目新しいです。foldLeftを使って、sum/product/lengthを実装せよ。1)reverseを実装せよ。x))foldRightでコンストラクトすると普通の順でしたが、foldLeftを使うと逆順になりますね。foldRightを使ってfoldLeftを記述できるか?またその逆は?難問マークは、なんか辛い問題に付けられているらしいです。a3)となっていることを考えると、リストをひっくり返して適用すれば同じようなことができそうです。fの適用順も違いますので、引数の順をひっくり返したf2を用意しました。}テスト用コードです。_))上手く行ってそうです。reverseでfoldLeftを使っているので、foldLeft2をfoldLeftとして使うと無限ループしてしまいました。解説を読むと、何ともいかついコードが現れました。g(f(a,b)))(z)ぱっと見では理解できませんが、具体的なListなどを放り込んであげると見えてきました。うまーく関数を渡すことで、処理順を変えています。これがパッと書けるとステキ。foldLeftを使ってappendを実装せよ。_))うーん、スッキリ。定義した関数を使って、複数のリストからなるリストを1つのリストとして連結する関数を実装せよ。appendを使って各要素をListとみなしてくっつけていけば出来そうです。_))IntelliJの教えに従い、appendは以下のように簡単に呼び出せます。List[A])(append)各要素に1を足したリストを返す関数を実装せよ。y))List[Int]をList[Double]に変換する関数を実装せよ。y))あのmapがこんなにも簡単に!filter関数を記述せよ。}ifが出てきて若干不格好です。flatMapを実装せよ。concat(map(as)(f))事前に作成した関数が活きました。flatMapを使ってfilterを実装せよ。条件を満たさない場合は空配列を返してあげることで、flattenした際に勝手に消えてくれそうです。いうわけで、受け取った関数を少しいじってflatMapに渡します。}リストを2つ受け取り、対応する要素同士を足しあわせたリストを返す関数を実装せよ。}なんだか不格好ですね。matchが入れ子になっていてどうにもみにくい......。↑を一般化したzipWithを作れ。}解説を見ると、2つのListをまとめてmatchで判定しています。(sub)が含まれているかを判定する、hasSubsequenceを作れ。効率的なのは難しいかもしれない。5章でもう一度取り上げる。手前から順番にsub.length個取り出すのを試してみると実現できそうです。takeを実装し、それを利用して作りました。}挙動は大丈夫そうですが、相変わらず若干不格好です。答えがどうなっているか見ると、startsWithをまず作って利用しています。前方から一致を見てゆく方法です。シンプルな上に両方末尾再帰になっていて何とも凄いです。著者的にも「正しい挙動をするかわかりにくい」そうです。5章で再度取り上げる胸熱展開らしいので、そこまで待機......。ここまで大量の練習問題が出てきて満身創痍ですが、さらに新しいデータ構造が出てきます。代数的データ型の説明があり、Treeの実装、及び練習問題が出てきます。2分木のノード数を数えるsize、最大の要素を返すmaximum、二分木のルートから任意のノードへの最長距離を返す関数depth、二分木の各要素を変換するmapを実装せよ。}上記関数を一般化したfoldを実装せよ。それを使って上記関数を再実装せよ。Tree[B])(Branch(_,_))いやー、短い実装だ。型にガイドされながら書けます。一般化のスキルを磨いてね!という修行を課して本章は締められています。思ったこと大量の練習問題がありましたが、それぞれ思ったより短く書けてびっくりしました。解いていると、何となく思考方法が見えてきたような気がしないでもないです。木の走査など、「めんどくさい......」となる処理でもシンプルに書けるのは、一度体験する価値があると思います。次章はエラー処理で、普段のプログラミングでも困りがちな箇所にフォーカスしてゆくそうです。reserved.スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。