I have problems with following code: http://lisper.ru/apps/format/96
The problem is in “normalize” function, which does not work.
It fails on the fifth line: (zero-p a indexes i)
(defun normalize (a &optional indexes i)
"Returns normalized A."
(progn
(format t "Data=~A ~A ~A" a indexes i)
(if (zero-p a indexes i)
a ;; cannot normalize empty vector
(let* ((mmm (format t "Zero?=~a" (zero-p a indexes i)))
(L (sqrt (+ (do-op-on * a :x a :x indexes i indexes i)
(do-op-on * a :y a :y indexes i indexes i)
(do-op-on * a :z a :z indexes i indexes i))))
(mmm (format t "L=~a" L))
(L (/ 1D0 L))
(mmm (format t "L=~a" L))) ; L=1/length(A)
(make-V3 (* (ref-of a :x indexes i) l)
(* (ref-of a :y indexes i) l)
(* (ref-of a :z indexes i) l))))))
in function “normalize” I call the macro “zero-p”, which in turn calls macro “ref-of”, which is the last in the chain.
(defmacro zero-p (v &optional indexes index)
"Checks if the vector is 'almost' zero length."
`(and (< (ref-of ,v :x ,indexes ,index) *min+*)
(< (ref-of ,v :y ,indexes ,index) *min+*)
(< (ref-of ,v :z ,indexes ,index) *min+*)
(> (ref-of ,v :x ,indexes ,index) *min-*)
(> (ref-of ,v :y ,indexes ,index) *min-*)
(> (ref-of ,v :z ,indexes ,index) *min-*)))
Here is ref-of:
(defmacro ref-of (values coordinate &optional indexes index)
"Please see DATA STRUCTURE for details."
(if indexes
(cond ((eq coordinate :x) `(aref ,values (aref ,indexes ,index)))
((eq coordinate :y) `(aref ,values (+ 1 (aref ,indexes ,index))))
((eq coordinate :z) `(aref ,values (+ 2 (aref ,indexes ,index))))
(T (error "The symbol ~S is not :X, :Y or :Z." coordinate)))
(cond ((eq coordinate :x) `(aref ,values 0))
((eq coordinate :y) `(aref ,values 1))
((eq coordinate :z) `(aref ,values 2))
(T (error "The symbol ~S is not :X, :Y or :Z." coordinate)))))
Also, in “normalize” I call the macro “do-op-on”, which calls “ref-of” as well.
(defmacro do-op-on (op name1 coord1 name2 coord2 &optional is1 i1 is2 i2)
"Example: (do-op-on * A :x B :y i n) == A[i[n]].x*B.y"
`(,op (ref-of ,name1 ,coord1 ,is1 ,i1) (ref-of ,name2 ,coord2 ,is2 ,i2)))
As a result, instead of having this: (aref some-array 0) I have (aref NIL NIL) which is created in “ref-of”.
I suppose that I lose the symbol A from the call (normalize A). I just feel that the symbol does not survive the macroexpanson. The thing is, macroexpansoin works in REPL for each macro independently.
Can anyone explain where is the mistake?
Note that the macros
ZERO-PandREF-OFare expanded when you evaluate, compile or load theDEFUNforNORMALIZE. Their arguments are the symbolsINDEXESandINDEX, and both of those are notNIL, so theIFs in theREF-OFforms will all take the first branch and expand intoAREFforms whereINDICESandINDEXcan’t be bound toNIL. In short, you’ve gotten evaluation time and macroexpansion time confused, which is an easy thing to do when you are just starting with macros.However, when you call the function
NORMALIZEwith only one argument, the variablesINDICESandINDEXare bound to a default value ofNIL, soAREFcomplains that it’s getting invalid arguments.The best solution I can offer you is to just make
ZERO-PandREF-OFinto functions instead of macros. They’ll work just fine as functions, and you shouldn’t make something a macro unless you’re sure it needs to be a macro. If you really do want to keep them as macros, give default values toINDICESandINDEXthat make sense and get rid of the optional values inREF-OFandZERO-P—I’m pretty sure havingINDEXdefault to 0 andINDICESdefault to#(0 1 2)will work.EDIT to add: Wanting to avoid function call overhead is almost certainly not a good reason to use macros in Lisp. In the first place, you shouldn’t even worry about function call overhead until after you’ve done some profiling and testing. In the second place, if you do have a problem with function call overhead, you should
DECLAREthe functions in questionINLINEinstead of using macros to do the inlining.EDITed again to add: If your functions are being expanded inline, your compiler should be able to figure out that it can replace
with