2010/06/02

Scheme マクロのデバッグ4種

マクロのデバッグ方法をいくつか。(* 追記あり)

expander

expander を使うのがオーソドックスみたいですね。
Gauche なら Common Lisp と同じく、macroexpand, macroexpand-1 などがあります。
(define-syntax nth-value
(syntax-rules ()
((_ n values-body)
(call-with-values
(lambda () values-body)
(lambda vals
(list-ref vals n))))))
(macroexpand-1 '(nth-value 0 (apply values '(a b c d e f g))))
;; (#<identifier user#call-with-values>
;; (#0=#<identifier user#lambda> () (apply values '(a b c d e f g)))
;; (#0# #1=#<identifier user#vals> (#<identifier user#list-ref> #1# 0)))
(macroexpand '(nth-value 3 (apply values '(a b c d e f g))))
;; (#<identifier user#call-with-values>
;; (#0=#<identifier user#lambda> () (apply values '(a b c d e f g)))
;; (#0# #1=#<identifier user#vals> (#<identifier user#list-ref> #1# 3)))
(macroexpand '(nth-value 10 (apply values '(a b c d e f g))))
;; (#<identifier user#call-with-values>
;; (#0=#<identifier user#lambda> () (apply values '(a b c d e f g)))
;; (#0# #1=#<identifier user#vals> (#<identifier user#list-ref> #1# 10)))
view raw debug1.scm hosted with ❤ by GitHub


mac

On Lisp よろしく mac マクロを定義しておくと便利そうです。
(define-syntax mac
(syntax-rules ()
((_ code)
(macroexpand-1 'code))))
(mac (nth-value 0 (apply values '(a b c d e f g))))
;; (#<identifier user#call-with-values>
;; (#0=#<identifier user#lambda> () (apply values '(a b c d e f g)))
;; (#0# #1=#<identifier user#vals> (#<identifier user#list-ref> #1# 0)))
view raw debug2.scm hosted with ❤ by GitHub


リーダーマクロ

Gacuhe #?= リーダーマクロはどうでしょう?うーん。
(define-syntax nth-value
(syntax-rules ()
((_ n values-body)
#?=(call-with-values
(lambda () values-body)
(lambda vals
(list-ref vals n))))))
(nth-value 0 (apply values '(a b c d e f g)))
;; #?=(call-with-values (lambda () (apply values '(a b c d e f g))) ...
;; #?- a
;; a
(define-syntax nth-value
(syntax-rules ()
((_ n values-body)
#?=(call-with-values
(lambda () #?=values-body)
(lambda vals
(list-ref #?=vals n))))))
(nth-value 0 (apply values '(a b c d e f g)))
;; #?=(call-with-values (lambda () (debug-print (apply values '(a b ...
;; #?="(stdin)":140:(apply values '(a b c d e f g))
;; #?- a
;; #?+ b
;; #?+ c
;; #?+ d
;; #?+ e
;; #?+ f
;; #?+ g
;; #?=vals
;; #?- (a b c d e f g)
;; #?- a
;; a
view raw debug3.scm hosted with ❤ by GitHub


quote

これは初見。任意のパターンの展開部分を quote しちゃう。これは意外と便利かも知れません。
*** Debugging trick
One very easy debugging trick is to wrap the template with a quote:
(define-syntax nth-value
(syntax-rules ()
((_ n values-body)
'(call-with-values
(lambda () values-body)
(lambda vals
(list-ref vals n))))))
(nth-value 0 (apply values '(a b c d e f g)))
;; (call-with-values (lambda () (apply values '(a b c d e f g)))
;; (lambda vals (list-ref vals 0)))
(nth-value 3 (apply values '(a b c d e f g)))
;; (call-with-values (lambda () (apply values '(a b c d e f g)))
;; (lambda vals (list-ref vals 3)))
(nth-value 10 (apply values '(a b c d e f g)))
;; (call-with-values (lambda () (apply values '(a b c d e f g)))
;; (lambda vals (list-ref vals 10)))
view raw debug4.scm hosted with ❤ by GitHub


複数のパターンがある場合に、特定のパターンだけ quote してみるとか・・・。
(define-syntax letstar
(syntax-rules ()
((_ () body ...)
'(let ()
body ...))
((_ ((var init)) body ...)
(let ((var init))
body ...))
((_ ((var1 init1)(var2 init2) ...) body ...)
(let ((var1 init1))
(letstar ((var2 init2) ...) body ...)))))
(letstar ()
(display 'a))
;; (let () (display 'a))
(letstar ((x 1))
(display 'a)
(display x))
;; a1#<undef>
(letstar ((x 1)
(y 2)
(z (+ x y)))
(print z))
;; 3
;; #<undef>
view raw debug5.scm hosted with ❤ by GitHub


マクロ初心者な私の知る限りこんなところでしょうか・・・。

追記

gaucheにはmac相当の%macroexpandがあるみたいです。さらにsyntax-rulesマクロなどをmacroexpandした際の表示を見やすくするunwrap-syntaxも便利です。


追記



The Reasoned Schemer

0 件のコメント:

コメントを投稿