ふしぎのapply

(apply map list '((1 2 3) (4 5 6))) ;=> ((1 4) (2 5) (3 6))

これをみて、行列の転置みたいなことができるのにまず目から鱗が落ちた。

(apply + 1 2 '(3 4 5)) ;=> 15

これはapplyの一般的な使い方だけども、普通に関数をlambdaで定義している時の「常識」からすると、さっきのと比較してapplyの2番目の引数がかたや手続きでかたや数値というのが最初不思議に見えた。何番目の引数はこういうオブジェクトで、というのは普通仮定して関数を定義するからだ。だから最初はマクロでこういうことをやっているのか?と思えた。

マクロでやってるのかと思ったのは、applyのやっていることは、よく考えると1番目の引数となる手続きに、残りの引数を、最後の引数のリストは内容を展開して丸投げして適用するということで、つまり

(apply proc args ... list) → (proc args ... <expanded list>)

というような変換のように見えるからだ。しかしながら、単なる変換では最後の引数であるリストを展開したりできないから、「S式の変換」たるマクロでこれをやるのは無理(だと思う)で、applyが手続きだというのは納得できる。けどapplyってapplyを使わずに定義できるんだろうか?という疑問は解消されずに残る。

あと関連して強く不思議だと思った点は、関数適用とマクロ呼び出しとの違いは、あたかもないかのように見えるところ。定義の仕方はずいぶん違う。いくつかの例を見て、マクロ定義というのは構文の定義だと勝手に思い込んでいた節があって、たとえばfor-eachは手続きだけど、プログラミングGaucheの19章に乗っているbreak/nextがついたfor-eachは(本の中ではfor-each-ext)define-syntaxによって定義しているのをなんとなく不思議に感じたりしていた。実態は違うものだけれども、実際に両者を使う時にはその違いをあまり意識することができない。呼び出しの形があまり構文っぽく見えないものも、マクロで定義することがある。

一方で、letとか、condとかよく見るマクロはあきらかに「構文」に見える。でもマクロを展開していけば全部関数適用に帰着すると考えれば、形が同じに見えるのもむべなるかなという感じがするが、そこらへんはまだ理解不十分だ。そういえば、andやorが関数でなくてマクロだと言うのも、関数だとすれば全部の引数を評価するはめになるから当然と言えば当然だがandやorはいくつもの条件式(述語?)を引数にとり真偽を返す「関数」のようにも見えるから、不思議だった。