从Common Lisp宏内部返回可调用的函数/闭包

问题描述 投票:0回答:1

我想定义以下形式的宏,其中每个规则(嵌套在参数列表中)都记录在哈希表中:

(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时,我得到了可以用wh作为参数调用的函数:

(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)(* ...

macros closures common-lisp
1个回答
1
投票

编写宏的基本规则

© www.soinside.com 2019 - 2024. All rights reserved.