Макросы против функций - PullRequest
3 голосов
/ 29 мая 2019

Ранние шаги с макросами и поиском разъяснений.

(defmacro nil! (x)      
  (list 'setf x nil))

Пол Грэм пишет на стр. 169 ANSI CL

nil!, ntimes и while вседолжны быть написаны как макросы, потому что все должны контролировать способ, которым их аргументы оцениваются.

Я посмотрел на nil! и подумал, подожди минутку, я хочу попробовать написать это какфункция.Оказалось, что он прав, как и ожидалось, но хотел выяснить, почему.Если я сделаю

(defun nil!f (x)
  (setf x nil))

(setf a 9)
(nil!f a)
; a is still 9, not nil

Заставив себя на это, я замечу, что это странное использование функции, потому что я бы не стал setf параметром.Если бы я собирался setf в функции, это скорее было бы глобальным, а не параметром.

Если я правильно понял, параметр x создает новую лексическую область, которая затемняет a, который я установил на верхнем уровне.Это означает, что мы можем передать значение функции, но не переменной.

В то время как с макросами мы можем иметь дело с переменными.

Конечно, мы можем сделать это

(defun nil!f-a ()
  (setf a nil))

, но теперь мы потеряли возможность передавать переменную этой конкретной функции, так что это тупая версия оригинала.

Следовательно, вот что макрос позволяет вам сделать здесь:?

Второй вопрос: является ли это верным утверждением

"В CL вы не можете передать переменную в функцию"

Здесь я даю ...

1 Ответ

6 голосов
/ 29 мая 2019
(defun nil!f (x)
  (setf x nil))

Если вы сделаете это, вы можете установить только новую локальную переменную x в nil. В обычном Common Lisp невозможно, чтобы это имело другой эффект.

(defmacro nil! (x)      
  (list 'setf x nil))

(nil! foo)

Вышеупомянутое выражение будет заменено перед выполнением на

(setf foo nil)

Мы можем проверить, что:

CL-USER 110 > (macroexpand-1 '(nil! foo))
(SETF FOO NIL)

Таким образом, поскольку до выполнения вы можете выполнять все виды манипуляций с источником (!).

«В CL нельзя передавать переменную в функцию»

Это верно для лексических переменных. Динамически связанные переменные могут быть переданы в виде символов.

Динамически связаны:

CL-USER 111 > (flet ((f (sym)
                       (symbol-value sym)))
                (let ((a 10))
                  (declare (special a))
                  (f 'a)))
10

Лексически связано:

CL-USER 112 > (flet ((f (sym)
                       (symbol-value sym)))
                (let ((a 10))
                  (f 'a)))

Error: The variable A is unbound.
...