换句话说,是否有可能以类似于“如何”flet
或“如何”的方式在本地定义一个函数labels
?我的最终目标是有一个类似的宏,labels
而不是使用常规函数的实例,funcallable-standard-class
而不必使用funcall
. 用例可能如下所示:
(funcallable-let ((foo func-class :initargs ...))
(foo ...))
symbol-macrolet
似乎只在不在头部位置时才会膨胀。如果我尝试(setf (symbol-function 'foo) (make-instance 'some-funcallable-class))
将此符号设置为全局而不是封闭的范围let
。
这是我到目前为止所能得到的(但它不起作用,因为宏在这种情况下不会扩展......)
(defclass func ()
((state :initarg :state :accessor state-of))
(:metaclass sb-mop:funcallable-standard-class))
(defmethod initialize-instance :after ((this func) &rest initargs)
(declare (ignore initargs))
(sb-mop:set-funcallable-instance-function
this (lambda ()
(format t "~&I am: ~s, my state is: ~s" this (state-of this)))))
(defmacro funcallable-let (bindings &body body)
(loop :for binding :in bindings
:for name := (car binding)
:for class := (cadr binding)
:for init-args := (cddr binding)
:collect `(,name (make-instance ',class ,.init-args)) :into classes
:collect `(,name (&rest args) (list 'apply '',name args)) :into macrolets
:collect name :into ignorables
:finally
(return
`(let ,classes
(declare (ignorable ,@ignorables))
(macrolet ,macrolets
,@body)))))
(defun test-funcallable-let ()
(funcallable-let ((f func :state :f-state)
(g func :state :g-state))
(f) (funcall 'g)))
这是稍加修改的 Lars 的 Brinkoff 宏:
(defmacro funcallable-let (bindings &body body)
(loop
:for binding :in bindings
:for symbol := (gensym)
:for name := (car binding)
:for class := (cadr binding)
:for init-args := (cddr binding)
:collect `(,symbol (make-instance ',class ,.init-args)) :into lets
:collect `(,name (&rest args) (apply ',symbol args)) :into flets
:collect symbol :into ignorables
:finally
(return
`(let ,lets
(declare (ignorable ,@ignorables))
(flet ,flets ,@body)))))
这也行不通。