在Common Lisp中,是否可以在特定范围内重新定义已定义的函数?例如,给定一个调用函数B的函数A.我可以在调用A时暂时重新定义B吗?
我正在寻找一个let块的东西,但这可以重新定义函数.
Vat*_*ine 12
在给定的词汇范围内,是的.使用FLET或LABELS.使用FLET定义的任何函数都无法调用在相同词法范围内定义的函数,如果您需要(例如,对一组相互递归函数进行自递归),则需要使用LABELS.
请注意,FLET和LABELS都只建立词法阴影,不应该用于遮蔽COMMON-LISP包中的函数,也不会动态更改从表单建立的词法范围外调用的函数.
如果你想使用动态范围重新定义/遮蔽现有函数,这是我已经使用了一段时间的宏.
(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))))))
Run Code Online (Sandbox Code Playgroud)
用法:
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>
Run Code Online (Sandbox Code Playgroud)
请注意,它依赖于Doug Hoyte的defmacro!宏,可在Let Over Lambda中找到.
另外,正如所写,它是照应的(有趣的原始体内可用).如果你想要它完全卫生,只需将fun-orig改为,g!fun-orig's.
我经常在编写单元测试时重新定义函数.在特定单元测试范围内的模拟函数是有帮助的,有时需要使用动态(非词法)范围来完成.
| 归档时间: |
|
| 查看次数: |
1934 次 |
| 最近记录: |