宏在功能中不起作用

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中工作.

任何人都可以解释错误在哪里?

Pil*_*lsy 7

请注意,在评估,编译或加载for 时ZERO-P,REF-OF会扩展宏.他们的论据是符号和,和这两个都没有,所以在S 的形式将所有采取的第一个分支,并扩展到形式,其中并不能必然.简而言之,您已经将评估时间和宏扩展时间混淆了,当您刚刚开始使用宏时,这是一件容易的事情.DEFUNNORMALIZE INDEXESINDEXNILIFREF-OFAREFINDICESINDEXNIL

但是,当您NORMALIZE只使用一个参数调用该函数时,变量INDICESINDEX绑定到默认值NIL,因此AREF抱怨它获得了无效参数.

我可以为您提供最好的解决方案是只作ZERO-PREF-OF进入功能,而不是宏.它们作为函数可以正常工作,除非你确定它需要是一个宏,否则你不应该创建宏.如果你真的想保持他们作为宏,给予默认值INDICESINDEX是否有意义和摆脱可选值REF-OFZERO-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)

  • 不,如果您只想简化代码,请始终查看是否可以先将事物分解为较小的函数.函数比宏更简单 - 它们更容易测试,可以跟踪它们,并且它们出现在调试器回溯中.它们也可以直接用于"MAPCAR","REDUCE"或"EVERY"等功能. (3认同)