個人事業主になったので真面目にアウトプットしてみるブログ

フリーで顧客の会社に潜り込んでAndroidアプリつくって、とりあえず食っていけるようにアウトプットを増やしていくブログです。

Androidプログラマの関数型プログラミング勉強振り返り

関数型プログラミングがわからなかった。

  • 遅延評価がわからなかった(なにそれおいしいの?)
  • 純粋関数がわからなかった(こわせるよ?)
  • 参照透過性がわからなかった(オブジェクト指向のストラテジーとかに似てる?)
  • 副作用がわからなかった(結局副作用ってなんのことを指すの?)
  • ラムダがわからなかった(関数の参照・・・コールバックだよね?)
  • 高階関数がわからなかった(メソッドチェーンで書くシーケンシャルな処理だよね?)
  • イミュータブルがわからなかった(コンフリクトおきない?)
  • 状態がなくなるがわからなかった(結局状態は必要では?)
  • 宣言的がわからなかった(どれも宣言的といえなくはない?)

今はなんとなくわかる。

  • 遅延評価は、今、その処理の実行をする必要ないけど今書ける処理として書いておくやつ。書かれている場所と実行タイミングが異なって、メモリに優しい書き方。けどやりすぎる評価されるタイミングが重なって辛いとか、色々ありそう。
  • 入力が同じだったら純粋関数は結果が変わらない関数。自分でそうつくらないといけない。なので関数外のスコープの変数を参照してはいけない(やらないと無理な時もあるかも)。純粋関数もJavaにかかればあっという間に壊せる。なので出来るだけJavaよりはKotlinを選んで、末端までイミュータブルなデータを利用する。一応Stringも普通に扱えばImmutable。data classは積極的に使おう。普通のclassのインスタンスを純粋関数に代入しては壊れる元。
  • 透過参照性は組み替えても処理の全体的な性質が変わらなようにできるようなもの。純粋関数のみで構成し、うまく使うことで戦略的な組み替えが可能になる。べつに戦略的につくらなくてもいい。純粋関数でボトムアップとしてつくれば結果的透過参照性のある処理のかたまりができる(だよね?)
  • 副作用は純粋関数以外のもので構成され、他影響を与えるもの。つまりクラスのメンバ変数の参照や代入によって他の処理、次の処理の結果がインプットは同じなのに変わる可能性があるもの。同じスコープ関数の外にある変数に値を再代入することを破壊的代入、もしくは自殺行為という。ただしクロージャ的なものはスコープ外で宣言しないとできないし、クロージャへの参照のスコープを限定的にすれば、その関数(スコープ)の外からみれば純粋関数。外から見て純粋かというのは大事かも?DBやFileのIOや通信結果も副作用といえばそう。その失敗や一定の値を返さない事によって他の処理の期待値が壊れて不協和音、システムの破壊につながるような処理は副作用。適切にリトライなり、冪等的にロールバックしたり、結果をエラーハンドリングに流すなりして、全体的にはあらかじめ決められた処理として動いていれば問題ない。イメージ的には正の数の時はこの関数、負のときにはこの関数、結果的にプロットされる全体像がみえていればいい。みたいな感じ。かな?
  • ラムダは遅延評価をさせるもの。もしくは遅延評価を前提にした透過参照的に宣言された大きな処理、再利用性の高い処理への組み込み単位。カリー化などを使って部分適用を利用しながらラムダ内の評価タイミングを遅らせながらラムダを評価する材料をあつめるみたいな段階的なことも可能。変数のように扱えるので、プログラムの表現方法が格段にあがる。ただし評価される時のオーバーヘッドが通常の処理よりあるのでJavaやKotlinにはあるので注意。必然的な部分にとどめないともっさりするかも?関数が第一級、参照として扱えるみたい話もラムダのこと。
  • 高階関数は関数が引数だったり、返り値が関数になるような関数のこと。JavaやKotlinだとラムダのこと。ラムダを引数にしたり、ラムダをかえすようなものをいう。カリー化は後者の良い例で、filter/map/zipみたいなやつが前者の良い例。前者は遅延評価を前提としていて、実際には必要になった時だけそのラムダが評価される。別に作っていけないわけではないので必要だとおもったら作るのが普通。別にモナドには高階関数がいくつかあることが条件にあるけどモナドを作る必要はない。(モナドはしらないでもプログラムはある程度できる、スタイルの問題だったり、作らなくても自然とつかっていたりするかも)
  • イミュータブルはどんなタイミングでみても全く同じであること。コレクション(リスト、マップ、セット)や構造体(すべてfinalでメンバ変数を定義したDTOみたいなもの、data classなど)。その値を変更する場合は必ず別のインスタンスにシャローコピーを施しながら、変更したい値だけを入れ替える。data classでいうとcopy関数で簡単にそれが可能。イミュータブルでないものは、addやremoveが可能なコレクションや、varで宣言されたフィールドが存在するclassなど。ただし。
val printlist: (List<Int>) -> (() -> Unit) = { list -> {
    println(list)
} }
printlist(mutableListOf(1, 2, 3))()

みたいにListに対してMutableList(変更可能なリスト)を渡すことができるので、Kotlinでのリストは実質イミュータブルなものはない。リードオンリーになるので、正確なイミュータブルなリストを使いたい場合はEclipse Collectionsを使うと良いらしいよ。

残り二つは時間の都合でまたこんどー。