関数型プログラミングとは?
自分の中で、「カリー化ってどんなメリットがあるの?」や「モナドってどのようにつかうの?」と、しっかりと関数型プログラミングを理解できていない節があったので、自分の理解のために記録したものです。
間違っている点や理解が不足している点があればご指摘をいただけると幸いですm(_ _)m
そもそも関数型プログラミングとは?
ざっくりと言えば、
「プログラムの構成に、副作用のない関数を利用し、組み立てていくプログラミングのスタイル」
のことである。
暫し、オブジェクト指向のプログラミングのスタイルと比較されることがあるが、オブジェクト指向は、データ(状態)と操作を格納したコンテナを基本要素とすることで様々なメリットを享受することができるプログラミングのスタイルのこと。
オブジェクト指向と関数型言語のプログラミングのスタイルの比較は、他で書いてありそうなので割愛。
関数型プログラミングの条件
-
関数を言語の最も基本的な要素として扱う(ファーストクラスオブジェクトとしての関数)
関数を値として扱うこと(引数や返り値などに利用)で、操作を抽象化し、新しい制御構造を作る便利な手段にもなる。これにより、無名関数、高階関数、カリー化などのメリットが受けられる。
-
参照透過性を確保できること
参照透過性とは、プログラムの構成要素が同じであれば同じ結果を返す性質のことで、メソッドは、引数をとり、結果値を返す方法だけで環境と通信すること(副作用がないともいう)
結局、関数型プログラミングって何のメリットがあるか?
-
コードのモジュール性が高まる
大規模なソフトウェアを構築するためには、コードが巨大化していく傾向がある。巨大に膨れ上がったコードを複雑にしないために、全体を分割し、小さなモジュールとして構成していく方法がある。
関数型プログラミングでは、データ、変数、関数を関数を使ってつなぎ合わせることでコードを簡潔にさせる。
- モジュールの独立性
参照透過性は、コードがモジュールの独立性を保証してくれる。そのため、参照透過性を持つデータや変数は、周囲にどのようなコードがあってもその値は不変(イミュータブル)である。また、参照透過な関数の結果は、引数のみに依存し、それ以外のコードの影響も受けない。
- モジュールの汎用性
どこでも使うことができるためには、関数を組み合わることが重要である。そのためには、関数同士を組み合わせる場面で、引数の数を一致させておくと組み合わせがしやすい。これを行う方法の一つとして、カリー化(引数の個数を一つに限定しておく)がある。
また、汎用性を高めるために、関数渡しも重要である。
-
コードのテストを容易にする
参照透過性のあるコードは依存関係が明確であり、テストを何度繰り返しても結果は不変であるため。
関数型プログラミングを支える技術
-
カリー化
カリー化は、複数の引数を持つ関数を一つの引数だけを持つ関数に変換することであり、カリー化関数は高階関数の一部である。
※ 普段は、scalaを書いてますが、javascriptで書いてみます。
-
コールバック関数によるモジュール化
下記の2つは、コードの結合度が違う。doCall関数とsucc関数は密に結合している。(doCall関数の挙動を変更するにはdoCall関数そのものの定義を書き直す必要がある)
一方で、コールバック関数を間接的に呼び出す例では、コールバック関数を受け取るsetupCallback関数とコールバック関数であるsucc関数が分離されている。そのため、モジュールとして独立している。
-
継続渡し
どちらかというと、反復処理をさせるものと条件分岐をさせるもので分離したほうが良い。条件分岐の時は、成功継続と失敗継続など分けることが多い。
高階関数を利用したデザインパターンの一つで、値にコンテキストを付与し、コンテキストを付与したまま処理を合成することで実現。
モナドの基本構造
- unit関数
モナドのインスタンスを生成するための関数。T => M[T] という型情報を持つ。Mはモナドの型のこと。
- flatMap関数
モナドから値を取り出して、何らかの処理をし施した後に、その結果を再びモナドに詰め込むための関数。
モナド則
- 右単位元則
モナドのインスタンスから値を取り出して、unit関数を適用した結果は、元のモナドのインスタンスに等しい
- 左単位元則
ある値から作られたモナドのインスタンスに対してflatMap関数を介してf関数を適用した結果は、元の値に対してf関数を適用した結果に等しい
モナドの処理を結合することができる
- 恒等モナド
値にコンテキストを付加することなく、そのまま値として扱うモナド。
- Maybeモナド
値に正常か異常かのコンテキストを付与し、エラーチェックを不要にしたモナド。
- IOモナド
副作用への対処(外部ディスプレイへの出力、ファイルへの書き出しなど)で利用される
IOモナドの型情報は、FUN[WORLD => PAIR[T, WORLD]]