参照透過性

参照透過性（さんしょうとうかせい、）は、計算機言語の概念の一種である。ある式が参照透過であるとは、その式をその式の値に置き換えてもプログラムの振る舞いが変わらない(言い換えれば、同じ入力に対して同じ作用と同じ出力とを持つプログラムになる)ことを言う。具体的には変数の値は最初に定義した値と常に同じであり、関数は同じ変数を引数として与えられれば同じ値を返すということになる。当然変数に値を割り当てなおす演算である代入 (Assignment) を行う式は存在しない。このように参照透過性が成り立っている場合、ある式の値、例えば関数値、変数値についてどこに記憶されている値を参照しているかということは考慮する必要がない、即ち参照について透過的であるといえる。

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

また以上に関連して。

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

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

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

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

以上のような理由からMLのように、基本的には関数型を指向して作られていながら補助的に代入の機能も備え、式に状態を持たせられるようにするケースがしばしばある。Haskellではモナド (Monad) 型と構文糖衣を利用して参照透過性を保ったまま手続き型的な表現を可能にしている。また、Haskellと相互に影響を与え合ったもう一つの純粋関数型言語Cleanでは、一度参照したら二度と参照しないという一意性をその値の型に付加属性として与え、代入を利用しつつ参照透過性を維持し、効率化も実現している。

 参照透過性の解釈の変化 
Haskellでは上述のような問題点を解決するための試みがなされ、新しい仕様であるHaskell 2010でSTモナドとして結実した。参照透過性を満たす関数は引数が同じなら同じ値を返すものであるから、代入を使ってもその性質を満たし、なおかつ他の計算にも影響しなければよいとするものである。わかりやすい例として再帰関数がある。合計や階乗などは代入を使った反復であっても、与えられた引数が同じなら結果も同じである。代入をその関数の内部だけにとどめ、結果の取得は変数の内容をコピーして返す関数を使わせることで、確実に副作用から切り離すといった工夫を盛り込んだ。これがSTモナド（State Transformerモナド）である。

 参考文献 

 関連事項 
 関数 (プログラミング)
 関数型言語
 手続き型言語
 変数 (プログラミング)
 モナド (プログラミング)
 Lisp
 ML (プログラミング言語)
 Haskell
 分散処理
 メモ化
 副作用 (プログラム)
 冪等性

Category:プログラミング言語理論
Category:関数型プログラミング