cut の拡張
cut は Scheme でプログラミングする上で頻出するマクロだが、先日述べた様にネストした内側にスロットを入れられないといった制約もある。 実装の困難さや、利用の際にミスを誘発しやすくなるといったデメリットを考慮したのだろうけども、それよりも「どういう仕様にするのが自然なのか」を確定するのが難しいという理由が最も大きいと思う。 ネストした内側までスロットを入れられるのならば cut 自体をネストした場合にはどうなるべきなのかとか、内側で <> という名前を導入してたらそれより下の <> はスロットとみなさないようにするのがいいとか、そしたら一貫性に欠けるとか、そういうことである。
そんなことを考えていると、以下のような記事を見掛けた。
Gaucheで、
(map (lambda (x) (* x x)) '(1 2 3))をcutを使うなら、どう書けばいいんだろう。
http://d.hatena.ne.jp/yaotti/20080805/1217911733
cut内で特定の引数を2回以上使いたいってことなんだけど。
これは cut で実現することは出来ないと思う。
そういったことを実現するマクロ (仮に cut* という名前にしよう) を用意するならばどういう仕様だろうかと考えてみた。 スロットに番号を付けて識別するというのはどうだろうか。
(map (cut* * <0> <0>) '(1 2 3))
ところが、これにも問題点を発見した。 arity はどうなるべきなのか。 以下のふたつの式を考えてみよう。
((cut* * <0> <2>) 1 2 3) ((cut* * <0> <1>) 1 2 3)
前者はみっつの引数を受取り、まんなかの引数は使わずに捨てていると解釈して問題ないだろう。 後者は最後の引数を捨てると解釈するべきなのか、 ふたつの引数を受取る関数にみっつの値を渡したのでエラーと解釈するべきなのか、どちらが自然だろう。
ダミーの仮引数を用意する形に展開すれば「多く渡す分には捨てるだけ」にも出来るが、エラーになるべき箇所で素通ししてしまうかもしれないのだ。
と、言うわけで、細かいことを考えはじめるとキリが無いと思った次第。 私にはこの程度しか思いつかないけれども、専門家達が議論してたらいつまでたっても決まらないのも仕方ないというものだ。 R5RS が確定してから R6RS までが高々 9 年というのはむしろ驚異的に早いとさえ思えてくる。
尤も、勝手な「俺仕様」のマクロを簡単に用意出来るのも Lisp 系言語の醍醐味なので、実際に cut* を書いてみようと思っている。 やってみることで見えることもあるだろう。
Document ID: 6ee1421b90b47d139fd29469196a4c82