常见的lisp:重新定义范围内的现有函数?

时间:2010-06-19 07:55:33

标签: common-lisp

在Common Lisp中,是否可以在特定范围内重新定义已定义的函数?例如,给定一个调用函数B的函数A.我可以在调用A?

时暂时重新定义B.

我正在寻找一个let块的东西,但这可以重新定义函数。

4 个答案:

答案 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