50年の歴史に秘められた高階プログラミングのヒミツ

「Collection & Copy - JavaScriptにおける高階プログラミング(http://d.hatena.ne.jp/brazil/20051004/1128435079)」というJavaScriptでの高階プログラミング入門記事の和訳エントリがはてなブックマークで大人気になっている。
だめだよー、高階プログラミングの秘密ばらしちゃ。他の人との生産性の差がつかなくなるじゃないか。でもまあ、この記事はさすがに入門だけあって全体的にあっさり書かれていて、特に記事中で紹介されている高階関数reduceの定義が中途半端。これだけ読んでもそんなたいした高階プログラミングはできないだろう。ひと安心。
でもこれを足がかりに、RubyのEnumerableモジュール*1のeachメソッドやinjectメソッド、さらにLispのmap関数とかfold関数を勉強されると、勘のいい人には高階プログラミングをマスターされてしまうかもしれない。さらにさらに「なぜ関数プログラミングは重要か」(http://www.sampou.org/haskell/article/whyfp.html)までを読みこなされてしまうと非常に困る。ううむどうしよう。

しかしあれだなあ。今頃こうやって「高階」を扱うエントリが人気になっているということは、Paul Grahamが「技術野郎の復讐---Revenge of the Nerds---」*2で言っている、「世の中のプログラマプログラミング言語はすごい遠まわりをしながら、50年も昔、1958年に"発見"されたLispに追いつこうとしている」って話は本当みたいだなあ。なんだか悲しい。

追記

ああ、それともう一つ該当記事で気になったこと。JavaScriptみたいに関数をファーストクラスオブジェクトとして使える言語の例としてRubyがあげられてるけど、これには違和感がある。Rubyはオブジェクトとインスタンスメソッドの結合が密で、厳密にいうとインスタンスメソッドはファーストクラスオブジェクトではなく変数には代入できない。Procオブジェクトは代入できるけど。その意味では、Pythonのほうが例としてふさわしい。Pythonではインスタンスメソッドもただの関数にすぎない上に、ファーストクラスオブジェクトだし。

さらに追記 高階プログラミングの思い出

そういえば、学生時代友人から「scheme使うときは、mapみたいに『ある構造に関数を適用させる関数』を多用するよな?」と言われたことがある。今にして思えば、彼は先の入門記事にあるreduceのような関数のことを言っていて、それこそが関数型言語を使いこなすキモなのだけれども、当時高階プログラミングの勘所がわかっていなかった僕は「え?そう」とか気の抜けた返事を返してしまった。ごめんよ。

さらにさらに追記 高階プログラミングの例

http://d.hatena.ne.jp/sshi/20050317/p1
半年くらい前に、ひとさまのソースを参考にクロスブラウザXMLHTTPRequestを提供するJavaScriptコード*3を自作したのだけど、この中にも高階なプログラミングを使っている。
XMLHTTPRequestオブジェクトの作り方はブラウザによって違うので、その差を吸収するには、XMLHTTPRequestオブジェクトを生成する関数にブラウザを識別するコードをしこんでおくのが普通だろう。でもそうすると、XMLHTTPRequestオブジェクトを生成するたびに識別するコードも走ることになる。
xmlhttprequest.jsの中ではJSファイルが読みこまれたタイミングでブラウザ識別関数を走らせている。このブラウザ識別関数が実は高階関数になっていて、返り値として『そのブラウザに応じたXMLHTTPRequestオブジェクト生成関数』を返すようになっている。つまり、この返り値を適当な変数に代入しておけば、後のコードの中ではこれをXMLHTTPRequestオブジェクト生成関数として使えて、何回オブジェクトを生成しようがブラウザ識別コードは最初の一回しか走らない*4、という寸法。

*1:http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=Enumerable;em=Enumerable

*2:http://www.shiro.dreamhost.com/scheme/trans/icad-j.html

*3:http://sshi.s57.xrea.com/ajax/xmlhttprequest.js

*4:具体的には、XMLHTTP._probe()がブラウザ識別関数で、JSが読みこまれたタイミングでXMLHTTP.makeという変数にその返り値(生成関数)を代入している。