「参照透過である」とは、何から何への参照がどういう条件を満たすことを言うのか

関数型プログラミングが流行していることもあって、頻繁に耳にする「参照透過性」という用語について考えます。 ∥ 参照透過性 - Wikipedia

その過程で目にした、Stack Overflow 上の Reddy 氏の発言が面白かったので、ザックリと訳します。

用語の起源と、それがプログラミング言語に導入された経緯

一応意味は分かってはいるんですが、なぜ「副作用のない関数呼び出し」やら「変数への再代入の禁止」といった特性を「参照透過性」と呼称するのかが分かりませんでした。この場合の「参照」は、何が何を参照することであり、また、それがどういう状態にあることを「透過である」としているのかが、通り一遍調べてみても分かりませんでしたので、掘りに行ってきます。

どうやら、「式(あるいは値、関数でも良いですが)と、その式の指し示す実体(評価した結果、“referent”)との間の「参照」関係が、(文脈や副作用といったものから独立なので)至って明瞭(transparent)である」ことを「参照透過である」とするようです。変数への再代入ができないことや副作用云々といった議論は、そのための、特定のプログラミング言語における必要条件でしかありません。

Note: 「参照」における “symbol” や “sign” と “referent” との関係性については、右記を参照。 ∥ Referent - Wikipedia, the free encyclopedia

引用でソシュールは “The signified (引用注: = signifié) is not to be confused with the "referent". The former is a "mental concept", the latter the "actual object" in the world” と言っているが、referent にも概念としてしか存在しないものは多々あるわけで、この区別に何か意味はあるんだろうか? 心理面での議論をする際には比較的に前者を、言語や現実世界の話をする際には後者を用いる傾向がある、程度に考えておけばいいのかな。 ∥ Sign (linguistics) - Wikipedia, the free encyclopedia

おそらく翻訳の際に、“referential transparency” からの直訳で「参照透過性」としてしまったのだと思われますが、英語の “transparent” には、物質的な「透明な」から派生して、「明瞭な」とか「ありのままであきらかな」といった意味があります。日本語としては、「参照明瞭性」とでもした方が本来の意味に近く、理解しやすかったのではないかと思います。

追記(2015/10/19): はてブのコメントの tanimina 氏によると「referential transparencyの訳は哲学では「指示的に透明」が使われているはず(『言語哲学大全III』など) 」とのこと。ほんとうだ、検索すると、少ないながらもヒットします

Reddy 氏の発言、和訳

上記の Stack Overflow でベストアンサーになっているのは、Uday S. Reddy 氏。バーミンガム大の計算機科学の教授で、関数型言語や OOP について研究をしておられるようです。

日本語の「"参照透過" "分析哲学"」でググっても全くヒットが無いところを見ると需要はあるのではないかと思ったので、ザックリと訳してみます。私が勘違いしている箇所もあるかも知れませんし、当該分野における定番の訳語から外れているところもあるかも知れませんので、それら、指摘をいただけると助かります。

Claudiu 氏の質問 ∥ functional programming - What is referential transparency? - Stack Overflow

「参照透過性(“referential transparency“)」とはどういう意味なのでしょうか? 「等価なものを等価なもので置換できるという性質である」と聞きましたが、これでは説明としては不十分であるように思えるのですが

分析哲学における「参照透過性」の考え方と、プログラミング言語への導入

Reddy 氏の回答 ∥ functional programming - What is referential transparency? - Stack Overflow

「参照透過性」の語は、おおもととしては分析哲学の用語から来ています。分析哲学は哲学の一分野で、自然言語の構成要素(construct)、命題(statement)、項(argument)の解析に、論理学や数学の手法を用いる学問です。分析哲学という分野は、計算機科学という分野外では、もっとも「プログラミング言語意味論」に近しいところにあると言えるでしょう。参照透過という考え方は、哲学者のクワインによって導入されましたが、その考え方は、バートランド・ラッセルやアルフレッド・ホワイトヘッドのアプローチでも暗黙的に用いられています(訳注: アルフレッド・ノース・ホワイトヘッド - Wikipedia)。

「参照透過性」の考え方の核心部分は、とてもシンプルかつ明快なものです。分析哲学における “referent(指示対象)” という用語は、「式(expression)が言及するところのモノ」を意味します。それ(指示対象)とは、ザックリ言えば、プログラミング言語の意味論で言うところの「意味」と同じものです。Andrew Birkett 氏がブログ記事で用いている例を流用させていただきますが、「スコットランドの首都」の語は、都市としてのエディンバラを指します。これがまさに “referent” の例です。

