2012-12-21 21 views
9

कुछ ऐसा है जो मैं सामान्य लिस्प के बारे में नहीं समझ सकता।अनियंत्रित प्रतीकों प्रतीकों

मान लें मैं एक मैक्रो इस के समान लिख रहा हूँ:

(defmacro test-macro() 
    (let ((result (gensym))) 
     `(let ((,result 1)) 
     (print (incf ,result))))) 

से मैं

> (test-macro) 
2 
2 

कर सकते हैं अब मैं इसे कैसे

> (macroexpand-1 '(test-macro)) 
(LET ((#:G4315 1)) (PRINT (INCF #:G4315))) ; 
T 

ठीक फैलता देखना चाहते हैं। जीन्सिम के साथ उत्पन्न अद्वितीय प्रतीकों हैं जो अनियंत्रित के रूप में मुद्रित किए गए थे।

तो जहां तक ​​मुझे पता है कि अनियंत्रित प्रतीकों वे प्रतीक हैं जिनके लिए मूल्यांकनकर्ता आंतरिक रूप से बाध्यकारी प्रतीक-डेटा नहीं बनाता है।

तो, यदि हम उस रूप में मैक्रो-विस्तार करते हैं तो वहां एक त्रुटि होनी चाहिए (incf #: G4315)। यह परीक्षण करने के हम सिर्फ आरईपीएल में उस रूप का मूल्यांकन कर सकते हैं:

> (LET ((#:G4315 1)) (PRINT (INCF #:G4315))) 
*** - SETQ: variable #:G4315 has no value 

तो क्यों मैक्रो है कि इस स्ट्रिंग के लिए फैलता है पूरी तरह से काम करता है और प्रपत्र पर ही नहीं करता है?

उत्तर

16

प्रतीकों को पैकेज में प्रशिक्षित किया जा सकता है या नहीं। एक पैकेज में प्रशिक्षित एक प्रतीक देखा और पाया जा सकता है। पैकेज में एक अनियंत्रित प्रतीक नहीं देखा जा सकता है। किसी निश्चित नाम का केवल एक प्रतीक पैकेज में हो सकता है। केवल एक प्रतीक CL-USER::FRED है।

आप लिखें:

तो जहाँ तक मुझे पता है uninterned प्रतीकों प्रतीक है जिसके लिए मूल्यांकनकर्ता आंतरिक रूप से बाध्यकारी प्रतीक-डेटा बनाने शामिल नहीं कर रहे हैं।

यह गलत है। अनियंत्रित प्रतीकों प्रतीक हैं जो किसी भी पैकेज में इंटर्न नहीं हैं। अन्यथा वे पूरी तरह से ठीक हैं। प्रशिक्षित का अर्थ है पैकेज के रजिस्ट्री में इसके प्रतीकों के लिए पंजीकृत है।

एस अभिव्यक्ति पाठक प्रतीक नाम और दौरान पैकेज पढ़ने प्रतीकों की पहचान करने के लिए उपयोग करता है। यदि ऐसा कोई प्रतीक नहीं है, तो यह इंटर्न किया गया है। यदि कोई है, तो यह वापस आ गया है।

(read-from-string "FOO") -> symbol `FOO` 

दूसरी बार:

(read-from-string "FOO") -> symbol `FOO` 

यह हमेशा एक ही प्रतीक FOO है

पाठक अप वर्तमान पैकेज में यहां उनके नाम से प्रतीक देखो, नहीं करता है।

(eq (read-from-string "FOO") (read-from-string "FOO")) -> T 

#:FOO नाम FOO के साथ एक uninterned प्रतीक के लिए वाक्य रचना है। यह किसी भी पैकेज में प्रशिक्षित नहीं है। यदि पाठक इस वाक्यविन्यास को देखता है, तो यह एक नया अनियंत्रित प्रतीक बनाता है।

(read-from-string "#:FOO") -> new symbol `FOO` 

दूसरी बार:

(read-from-string "#:FOO") -> new symbol `FOO` 

दोनों प्रतीकों अलग हैं। उनके पास एक ही नाम है, लेकिन वे अलग-अलग डेटा ऑब्जेक्ट्स हैं। पैकेजों की तुलना में प्रतीकों के लिए कोई अन्य रजिस्ट्री नहीं है।

(eq (read-from-string "#:FOO") (read-from-string "#:FOO")) -> NIL 

इस प्रकार अपने मामले (LET ((#:G4315 1)) (PRINT (INCF #:G4315))) में, uninterned प्रतीकों विभिन्न वस्तुओं रहे हैं। दूसरा तो एक अलग चर है।

कॉमन लिस्प डेटा मुद्रित करने के लिए एक तरीका है, ताकि पहचान मुद्रण के दौरान संरक्षित है/पढ़ने:

CL-USER 59 > (macroexpand-1 '(test-macro)) 
(LET ((#:G1996 1)) (PRINT (INCF #:G1996))) 
T 

CL-USER 60 > (setf *print-circle* t) 
T 

CL-USER 61 > (macroexpand-1 '(test-macro)) 
(LET ((#1=#:G1998 1)) (PRINT (INCF #1#))) 
T 

अब आप देख मुद्रित रों अभिव्यक्ति पहले प्रतीक के लिए एक लेबल #1= है । इसके बाद में यह वही चर संदर्भित करता है। इसे वापस पढ़ा जा सकता है और प्रतीक पहचान संरक्षित हैं - भले ही पाठक पैकेज को देखकर प्रतीक की पहचान नहीं कर सके।

इस प्रकार मैक्रो एक रूप बनाता है, जहां केवल एक प्रतीक उत्पन्न होता है। जब हम उस फॉर्म को प्रिंट करते हैं और इसे वापस पढ़ना चाहते हैं, तो हमें यह सुनिश्चित करना होगा कि अनियंत्रित प्रतीकों की पहचान संरक्षित है। *print-circle* के साथ प्रिंटिंग T पर सेट करने में मदद करता है।

प्र: हम GENSYM (प्रतीक उत्पन्न) का उपयोग करके मैक्रो में uninterned उत्पन्न प्रतीकों का उपयोग करते हैं?

इस तरह हम अद्वितीय नए प्रतीक प्राप्त कर सकते हैं जो कोड में अन्य प्रतीकों से टकराव नहीं करते हैं। उन्हें gensym फ़ंक्शन द्वारा नाम मिलता है - आमतौर पर अंत में एक संख्याबद्ध संख्या के साथ। चूंकि वे ताजा नए प्रतीक हैं जो किसी भी पैकेज में प्रशिक्षित नहीं हैं, इसलिए कोई नामकरण संघर्ष नहीं हो सकता है।

CL-USER 66 > (gensym) 
#:G1999 

CL-USER 67 > (gensym) 
#:G2000 

CL-USER 68 > (gensym "VAR") 
#:VAR2001 

CL-USER 69 > (gensym "PERSON") 
#:PERSON2002 

CL-USER 70 > (gensym) 
#:G2003 

CL-USER 71 > (describe *) 

#:G2003 is a SYMBOL 
NAME   "G2003" 
VALUE   #<unbound value> 
FUNCTION  #<unbound function> 
PLIST   NIL 
PACKAGE  NIL      <------- no package 
+1

अगर मैं अपने स्पष्टीकरण सही ढंग से समझ में आया, 'gensym' अभी भी सही ढंग से काम करेंगे तो भी यह प्रतीक के नाम करने के लिए एक गिना संख्या जोड़ नहीं था, यानी अगर यह एक ही नाम के साथ हर बार एक uninterned प्रतीक लौटे इसे (उसी तर्क के साथ) कहा जाता है। क्या वो सही है? यदि हां: तो यह संख्या क्यों जोड़ता है? ताकि कोई आसानी से बता सके कि कौन से प्रतीक समान हैं और जो 'मैक्रो-विस्तार' के आउटपुट में नहीं हैं? – sepp2k

+4

@ sepp2k: सही, संख्या केवल यह पता लगाने में आसान है कि अनियंत्रित प्रतीक अलग हैं और जो समान हो सकता है। यह एक डीबगिंग सहायता है। पहले लिस्प बोलीभाषाओं में (पैकेज के बिना) यह अधिक महत्वपूर्ण हो सकता था। –

+0

बहुत बहुत धन्यवाद। * प्रिंट-सर्कल * स्पष्टीकरण वास्तव में यह समझने में सहायक होता है कि यह कैसे काम करता है। और अनियंत्रित प्रतीकों के बारे में कुछ स्पष्टीकरण के लिए भी धन्यवाद। – JustAnotherCurious

0

gensym एक प्रतीक उत्पन्न करते हैं और जब आप इसे प्रिंट करते हैं तो आपको उस प्रतीक का "स्ट्रिंग" प्रतिनिधित्व मिलता है जो "पाठक" प्रतिनिधित्व के समान नहीं होता है यानी प्रतीक का कोड प्रस्तुत करता है।

संबंधित मुद्दे