如何使用函数(或闭包)对象设置本地函数定义?

nbt*_*rap 5 lisp common-lisp

问题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.如果有的话,任何人都知道如何干净利落地完成这项工作?

650*_*502 5

你可以轻松地建造一个蹦床

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