Разница между определением макроса и определением функции

Я пытаюсь изучить Лисп, но я застрял на этом примере (вы можете найти его в "ANSI Common Lisp" Пола Грэма, стр. 170):

(defmacro in (obj &rest choices)
    (let ((insym (gensym)))
        `(let ((,insym ,obj))
             (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
                           choices)))))

Затем Грэм заявляет:

Второй макрос [...] in возвращает true, если его первый аргумент eql для любого из других аргументов. Выражение, которое мы можем записать как:

(in (car expr) '+ '- '*)

в противном случае нам пришлось бы писать как

(let ((op (car expr)))
    (or (eql op '+)
        (eql op '-)
        (eql op '*)))

Почему я должен писать макрос, если следующая функция, которую я написал, кажется ведет себя точно так же?

(defun in-func (obj &rest choices)
    (dolist (x choices)
        (if (eql obj x)
            (return t))))

Я не понимаю, упускаю ли я что-то, или в данном случае in-func эквивалентно in.


person vrde    schedule 03.05.2011    source источник
comment
Одна вещь, которую вам не хватает, - это то, что dolist также макрос, хотя и более сложный.   -  person geekosaur    schedule 04.05.2011
comment
geekosaur: да, dolist - это макрос, но в целом есть хороший смысл избегать написания макросов new, если вы можете делать то же самое с функциями. Макросы могут усложнить код для будущих читателей, поскольку они не следуют обычным правилам оценки. (Но, конечно, в этом случае in определяется как макрос именно из-за этого.)   -  person Eli Barzilay    schedule 04.05.2011
comment
@ Эли, да, это меня и волновало.   -  person vrde    schedule 05.05.2011


Ответы (2)


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

Расширенный макрос in последовательно оценивает варианты. Если он достигает выбора, который равен первому аргументу, он возвращает истинное значение без оценки каких-либо дополнительных форм.

Напротив, функция in-func будет оценивать все варианты во время вызова функции.

person Terje Norderhaug    schedule 03.05.2011
comment
это означает, что если мои функции ссылочно прозрачны, нет разницы между макросами и функциями? - person Vladimir Keleshev; 08.05.2011

Два других ответа верны, но для большей конкретики рассмотрим это взаимодействие:

CL-USER(1): (defmacro in ...)
IN
CL-USER(2): (defun in-func ...)
IN-FUNC
CL-USER(3): (defvar *count* 0)
*COUNT*
CL-USER(4): (defun next () (incf *count*))
NEXT
CL-USER(5): (in 2 1 2 3 (next))
T
CL-USER(6): *count*
0
CL-USER(7): (in-func 2 1 2 3 (next))
T
CL-USER(8): *count*
1
person Eli Barzilay    schedule 04.05.2011