为什么这个宏工作方式而不是另一个?

时间:2012-07-04 18:30:03

标签: common-lisp sbcl

这是我在尝试使用的“clx-user-callable.lisp”中定义的宏。

(in-package :clx-gui)

(defmacro get-callback-wrapper (callback)
  (declare (ignorable callback))
  (let* ((func-name (gensym))
         (wrapper-name (intern (format nil "WRAPPER-~a" func-name) )))
    `(defun ,wrapper-name (caller-instance)
       (funcall ,callback) ;; User callbacks wont have arguments
       (closemenu caller-instance))))

我以这种方式调用此宏,它可以正常工作。

(in-package :clx-gui-test-app)

(create-user-menuitem "MyUserMenu" "MyEntryDialog"
                      (get-callback-wrapper 'my-callback))

(create-user-menuitem "MyUserMenu" "MyChoiceDialog"
                      (get-callback-wrapper 'my-callback2))

(create-user-menuitem "MyUserMenu" "MyMessageDialog"
                      (get-callback-wrapper 'my-callback3))

如果我改变代码以这种方式使用宏,通过将回调的符号名称传递给调用宏的函数,它不会返回不同的包装函数,但总是返回相同的包装函数。调用宏的函数与宏定义位于同一文件和包中。

(in-package :clx-gui-test-app)
(create-user-menuitem "MyUserMenu" "MyEntryDialog" 'my-callback)
(create-user-menuitem "MyUserMenu" "MyChoiceDialog" 'my-callback2)
(create-user-menuitem "MyUserMenu" "MyMessageDialog" 'my-callback3)

我尝试将软件包添加到宏定义中,但这没有帮助。

(wrapper-name (intern (format nil "WRAPPER-~a" func-name)
                      (symbol-package callback) )))

我做错了什么?

我正在使用SBCL-1.0.57和Slime。

1 个答案:

答案 0 :(得分:1)

CL-USER>
(defparameter foo1 (gensym))
FOO1
CL-USER> 
foo1
#:G4619
CL-USER> 
(defparameter foo2 '#:G4619)
FOO2
CL-USER> 
foo2
#:G4619
CL-USER> 
(eq foo1 foo2)
NIL
CL-USER> 
~           

或另一项有趣的练习:

(defmacro make-fun ()  
  `(defun ,(intern (format nil "WRAPPER-~a" (gensym))) ()
     'bar))

CL-USER> 
(make-fun)
WRAPPER-G4726
CL-USER> 
(make-fun)
WRAPPER-G4730
CL-USER> 
(make-fun)
WRAPPER-G4734
CL-USER> 
(make-fun)
WRAPPER-G4738
CL-USER> 
(defun WRAPPER-G4745 ()
  'foo)
WRAPPER-G4745
CL-USER> 
(make-fun)
WRAPPER-G4745
CL-USER> (wrapper-G4745)
BAR
CL-USER>

哦,伙计,我们只是写了这个功能!

如果你想用某种前缀名称来表示gensym,可以在gensym调用中做(作为可选参数)。但所有这些只是一个练习,b / c我仍然会在OP问题中使用lambda。

这是一个更简单的替代实现(IMO),应该可以满足您的需求:

(defun get-callback-wrapper (callback)
  (lambda (caller-instance)
    (funcall callback) 
    (closemenu caller-instance)))

这会产生我认为你正在追求的词汇封闭。