Macro does not work in function

I have problems with the following code: http://lisper.ru/apps/format/96

The problem is the "normalization" of a function that does not work.
It does not work 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 :xa :x indexes i indexes i) (do-op-on * a :ya :y indexes i indexes i) (do-op-on * a :za :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 the function "normalize" I call the macro "zero-p", which in turn calls the 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's a link:

 (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 "do-op-on" macro, which also calls "ref-of".

 (defmacro do-op-on (op name1 coord1 name2 coord2 &optional is1 i1 is2 i2) "Example: (do-op-on * A :x B :yin) == A[i[n]].x*By" `(,op (ref-of ,name1 ,coord1 ,is1 ,i1) (ref-of ,name2 ,coord2 ,is2 ,i2))) 

As a result, instead: (aref some-array 0) I have (aref NIL NIL) which is created in "ref-of".

I believe that I am losing the character A from the call (normalize A) . I just feel that the symbol does not stand up to macro exponson. The fact is that macroexpansoin works in REPL for each macro independently.

Can someone explain where the error is?

+4
source share
2 answers

Note that the ZERO-P and REF-OF macros expand when evaluating, compiling, or loading DEFUN for NORMALIZE . Their arguments are the characters INDEXES and INDEX , and both of them are not NIL , so the IF form in REF-OF forms will take the first branch and expand into AREF forms, where INDICES and INDEX cannot be bound to NIL . In short, you have lost evaluation time and macro expansion time, which is easy to do when you are just starting out with macros.

However, when you call the NORMALIZE function NORMALIZE only one argument, the INDICES and INDEX variables INDICES bound to the default value of NIL , so AREF complains that it receives invalid arguments.

The best solution I can offer you is simply to make ZERO-P and REF-OF in function instead of macros. They will work fine as functions, and you should not do something with a macro unless you are sure that it should be a macro. If you really want to save them as macros, specify the default values INDICES and INDEX , which make sense and get rid of the optional values ​​in REF-OF and ZERO-P --- I'm sure that INDEX is default 0 and INDICES is default #(0 1 2) will work.

EDIT to add: Desiring to avoid function overhead is almost certainly not a good reason to use macros in Lisp. First, you don’t even have to worry about overhead function calls until you have done some profiling and testing. Secondly, if you have a problem with the utility functions of a function call, you must DECLARE functions in question INLINE , instead of using macros to perform the insertion.

EDITed add again: if your functions are expanded inline, your compiler should be able to figure out what it can replace

 (cond ((eq :x :x) 'foo) ((eq :x :y) 'bar) ((eq :x :z) 'quux) (t (error "~A is not one of :X, :Y or :Z" :x)) 

from

 'foo 
+7
source

What is PRAGMA ? This is not a standard. Perhaps you mean PROGN (which is not even necessary, since DEFUN provides an implicit PROGN )?

Why all the macros? Is there any reason to forbid such a form as (reduce (lambda (rc) (* (ref-of A c) r)) (list :x :y :z) :initial-value 1) ? This is similar to the case of premature optimization .

Pillsy's answer is true: when a REF-OF expands (due to the use of ZERO-P ), its INDEXES will have the INDEXES character as its value, and not the value passed to NORMALIZE (for example, a wise INDEX will be I ).

+1
source

Source: https://habr.com/ru/post/1305210/


All Articles