flet
的问题是必须内联定义其中绑定的函数。换句话说,没有办法做到这一点:
(new-flet ((a (lambda (f x)
(funcall f (* x 2))))
(b (function-generator)))
(a #'b 10))
我考虑过自己定义这样一个宏,但问题是flet
似乎是唯一的方式来设置本地函数值。 symbol-function
始终仅获取全局定义,function
不能与setf
一起使用。如果有的话,任何人都知道如何干净利落地完成这项工作?
答案 0 :(得分: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)))
使用此方法的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))))
在您的示例中扩展为
(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)))
答案 1 :(得分:1)
时
(let* ((a (lambda (f x) (funcall f (* x 2))))
(b (function-generator)))
(funcall a b 10))
你问题的一个相当干净的解决方案?
答案 2 :(得分:1)
如何将变量与let
绑定,以便它们setf
能够,然后使用flet
作为let
的正文,以便它们'能够funcall
能够和(function …)
能够。例如,我给了一个愚蠢的小函数而不是(generate-function)
:
(let ((a (lambda (f x)
(funcall f (* x 2))))
(b (lambda (&rest args)
(print (list* 'print-from-b args)))))
(flet ((a (&rest args)
(apply a args))
(b (&rest args)
(apply b args)))
(a #'b 10)))
我们可以相对容易地将它包装在一个宏中:
(defmacro let/flet (bindings &body body)
(let ((args (gensym (string '#:args-))))
`(let ,bindings
(flet ,(loop :for (name nil) :in bindings
:collect `(,name (&rest ,args) (apply ,name ,args)))
,@body))))
现在
(let/flet ((a (lambda (f x)
(funcall f (* x 2))))
(b (lambda (&rest args)
(print (list* 'print-from-b args)))))
(a #'b 10))
扩展到第一个代码块。请注意,您也可以在正文中使用(a b 10)
,因为b
的绑定与#'b
的值相同。您也可以对变量使用setf
:
(let/flet ((a (lambda (x)
(print (list 'from-a x)))))
(a 23)
(setf a (lambda (x)
(print (list 'from-new-a x x))))
(a 23))
打印
(FROM-A 23)
(FROM-NEW-A 23 23)
答案 3 :(得分:0)
如果有人对labels
等价物感兴趣,请点击这里:
(defmacro my-labels ((&rest definitions) &rest body)
(let ((gensyms (loop for d in definitions collect (gensym)))
(names (loop for d in definitions collect (car d)))
(fdefs (loop for f in definitions collect (cadr f)))
(args (gensym)))
`(let (,@(loop for g in gensyms collect (list g)))
(labels (,@(loop for g in gensyms for n in names
collect `(,n (&rest ,args) (apply ,g ,args))))
,@(loop for g in gensyms for f in fdefs
collect `(setf ,g ,f))
,@body))))
这有点像Scheme的letrec
。