エラーにするタイミング

Racket で代入不可の変数を作るマクロを見掛けた。

(define-syntax set
  (syntax-rules ()
    ((set id e)
     (begin
       (define id~ e)
       (define-syntax id
         (syntax-id-rules (set!)
           ((set! id _) (error 'id "is not modifiable."))
           ((id . es) (id~ . es))
           (id id~)))))))
http://d.hatena.ne.jp/reinyannyan/20100624/p1

しかし、これは実行時に通過して初めてエラーが検出される。 以下のようなケースではエラーとしては報告されない。

(set x 'hoge)
(if #f (set! x 'huga) #t)

set! の第一引数に現れたらダメなんだから、マクロ展開時に捕捉してしまった方がいいと思う。
その考え方を踏まえて修正したのがこれ。

(define-syntax set
  (syntax-rules ()
    ((_ id e)
     (begin
       (define id~ e)
       (define-syntax id
         (make-set!-transformer
          (lambda(x)
            (syntax-case x (set!)
              ((set! id _)
               (raise-syntax-error 'id "is not modifiable."))
              (id #'id~)))))))))

ちなみに R6RS だったらこうなる。

(define-syntax set
  (syntax-rules ()
    ((_ id val)
     (begin
       (define id~ val)
       (define-syntax id
         (make-variable-transformer
          (lambda(x)
            (syntax-case x (set!)
              ((set! id _)
               (syntax-violation 'set "is not modifiable." x #'id))
              (id #'id~)))))))))

あまり代わり映えしない。 Racket があえて R6RS を捨てて独自の語彙を導入した意義は何なんだろう。 今のところは Racket は R6RS もサポートしているのでなおさらよくわからない。 構文の名前が違うだけに見える。
ところで、 violation の綴りをうっかり vioration と間違えてしまうことがよくある自分はいかにも日本人的だと思った。
Document ID: 83959a48f4ee9af5923a04663037cd63