関数に関する世界観です。
僕は、Common Lispの本を読んでいて、ひとつ、思ったことがあります。
それは、「プログラミングとは関数である」ということです。
この関数とは、単にサブルーチンのように、処理を部分化するだけではありません。「値を与えて呼び出し、値を返り値として返す」ということ、それこそがプログラミングの本質なのです。
関数には、僕はポインタが必要だと思います。なぜなら、関数との間で「勝手口」を共有するために、ポインタが必要となるからです。
勝手口とは、すなわち、「その世界と別の世界を繋ぐ糸電話」のようなものです。そして、これはまさしく「関数に引数を与え、returnで値を返す」ということです。
たとえば、オブジェクト指向のクラスの持つメソッドには、オブジェクトを返すメソッドがあります。たとえば、TimeDateクラスがあったとして、これに今日の日付を返すgetToday()メソッドがあったとします。数値を返す場合もあると思いますが、一般的には日付を格納するDayクラス(Day型)のオブジェクトとして、getToday()メソッドは今日を示すDay型のオブジェクトを返します。
これが、たとえば以下のように、
TimeDate td = new TimeDate(); Day today = td.getToday(); System.out.println(today.toString());
のように、どんどん「.」で繋がって、オブジェクト指向は実現します。
ですが、これもまた関数です。ポインタとも同じです。なぜなら、「関数的返り値と同様の、メッセージングのためのオブジェクトがあるだけにすぎない」からです。
オブジェクト指向は、メッセージのためにオブジェクトをあっちやらこっちやらに渡しているだけにすぎず、これは参照型でありポインタでありますが、「関数に引数を与え、returnで値を返す」ということと、まったく同じことをオブジェクト指向は行っています。
また、「型」とは、要するにメッセージの媒体の「プロトコル」であると言えます。型は、「どのようなオブジェクトが返ってきたにせよ、そのオブジェクトを操作するための共通の決まり事を約束する」ということです。なので、Day型のオブジェクトが返り値として返ってくるということが最初から分かっているから、Day型のオブジェクトを「今日」というメッセージの伝達に使うことができるのです。
また、変数と関数を別々のものであると考える必要はないかもしれません。変数は「静的数」、すなわち、参照する際にその実体が物理的に存在するものであり、関数は「動的数」、すなわち、参照する際に動的に作り出されて実体が仮想的に存在するものであると考えられます。
ここで言えるのは、「関数とは数の仮想化である」ということです。関数は、実行してはじめて動的に作り出される変数であると言えます。なので、たとえば、
var x = 10;
が変数だったとしたら、
var y = getTen();
が関数です。あるいは、変数をHTMLであり、関数をCGIであるとも言えます。もし、変数しかなかったとしたら、動的に作り出したくなった場合に困るかもしれませんが、関数しかなかったとしても、おそらく変数を「静的な関数」だと思えば、それは成り立つでしょう。
あるいは、変数を「実体がある」、関数を「実体がない」とすれば、変数は「データを数値で指定する」ということであり、関数は「データを数式で指定する」ということであるとも言えます。たとえば、
var x = [0, 2, 4, 6]
が変数的な配列だとしたら、
var y = [i * 2 for i in range(4)]
が関数的な配列であると言えます。
何が言いたいかと言えば、結局すべては関数であるということです。あるいは、メッセージングだと言っても良いでしょう。プログラミングは、「呼び出して値が返る」ということ、それによって「世界と世界がメッセージをやり取りする」ということなのです。
また、ほかにプログラミングの要素について重要なものがあるとしたら、それは無名関数です。ブロックとか、ラムダ式とか、関数オブジェクトとか、時には関数ポインタとか呼ばれることもあるそれです。ここでは、関数に変数を与えるだけではなく、「関数に対して関数を与える」ということができます。ですが、関数と変数が静的あるいは動的しか違わないもの、あるいは具体的な値を指定するか動的に作り出されるコードを指定するかということが分かっていれば、これはまさしく「世界に対してメッセージとして世界を与えるもの」であると言えます。
そう、すべては、「世界と世界のメッセージのやり取り」です。では、世界とは何でしょうか。世界とは、「それぞれがやらせたいこと」にほかなりません。それぞれがパソコンにやらせたいこと、すなわち「方法や手順」の中で、さらに「具体的な値」や「追加的な方法な手順」を与える、その「与えるということそのものがメッセージング」ということなのです。
そう、関数こそ、プログラミングのすべてです。それはメッセージングであり、「このようにしろと決まっている手順の中で、その中のさまざまな具体的な手順をさまざまな状況や場合に応じて書き換えること」です。これこそ、「関数とは何か」という問題についての、正しい定義であると言えるでしょう。
if文やfor文を使ったアルゴリズム、あるいはデータ構造は、その状況や手順を成り立たせるための「決まり事」にすぎません。ですが、プログラマのメインの仕事は、その「決まり事を書くこと」です。関数が方法や手順であったとしたら、if文やfor文はその方法や手順を書くための「用語集」であり、スタックやリストなどのデータ構造は「詳細な言葉の定義」であり、そして実際のアルゴリズムは「言語化」であると言えます。そのような言語の中で、具体的な値すなわち「意味」を与えるのか、それとも値を仮想化した「論理」を与えるのかが違うだけにすぎません。そして、プログラマの仕事とは、それらすべてを集約したうえで、ひとつの世界、すなわち「太陽系」を作り出すことなのです。
ここで僕が「関数」という言葉を使って何を表現したいのかというと、それは「プログラマブルに操作できる」ということです。
たとえば、青い画面を表示するだけなら、テレビにだってできます。パソコンを使わなくても、決まりきった静止画や動画をテレビのようなモニターを映すことはできます。CPUは必要ありません。
ですが、そこにCPUとソフトウェアが繋がることで、たとえば「マウスを上にやればメニューがでて、そのメニューをクリックすると青い画面が赤い画面やオレンジの画面などに変わる」といった、処理ができます。
これは、ユーザーが明示的に操作した場合だけではありません。あらかじめ決められたデータフォーマットのデータをCPUを内蔵するモニターに与えて、その中でプログラムを処理することで、ソフトウェアとデータファイルを使ってモニターに表示する内容を変えることができます。インターネットなどのネットワークに繋がっていれば、そのデータファイルがローカルにある必要はなく、先ほどのマウスを上にやるとでてくるメニューの中にURLを入力すれば、URLのアドレスに存在するページにアクセスしてそれを表示することだってできるでしょう。
このように、コンピュータとは「プログラマブルに動作を変えられる」ということです。そして、これこそが「関数」の本質です。関数は、データを単にあっちからこっちへと移すだけではなく、その移す過程において「内容を変更する」ことや「内容を計算して作り出す」ことができます。そう、関数とはそのためにある「メッセージ記述装置」なのです。
実際のところ、プログラミングはそんなに難しいものではありません。
なぜなら、「全部関数でやればいい」というだけだからです。
ボタンやメニューの表示、ウィンドウの表示、Webブラウザにおける移動や更新、ブックマークの管理と情報の参照など、すべて、関数で行い、関数が返すデータを参照しながら作ればいいのです。
ですが、場合によっては、関数と関数の間でデータを共有したい時もあります。関数にデータを渡して返り値からデータを受け取る方法もありますが、関数の中からデータを参照・変更する場合、あるいは関数と関数の間で共通のデータを共有する場合には、オブジェクト指向の考え方を使います。
関数とオブジェクト指向の考え方を組み合わせて、関数にオブジェクトを渡す、あるいは関数からオブジェクトを生成して返すという方法もあります。
ですが、基本的にプログラミングとは関数です。関数によってデータを参照・編集すること、関数にデータを渡し、関数から返ってきたデータを適切に扱うこと、これがプログラミングであると言えます。
関数型プログラミングも参照のこと。
Smalltalkも参照のこと。