是否有一个let/flet/labels之类的概念用于绑定闭包以避免funcall?

che*_*yst 3 closures common-lisp function-call

虽然过了让lambda我发生了

(defmacro! dlambda (&rest ds)
  `(lambda (&rest ,g!args)
     (case (car ,g!args)
       ,@(mapcar
           (lambda (d)
             `(,(if (eq t (car d))
                  t
                  (list (car d)))
               (apply (lambda ,@(cdr d))
                      ,(if (eq t (car d))
                         g!args
                         `(cdr ,g!args)))))
           ds))))
Run Code Online (Sandbox Code Playgroud)

他们随后如此调用:

(setf (symbol-function 'count-test)
    (let ((count 0))
      (dlambda
        (:inc () (incf count))
        (:dec () (decf count)))))
Run Code Online (Sandbox Code Playgroud)

是否有像flet/labels/let这样的结构,我可以将结果闭包绑定到,以避免以全局方式使用funcall或setf符号函数?所以我可以这样做:

(with-closures ((counter (let ((count 0))
                          (dlambda
                           (:inc () (incf count))
                           (:dec () (decf count))))))
              (counter :incf))
Run Code Online (Sandbox Code Playgroud)

cor*_*ump 5

你可以写一个宏:

(defmacro as-functions ((&rest names) &body body)
  (assert (every #'symbolp names) () "Names must be symbols")
  (let ((args (copy-symbol :args)))
    `(flet
         ,(mapcar (lambda (n) `(,n (&rest ,args) (apply ,n ,args))) names)
       ,@body)))
Run Code Online (Sandbox Code Playgroud)

对于每个符号snames,结合在此符号函数命名空间当前由该符号在结合的函数变量的命名空间.这可以隐藏s在当前词法范围中已经命名的任何函数,但由于它是明确完成的,所以程序员不应该感到意外.例如:

(let ((a (lambda (u) (+ 3 u)))
      (b (lambda (u) (* 2 u))))
  (as-functions (a b)
    (a (b 3))))
Run Code Online (Sandbox Code Playgroud)

......宏观扩展为:

(LET ((A (LAMBDA (U) (+ 3 U))) (B (LAMBDA (U) (* 2 U))))
  (FLET ((A (&REST #:ARGS)
           (APPLY A #:ARGS))
         (B (&REST #:ARGS)
           (APPLY B #:ARGS)))
    (A (B 3))))
Run Code Online (Sandbox Code Playgroud)

......并评估为9.

与绑定构造相反,这可以与函数参数一起使用:

(defun compose (f g)
  (as-functions (f g)
    (lambda (x) (f (g x)))))
Run Code Online (Sandbox Code Playgroud)

也提供绑定

根据jkiiski的评论,这里是一个修改版本,(name fun)除了单个符号之外还接受绑定.这看起来像FLET,除了可以在运行时计算函数.

(defmacro as-functions ((&rest names) &body body)
  (let ((args (copy-symbol :args)))
    `(flet
         ,(mapcar
           (lambda (name)
             (etypecase name
               (symbol `(,name (&rest ,args) (apply ,name ,args)))
               (cons (destructuring-bind (name fun) name
                       `(,name (&rest ,args) (apply ,fun ,args))))))
           names)
       ,@body)))
Run Code Online (Sandbox Code Playgroud)

所以:

(defun thing (f g h)
  (as-functions (f (k (compose g h)))
    (f (k 3))))
Run Code Online (Sandbox Code Playgroud)

编辑:我记得读过这样一个宏以前,使用MACROLET:看到这个答复从埃里克·纳格姆在comp.lang.lisp的回复:为什么不计划一个Lisp?

  • 如果我们考虑一下效率,考虑剩余 arglists,在列表参数上应用函数和添加的非内联函数可能需要更多的工作来“生产”代码。另请参阅动态范围声明... (2认同)