在通用Lisp中,是否可以在一定範圍內重新定義已定義的函數?例如,給定一個調用函數B的函數A.我可以在呼叫A期間暫時重新定義B嗎?Common lisp:重新定義範圍內的現有函數?
我正在尋找沿着let塊的東西,但可以重新定義函數。
在通用Lisp中,是否可以在一定範圍內重新定義已定義的函數?例如,給定一個調用函數B的函數A.我可以在呼叫A期間暫時重新定義B嗎?Common lisp:重新定義範圍內的現有函數?
我正在尋找沿着let塊的東西,但可以重新定義函數。
本地功能可以與FLET and LABELS一起引入。
在給定的詞彙範圍內,是的。使用FLET或LABELS。任何由FLET定義的函數都將無法調用在同一個詞法範圍中定義的函數,如果需要(用於一組相互遞歸函數的自遞歸),則需要使用LABELS。
請注意,FLET和LABELS都只建立詞彙投影,不應該用於影射COMMON-LISP軟件包的函數,也不會動態地改變表單建立的詞彙範圍之外的函數。
您可以模擬像這樣的玩意兒動態綁定:
(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
如果你想使用動態範圍重新定義/隱藏現有函數,這是我一直使用的宏。
(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。
我最常在編寫單元測試時重新定義函數。在特定單元測試範圍內嘲諷函數是有幫助的,有時需要用動態(而不是詞法)範圍來完成。
因此,由於它的詞法範圍,它只會影響flet/labels的實際主體,而不會影響整個funcion調用層次結構,可以這麼說嗎? – 2010-06-23 18:18:57
完全如此,它只會在詞彙範圍內「存在」,而不會對其他功能產生一點點盲目性。據我所知,沒有任何動態綁定符號 - 函數映射的方法。 – Vatine 2010-07-02 14:48:36