问题flet在于必须内联定义其中绑定的函数.换句话说,没有办法做到这一点:
(new-flet ((a (lambda (f x)
(funcall f (* x 2))))
(b (function-generator)))
(a #'b 10))
Run Code Online (Sandbox Code Playgroud)
我考虑过自己定义这样一个宏,但问题是这flet似乎是设置本地函数值的唯一方法.symbol-function始终只获取全局定义,function不能与之一起使用setf.如果有的话,任何人都知道如何干净利落地完成这项工作?
你可以轻松地建造一个蹦床
(defun function-generator (x)
(lambda (y) (* x y)))
(let ((fg (function-generator 42)))
(flet ((a (f x) (funcall f (* x 2)))
(b (x) (funcall fg x)))
(a #'b 10)))
Run Code Online (Sandbox Code Playgroud)
new-flet使用这种方法的宏实现是
(defmacro new-flet (bindings &body body)
(let ((let-bindings (list))
(flet-bindings (list))
(args (gensym)))
(dolist (binding bindings)
(let ((name (gensym)))
(push `(,name ,(second binding))
let-bindings)
(push `(,(first binding) (&rest ,args)
(apply ,name ,args))
flet-bindings)))
`(let ,(nreverse let-bindings)
(flet ,(nreverse flet-bindings)
,@body))))
Run Code Online (Sandbox Code Playgroud)
在你的示例中扩展为
(macroexpand-1 '(new-flet ((a (lambda (f x) (funcall f (* x 2))))
(b (function-generator)))
(a #'b 10)))
==> (LET ((#:G605 (LAMBDA (F X)
(FUNCALL F (* X 2))))
(#:G606 (FUNCTION-GENERATOR)))
(FLET ((A (&REST #:G604)
(APPLY #:G605 #:G604))
(B (&REST #:G604)
(APPLY #:G606 #:G604)))
(A #'B 10)))
Run Code Online (Sandbox Code Playgroud)