参照透過性

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動先: 案内検索

参照透過性(さんしょうとうかせい、テンプレート:Lang-en-short)は、計算機言語の概念の一種で、文脈によらずの値はその構成要素(例えば変数や関数)によってのみ定まるということを言う。具体的には変数の値は最初に定義した値と常に同じであり、関数は同じ変数を引数として与えられれば同じ値を返すということになる。当然変数に値を割り当てなおす演算である代入 (Assignment) を行う式は存在しない。このように参照透過性が成り立っている場合、ある式の値、例えば関数値、変数値についてどこに記憶されている値を参照しているかということは考慮する必要がない、即ち参照について透過的であるといえる。

参照透過性が成り立つ言語は式の値がプログラムのテキストから定まるという特徴から宣言型言語 (Declarative language) と呼ばれたり、関数の数学的性質が保たれるという特徴から純粋関数型言語 (Pure functional language) と呼ばれたりする。一方変数の値の変更が認められているような参照透過的でない言語を手続き型言語と呼ぶ。ただ、手続き型言語は機械語プログラミングとの繋がりという歴史的な事情により手続きが式でなく命令列で表現されたことから命令型言語と呼ばれることもあり、そのような場合との対比で単に式(例えば関数や変数の組み合わせ)でプログラムが表現されているだけの言語、あるいは高階関数の仕組みを備えた言語をひっくるめて、代入が可能であるかないかを問わず、関数型言語と呼ぶことも多いので注意が必要である。結局現状では単に関数型言語という場合は参照透過的な言語(即ち純粋関数型言語)とそうでない関数型言語を両方とも含むということになっている。

また以上に関連して分散処理を記述する場合に、あるデータがどのノード上にあるかを意識せず透過的にアクセスできるという性質も参照透過性と呼ばれる。

代入と参照透過性を取り巻く技術的課題

参照透過性が成り立つような言語では変数の値を定義する構文はあっても変数の値を再定義するような変数への代入 (Assignment) を行う構文は存在せず、ある式の値、例えば関数値、変数値についてどこに記憶されている値を参照しているかということを考慮する必要がない。

ただこのような違いがありながらも参照透過性の有無は、計算理論上は言語の記述能力を左右しない。代入はプログラム、またその要素である関数内での変数の変更を許す、つまり内部状態を作るため数学的にはチューリングマシンのような状態機械でモデル化できる一方、純粋関数型言語はラムダ計算でモデル化できるが、両者で記述できるプログラムの集合は同一であることが証明されているからである。とはいえ、人間にとっての記述しやすさ、可読性、現時点の技術で実現した場合の実行効率などは両者で当然異なる。

例えば関数値、変数値についてどこに記憶されている値を参照しているかということを考慮する必要がないということは記憶領域の使い方の管理がプログラマの手から完全に離れているということを意味するため、プログラムの表現を簡明にすることに寄与する一方で、実行効率向上のためには言語処理系によるデータの管理と最適化を多分に必要とする。具体的な例を挙げれば、参照透過性が成り立つような言語では大きなデータ構造(例えば要素数の多い配列レコード型など)の極一部を変更するような場合でも主記憶上にあるデータ構造の一部だけを単純に書き直すことが出来ない(例えばAとBが同じ式で配列として定義されているときにBの3番目を変更したらAの3番目をアクセスする式の値がどうなるか)。

また、当然のことながら参照透過性が成り立つような言語では参照され共有されている記憶領域に格納された値を監視するようなコードは書けない。このことはプログラムの動作を副作用の考察なしに追跡し、その実行をスケジューリングできるというようにプログラム理解を簡単にし最適化の可能性を広げる一方で、変数で同期を取るような素朴な並行・並列処理プログラムは最早書けず、入力動作を表現するためには様々な工夫が必要となり、スケジューリングに左右されないように出力を順序正しく行うためにも様々な工夫が必要となることを意味する。

以上のような理由からMLのように、基本的には関数型を指向して作られていながら補助的に代入の機能も備え、式に状態を持たせられるようにするケースがしばしばある。Haskellでは、モナド (Monad) 型と構文糖衣を利用して参照透過性を保ったまま手続き型的な表現を可能にしている。

関連事項