言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

なぜポイントフリースタイル = コンビネータが重要なのか

「Joy: Forth の関数なイトコ」 http://d.hatena.ne.jp/propella/20070517/p1 をちゃんとアップしてからとも思ったんだけど、書く勢いが無くなる前に書きます。私が http://www.latrobe.edu.au/philosophy/phimvt/joy/forth-joy.html を読んで超感動したのは最後の Joy Algebra の章です。なぜ感動したかと言うと、メタファを適切に選ぶ事によってこんなに話が単純になるのか!という事を思い知らされたからです。そして、コンビネータがどれだけこれからのプログラミングで重要になるか確信が持てたからです。順を追ってのちゃんとした説明は、もうちょっと勉強してからじゃないと書けないけど、頭の中にある気持ちだけ書きます。

25年前に私がプログラミングを始めた頃、マイコンハッカー機械語で書いていました。そろそろホビイストにもコンパイラが手に入るようになっていましたが、コンパイラが作った機械語より手で書いたほうが小さくて速かったからです。ところが現在、大きなプログラムをコンパイラより上手に機械語に出来る人なんて居ないでしょう。コンパイラソースコードを使って大胆に最適化を行うからです。

それと同じ事がアルゴリズムのレベルで起こります。コンパイラの行う最適化は字句レベルの物です。掛け算をビットシフトに変換したり、不要なループを削除したりしますが、もっと大きな単位でプログラムを書き換える事は出来ません。それでははじめから無駄の多いアルゴリズムを書き換える事は出来ません。ある方法と同じ働きをするもっと良い方法を機械的に作る単純な方法が無いからです。しかし今みんながやろうとしていて、しかも求められているのはアルゴリズムの書き換えです。そしてコンビネータはその良い手がかりになります。

なぜプログラムの機械的な書き換えが求められているか一応さらっと書きます。一つは単なる外部状況の変化で、マルチコア CPU の普及で並列処理を書かなくてはいけなくなったからです。今くらいなら人間ワザでも大丈夫なレベルですが、将来何千個ものコアを使うプログラムを人間が書けるとは思えません。逐次処理で書いても勝手に並列にしてくれないと困るのです。もう一つはプログラマ自身の問題です。昨今「リファクタリング」という言葉が流行ってますが、同じ働きをする美しいプログラムというのは、効率の面からも審美的な面からも計り知れない価値があります。そしてそのような美しいプログラムを書くためにもっと機械の手助けが必要なのです。

という事は必要な事が二つあります。一つは、機械がプログラムを意味を変えず表現を変換出来る事(最適化の為に)。もう一つは、そういった変換のプロセスが人間にも理解可能である事(リファクタリングの為に)。

特に後者の為にコンビネータが重要になってきます。プログラムの書き換えにはコンビネータがぴったりなのです。以下ド・モルガンの法則の例です。

Haskell: \a b -> not (a && b) ==  \a b -> (not a) || (not b)

Joy:                 and not  ==  [not] app2 or

どっちが単純かは一目瞭然です。ラムダ(Haskell) で書くと仮引数 a, b の変換が要るので、複雑なパターンマッチングが必要になります。しかし仮引数を使わないコンビネータ(Joy) で書くと、単にシンボルの列を置き換えるだけです。これならワードパットでも出来ます。Haskell でもポイントフリースタイル(変数を使わないで書く http://haskell.org/haskellwiki/Haskell/Pointfree) で書けば Joy のように書けます。

Joy の素晴らしいところは、このコンビネータやカリー化といった難しい概念を単にスタック操作として軽々説明している所です。これはメタファの勝利です。初学者にとってカリー化ほど苦痛な物はありません。引数として関数が来て関数を返して、、、とやってるうちに何が何だか分からなくなります。しかし、スタックだといわれると同じ事なのにすっきり頭に入るのです。そして何よりも、スタックがもう何十年も前からある当たり前の技術であり、どんなプログラミング言語にも内部で使われているにも関わらず、改めて凄い魅力があるという事に驚かされます。Joy のアイデアはコンピュータ科学の中では新鮮ではないかも知れませんが、素晴らしいメタファというのは素晴らしいアイデア並みに大切なのです。

関係ある日記