我想定义以下形式的宏,其中每个规则(嵌套在参数列表中)都记录在哈希表中:
(proc-rule
((100 ((+ w 10) (- h 25)))
((+ ip 12) ((* w .2) (* h .1)))
((* ip 2) ((+ ix (* 2 w)) iy))
(45.5 ((+ ix (* 2 w)) iy)))
table)
这些规则可以包含对特定参数名称的引用。第一个列表(这也是唯一的一个!):
(100 ((+ w 10) (- h 25)))
具有一个值的头部,和一个由另外两个expressions(可以表示w y
表示)组成的尾部,我以这种方式将其添加到哈希表中:
(setq table (make-hash-table :test #'equalp))
(defmacro proc-rule (rule table)
(destructuring-bind (ip (ix iy)) (car rule)
`(progn
;; Record the initial forms
(setf (gethash ,ip ,table) #'(lambda (w h) (list ,ix ,iy)))
;;
)))
现在为止按预期工作,当寻找值100
时,我得到了可以用w
和h
作为参数调用的函数:
(funcall (gethash 100 table) 100 100) ; (110 75)
现在,我想遍历其余规则,并将它们添加到表中。每个规则的开头可以是引用第一个规则的开头(称为ip
)的表达式,也可以是另一个新值(对其求值。这又是完整的宏定义):
(defmacro proc-rule (rule table)
(destructuring-bind (ip (ix iy)) (car rule)
`(progn
;; Record the initial forms
(setf (gethash ,ip ,table) #'(lambda (w h) (list ,ix ,iy)))
;; Add the rest of the rules
(dolist (pattern (cdr rule))
(setf (gethash (car pattern) ,table)
#'(lambda (w h) (list (caadr pattern) (cadadr pattern)))))
)))
此键的值也是一个带有两个参数W H
的闭包,该参数现在还可以包含对传入参数的引用,这些参数我已标记为ix iy
。编译此扩展:
(PROGN
(SETF (GETHASH 100 TABLE) #'(LAMBDA (W H) (LIST (+ W 10) (- H 25))))
(DOLIST (PATTERN (CDR RULE))
(SETF (GETHASH (CAR PATTERN) TABLE)
#'(LAMBDA (W H) (LIST (CAADR PATTERN) (CADADR PATTERN))))))
由于不带引号,(cdr rule)
,导致一个funcall错误:
(((+ IP 12) ((* W 0.2) (* H 0.1))) ((* IP 2) ((+ IX (* 2 W)) IY))
(45.5 ((+ IX (* 2 W)) IY)))
将该部分更改为(cdr ',rule)
,结果当然是记录了引用的cons作为键的值,以便:
(funcall (gethash 45.5 table) 100 100) ;(((+ IX (* 2 W)) IY) NIL)
我如何才能将这些规则的尾部保存为函数主体而不是笨拙,以便调用它们来计算提供的表达式?
第二个问题:总的来说这是一个好的设计,如果不是,请解释为什么不呢? (我希望用户以更方便的形式提供表达式,例如((+ ip 12) ((* w .2) (* h .1))
。)>
我想定义以下形式的宏,其中每个规则(嵌套在参数列表中)都记录在哈希表中:( proc-rule((100((+ w 10)(-h 25 )))(((+ ip 12)((* w .2)(* ...
编写宏的基本规则