React-Redux から振り返る関数型プログラミング
React-Redux を3ヶ月ほど利用して関数型プログラミングのエッセンスをつかめてきました。
エッセンスとなるキーワードの解説を、「何が嬉しいのか」「React-Redux がどうしているか」と合わせて書いていきます。
キーワード
- 純粋関数
- 参照透過性
- 副作用
- イミュータブル
- 関数オブジェクト
- 関数合成
- 関数の部分適用、カリー化
純粋関数
参照透過性があり、副作用の無い関数を純粋関数という。 関数型プログラミングでは純粋関数の割合が大きくなるように書いていく。
参照透過性
式(関数や変数)の表現が、あるインプットに対して常に同じアウトプットを返すこと。 ステートや、インプットではないデータによって関数のアウトプットが変わらないこと。
何が嬉しいのか?
- テストがしやすい
- 遅延実行/並列処理で使いやすい
副作用(がない)
副作用とは、関数の中で
- インプットの値を書き換える(Javaでいう、
Collections#sort()
など) - グローバルなデータソースを書き換える(DBやキャッシュへの書き込み、enqueue/dequeue)
ことで、他の式評価に影響を与えること。
この副作用を避ける、あるいは意識的にコントロールし、「副作用がない」状態を目指す。
何が嬉しいのか?
- 関数によってインプットが書き換えられる心配がない
- 他の関数の参照透過性を崩すことがない
React-Redux での利用例
- reducer
reducer
は純粋関数である(べき)state
とaction
からnextState
を返し、参照透過性を保つObject.assign()
やspread operator
(...
) を利用してイミュータブルなnextState
を返す。- APIコールやファイルI/Oなどの副作用を持つ処理は
redux-thunk
などを使って事前に処理する
関数オブジェクト
関数をオブジェクトとして扱うことで、抽象度の異なる関数を状況に応じて使い分ける。
関数合成
複数の関数を順番に適用する、一つの関数を返す。(compose
)
何が嬉しいのか?
- ネストを避けて、一つの関数オブジェクトとして扱えるためコードの見通しがよくなる。
関数の部分適用、カリー化
- 関数の一部の引数を固定して新たな関数を返すことが部分適用
- 関数を単一の引数を持つ関数のチェーンにすることがカリー化
- カリー化した関数は部分適用しやすい
何が嬉しいのか?
- 一つの関数から抽象度に応じた様々な関数を定義し、共有できる。
- イベント発火時に呼ぶ関数をあらかじめ部分適用しおくことで、呼び出し時のコードがシンプルになる。
React-Redux での利用例
createStore
の際にcompose
した関数オブジェクトを渡す。- 以下のようにして、
ActionCreator
を記述する際の boilerplateをへらす redux.js.org bindActionCreators
はdispatch
をもとのactionCreator
と合成した関数を、もとのactionCreator
と同名のメソッド名で返す。
// 本来は実行時にこう書くところを dispatch(someAction(payload)) // 多分こんな感じにして export someAction = (payload) => dispatch(someAction(payload)) // 実行時にはこうかける someAction(payload)