В результате отладки своего проекта наткнулся на вот такое "нихрена себе!":
CL-USER> (defmacro broken ()
(let ((x (gensym)))
`(format nil "x = ~a" ',x)))
BROKEN
CL-USER> (values
(broken)
(let (not-used)
(broken))
(let (not-used)
(broken))
(let ()
(broken)))
"x = G10330"
"x = G0"
"x = G0"
"x = G10331"
SBCL собран из trunk. Проверялось так же на 1.0.29/win32 (последний релиз на 17.06.2009), 1.0.13/win32, 1.0.18/linux. Везде результат один.
Для сравнения (как должно быть):
ECL (Embeddable Common-Lisp) 9.5.1
Copyright (C) 1984 Taiichi Yuasa and Masami Hagiya
Copyright (C) 1993 Giuseppe Attardi
Copyright (C) 2000 Juan J. Garcia-Ripoll
ECL is free software, and you are welcome to redistribute it
under certain conditions; see file 'Copyright' for details.
Type :h for Help. Top level.
> (defmacro broken ()
(let ((x (gensym)))
`(format nil "x = ~a" ',x)))
BROKEN
> (values
(progn
(broken))
(let (not-used)
(broken))
(let (not-used)
(broken))
(let ()
(broken)) )
"x = G111"
"x = G112"
"x = G113"
"x = G114"
>
Т.е. что мы видим? Наличие формы let с какой-либо переменной (не обязательно динамической), срывает нафиг dynamic scope в macro expansion time. Это пиздец, господа!
UPD:
ОтрепортилUPD2: Это не бага, это я йолоп. (gensym) не гарантирует уникальность имени. Он гарантирует уникальность объектов. А подробности такого поведения SBCL в комментах к баге. Такие дела.