代码之家  ›  专栏  ›  技术社区  ›  Erik Öjebo

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

  •  10
  • Erik Öjebo  · 技术社区  · 14 年前

    在Common Lisp中,是否可以在特定范围内重新定义已定义的函数?例如,给定一个调用函数B的函数a,我可以在调用a的过程中临时重新定义B吗?

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

    4 回复  |  直到 14 年前
        1
  •  12
  •   Vatine    14 年前

    在给定的词汇范围内,是的。使用FLET或标签。使用FLET定义的任何函数都无法调用在同一词法范围内定义的函数,如果需要(例如,对于一组相互递归的函数的自递归),则需要使用标签。

    请注意,FLET和标签都只建立词法隐藏,不应用于隐藏COMMON-LISP包中的函数,也不会动态更改表单建立的词法范围之外调用的函数。

        2
  •  7
  •   Rainer Joswig mmmmmm    14 年前

    本地功能可以通过 FLET and LABELS .

        3
  •  7
  •   Clayton Stanley    11 年前

    如果您想使用动态范围重新定义/隐藏现有函数,这是我已经使用了一段时间的宏。

    (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 .

    同样是书面的,它是回指(有趣的原语可以在体内找到)。如果你想让它完全卫生,只需将乐趣原语改为,g!有趣的奥利格。

    在编写单元测试时,我通常会重新定义函数。在特定单元测试的范围内模拟函数是有帮助的,有时这需要在动态(而不是词汇)范围内完成。

        4
  •  2
  •   Paralife    13 年前

    您可以像这样模拟FUN的动态绑定:

    (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