2010-06-19 57 views

回答

12

在給定的詞彙範圍內,是的。使用FLET或LABELS。任何由FLET定義的函數都將無法調用在同一個詞法範圍中定義的函數,如果需要(用於一組相互遞歸函數的自遞歸),則需要使用LABELS。

請注意,FLET和LABELS都只建立詞彙投影,不應該用於影射COMMON-LISP軟件包的函數,也不會動態地改變表單建立的詞彙範圍之外的函數。

+0

因此,由於它的詞法範圍,它只會影響flet/labels的實際主體,而不會影響整個funcion調用層次結構,可以這麼說嗎? – 2010-06-23 18:18:57

+0

完全如此,它只會在詞彙範圍內「存在」,而不會對其他功能產生一點點盲目性。據我所知,沒有任何動態綁定符號 - 函數映射的方法。 – Vatine 2010-07-02 14:48:36

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 
5

如果你想使用動態範圍重新定義/隱藏現有函數,這是我一直使用的宏。

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

注意,它依賴於道格·霍伊特的defmacro!宏,可在Let Over Lambda

也如書面,它是照應(有趣的是在體內可用)。如果你希望它完全衛生,只需將fun-orig改爲g!fun-orig。

我最常在編寫單元測試時重新定義函數。在特定單元測試範圍內嘲諷函數是有幫助的,有時需要用動態(而不是詞法)範圍來完成。