簡體   English   中英

宏在功能中不起作用

[英]Macro doesn't work in the function

我有以下代碼的問題: 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-*)))

這是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)))))

此外,在“規范化”中,我調用宏“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)在“ref-of”中創建。

我想我從通話中丟失了符號A (normalize A) 我只是覺得這個符號不能在macroexpanson中存活下來。 問題是,macroexpansoin獨立地在每個宏的REPL中工作。

任何人都可以解釋錯誤在哪里?

請注意,在評估,編譯或加載DEFUN for NORMALIZEREF-OF會擴展宏ZERO-PREF-OF 它們的參數是符號 INDEXESINDEX ,並且它們都不是NIL ,因此REF-OF形式的IF將全部采用第一個分支並擴展為AREF形式,其中INDICESINDEX不能綁定到NIL 簡而言之,您已經將評估時間和宏擴展時間混淆了,當您剛剛開始使用宏時,這是一件容易的事情。

但是,當您僅使用一個參數調用函數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))

'foo

什么是PRAGMA 這不標准。 也許你的意思是PROGN (因為DEFUN提供了一個隱含的PROGN ,所以甚至沒有必要)?

為什么所有的宏? 有沒有理由不允許像(reduce (lambda (rc) (* (ref-of A c) r)) (list :x :y :z) :initial-value 1) 這似乎是一個過早優化的情況。

Pillsy的答案是正確的:當REF-OF被擴展時(從使用ZERO-P ),它的INDEXES將使用符號INDEXES作為其值,而不是傳遞給NORMALIZE的值(就像明智的INDEX將是I )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM