[英]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 NORMALIZE
時REF-OF
會擴展宏ZERO-P
和REF-OF
。 它們的參數是符號 INDEXES
和INDEX
,並且它們都不是NIL
,因此REF-OF
形式的IF
將全部采用第一個分支並擴展為AREF
形式,其中INDICES
和INDEX
不能綁定到NIL
。 簡而言之,您已經將評估時間和宏擴展時間混淆了,當您剛剛開始使用宏時,這是一件容易的事情。
但是,當您僅使用一個參數調用函數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))
同
'foo
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.