番外編 (gensym) を含んだコードのテスト - Scheme VM を書く
コード変換のコードを書くときに (gensym) を使うことがあります。
展開された変換後のコードができるだけ名前空間を汚さないようにするために使うのですが、(gensym) を使うとテストがしづらいという問題があります。
例えば以下の展開コードには G70 という (gensym) によって生成されたシンボルが使われています。
(if a b (G70 c))
この G70 は実行するたびに変化してしまいます。(gensym の動作としては当然ですが。)
なのでテストの expected を書きづらいのです。
しばらくこの問題を放置していましたが、(gensym) を差し替えれば良いことに今日やっと気づきました。
こんな基本的な手法に気づくのが遅れるとは反省しきり。
良く使うと思うので with-gensym マクロを書いてみました。(Gauche で動作確認)
第1引数に gensym と差し替えたい手続きを、第2引数以降に評価したい式を書きます。
仕様例
(with-gensym (lambda () 'xyz) (cond->if '(cond (a b) (c => d) (else f))))
上の例では、(gensym) は必ず 'xyz を返すようになります。
(define-macro with-gensym (lambda (proc . body) (let ([org (gensym)] [ret (gensym)]) `(let* ((,org gensym)) (set! gensym ,proc) (let ((,ret (begin ,@body))) (set! gensym ,org) ,ret)))))