2010-06-19 8 views

cevap

12

Belirli bir sözcük kapsamı içinde, evet. FLET veya ETİKETLER kullanın. FLET ile tanımlanan herhangi bir işlev, aynı sözcüksel kapsamda tanımlanmış işlevleri çağırmayacaktır, eğer isterseniz (ki, bir grup karşılıklı olarak tekrar eden fonksiyonlar için özyinelemeli olarak), LABELS'i kullanmanız gerekecektir.

Hem FLET hem de LABELS'in yalnızca sözcüksel gölgeleme oluşturduğunu, COMMON-LISP paketinden gölge işlevleri için kullanılmaması gerektiğini ve formun oluşturduğu sözcük kapsamı dışında hangi işlevin çağrıldığını dinamik olarak değiştirmeyeceğini unutmayın.

+0

Yani, sözcüksel olarak kapsamlandığı için, yalnızca flet/etiketlerin gerçek gövdesini etkileyecek ve tüm funcion çağrı hiyerarşisini değil, konuşacak? –

+0

Tam olarak, diğer işlevler için kör bir fark yaratmayarak, yalnızca söz konusu kapsam dahilinde "var" olacak. Bildiğim kadarıyla, sembol-işlev eşleştirmelerini dinamik olarak bağlamak için herhangi bir yol yoktur. – Vatine

1

Böyle hayranları için dinamik bağlayıcı simüle edebilirsiniz:

(defmacro setvfun (symbol function) 
     `(progn 
     (setf ,symbol ,function) 
     (setf (symbol-function ',symbol) (lambda (&rest args) (apply (symbol-value ',symbol) args))))) 

ve sonra, örneğin,

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

ile elde edersiniz:

REPL> (test) 
==>initial-definition 
==>initial-definition 
==>Dynamically REDEFINED with args: Hello 
==>initial-definition 
5

Eğer isterseniz Dinamik kapsamı kullanarak varolan bir işlevi yeniden tanımla/gölgeleyin, bu bir süredir kullandığım bir makrodur.

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

Kullanımı: Doug Hoyte en defmacro dayanmasıdır

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> 

Not! Makro, Let Over Lambda kullanılabilir. Ayrıca, yazılı olduğu gibi, anaporiktir (vücutta eğlence mevcuttur.). Tamamen hijyenik olmasını istiyorsanız, eğlence nesnelerini, g! Fun-orig'in için değiştirin.

Birim testleri yazarken çoğu zaman işlevleri yeniden tanımlarım. Belirli bir birim testi kapsamında hareket etme işlevleri yararlıdır ve bazen bunun dinamik (sözcüksel değil) kapsam ile yapılması gerekir.

İlgili konular