コンテキスト内のある語を、文全体の意味を変えることなく、「その語が指し示すところの実体」で置換することが可能な時、そのコンテキストは「参照透過である」と言います。例を挙げます。

スコットランドの国会は、スコットランドの首都で開かれる。

この文は、下記と等価です。

スコットランドの国会は、エディンバラで開かれる。

上記の「スコットランドの国会は~」のコンテキストは、参照透過です。それは、「スコットランドの首都」を「エディンバラ」に入れ替えても意味が変わらないからです。別の言い方をするならば、コンテキストに関連があるのは、コンテキスト内の語が指し示す対象だけであり、それ以外とは無関係であるということです。コンテキストが「参照透過である」とは、このような考え方です。

一方で、以下のセンテンスはどうでしょう。

エディンバラは 1999 年以降、スコットランドの首都(訳注: 定冠詞付きの “the capital”)である。

こちらでは、先程のような置換はできません。同様に置換してしまうと、「エディンバラは 1999 年以降、エディンバラである」となり、おかしなことになってしまいますし、元の文章とは意味も違ってしまっています。よってこちらの「エディンバラは~」の文脈は、参照不透明(「参照透過」の逆)であると言います。こちらの例ではあきらかに、語が指し示すところのもの以外の何かを考慮に入れる必要が生じています。さて、その「何か」とは何なのでしょう?

上記の「スコットランドの首都」のような語は、“definite term”(確定記述)と呼ばれ、長い間、論理学者や哲学者を少なからず悩ませていました(訳注: Definite description - Wikipedia, the free encyclopedia)。ラッセルとクワインは、こういった語はじっさいには「参照的」なものではないと分類しました。つまり上記の例では、語は、何らかの実体を指し示すような使われ方をしているわけではない、と考えたのです。上記のセンテンスを理解する正しい方法は、以下のように言い換えることとなります。

スコットランドは 1999 年以降、とある首都(訳注: 不定冠詞付きの “a capital”)を有し、その首都とはエディンバラである。

このセンテンスであれば奇妙な変形はできませんので、これで問題は解決します。クワインの指摘した点は、「自然言語はやっかいなものであるか、あるいは、すくなくとも煩雑なものである」ということです。自然言語は実用面で便利になるように作られているものである一方、哲学者や論理学者は、正しい手法で言語を理解することで、そこに明快さをもたらさなければならないからです。参照透過は、そういった「意味の明快さ」をもたらすためのツールなのです。

この考え方は、プログラミングの分野においてもそれほど大きな違いはありません。ここまで見てきたように、参照透過の考え方は言語を理解するための(あるいは、意味を付与する際の)ツールです。プログラミング意味論の分野の基礎をなしたクリストファー・ストレイチーは、参照透過の考え方を、意味論の研究で応用しました。彼の論の基礎となる論文「プログラミング言語の基礎概念(Fundamental concepts in programming languages)」は、上記リンクの web 上で読むことができます(訳注: クリストファー・ストレイチー - Wikipedia)。これは素晴らしい論文ですし、内容は誰でも読めば理解できるものですので、ぜひ目を通して欲しいと思います。得るところがあること請け合いです。下記のパラグラフで、彼は「参照透過」の語を導入しています。

式(expression)は、極めて有用な特性をいくつか持ちますが、その一つが、クワインによって「参照透過」と呼ばれたものです。要点としては、参照透過とは、ある式が、その内側に入れ子でさらに式を含む場合、式全体の値を求めようとするならば、考慮しなければならないのは内側の式の値だけであるということです。内側の式が持つそれ以外の属性(たとえば内部構造や、構成コンポーネントの数や特性、評価される順序、印刷に使われたインクの色)などは重要ではなく、主となる式の値に影響しないということです。

上記で「要点としては」と言っていることからも分かるように、ストレイチーはここで話を簡単にするために「意訳」をしています。関数型言語のプログラマが読めば、このパラグラフを彼らなりの方法で理解することでしょう。当該論文では上記以外の 9 箇所で「参照透過」の語が用いられていますが、それらはお互いにあまり関連づけて書かれてはいないようです。実のところ、ストレイチーの論文全体は「命令的プログラミング言語」を主眼に書かれています。こんにち関数型のプログラマは、命令的プログラム言語が参照透過ではないことを非難しているわけですが、そのことを知ったら、ストレイチーも草葉の陰で泣くことでしょう。

