我遇到以下代码问题: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))))))
在函数“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-*)))
以下是参考:
(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)))))
另外,在“normalize”中我调用宏“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)))
结果,而不是这个:(aref some-array 0)
我在“ref-of”中创建了(aref NIL NIL)
。
我想我从通话(normalize A)
中丢失了符号A.我只是觉得这个符号不能在macroexpanson中存活下来。问题是,macroexpansoin独立地在每个宏的REPL中工作。
任何人都可以解释错误在哪里?
答案 0 :(得分:7)
请注意,在评估,编译或加载ZERO-P
REF-OF
时,会扩展宏DEFUN
和NORMALIZE
。他们的论点是符号 INDEXES
和INDEX
,而且这两个都不是NIL
,所以IF
在REF-OF
中表单将全部采用第一个分支并扩展为AREF
表单,其中INDICES
和INDEX
无法绑定到NIL
。简而言之,您已经将评估时间和宏扩展时间混淆了,当您刚开始使用宏时,这是一件容易的事情。
但是,当您仅使用一个参数调用函数NORMALIZE
时,变量INDICES
和INDEX
将绑定到默认值NIL
,因此{{1抱怨它得到了无效的参数。
我能为您提供的最佳解决方案是将AREF
和ZERO-P
转换为函数而不是宏。它们作为函数可以正常工作,除非你确定它需要是一个宏,否则你不应该创建宏。如果您确实希望将它们保留为宏,请将REF-OF
和INDICES
的默认值设为有意义,并删除INDEX
和REF-OF
中的可选值 - - 我非常确定ZERO-P
默认为0,INDEX
默认为INDICES
。
编辑添加:想要避免函数调用开销几乎肯定不是在Lisp中使用宏的好理由。首先,在完成一些分析和测试之后,您甚至不应该担心函数调用开销。第二,如果你确实遇到函数调用开销问题,你应该#(0 1 2)
有问题的函数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))
答案 1 :(得分:1)
什么是PRAGMA
?这不标准。也许你的意思是PROGN
(由于DEFUN
提供了隐式PROGN
,因此甚至没有必要?)
为什么所有的宏?是否有理由拒绝(reduce (lambda (r c) (* (ref-of A c) r)) (list :x :y :z) :initial-value 1)
之类的表格?这似乎是premature optimization的情况。
Pillsy的答案是正确的:当REF-OF
展开时(使用ZERO-P
),其INDEXES
将使用符号INDEXES
作为其值,而不是传入NORMALIZE
的值(与智慧INDEX
一样,将为I
)。