avp*_*avp 4 lisp macros common-lisp
我有以下代码的问题:http://lisper.ru/apps/format/96
问题在于"规范化"功能,这是行不通的.
它在第五行失败:(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))))))
Run Code Online (Sandbox Code Playgroud)
在函数"normalize"中我调用宏"zero-p",后者又调用宏"ref-of",这是链中的最后一个.
(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-*)))
Run Code Online (Sandbox Code Playgroud)
这是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)))))
Run Code Online (Sandbox Code Playgroud)
此外,在"规范化"中,我调用宏"do-op-on",它也称为"ref-of".
(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)))
Run Code Online (Sandbox Code Playgroud)
结果,而不是这样:(aref some-array 0)我(aref NIL NIL)在"ref-of"中创建了它.
我想,我失去符号A从通话(normalize A).我只是觉得这个符号不能在macroexpanson中存活下来.问题是,macroexpansoin独立地在每个宏的REPL中工作.
任何人都可以解释错误在哪里?
请注意,在评估,编译或加载for 时ZERO-P,REF-OF会扩展宏.他们的论据是符号和,和这两个都没有,所以在S 的形式将所有采取的第一个分支,并扩展到形式,其中并不能必然.简而言之,您已经将评估时间和宏扩展时间混淆了,当您刚刚开始使用宏时,这是一件容易的事情.DEFUNNORMALIZE INDEXESINDEXNILIFREF-OFAREFINDICESINDEXNIL
但是,当您NORMALIZE只使用一个参数调用该函数时,变量INDICES并INDEX绑定到默认值NIL,因此AREF抱怨它获得了无效参数.
我可以为您提供最好的解决方案是只作ZERO-P和REF-OF进入功能,而不是宏.它们作为函数可以正常工作,除非你确定它需要是一个宏,否则你不应该创建宏.如果你真的想保持他们作为宏,给予默认值INDICES和INDEX是否有意义和摆脱可选值REF-OF和ZERO-P---我敢肯定有INDEX默认为0,INDICES默认#(0 1 2)会工作.
编辑添加:想要避免函数调用开销几乎肯定不是在Lisp中使用宏的好理由.首先,在完成一些分析和测试之后,您甚至不应该担心函数调用开销.第二,如果你确实遇到函数调用开销的问题,你应该使用有DECLARE问题的函数INLINE而不是使用宏来进行内联.
编辑再次补充:如果你的职能正在扩展内联,编译器应该能够弄清楚,它可以取代
(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))
Run Code Online (Sandbox Code Playgroud)
同
'foo
Run Code Online (Sandbox Code Playgroud)