Разница между определением макроса и определением функции - PullRequest
8 голосов
/ 04 мая 2011

Я пытаюсь выучить Лисп, но я застрял в этом примере (вы можете найти его в "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.

Ответы [ 2 ]

7 голосов
/ 04 мая 2011

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

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

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

3 голосов
/ 04 мая 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
...