Подход с использованием format
вообще не работает, если некоторые переменные, связанные с вводом-выводом, изменены. Использование format
для генерации имен символов, как правило, довольно хрупкое и непереносимое. Однако эту это трудную проблему решить, и может быть проще решить ее с помощью построения списка, а не только обратных кавычек. Например, в этом случае мы могли бы иметь:
(defmacro definline (name variables &body body)
(list 'define-compiler-macro name variables
`(list* 'let (list ,@(mapcar (lambda (variable)
`(list (quote ,variable) ,variable))
variables))
',body)))
Это работает так, что:
CL-USER> (pprint (macroexpand-1 '(definline foobar (a b)
(print "foobar")
(+ a b))))
(DEFINE-COMPILER-MACRO FOOBAR
(A B)
(LIST* 'LET (LIST (LIST 'A A) (LIST 'B B)) '((PRINT "foobar") (+ A B))))
который, если я что-то неправильно понимаю, должен иметь те же результаты, что и:
(define-compiler-macro foobar (a b)
`(let ((a ,a) (b ,b))
(print "foobar")
(+ a b)))
Я не думаю, что обязательно возможно сгенерировать последнюю форму, используя только обратные кавычки. Проблема в том, что, поскольку спецификация не определяет, как именно реализована обратная кавычка, это не так просто, как что-то вроде
(define-compiler-macro foobar (a b)
(backquote (let ((a (unquote a))
(b (unquote b)))
(print "foobar")
(+ a b)))
Если ваша реализация действительно реализует это таким образом, вы можете написать расширение, которое генерирует этот тип вывода. Если вы не получите такую гарантию от своей реализации, я не думаю, что есть способ получить «переменную запятой», которую вам нужно ввести в слой выше. Трудно сделать это ясно, но вы можете посмотреть на эту попытку:
(defmacro definline (name variables &body body)
`(define-compiler-macro ,name ,variables
`(let ,',(mapcar (lambda (variable)
`(,variable (unquote ,variable)))
variables)
,@',body)))
Это даст такие результаты, как:
(DEFINE-COMPILER-MACRO FOOBAR
(A B)
'(LET ((A (UNQUOTE A)) (B (UNQUOTE B)))
(PRINT "foobar")
(+ A B)))
Обратите внимание, что SBCL уже достаточно умен, чтобы заменить обратную кавычку обычной кавычкой, так как внутри нет ничего, что нужно было бы снимать с кавычек. mapcar
, генерирующий форму, которая встраивается, не может генерировать код с запятыми в нем, потому что не указано, как эти запятые реализованы, и, согласно 2.4.7 Запятая, "запятая недействительна, если используется не внутри тела выражения обратной кавычки". Я думаю, это означает, что ваш лучший вариант что-то вроде:
(defmacro definline (name variables &body body)
`(define-compiler-macro ,name ,variables
`(let ,(mapcar 'list
',variables
(list ,@variables))
,@',body)))
Расширение этого будет отличаться в разных реализациях, но в SBCL это:
(DEFINE-COMPILER-MACRO FOOBAR (A B)
`(LET (SB-IMPL::BACKQ-COMMA (MAPCAR 'LIST '(A B) (LIST A B)))
(PRINT "foobar")
(+ A B)))
В CCL вы получаете:
(DEFINE-COMPILER-MACRO FOOBAR (A B)
(LIST* 'LET
(LIST* (MAPCAR 'LIST '(A B) (LIST A B))
'((PRINT "foobar") (+ A B)))))
В КЛИСПЕ:
(DEFINE-COMPILER-MACRO FOOBAR (A B)
(CONS 'LET
(CONS (MAPCAR 'LIST '(A B) (LIST A B)) '((PRINT "foobar") (+ A B)))))
person
Joshua Taylor
schedule
19.02.2014