一文字マクロ文字
パターンマッチがある関数型言語でよく見かける_変数*1をsbclでも使えないかと少し試してみた。
結局満足出来る結果は得られなかったが、作成したものの一部をメモして残しておく。
;; 以下は、マクロ文字候補文字xが ;; シンボル名の一部として解釈できない文脈で現れた場合にだけ、 ;; マクロ文字として扱うための定義群 ;; ;; x -> マクロ文字 ;; xYYY -> シンボル ;; YYYxZZZ -> シンボル ;; x"YYY" -> マクロ文字 + 文字列 ;; マクロ文字候補xが、シンボルの頭文字ならそのシンボルを、そうでないなら(intern x)を返す ;; 関数名はてきとう (defun read-xYYY-symbol (x stream) (let ((*readtable* (copy-readtable))) ; xを普通の文字として、再度読み込んでみる (set-syntax-from-char x x *readtable*) (unread-char x stream) (read stream))) ;; マクロ文字#\!の定義 (set-macro-character #\! (lambda (stream char) (let ((sym (read-xYYY-symbol char stream))) (if (eq sym (intern "!")) "ビックリ" sym))) t) ; 第二引数(non-terminating-p)にtを渡すと、#\!がシンボル名の途中に現れた場合、シンボル名の一部として解釈されるようになる ;; 動作例 > ! --> "ビックリ" > '!abc --> !ABC > 'abc!def --> ABC!DEF > '! --> "ビックリ"
;; ついでに_の定義例 (set-macro-character #\_ (lambda (stream char) (let ((sym (read-xYYY-symbol char stream))) (if (eq sym (intern "_")) (gensym) sym))) t) > (destructuring-bind (_ (a b _)) '(1 (2 3 4)) (+ a b)) ;; 一応動くが、sbclの場合、警告が出力される ; in: LAMBDA NIL ; (LET* ((#:G652 (CAR #:WHOLE654)) ; (A (CAR #:REQUIRED-656)) ; (B (CAR (CDR #:REQUIRED-656))) ; (#:G653 (CAR (CDR #)))) ; (+ A B)) ; ; caught STYLE-WARNING: ; The variable #:G652 is defined but never used. ; ; caught STYLE-WARNING: ; The variable #:G653 is defined but never used. ; ; compilation unit finished ; caught 2 STYLE-WARNING conditions --> 5
こういうこと(一文字のマクロの定義)をしたい場合、大抵はdefine-symbol-macroを使えば良い。
必要なのは、マクロ展開よりも早い段階で展開されるマクロ(つまりリードマクロ)が欲しい時くらい?