Reputation: 358
In Common Lisp (SBCL 1.0.58) why does the macro OR use a gensym, but not AND?
For example,
CL-USER> (macroexpand '(and 1 2 3 4 5))
(IF 1
(AND 2 3 4 5)
NIL)
T
CL-USER> (macroexpand '(or 1 2 3 4 5))
(LET ((#:G967 1))
(IF #:G967
#:G967
(OR 2 3 4 5)))
T
CL-USER>
I looked at defboot.lisp where the macros are defined but found nothing relevant in the comments.
Upvotes: 10
Views: 825
Reputation: 262939
That's because the implemented logic operators are intended to be short-circuiting and to return the value produced by the last form they evaluated.
To achieve this, and
does not need a gensym
because the last form it evaluates will either produce NIL
or be the result of the final tail call to itself.
On the other hand, or
has to return the first non-NIL
value it evaluates, so it cannot rely on the tail call. It needs a gensym
to do that, because without one:
(IF 1
1
(OR 2 3 4 5))
1
appears twice in the expansion, and in our case that means the expression that produces 1
is evaluated twice. And you never want that in your macros.
Upvotes: 17
Reputation: 15759
Let's say a
is false, but b
, c
, and d
are true. Now, because of short-circuiting we have:
(or a b c d) => b
(and a b c d) => nil
(or b c d) => b
(and b c d) => d
As you can see, in the AND
case, the value of the leftmost argument is never used as the return value of the form (unless there is only one argument, in which case the expansion is different). In the OR
case, on the other hand, the value of the leftmost argument is the return value if it is true. Therefore, AND
can discard the value after testing it for truthiness (and thus does not need to store it in a temporary variable), but OR
can't.
Upvotes: 4