この点については誤解がありますので、順次、解き明かして行きましょう。先ほど、自然言語は実用面で便利なように作られているために、「やっかいなものであるか、あるいは、すくなくとも煩雑なものである」と述べました。プログラミング言語においてもこれは同様であり、やはりそれも実用面で便利なように作られていることから、「やっかいなものであるか、あるいは、すくなくとも煩雑なものである」と言わざるを得ません。だからといって、それらの言語が我々を混乱させるとは限りません。意味の明快さを求めるために、参照透過なメタ言語を用いて、それらの言語を正しく理解する必要があるだけです。先に引用した論文でも、ストレイチーはまさにそのような試みを行なっています。彼は、それを elementary concepts に分解することで、明快さを失うことなしに命令型プログラミング言語の意味を解説しています。彼の分析の重要な点は、プログラミング言語の変数は「左辺値」「右辺値」という 2 種の「値」をも持つということです。ストレイチーの論文以前では、この考え方は理解されておらず、非常に混乱していました。こんにちでは、C 言語の解説ではこの点には当然言及されますし、C プログラマはその違いを理解しています(その他の言語のプログラマがそれを理解しているかは何とも言えませんが)。

クワインにせよストレイチーにせよ、彼らは言葉の構成要素の意味に関心を持っていました。ここで言う「意味」には、いくつかの文脈依存のものを含みます。たとえば、先の例「エディンバラは 1999 年以降、スコットランドの首都である」においては、「スコットランドの首都」というものは、それがいつの時点を問題にしているかに依存しているという事実を含んでいます。このような文脈依存性は実に現実を反映していると言えますが、それは自然言語においてもプログラミング言語においても同様です。また、関数型言語おいても変数は、それが未束縛・束縛であるかにかかわらず、その変数が現れる文脈を尊重してインタープリトされる必要があります。そういった各種の文脈依存性は、さまざまな要因で参照透過性を損ないます。語の意味は、それらの語が依存する文脈を意識することなく理解することは不可能なのです。クワインは、様相論理(modal logic)に関心を持っていました(訳注: 様相論理 - Wikipedia)。様相論理は参照不透明ですが、それを参照透過なフレームワークへと変換することによって(つまり、必要性を証明可能性として意識することによって)「きれいに」されるべきであると考えていたのです。しかし彼は、この論争においては完全な敗北を喫しました。論理学者にとっても哲学者にとっても、クリプキの可能世界セマンティクスが適切であることが判明したためです(訳注: ソール・クリプキ - Wikipedia, 可能世界論 - Wikipedia)。これは、命令型言語にとっても同様だと思われました。ストレイチーによって解説された状態依存と、Reynolds によって解説された store 依存は(クリプキの可能世界セマンティックと同様がそうであったように)、完全に妥当であるとされました。関数型のプログラマは、これらの研究を十全には知りません。彼らの参照透過に関する研究には、大いに注意を払われてしかるべきだと思います。

【追記: 上記の例で、「スコットランドの首都」のようなシンプルなフレーズでさえも、多段の意味が内包されていることを見てきました。一つ目のレベルとしては、我々は現在の当該首都について話しているわけですが、また次のレベルでは、歴史上、スコットランドに存在した複数の首都について話していることになります。私たちはごく自然に、ある文脈へと「ズームイン」したり、そこから「ズームアウト」したりと、さまざまな文脈に渡ってごく自然に行き来することを、日常的に行なっています。我々はそのような能力を活用することで、自然言語をとても効率的に使いこなしています。これは、命令的プログラング言語においても同様です。ある時は変数 x を、代入の右辺値として、その値について問題にしたかと思えば、次には左辺値として用いていたりします。学習者がそのことから混乱を来すことは稀でしょう。しかしだからと言って、彼らが言語の構造内に内在する全ての意味レイヤについて説明することができるかどうかとは無関係です。それら意味のレイヤは必ずしも「明瞭」であるとは限りませんので、科学的手法による解析の対象として研究されるべきです。しかしだからと言って、普通の人がそういったレイヤ化された意味に対して不可説明性を抱えていることが、それに混乱しているということを意味するわけではありません。】

下の別項「補遺」は、関数型と命令型のプログラミングに関して、上記の議論と関連します。

関数型言語界隈へストレイチーやランディンがもたらしたもの

上記への補足として、Reddy 氏の回答が続きます ∥ functional programming - What is referential transparency? - Stack Overflow

この「補遺」は、上記、私の 3/25 の書き込みにおける議論を、関数型・命令型のプログラミングにおける関心事項により近づけるためのものです。

