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
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.
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 ***
········@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.