8

I'm trying to learn Lisp but I got stuck by this example (you can find it on "ANSI Common Lisp", by Paul Graham, page 170):

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

Graham then states:

The second macro [...] in returns true if its first argument is eql to any of the other arguments. The Expression that we can write as:

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

we would otherwise have to write as

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

Why I should write a macro when the following function I wrote seems to behave in the same way?

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

I do not understand if I am missing something or, in this case, in-func is equivalent to in.

3
  • 1
    One thing you're missing is that dolist is also a macro, albeit a more complicated one. Commented May 3, 2011 at 23:42
  • 2
    geekosaur: yes, dolist is a macro, but in general there is a good point in avoiding writing new macros if you can do the same with functions. Macros can make code harder for future readers since they don't follow the usual evaluation rules. (But of course in this case in is defined as a macro exactly because of that.) Commented May 4, 2011 at 0:11
  • @Eli yep, that was exactly my concern. Commented May 5, 2011 at 16:07

2 Answers 2

7

The difference in using the macro vs function is in whether all the choices always are evaluated.

The expanded in macro evaluates the choices sequentially. If it reaches a choice that is eql to the first argument, it returns a true value without evaluating any more forms.

In contrast, the in-func function will evaluate all the choices at the time the function is called.

Sign up to request clarification or add additional context in comments.

1 Comment

that means if my functions are referentially transparent, there is no difference between macros and functions?
3

The two other answers are correct, but to make things more concrete, consider this interaction:

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 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.