関数型言語のプログラマによる参照透過に関する考え方は、以下の 3 点において、標準的な参照透過の概念と異なっているようです。

  • 哲学者や論理学者は用語として「reference(参照)」「denotation(明示的な意味)」「designatum(指示されるもの)」「bedeutung(Frege が用いるドイツ語の用語)」などを用いるのですが、関数型のプログラマは「値(value)」を用います(これは関数型のプログラマに限った話ではなく、ランディンやストレイチーとその後継者達も “reference” や “denotation” の意味で「値」を用いています(訳注: ピーター・ランディン ∥ Peter Landin - Wikipedia, the free encyclopedia)。これはどうやら、単なる用語の簡略化であり、ランディンやストレイチーが導入したもののようなのですが、厳密な議論の際にはそれらは大きな違いになり得ますので、注意を要します)

  • 関数型のプログラマは、これらの「値」はプログラミング言語の外ではなく内側に存在していると考えているようですが、この点では、哲学者のみならず、プログラミング言語の意味論の研究者たちとも全く異なっています

  • 彼らは、これらの「値」は評価のプロセスを経て得られると考えているようです

たとえば、今朝の時点の Wikipedia の「参照透過」に関する項目を見てみると、そこには下記のような記述があります。

式は、プログラムの挙動を変えることなしに、その式をその値と置換することが可能であるならば(言い換えると、同じ入力に対して、同様の効果と出力をするプログラムを生成することができるならば)、その式は参照透過であると言える。

これは、哲学者や論理学者が言うところとは、全く相容れません。哲学者・論理学者の考え方では、あるコンテキストが参照透過であるということは、そのコンテキスト内のある expression が、それと同一の実体を指す expression(同一指示の(coreferential)expression)と交換可能であることを言うのです。ここで言う「哲学者」や「論理学者」とは誰かですって? それはフレゲでありラッセルでありホワイトヘッドであり、カーナップ、クワイン、チャーチ他、数え切れないほどのその他大勢のことです。どの一人を取っても、ハンパない大人物たちであり、彼ら論理学者の知性の力を統合すれば、地球を壊滅させるに値するほどの偉人達です。彼らは、一つの点については意見を一致させます、「referent・denotation は形式言語の外側に存在し、言語内の expression は、それらに対して言及することしかできない」と。つまりは、人が言語を用いて出来ることというのはせいぜい、一つの expression を、それと同一の実体を指し示す他の expression に入れ替える程度のことだということです。referent・denotation そのものは、言語内には存在しないのです。しかし、だとするならばなぜに関数型のプログラマたちは、こうも古くから確立された考え方から逸脱した捉え方をしているのでしょうか?

ランディン(強調引用者):

(a) 各式はネストされたサブ式の構造を持ち、 (b) 各サブ式は何か(数や真偽値、算術関数)を指し示し (c) 式が指し示すところのもの(つまりは、その「値」)は、それらサブ式の値のみに依存し、それ以外の属性には依存しない。

ストイ(強調引用者):

式にとって問題になるのはその式の値のみであり、あらゆるサブ式は、それと等価な値によって置換することが可能である。さらに言うならば、式の値は、一定の制約はあるものの、どこで現れようとも同一である。

バード, ワドラー(強調引用者):

式の値は、その式の構成要素となっている式(もしあれば)のみに依存する。そして、それらのサブ式は、自由に同じ値を提供する他のものと交換可能である。

こうして振り返ってみると、ランディンやストレイチーによる、用語を簡略化しようとする努力によって “reference” や “denotation” が「値」に置き換えられたわけですが、これは軽率だったと言えるでしょう。その結果、人は「値」と聞くや、評価のプロセスを想起する衝動が生じるようになってしまい、上記のような考えに至ってしまいました。同様に、評価によって生じるものが「値」であると(たとえ、それがあきらかに denotation でないと分かっていたとしても)考える衝動も生じています。このような「参照透過」の考え方を、私は関数型プログラマらの中に見てきました。しかし、初期の意味論の研究者によって語られた「値」は、評価の結果や関数等の出力ではなかったのです。denotation のことだったのです。

