Lisp 试图使宏类似于defparameter,defvar,但宏仅返回s表达式
我试图制作宏来定义各种对象,类似于Lisp 试图使宏类似于defparameter,defvar,但宏仅返回s表达式,lisp,common-lisp,Lisp,Common Lisp,我试图制作宏来定义各种对象,类似于defparameter和defvar。defregion1宏起作用:在执行时,它使用objectregion定义一个变量。但是,defregion2仅返回必须手动执行的表达式。代码如下: (defclass location () ((x :initarg :x :accessor x) (y :initarg :y :accessor y))) (defclass region () ((x :initarg
defparameter
和defvar
。defregion1
宏起作用:在执行时,它使用objectregion
定义一个变量。但是,defregion2
仅返回必须手动执行的表达式。代码如下:
(defclass location ()
((x
:initarg :x
:accessor x)
(y
:initarg :y
:accessor y)))
(defclass region ()
((x :initarg :x
:accessor x)
(y :initarg :y
:accessor y)
(w :initarg :w
:accessor w)
(h :initarg :h
:accessor h)))
(defmacro deflocation (var x y)
`(defparameter ,var `(make-instance 'location :x ,x :y ,y)))
(defmacro defregion1 (var x y w h)
`(defparameter ,(intern (symbol-name var))
(make-instance 'region :x ,x :y ,y :w ,w :h ,h)))
(defmacro defregion2 (var l1 l2)
`(with-slots ((x1 x) (y1 y))
,l1
(with-slots ((x2 x) (y2 y))
,l2
`(defparameter ,(intern (symbol-name ,var))
(make-instance 'region
:x ,x1 :y ,y1 :w (- ,x2 ,x1) :h (- ,y2 ,y1))))))
defregion1
的输出:
(defregion1 *test-reg1* 1 2 3 4)
=> *test-reg1*
延迟区域2的输出:
(deflocation *l1* 20 30)
(deflocation *l2* 50 60)
(defregion2 '*test-reg2* *l1* *l2*)
=> (DEFPARAMETER *TEST-REG2*
(MAKE-INSTANCE 'REGION :X 20 :Y 30 :W (- 50 20) :H (- 60 30)))
我希望*test-reg2*
也成为一个变量。这里怎么了?您有两个嵌套的反引号
但您的宏也是由内而外的:您确实希望defparameter
处于顶层,因此这样做会更好:
(defmacro defregion2 (var l1 l2)
`(defparameter ,(intern (symbol-name ,var))
(with-slots ((x1 x) (y1 y))
,l1
(with-slots ((x2 x) (y2 y))
,l2
(make-instance 'region :x x1 :y y1 :w (- x2 x1) :h (- y2 y1))))))
还有,你确定你想要这个有点奇怪的内室吗?这将要做的是将您给出的符号的名称作为参数,并在当前包中插入它。比如说
(defregion2 x:*foo* ...)
将导致当前包中出现符号*foo*
,而不是给x:*foo*
赋值。(当然,如果当前包是x
,那么所有这些都会折叠成同一个东西)
我想你可能想要
(defmacro defregion2 (var l1 l2)
`(defparameter ,var
(with-slots ((x1 x) (y1 y))
,l1
(with-slots ((x2 x) (y2 y))
,l2
(make-instance 'region :x x1 :y y1 :w (- x2 x1) :h (- y2 y1))))))
您的代码也可能不卫生,因为它将变量(实际上是符号宏)绑定到对l2
可见的名称:这样会更安全
(defmacro defregion2 (var l1 l2)
`(defparameter ,var
(let ((l1 ,l1) (l2 ,l2))
(with-slots ((x1 x) (y1 y))
l1
(with-slots ((x2 x) (y2 y))
l2
(make-instance 'region :x x1 :y y1 :w (- x2 x1) :h (- y2 y1)))))))
现在可以从扩展中看到,这是安全的:
(defregion2 *thing*
(expression-involving x1 x2)
(another-expression-involving x1 x2))
扩展到
(defparameter *thing*
(let ((l1 (expression-involving x1 x2))
(l2 (another-expression-involving x1 x2)))
(with-slots ((x1 x) (x2 y)) l1
(with-slots ((x2 x) (y2 y)) l2
(make-instance 'region :x x1 :y y1 :w (- x2 x1) :h (- y2 y1))))))
您可以看到中的x1
(另一个涉及x1…
的表达式不是由与插槽绑定的表达式
谢谢。至于intern
,它一直在对未绑定变量求值,所以我尝试修复它。但这似乎是嵌套反报价的问题。