From: ··············@googlemail.com
Subject: in macro from ANSI Common Lisp
Date: 
Message-ID: <1164842233.865090.50800@j72g2000cwa.googlegroups.com>
In chapter 10 of ANSI Common Lisp, Paul Graham defines a bunch of
utility macros that cannot be defined as functions.  In it, he defines
the 'in' macro as follows:

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

This will return true if the first argument is eql to any of the &rest
arguments.  Just curious why this can't be defined as a function.  I've
used this:

(defun in (op &rest exps)
   (if (null exps)
       nil
       (or (eql op (car exps))
            (apply #'in (cons op (cdr exps))))))

and it seems to work just the same.  I've been trying to think of a
scenario where the macro would succeed and the function would fail.
Any help would be appreciated.  Thanks.

From: ··············@googlemail.com
Subject: Re: in macro from ANSI Common Lisp
Date: 
Message-ID: <1164843468.892288.200750@h54g2000cwb.googlegroups.com>
On Nov 30, 12:17 am, ···············@googlemail.com"
<··············@googlemail.com> wrote:
> In chapter 10 of ANSI Common Lisp, Paul Graham defines a bunch of
> utility macros that cannot be defined as functions.  In it, he defines
> the 'in' macro as follows:
>
> (defmacro in (obj &rest choices)
>   (let ((insym (gensym)))
>     `(let ((,insym ,obj))
>       (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
>                     choices)))))
>
> This will return true if the first argument is eql to any of the &rest
> arguments.  Just curious why this can't be defined as a function.  I've
> used this:
>
> (defun in (op &rest exps)
>    (if (null exps)
>        nil
>        (or (eql op (car exps))
>             (apply #'in (cons op (cdr exps))))))
>
> and it seems to work just the same.  I've been trying to think of a
> scenario where the macro would succeed and the function would fail.
> Any help would be appreciated.  Thanks.


Excellent responses!  Thanks for the help.
From: Pascal Bourguignon
Subject: Re: in macro from ANSI Common Lisp
Date: 
Message-ID: <8764cx91cz.fsf@thalassa.informatimago.com>
···············@googlemail.com" <··············@googlemail.com> writes:

> On Nov 30, 12:17 am, ···············@googlemail.com"
> <··············@googlemail.com> wrote:
>> In chapter 10 of ANSI Common Lisp, Paul Graham defines a bunch of
>> utility macros that cannot be defined as functions.  In it, he defines
>> the 'in' macro as follows:
>>
>> (defmacro in (obj &rest choices)
>>   (let ((insym (gensym)))
>>     `(let ((,insym ,obj))
>>       (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
>>                     choices)))))
>>
>> This will return true if the first argument is eql to any of the &rest
>> arguments.  Just curious why this can't be defined as a function.  I've
>> used this:
>>
>> (defun in (op &rest exps)
>>    (if (null exps)
>>        nil
>>        (or (eql op (car exps))
>>             (apply #'in (cons op (cdr exps))))))
>>
>> and it seems to work just the same.  I've been trying to think of a
>> scenario where the macro would succeed and the function would fail.
>> Any help would be appreciated.  Thanks.
>
>
> Excellent responses!  Thanks for the help.

You could still implement it as a function, but note how it's hideous:

(defun fin (obj &rest closures)
   (dolist (clos closures NIL)
      (when (eql obj (funcall clos))
         (return-from fin T))))


(fin 5
   (lambda () 53)
   (lambda () (+ 4 1))
   (lambda () (/ 1 0))
   (lambda () (world-sys:explode-world)))


Essentially, this macro implement this syntactic abtraction:

(fin ...
   (lambda () ...)
   (lambda () ...)
   ...)


(defmacro in (obj &rest expressions)
   `(fin ,obj ,@(mapcar (lambda (expr) `(lambda () ,expr)) expressions)))


Well, once you introduce macros to implement syntactic abstractions,
you can also use them for some optimizing, and generate lighter code,
such as the one you wrote, instead of building all these closures and
passing them as parameter to the FIN function...  Ah! Good macros!!


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein
From: Zach Beane
Subject: Re: in macro from ANSI Common Lisp
Date: 
Message-ID: <m3mz69de98.fsf@unnamed.xach.com>
···············@googlemail.com" <··············@googlemail.com> writes:

> In chapter 10 of ANSI Common Lisp, Paul Graham defines a bunch of
> utility macros that cannot be defined as functions.  In it, he defines
> the 'in' macro as follows:
> 
> (defmacro in (obj &rest choices)
>   (let ((insym (gensym)))
>     `(let ((,insym ,obj))
>       (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
>                     choices)))))
> 
> This will return true if the first argument is eql to any of the &rest
> arguments.  Just curious why this can't be defined as a function.  I've
> used this:
> 
> (defun in (op &rest exps)
>    (if (null exps)
>        nil
>        (or (eql op (car exps))
>             (apply #'in (cons op (cdr exps))))))
> 
> and it seems to work just the same.  I've been trying to think of a
> scenario where the macro would succeed and the function would fail.

I can think of a situation:

   (in 5 53 (+ 4 1) (/ 1 0) (world-sys:explode-world))

A macro that acts like IN is not something I'd tend to use
frequently.

Zach
From: Ari Johnson
Subject: Re: in macro from ANSI Common Lisp
Date: 
Message-ID: <m2wt5d95rp.fsf@hermes.theari.com>
···············@googlemail.com" <··············@googlemail.com> writes:

> In chapter 10 of ANSI Common Lisp, Paul Graham defines a bunch of
> utility macros that cannot be defined as functions.  In it, he defines
> the 'in' macro as follows:
>
> (defmacro in (obj &rest choices)
>   (let ((insym (gensym)))
>     `(let ((,insym ,obj))
>       (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
>                     choices)))))
>
> This will return true if the first argument is eql to any of the &rest
> arguments.  Just curious why this can't be defined as a function.  I've
> used this:
>
> (defun in (op &rest exps)
>    (if (null exps)
>        nil
>        (or (eql op (car exps))
>             (apply #'in (cons op (cdr exps))))))
>
> and it seems to work just the same.  I've been trying to think of a
> scenario where the macro would succeed and the function would fail.
> Any help would be appreciated.  Thanks.

(macroexpand-1 '(in :gamma :alpha :beta :gamma :delta))
 ==>
(LET ((#:G85 :GAMMA))
  (OR (EQL #:G85 :ALPHA)
      (EQL #:G85 :BETA)
      (EQL #:G85 :GAMMA)
      (EQL #:G85 :DELTA)))

This evaluates a total of 4 expressions with a total of 1 stack value:
  :GAMMA               ; store value on call stack
  :ALPHA               ; store on call stack
  (EQL #:G85 :ALPHA)   ; false, move on to next
  :BETA                ; store on call stack
  (EQL #:G85 :BETA)    ; false, move on to next
  :GAMMA               ; store on call stack
  (EQL #:G85 :GAMMA)   ; true, short-circuit to return from LET

Versus:
(in :gamma :alpha :beta :gamma :delta) ; the function

Which results in the following evaluations:
  (symbol-function 'IN)        ; look up the function to apply
  :GAMMA                       ; store value on call stack
  :ALPHA                       ; store value on call stack
  :BETA                        ; store value on call stack
  :GAMMA                       ; store value on call stack
  :DELTA                       ; store value on call stack
followed by a function call, and somewhere along the way 4 CONSes to make
the &rest list, then:
  (null exps)                  ; false, take second branch of IF
  (car exps)                   ; store :ALPHA, probably in register
  op                           ; store :GAMMA, probably in register
  (eql OP (CAR EXPS))          ; false, go on to next
  #'in                         ; store value on call stack
  (cdr exps)                   ; store in register
  op                           ; store in register
  (cons OP (CDR EXPS))         ; another CONS, store value on call stack
  (apply #'IN (CONS OP (CDR EXPS)))  ; call the APPLY function, which
                                     ; calls IN
second invocation:
  (null exps)                  ; false, take second branch of IF
  (car exps)                   ; store :BETA in register
  op                           ; store :GAMMA in register
  (eql OP (CAR EXPS))          ; false, go on to next
  #'in                         ; store value on call stack
  (cdr exps)                   ; store in register
  op                           ; store in register
  (cons OP (CDR EXPS))         ; another CONS, store value on call stack
  (apply #'IN (CONS OP (CDR EXPS))) ; call the APPLY function, which
                                    ; calls IN
third invocation:
  (null exps)                  ; false, take second branch of IF
  (car exps)                   ; store :GAMMA in register
  op                           ; store :GAMMA in register
  (eql OP (CAR EXPS))          ; true, short-circuit out of OR

I think that's about right. :)
From: Pascal Costanza
Subject: Re: in macro from ANSI Common Lisp
Date: 
Message-ID: <4t6jb9F12gtttU1@mid.individual.net>
··············@googlemail.com wrote:
> In chapter 10 of ANSI Common Lisp, Paul Graham defines a bunch of
> utility macros that cannot be defined as functions.  In it, he defines
> the 'in' macro as follows:
> 
> (defmacro in (obj &rest choices)
>   (let ((insym (gensym)))
>     `(let ((,insym ,obj))
>       (or ,@(mapcar #'(lambda (c) `(eql ,insym ,c))
>                     choices)))))
> 
> This will return true if the first argument is eql to any of the &rest
> arguments.  Just curious why this can't be defined as a function.  I've
> used this:
> 
> (defun in (op &rest exps)
>    (if (null exps)
>        nil
>        (or (eql op (car exps))
>             (apply #'in (cons op (cdr exps))))))
> 
> and it seems to work just the same.  I've been trying to think of a
> scenario where the macro would succeed and the function would fail.
> Any help would be appreciated.  Thanks.

What's the difference between the two versions when you invoke (in 2 
(print 1) (print 2) (print 3))?


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/