読者です 読者をやめる 読者になる 読者になる

エラーにしたいとき

「Let Over Lambda」という本がある。 CommonLisp のマクロを取り上げた本だ。 略して LOL と呼ばれたりもする。 私自身は CommonLisp にそれほど関心がないので読んではいないのだけれども、 Lisp 系言語の書籍は少ないこともあってかよく話題にあがっているように見受けられる。

さて、この本に載っているマクロの `(... (,@(...)) ...) というような記述は無駄ではないか、 `(... ,(...) ...) で良いはずという意見を見掛けた。
この意見はもっともなことで、どちらでも展開結果は同じになるはずだ。 しかし、前者の方が良い理由がある。 前者の記法であれば、ここはリストであってアトムでは無いことが自明であると言う点だ。 マクロを読むときのヒントとして使える。 更にもうひとつ理由を挙げられる。 ユーザーが与えたフォームをテンプレート中に挿入するようなマクロであった場合に、リスト以外が与えられたらエラーに出来るという点だ。 マクロ展開した結果についてエラーとなるよりもマクロ展開に失敗してエラーとなる方が、多くの場合にエラー箇所がわかりやすいと思われる。 もちろん事前に listp でチェックしてもよいのだけれど。

似たようなことは Scheme についても言える。 例えば R5RS に載っている let* の定義例を見てみよう。

(define-syntax let*
  (syntax-rules ()
    ((let* () body1 body2 ...)
     (let () body1 body2 ...))
    ((let* ((name1 expr1) (name2 expr2) ...)
       body1 body2 ...)
     (let ((name1 expr1))
       (let* ((name2 expr2) ...)
         body1 body2 ...)))))

これは以下のように簡略化してもよいのではないかと思った人は多いかもしれない。

(define-syntax let*
  (syntax-rules ()
    ((let* () body ...)
     (let () body ...))
    ((let* ((name1 expr1) (name2 expr2) ...)
       body ...)
     (let ((name1 expr1))
       (let* ((name2 expr2) ...)
         body ...)))))

しかし、 let の body 部は空であってはいけないのだ。 故に let* の body 部も空であってはいけない。 定義例通りならば let* の body 部が空であってはいけないことはパターン部の記述から明らかであるが、簡略化版だとパターン部からだけでは読み取れない。

そして、うっかり let* の body 部を空にしてしまったとしたら展開されて let の構文にマッチしないとしてエラーになるので、 let* の使い方を誤ったのだということがわかりにくくなる可能性がある。

以前に C++ についても述べたこと ( http://saito.hatenablog.jp/entry/20090913/1252822014 ) だが、もう一度書いておこう。
想定する使い方にマッチするように書くのは当然だし、それに意識が向きがちだが、マッチしてはいけない場合のことを忘れていはいけない。

Document ID: 4f6ee468311431e92692640f6e7fd425