(訳注: 形式言語 - Wikipedia

ひとたび式の(いわゆる)「値」(かつての哲学者の講釈に従えば “referent”, “denotaion” ですが)を複雑な数学的・観念的なオブジェクトと見なすことができれば、あらゆる種類の可能性が開けてきます。

  • 3/25 の回答でも触れましたが、ストレイチーは命令型プログラミングの文脈で、変数を「左辺値」と解釈しました。それはとても洗練された観念的なオブジェクトであり、プログラミング言語内には直接的な表象(representation)を持たないオブジェクトです。
  • 彼はまた、言語内に現れるコマンドを、ある状態から他の状態への遷移関数と解釈しました。そういった関数は、先にも触れた複雑な数学的オブジェクトの一種であり、文法的な意味での「値」ではありません。
  • 副作用を持つ C 言語の関数呼び出しさえも「状態を変更するもの」として定義された「値」を持ち、それらの関数は、ある状態を、他の状態と値のペアへとマップします(これは、関数型用語で言う「モナド」にあたります)

関数型言語のプログラマたちは、それら命令型言語を「参照透過」とは呼びたがらないでしょうから、そういった複雑な数学的・観念的オブジェクトを「値」であると認めることも嫌がるでしょう。それでいてそれらの状態変換器が、彼らの好むところの文法や「モナド」などというバズワードによって取り込まれるや、「値」と呼ぶことに抵抗がなくなるようです。この姿勢は一貫性に欠くではないかと言わざるを得ません。たとえ彼らの「参照透過」の考え方にある程度の統一性が認められたとしてもです。

歴史を紐解くと、なぜこのような混乱が生じたかが、かすかに見えてきます。1962~67 年は、クリストファー・ストレイチーにとって、とても濃密な時期でした。1962~65 年、彼はモーリス・ウィルケスの元でパートタイムで研究を行い、後に CPL と呼ばれることになる言語をデザイン・実装しました。この言語は命令型の言語でしたが、強力な関数型言語としての能力も備える予定でした。ランディンはこのころストレイチーのコンサルタント会社の社員であり、ストレイチーのプログラミング言語に関する考え方から、大きな影響を受けました。1965 年に出された記念碑的な論文「次の 700 のプログラミング言語(Next 700 programming languages)」においてランディンは、高らかに関数型言語を世に問うこととなります(それは denotative 言語と呼ばれていました)。そしてその言語は、命令型プログラム言語とは「対照的である」と位置づけました。議論を追って行くと、ストレイチーがランディンの強固な意見に対して反論を行なっていることが分かります(強調引用者)。

~ denotative 言語(DL)は、既存の命令型言語群のサブセットをなします。それらは実に興味深いサブセットではあるのですが、慣れるまでは非常に使いづらいものでもあります。なぜこのような言語が必要なのかと言えば、今のところ、どのようにして命令やジャンプを含む言語によって証明を行なえば良いのか分かっていないからです。

(訳注: “ISWIM” は、ランディンによる 1966 年の論文 “The Next 700 Programming Languages” が初出となる抽象プログラミング言語。後に、Miranda や Haskell に影響を与えることになる ∥ ISWIM - Wikipedia

1965 年、ストレイチーはオックスフォードで助教授の地位につき、実質的に、命令とジャンプに関する理論の開発にフルタイムでたずさわっていたようです。1967 年、彼は理論を完成させ、コペンハーゲンのサマースクールで「プログラミング言語の根源的な考え方(Fundamental concepts in programming languages)」の講義を行いました。その講義ノートは出版される予定だったのですが、「不幸なことに編集に時間がかかってしまい、講義録は結局、完成することはありませんでした。ストレイチーのオックスフォードでの仕事も同様に、完成を見ることはありませんでした。しかし講義録は、私的な回し読みを経て、大きな影響を及ぼしました」(Martin Campbell-Kelly)。

このようにストレイチーの著作物は入手が困難だったため、二次ソースや伝聞に頼っていた人々には混乱をもたらしました。しかし現在では “Fundamental concepts” は web 上で入手が可能になっていますので、無理に推測に基いてあれこれする必要はなくなりました。これを読むことで、ストレイチーが意図したのはどのようなことだったのかを、私たちは考えるべきだと思います。特に注意すべきは、以下の箇所でしょう。

  • 第 3.2 節で彼は「右辺値の参照透過」について語っていますが、ここで “expression” について触れています
  • 第 3.3 節では「左辺値の参照透過性」について語られていますが、ここで “command” について言及しています
  • 第 3.4.5 節では「関数とルーチン」について語っています。そして、「右辺値コンテキストにおいて右辺値の参照透過性が損なわれるような状況は、式を複数のコマンドや単純な式に分解する操作によって回避しなければならない。それが難しいと思われるならば、コメントに記載しておくべきだ」と語っています。

右辺値、左辺値、複雑なオブジェクトなどの、命令型言語の観念的宇宙とでも言うものをかたちづくる要素への理解なしに「参照透過性」に言及することは、根本的に間違っています。