在Common Lisp中,是否可以在特定范围内重新定义已定义的函数?例如,给定一个调用函数B的函数A.我可以在调用A?
时暂时重新定义B.我正在寻找一个let块的东西,但这可以重新定义函数。
答案 0 :(得分:12)
在给定的词汇范围内,是的。使用FLET或LABELS。用FLET定义的任何函数都不能调用在同一个词法范围内定义的函数,如果你想要(例如,对一组相互递归函数的自递归),你需要使用LABELS。
请注意,FLET和LABELS都只建立词法阴影,不应该用于遮蔽COMMON-LISP包中的函数,也不会动态更改从表单建立的词法范围之外调用的函数。
答案 1 :(得分:7)
可以使用FLET and LABELS引入本地函数。
答案 2 :(得分:6)
如果要使用动态范围重新定义/遮蔽现有函数,这是我已经使用了一段时间的宏。
(defmacro! with-shadow ((fname fun) &body body)
"Shadow the function named fname with fun
Any call to fname within body will use fun, instead of the default function for fname.
This macro is intentionally unhygienic:
fun-orig is the anaphor, and can be used in body to access the shadowed function"
`(let ((fun-orig))
(cond ((fboundp ',fname)
(setf fun-orig (symbol-function ',fname))
(setf (symbol-function ',fname) ,fun)
(unwind-protect (progn ,@body)
(setf (symbol-function ',fname) fun-orig)))
(t
(setf (symbol-function ',fname) ,fun)
(unwind-protect (progn ,@body)
(fmakunbound ',fname))))))
用法:
Clozure Common Lisp Version 1.9-r15759 (DarwinX8664) Port: 4005 Pid: 4728
; SWANK 2012-03-06
CL-USER>
(defun print-using-another-fname (x)
(print x))
PRINT-USING-ANOTHER-FNAME
CL-USER>
(let ((*warn-if-redefine-kernel* nil))
(with-shadow (print (lambda (x)
(funcall fun-orig (+ x 5))))
(print-using-another-fname 10)))
15
15
CL-USER>
(print 10)
10
10
CL-USER>
请注意,它依赖于Doug Hoyte的defmacro!宏,可在Let Over Lambda中找到。
另外,正如所写,它是照应的(有趣的原始体内可用)。如果你想要它完全卫生,只需将fun-orig改为g!fun-orig's。
我经常在编写单元测试时重新定义函数。在特定单元测试范围内的模拟函数是有用的,有时需要使用动态(非词法)范围来完成。
答案 3 :(得分:1)
您可以像这样模拟动画绑定:
(defmacro setvfun (symbol function)
`(progn
(setf ,symbol ,function)
(setf (symbol-function ',symbol) (lambda (&rest args) (apply (symbol-value ',symbol) args)))))
然后,例如,
(setvfun some-fun (lambda() (format t "initial-definition~%")))
(defun test-the-fun (&rest args) (apply #'some-fun args))
(defun test ()
(test-the-fun)
(flet ((some-fun () (format t "Lexically REDEFINED (if you see this, something is very wrong)~%")))
(test-the-fun))
(let ((some-fun (lambda (x) (format t "Dynamically REDEFINED with args: ~a~%" x))))
(declare (special some-fun))
(test-the-fun "Hello"))
(test-the-fun))
你得到:
REPL> (test)
==>initial-definition
==>initial-definition
==>Dynamically REDEFINED with args: Hello
==>initial-definition