代码之家  ›  专栏  ›  技术社区  ›  avp

宏在函数中不起作用

  •  4
  • avp  · 技术社区  · 15 年前

    以下代码有问题: http://lisper.ru/apps/format/96

    问题在于“normalize”函数,它不起作用。
    它在第五行失败了: (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) 我有 (aref NIL NIL) 在“参考”中创建。

    我想我在电话里丢了符号A (normalize A) . 我只是觉得这个符号不能在宏扩展中生存。问题是,宏扩展在repl中独立地为每个宏工作。

    有人能解释一下错误在哪里吗?

    2 回复  |  直到 15 年前
        1
  •  7
  •   Pillsy    15 年前

    注意宏 ZERO-P REF-OF 在计算、编译或加载 DEFUN 对于 NORMALIZE . 他们的论点是 符号 INDEXES INDEX ,而这两个都不是 NIL 所以 IF S在 雷夫 表单都将采用第一个分支并扩展到 AREF 形式在哪里 INDICES 索引 无法绑定到 . 简而言之,您已经混淆了计算时间和宏扩展时间,当您刚开始使用宏时,这是一件容易的事情。

    但是,当您调用函数时 规范化 只有一个参数,变量 指数 索引 绑定到默认值 如此 阿雷夫 抱怨它得到了无效的参数。

    我能给你最好的解决办法就是 小精灵 雷夫 变成函数而不是宏。它们作为函数运行得很好,除非您确定某个对象需要是宏,否则不应该将其设为宏。如果确实要将它们保留为宏,请将默认值设置为 指数 索引 这是有意义的,并且去掉了 雷夫 小精灵 ——我很确定 索引 默认为0和 指数 默认为 #(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))
    

    具有

    'foo
    
        2
  •  1
  •   Chris Johnsen    15 年前

    是什么 PRAGMA ?这不是标准。也许你是说 PROGN (这甚至不是必要的,因为 DEFUN 提供隐式 孕酮 )?

    为什么都是宏?有什么理由不允许像 (reduce (lambda (r c) (* (ref-of A c) r)) (list :x :y :z) :initial-value 1) ?这看起来像是 premature optimization .

    皮尔西的回答是正确的:什么时候 REF-OF 扩展(从 ZERO-P ) INDEXES 会有这个符号 指标 作为其值,而不是传递到 NORMALIZE (像智者一样) INDEX I )