2010-06-19 4 views
10

सामान्य लिस्प में, क्या किसी निश्चित क्षेत्र में पहले से परिभाषित फ़ंक्शन को फिर से परिभाषित करना संभव है? उदाहरण के लिए, एक फ़ंक्शन ए दिया गया है जो फ़ंक्शन बी को कॉल करता है। क्या मैं ए को कॉल के दौरान अस्थायी रूप से बी को फिर से परिभाषित कर सकता हूं?सामान्य लिस्प: एक मौजूदा कार्य को एक दायरे में फिर से परिभाषित करें?

मैं लेट ब्लॉक की लाइनों के साथ कुछ ढूंढ रहा हूं, लेकिन यह कार्यों को फिर से परिभाषित कर सकता है।

उत्तर

7

स्थानीय कार्यों को FLET and LABELS के साथ पेश किया जा सकता है।

12

किसी दिए गए व्याख्यात्मक दायरे में, हां। FLET या लेबल का प्रयोग करें। FLET के साथ परिभाषित कोई भी फ़ंक्शन उसी व्याख्यात्मक दायरे में परिभाषित कार्यों को कॉल करने में असमर्थ होगा, यदि आप चाहते हैं कि (पारस्परिक रूप से पुनरावर्ती कार्यों के समूह के स्वयं-पुनरावर्ती) के लिए, आपको लेबल का उपयोग करने की आवश्यकता होगी।

ध्यान दें कि दोनों FLET और LABELS केवल अक्षीय छायांकन स्थापित करते हैं, COMMON-LISP पैकेज से कार्यों को छाया करने के लिए उपयोग नहीं किया जाना चाहिए और गतिशील रूप से यह नहीं बदलना चाहिए कि फॉर्म स्थापित होने वाले लेक्सिकल दायरे के बाहर से कौन सा फ़ंक्शन बुलाया जाता है।

+0

तो, के बाद से यह lexically scoped है यह केवल, flet/लेबल की वास्तविक शरीर और नहीं पूरे funcion कॉल पदानुक्रम को प्रभावित करेगा तो बात करने के लिए? –

+0

वास्तव में ऐसा है, तो यह केवल lexcial दायरे के भीतर "मौजूद" होगा, अन्य कार्यों के लिए अंतर का एक अंधे सा नहीं बना। जहां तक ​​मुझे पता है, गतिशील रूप से प्रतीक-से-फ़ंक्शन मैपिंग को बाध्य करने का कोई भी तरीका नहीं है। – Vatine

1

आप इस तरह funs के लिए गतिशील बाध्यकारी अनुकरण कर सकते हैं:

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

ध्यान दें कि यह डौग Hoyte के defmacro पर निर्भर करता है! मैक्रो, Let Over Lambda में उपलब्ध है।

के रूप में भी लिखा है, यह anaphoric (मजेदार मूल शरीर के भीतर उपलब्ध है) है। यदि आप इसे पूरी तरह से स्वच्छ बनाना चाहते हैं, तो बस मजेदार-उत्पत्ति को बदल दें, जी! मजेदार-उत्पत्ति।

मैं सबसे अधिक बार कार्यों को फिर से परिभाषित जब इकाई परीक्षण लेखन। किसी विशेष इकाई परीक्षण के दायरे में मॉकिंग फ़ंक्शंस सहायक होता है, और कभी-कभी इसे गतिशील (व्याख्यात्मक) दायरे के साथ करने की आवश्यकता नहीं होती है।