From: ········@gmail.com
Subject: help a newbie with a macro
Date: 
Message-ID: <1118125454.139343.137360@g49g2000cwa.googlegroups.com>
Hello,
I'm working on my Lisp raytracer (mainly to learn Lisp), and I came
across an opportunity to remove code dupe: Vector functions.  Most
vector functions tend to like something like this:

(defun dot-product (a b)
  (+ (* (v-x a) (v-x b))
     (* (v-y a) (v-y b))
     (* (v-z a) (v-z b))))

As you can see, the duplication comes when you have to do the same
thing for all three components.  I would like some macro, perhaps
called 'for-each-comp', that would let me do something like this:

(defun dot-product (a b)
  (+ (for-each-comp (v-c)
       (* (v-c a) (v-c b)))))

The macro should make three copies of the *-form, and for each replace
v-c with v-x or v-y or v-z.  What's the best way to do this?  I've
tossed around some ideas..but nothing strikes me as "the right way."

Thanks,
Steve

From: ··········@gmail.com
Subject: Re: help a newbie with a macro
Date: 
Message-ID: <1118130038.001334.167150@z14g2000cwz.googlegroups.com>
This guys already had the solution.

http://www.ptarmigangames.com/malcontent/archives/26

He uses SYMBOL-MACROLET to make x1 means (v-x v1) y1 means (v-y v1)

so the code looks quite clean.

If you really want to bind v-c dynamically to either v-x, v-y or v-z
then I gues you could write a macro to use MACROLET or FLET for it.
From: Barry Margolin
Subject: Re: help a newbie with a macro
Date: 
Message-ID: <barmar-43D661.03392907062005@comcast.dca.giganews.com>
In article <························@g49g2000cwa.googlegroups.com>,
 ········@gmail.com wrote:

> Hello,
> I'm working on my Lisp raytracer (mainly to learn Lisp), and I came
> across an opportunity to remove code dupe: Vector functions.  Most
> vector functions tend to like something like this:
> 
> (defun dot-product (a b)
>   (+ (* (v-x a) (v-x b))
>      (* (v-y a) (v-y b))
>      (* (v-z a) (v-z b))))
> 
> As you can see, the duplication comes when you have to do the same
> thing for all three components.  I would like some macro, perhaps
> called 'for-each-comp', that would let me do something like this:
> 
> (defun dot-product (a b)
>   (+ (for-each-comp (v-c)
>        (* (v-c a) (v-c b)))))
> 
> The macro should make three copies of the *-form, and for each replace
> v-c with v-x or v-y or v-z.  What's the best way to do this?  I've
> tossed around some ideas..but nothing strikes me as "the right way."

(defmacro combine (obj1 obj2 outer-op inner-op &rest field-ops)
  (let ((obj1-var (gensym))
        (obj2-var (gensym)))
    `(let ((,obj1-var ,obj1)
           (,obj2-var ,obj2))
       (,outer-op
          ,@(loop for op in field-ops
                  collect `(,inner-op (,op ,obj1-var) 
                                      (,op ,obj2-var)))))))

(defun dot-product (a b)
  (combine a b + * v-x v-y v-z))

With a little redesign it can be made to handle an arbitrary number of 
arguments, rather than being hardcoded for 2.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Christopher C. Stacy
Subject: Re: help a newbie with a macro
Date: 
Message-ID: <uy89ma9wk.fsf@news.dtpq.com>
········@gmail.com writes:
> The macro should make three copies of the *-form, and for each replace
> v-c with v-x or v-y or v-z.  What's the best way to do this?  I've
> tossed around some ideas..but nothing strikes me as "the right way."

I would probably use LOOP to create and COLLECT the various copies
of the form; the macro would expand into a DEFUN and use ,@ to
splice the collected forms into the body.