2013-03-27 4 views
4

Какова наилучшая практика для выборочной передачи оцененных аргументов в форму макроса?Вычислить аргументы макрокоманды

Чтобы уточнить: полезность макросов заключается в его способности получать неоцениваемый параметр, в отличие от правила оценки по умолчанию для форм функций. Тем не менее, для оценки аргументов макросов существуют законные варианты использования.

Рассмотрим надуманный пример:

(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)))))) 

ответ

4

Это немного смущает. Макрос не получает неоцениваемые параметры.

Макрос получает исходный код и создает исходный код. Помните также, что исходный код в Lisp фактически представлен как данные. Макрос создает код, который оценивает некоторые формы, а некоторые нет.

Макросы должны работать в компилирующей системе. Перед запуском. Во время компиляции. Все макрос видит исходный код, а затем он создает исходный код. Подумайте о макросах как преобразованиях кода, а не об оценке аргументов или нет.

Было бы хорошо, если мы можем заставить оценку *func-body* в качестве аргумента макрокоманды наш-Defun

Это не очень чистый. В скомпилированной системе вам необходимо убедиться, что *func-body* действительно имеет полезную привязку и что ее можно разрешить по адресу ВРЕМЯ КОМПЛЕКСА.

Если у вас есть макрос, как DEFUN, имеет смысл иметь исходный код статический. Если вы хотите, чтобы вставить некоторый исходный код в форму, то это может иметь смысл сделать это во время чтения:

(defun foo (i) #.`(,@*foo*)) 

Но это код, который я обычно хотел бы избежать.

2 библиотеки макросов (ADD-HOOK) и (REMOVE-HOOK) и нуждается в оценке его параметров.

Почему должно ADD-HOOK и REMOVE-HOOK быть макросами? Если у вас нет реальной причины, они просто должны быть функциями. Уже сейчас, когда они делают повторное использование трудным.

Если вы хотите сделать ADD-HOOK и REMOVE-HOOK макросами по какой-то причине, то UPDATE-HOOK обычно должен быть макросом тоже.

+0

Спасибо за объяснение. «Неоцененные параметры» означает, что макрос обходит правило рекурсивной оценки, которое применяется к параметрам функции и получает исходный файл s-exp, полученный от читателя. Проблема с макросом читателя «чтение времени». в этом сценарии есть то, что, как вы заметили, выражение внутри него, т. е. * func-body *, не имеет значения во время чтения. В этом случае я не писал (add-hook) и (remove-hook). Они написаны кем-то, кроме меня. Вот почему мне нужно выяснить способ ввода значения времени выполнения в свои аргументы. –

+2

@Wei Peng 彭 巍: макрос получает источник во время компиляции - задолго до оценки. –

0

список вы даете макрос имеет вид

(Quote (...)) 

Так что список вы на самом деле хотите это CADR списка вы получите.

Смежные вопросы