一人一党党

一人一人の、一人一人による、一人一人のための政治制度を!

関数型言語の純粋性は、自動車のシートベルトである

関数型言語のウソとホント - Qiita
http://qiita.com/hiruberuto/items/26a813ab2b188ca39019
が派手に荒れているけど、そのサイトのアカウントとるのが面倒くさいから、こっちに書く。
そのサイトの参考文献に挙げられている
なぜ関数プログラミングは重要か
http://www.sampou.org/haskell/article/whyfp.html
と殆ど同じだし、haskell設計者の一人であるサイモン・ペイトン・ジョーンズも同じ事を
Coders at Work プログラミングの技をめぐる探求 単行本(ソフトカバー)2011/5/25 Peter Seibel (著), 青木 靖 (翻訳)
http://www.amazon.co.jp/Coders-Work-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E6%8A%80%E3%82%92%E3%82%81%E3%81%90%E3%82%8B%E6%8E%A2%E6%B1%82-Peter-Seibel/dp/4274068471
で述べていたかも知れないが…。

表題に戻ろう。

引数に関数をとることが出来る「高階関数」は、関数型言語の欠くべからざる特徴として誰もが認めるところだろう。
「変数名で悩む必要が無いよ。変数なんて無いよ。」
と豪語する通り、可読性にまで影響が出るほど機能を削った
Lazy_K
http://legacy.e.tir.jp/wiliki?%CB%DD%CC%F5%3A%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%B8%C0%B8%ECLazy_K
は、関数型言語の最小公約数だ。
そのLazy_Kを以ってしても、高階関数を捨てることは出来なかった。

問題は、関数型言語に限らず、殆どの言語は高階関数機能を持っているということだ。
C言語ですら、関数ポインタを引数にとれる。
C言語の関数ポインタ実装を考えれば、アセンブラでも高階関数プログラミングは難しくは無い。
結局全ての言語はチューリング完全なのだから、互いの機能を模倣し合うことが出来る。
どこかのプログラマは、綺麗なオブジェクト指向プログラミングを、アセンブラコードから見出したらしい。

にも拘らず、アセンブラオブジェクト指向言語どころか構造化言語だとすら、考える人はいない。
全てを模倣できるアセンブラに、足りない機能など存在し得ないにも拘らず。
裏を返せば、○○言語を名乗るには、機能の欠如が必要ということだ。
構造化言語なら、GOTOがない。
オブジェクト指向言語なら、メッセージ以外にメンバ変数にアクセスする方法が無い。
これらの欠如した機能は、もし存在すれば○○言語の概念を破壊する。
サブルーチン内でGOTOが呼ばれる恐れがあれば、サブルーチンを呼び出した後の制御フローを追うのが難しくなる。
メンバ変数のアクセスがメッセージ以外でも行なわれると、メンバ変数のカプセル化が出来ない。
○○の概念が常に成り立つことを保証して初めて、○○言語と言えるのだ。
その保証のために邪魔な機能が、○○言語で欠ける事となる。
勿論、○○言語の概念を保証する代償として、機能の欠如は安くは無い。
特に、小規模プログラミングでは、これら機能の欠如は足枷以外の何者でも無い。
構造化をしたいなら、サブルーチンを書くときにGOTOで外へ跳ばなければ良い。
オブジェクト指向プログラミングをするなら、メンバ変数への直接アクセスをしなければ良い。
プログラム全体で統一されたコーディング規約を使えるなら、機能欠如を用いずとも○○の概念は保証され、足枷のみが残る。
逆に言えば、コーディング規約を信頼出来ない規模のプログラムを書きたければ、○○の概念を守るための足枷が必要になる。
一秒前の他人、あるいは、三カ月前の自分が書いたルーチンを、現在の自分が○○の概念に則って利用するためには、ルーチンを書いた彼等を縛り付けるシートベルトが必要なのだ。

関数型言語に於いては、必要呼びと参照透過性がシートベルトに当たる。
先に述べた様に関数型言語の特徴は高階関数であり、各ルーチンの間で遣り取りされるのは自身と同格のルーチンだ。
構造化言語の様に、制御フローを失ったデータではない。
遣り取りされたルーチンがどのような制御フローの中で何回実行されるかは、遣り取りしているルーチン次第なのだ。
プログラムが小規模であれば、遣り取りされたルーチンの実行タイミング・回数を追うことは易しいだろう。
しかし、三カ月前の自分が書いた怪しげなルーチンでそれを分析するのは、絶望的だ。
これでは恐ろしくて、せっかくの高階関数機能を使うことは出来ない。
この高階関数の危険性を取り除くのが、必要呼びと参照透過性だ。
参照透過性によって、引数のみによってそのルーチンの動作結果が定まるため、実行タイミング・回数は動作結果に影響しない。
そして必要呼びは、実行回数が最小限に抑えられる事を保証する。

シートベルトがあるからこそ、我々は安心して、急ブレーキを必要とする速度で自動車を飛ばすことが出来る。
関数型言語の力を引き出す上で、必要呼びと参照透過性は不可欠の「足枷」なのだ。

---

ちなみに、オブジェクト指向言語関数型言語と同様に、オブジェクトに伴うメソッドという形でルーチンを遣り取りしている。
このため、必要呼びと参照透過性の保証は、オブジェクト指向言語にも利益を与えるはずだ。
しかし、参照透過性を受け入れれば、オブジェクトは可変な状態を持つことが出来なくなる。
果たしてそれは、オブジェクト指向と言えるのだろうか?