基本的に関数型言語では参照透過性を保つことが求められます。
参照透過性とは?
プログラムの構成要素が同じもの同士は等しいという性質のこと。(例えば、3 ===3であれば常にtrueになるので参照透過性が保たれていると言えるでしょう。)
「参照透過性」を破壊するもの
破壊的メソッドを使う(メモリ上のデータが変更される)
例えば、配列に備わっているpushメソッドなどはそれです。pushを使った前と後の配列はそれぞれ別の値になってしまっています。(メモリ上のデータが変更されてしまう。)
変数に代入すること
1度関数を呼んで、引数に別の値を代入して、再度同じ関数を呼んだ際に結果が異なってしまう。
ではなぜ代入という操作が多くのプログラミング言語で採用されているのかといえばwhileなどの反復する操作に必要不可欠だからです。(ただ、例えばJavaScriptではあれば同じループでもmapなどループは回すが非破壊で新しい配列を生成して、参照透過性を保つためのメソッドが用意されていたりします。)
参照透過性がない関数を使う
Date.nowメソッド
呼ばれる度に別の値を返すため。
入出力を扱うメソッド
あくまで関数は値を返すことが主たる作用であるのに、入出力機能は副作用になる。
- 画面への表示
- ファイルへの書き込み
画面やファイルなどの値というのはプログラミング言語が処理を呼ぶ度に何が入っているかわからず処理系の管理下にありません。それに対して変数に対してプログラム内の変数などは処理系の管理下にあります。
対策
全て一度値が生成されたら中身が変更されない不変なデータにする。
JavaScriptにおける可変データとは「配列」や「オブジェクト」のこと。
不変なデータ構造としてのオブジェクト型を意識すること。
変数の参照透過性を保障する。
代入を使わない。
反復処理はどうするのか?(反復回数などの状態を更新する必要があるため)
再帰呼び出しを使って代入を排除する。
関数の参照透過性を保障する。
純粋関数を定義する。
副作用を持つ関数から副作用を持たない関数を呼び出して良いが、逆に副作用を持たない関数から副作用を持つ関数を呼び出してはいけない。(副作用を持たない関数から副作用を持つ関数を呼び出すとそれはもはや純粋関数ではなくなるため)
副作用を持たない関数
引数に日付を受け取って処理する関数
副作用を持つ関数
関数の内部で日付を生成して処理する関数
この記事へのコメントはありません。