2

这是我尝试使用的“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。

4

1 回答 1

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)))

这会生成我认为您所追求的词法闭包。

于 2012-07-06T03:33:13.530 回答