Какова наилучшая практика для выборочной передачи оцененных аргументов в форму макроса?Вычислить аргументы макрокоманды
Чтобы уточнить: полезность макросов заключается в его способности получать неоцениваемый параметр, в отличие от правила оценки по умолчанию для форм функций. Тем не менее, для оценки аргументов макросов существуют законные варианты использования.
Рассмотрим надуманный пример:
(defparameter *func-body* '((print i) (+ i 1)))
Предположим, что было бы неплохо, что *func-body*
может служить в качестве тела макроса our-defun
, который определяется как:
(defmacro our-defun (fun args &body body)
`(defun ,fun ,args ,@body))
Таким образом, после (our-defun foo (i) (+ 1 i))
, мы могли бы скажем (foo 1)
, чтобы получить 2
. Однако, если мы используем (our-defun foo (i) *func-body*)
, результат (foo 1)
будет ((PRINT I) (+ I 1))
(т. Е. Значение *func-body*
). Было бы неплохо, если бы мы могли вынудить оценку *func-body*
в качестве аргумента макросу our-defun
.
В настоящее время я могу думать о технике использования compile
и funcall
, чтобы сделать это, так как в
(funcall (compile nil `(lambda() (our-defun foo (i) ,@*func-body*))))
, после чего (our-defun 1)
напечатает 1 и вернуться 2
, как и предполагалось. Я могу подумать о том, чтобы сделать эту работу с eval
, но я предпочел бы держаться подальше от eval
из-за ее особенностей в области обзора.
Это приводит к моему вопросу в начале, есть ли более простой или родной способ сделать это?
P.S.,
А, не столь надуманный пример находится в функции (UPDATE-HOOK)
, которая использует две библиотеки макросов (ADD-HOOK)
и (REMOVE-HOOK)
и требует, чтобы оценить его параметры. Здесь используется описанная выше техника (funcall (compile nil `(lambda() ...)))
.
(defun update-hook (hook hook-name &optional code)
(funcall (compile nil `(lambda() (remove-hook ,hook ',hook-name))))
(unless (null code)
(compile hook-name `(lambda() ,@code))
(funcall (compile nil `(lambda() (add-hook ,hook ',hook-name))))))
Спасибо за объяснение. «Неоцененные параметры» означает, что макрос обходит правило рекурсивной оценки, которое применяется к параметрам функции и получает исходный файл s-exp, полученный от читателя. Проблема с макросом читателя «чтение времени». в этом сценарии есть то, что, как вы заметили, выражение внутри него, т. е. * func-body *, не имеет значения во время чтения. В этом случае я не писал (add-hook) и (remove-hook). Они написаны кем-то, кроме меня. Вот почему мне нужно выяснить способ ввода значения времени выполнения в свои аргументы. –
@Wei Peng 彭 巍: макрос получает источник во время компиляции - задолго до оценки. –