为什么这个符号扩展在 Common Lisp 中格式错误?
我正在尝试使用 SBCL 和 Slime 在这个关于 CLOS 的 教程 上进行练习( Emacs)。
我有这个类、实例和函数来设置插槽的值:
(defclass point ()
(x y z))
(defvar my-point
(make-instance 'point))
(defun with-slots-set-point-values (point a b c)
(with-slots (x y z) point (setf x a y b z c)))
使用 REPL,它工作正常:
CL-USER> (with-slots-set-point-values my-point 111 222 333)
333
CL-USER> (describe my-point)
#<POINT {1003747793}>
[standard-object]
Slots with :INSTANCE allocation:
X = 111
Y = 222
Z = 333
; No value
现在,练习表明使用 symbol-macrolet
我需要实现我的 版本代码>带槽。
我有我的 with-slots
的部分实现(我仍然需要插入添加操作):
(defun partial-my-with-slots (slot-list object)
(mapcar #'(lambda (alpha beta) (list alpha beta))
slot-list
(mapcar #'(lambda (var) (slot-value object var)) slot-list)))
调用它时它可以工作:
CL-USER> (partial-my-with-slots '(x y z) my-point)
((X 111) (Y 222) (Z 333))
因为符号宏的这种使用有效:
CL-USER> (symbol-macrolet ((x 111) (y 222) (z 333))
(+ x y z))
666
我尝试这样做:
CL-USER> (symbol-macrolet (partial-my-with-slots '(x y z) my-point)
(+ x y z))
但是,对于由于某种我不知道的原因,史莱姆抛出错误:
malformed symbol/expansion pair: PARTIAL-MY-WITH-SLOTS
[Condition of type SB-INT:SIMPLE-PROGRAM-ERROR]
为什么会发生这种情况?我该如何解决这个问题?
I am trying to do the exercises on this tutorial about CLOS using SBCL and Slime (Emacs).
I have this class, instance, and function to set values for the slots:
(defclass point ()
(x y z))
(defvar my-point
(make-instance 'point))
(defun with-slots-set-point-values (point a b c)
(with-slots (x y z) point (setf x a y b z c)))
Using the REPL, it works fine:
CL-USER> (with-slots-set-point-values my-point 111 222 333)
333
CL-USER> (describe my-point)
#<POINT {1003747793}>
[standard-object]
Slots with :INSTANCE allocation:
X = 111
Y = 222
Z = 333
; No value
Now, the exercises indicates that using the symbol-macrolet
I need to implement my version of with-slots
.
I have a partial implementation of my with-slots
(I still need to insert add the operation):
(defun partial-my-with-slots (slot-list object)
(mapcar #'(lambda (alpha beta) (list alpha beta))
slot-list
(mapcar #'(lambda (var) (slot-value object var)) slot-list)))
It works when calling it:
CL-USER> (partial-my-with-slots '(x y z) my-point)
((X 111) (Y 222) (Z 333))
Since this use of symbol-macrolet works:
CL-USER> (symbol-macrolet ((x 111) (y 222) (z 333))
(+ x y z))
666
I tried doing:
CL-USER> (symbol-macrolet (partial-my-with-slots '(x y z) my-point)
(+ x y z))
But, for some reason that I do not know, Slime throws the error:
malformed symbol/expansion pair: PARTIAL-MY-WITH-SLOTS
[Condition of type SB-INT:SIMPLE-PROGRAM-ERROR]
Why does this happen? How can I fix this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您不能将
with-slots
编写为在运行时调用的函数。相反,它需要是一个将源代码作为参数并返回其他源代码的函数。特别是如果给定这个参数,它应该返回这个结果:
您需要
因此您只需评估
一次。好吧,这里有一个函数可以完成大部分工作:
你可以检查一下:
所以这几乎是正确的,除了不可见变量确实需要不可见:
现在:
好吧,一个函数将源代码作为参数并返回其他值源代码是一个宏。因此,最后,我们需要将此函数安装为宏扩展器,并安排忽略宏函数获得的第二个参数:
现在:
当然,这将更传统地使用
defmacro
编写:但是这两个定义是等效的(模数需要一些
eval-when
ery才能使第一个与编译器一起正常工作)。You can't write
with-slots
as a function which is called at run time. Instead it needs to be a function which takes source code as an argument and returns other source code. In particular if given this argumentIt should return this result:
You need
<invisible-variable>
so you evaluate<object-form>
only once.Well, here is a function which does most of that:
And you can check this:
So that's almost right, except the invisible variable really needs to be invisible:
And now:
Well, a function which takes source code as an argument and returns other source code is a macro. So, finally, we need to install this function as a macroexpander, arranging to ignore the second argument that macro functions get:
And now:
This would be more conventionally written using
defmacro
, of course:However the two definitions are equivalent (modulo needing some
eval-when
ery to make the first work properly with the compiler).您需要返回在代入宏扩展时调用
slot-value
的表达式,而不是立即调用该函数。反引号对此很有用。您可以在
with-slots
宏中使用它,如下所示:You need to return expressions that will call
slot-value
when substituted into the macro expansion, rather than calling the function immediately. Backquote is useful for this.You use this in your
with-slots
macro like this: