2011-12-29 13 views
12

में प्रतीक उद्धृत करने के लिए मैंने Emacs Lisp के साथ प्रोग्रामिंग सीखना शुरू कर दिया है। मैं प्रतीक उद्धरण से बहुत उलझन में हूँ। उदाहरण के लिए:जब Emacs Lisp

(progn 
    (setq a '(1 2)) 
    (prin1 a) 
    (add-to-list 'a 3) 
    (prin1 a) 
    (setcar a 4) 
    (prin1 a) 
    (push 5 a) 
    "" 
) 

क्यों "जोड़-टू-सूची" समारोह में अपनी पहली तर्क के रूप में एक उद्धृत प्रतीक की जरूरत है, जबकि "setcar" और "धक्का" समारोह कोई तर्क उद्धरण की आवश्यकता है?

उत्तर

18

यहां एक आरेख है जो प्रतीक a और (setq a '(1 2)) के बाद इसका मान दर्शाता है। बक्से प्राथमिक डेटा संरचनाएं (प्रतीकों और विपक्ष) हैं और तीर पॉइंटर्स हैं (जहां डेटा का एक टुकड़ा दूसरे संदर्भ देता है)। (मैं एक छोटे से सरल बनाने रहा हूँ।)

symbol      cons    cons 
+-------+----------+  +------+------+ +------+------+ 
|name: |variable: |  |car: |cdr: | |car: |cdr: | 
| a  | |  |  | 1 | | | | 2 | nil | 
+-------+----|-----+  +------+--|---+ +------+------+ 
      |    ​↑   |  ↑ 
      +-------------+   +-------+ 

अभिव्यक्ति '(1 2) सही पर दो conses है, जो एक दो तत्व सूची में शामिल बनाता है। अभिव्यक्ति (setq a '(1 2)) प्रतीक a बनाता है यदि यह अस्तित्व में नहीं है, तो उसके "परिवर्तनीय स्लॉट" (भाग में प्रतीक का मूल्य शामिल है) बनाता है जो नव निर्मित सूची को इंगित करता है। setq एक अंतर्निहित मैक्रो है, और (setq a '(1 2))(set 'a '(1 2)) के लिए शॉर्टेंड है। set का पहला तर्क संशोधित करने का प्रतीक है और दूसरा तर्क प्रतीक के परिवर्तनीय स्लॉट को सेट करने का मान है।

(add-to-list 'a 3)(set 'a (cons 3 a)) के बराबर है, क्योंकि 3 सूची में नहीं है। यह अभिव्यक्ति चार चीजें करता है:

  1. एक नया विपक्ष सेल बनाएं।
  2. नया विपक्ष सेल का कार फ़ील्ड पर सेट करें।
  3. नया विपक्ष सेल का सीडीआर फ़ील्ड a के पूर्व (और अभी भी वर्तमान) मान पर सेट करें (यानी a के चर स्लॉट की सामग्री कॉपी करें)।
  4. नए विपक्षी सेल में a के परिवर्तनीय स्लॉट सेट करें।

है कि कॉल करने के बाद, डेटा संरचनाओं इस तरह शामिल देखो:

symbol      cons    cons    cons 
+-------+----------+  +------+--|---+ +------+------+ +------+------+ 
|name: |variable: |  |car: |cdr: | |car: |cdr: | |car: |cdr: | 
| a  | |  |  | 3 | | | | 1 | | | | 2 | nil | 
+-------+----|-----+  +------+--|---+ +------+--|---+ +------+------+ 
      |    ​↑   |  ↑   |  ↑ 
      +-------------+   +-------+   +-------+ 

setcar करने के लिए कॉल किसी भी नए डेटा संरचना का निर्माण नहीं करता है, और प्रतीक a पर लेकिन इस पर कार्रवाई नहीं करता है इसके मूल्य, जो विपक्ष सेल जिसका car वर्तमान में शामिल 3. (setcar a 4) के बाद, डेटा संरचनाओं इस तरह दिखना है:

symbol      cons    cons    cons 
+-------+----------+  +------+--|---+ +------+------+ +------+------+ 
|name: |variable: |  |car: |cdr: | |car: |cdr: | |car: |cdr: | 
| a  | |  |  | 4 | | | | 1 | | | | 2 | nil | 
+-------+----|-----+  +------+--|---+ +------+--|---+ +------+------+ 
      |    ​↑   |  ↑   |  ↑ 
      +-------------+   +-------+   +-------+ 

push है एक मैक्रो; यहां, (push 5 a)(set 'a (cons 5 a)) के बराबर है।

setq और push मैक्रो नहीं है (setq एक "विशेष रूप" है, जो जहाँ तक हम यहाँ चिंतित हैं के रूप में एक मैक्रो जिसकी परिभाषा दुभाषिया में बनाया गया है और लिस्प में उपलब्ध नहीं कराया गया है इसका मतलब है)। मैक्रोज़ को उनके तर्कों का मूल्यांकन नहीं किया जाता है और उन्हें विस्तारित करना चुन सकता है या नहीं। set, setcar और add-to-list कार्य हैं, जो उनके तर्कों का मूल्यांकन करते हैं। एक प्रतीक का मूल्यांकन करना इसके परिवर्तनीय स्लॉट की सामग्री देता है, उदा। प्रारंभिक (setq a '(1 2)) के बाद प्रतीक a का मान उस सेल कक्ष है जिसका कार 1 है।

आप अभी भी उलझन में कर रहे हैं, मैं (setq b a) के साथ प्रयोग करने की सलाह देते हैं और अपने आप के लिए देख रहा है जो अभिव्यक्ति की b संशोधित जब आप a पर (जो कि प्रतीक a पर कार्रवाई) और जो कार्य नहीं है (जो कि प्रतीक a के मूल्य पर कार्य करें)।

13

फ़ंक्शंस निष्पादन से पहले अपने तर्कों का मूल्यांकन करते हैं, इसलिए जब आपको एक वास्तविक प्रतीक (उदाहरण के लिए कुछ डेटा संरचना के सूचक के रूप में) पास करने की आवश्यकता होती है तो उद्धरण दें और जब यह चर वैल्यू हो तो उद्धरण न दें।

add-to-list अपने पहले तर्क के स्थान पर उत्परिवर्तन करता है, इसलिए इसे उद्धृत प्रतीक की आवश्यकता है।

push कोई फ़ंक्शन नहीं है, लेकिन एक मैक्रो; यही कारण है कि यह मूल्यांकन के बिना unquoted तर्क स्वीकार करने में सक्षम है। बिल्टिन फॉर्म, जैसे setcar, उस सीमा भी नहीं है।

+0

क्या आप बता सकते हैं कि कार्यान्वयन को देखे बिना अपने दस्तावेज़ से पूरी तरह से मैक्रो या फ़ंक्शन कुछ है या नहीं? – Tom

+1

@ टॉम प्रलेखन आमतौर पर बताता है कि पहली पंक्ति में तुरंत (पुश - पुश के लिए \ 'cl.el''' में लिस्प मैक्रो है)। –

+0

हां, लेकिन सेटकार के बारे में क्या? आप दस्तावेज़ से कैसे जानते हैं कि यह इसके तर्क का मूल्यांकन नहीं करता है? – Tom

8

दिया अब तक, quote के उपयोग और कार्यों के बीच अंतर को स्पष्ट एक हाथ पर अन्य उत्तर, और मैक्रो और विशेष रूपों दूसरी तरफ।

हालांकि, वे प्रश्न के दूसरे भाग तक नहीं पहुंचते हैं: क्योंadd-to-list है? क्यों वह अपने पहले तर्क की आवश्यकता होती है एक प्रतीक होने के लिए? यह एक अलग सवाल है कि यह तर्क का मूल्यांकन करता है या नहीं। यह add-to-list के डिजाइन के पीछे असली सवाल है।

एक कल्पना कर सकता कि add-to-list अपने आर्ग का मूल्यांकन किया है, और पहले आर्ग के मूल्य की उम्मीद एक सूची होने के लिए, और फिर एक तत्व के रूप कि सूची में दूसरा आर्ग के मूल्य को जोड़ा गया है और परिणाम वापस (नई सूची या एक ही सूची)। (1 2 buckle shoe) देने के लिए, - कि तुम (add-to-list foo 'shoe) कर सूची foo का मूल्य है कि करने के लिए प्रतीक shoe जोड़ने के लिए दिया जाएगा - कहते हैं कि (1 2 buckle)

बिंदु यह है कि ऐसा फ़ंक्शन बहुत उपयोगी नहीं होगा। क्यूं कर? क्योंकि सूची मूल्य आवश्यक रूप से सुलभ नहीं है। परिवर्तनीय foo इसे एक्सेस करने के तरीके के रूप में सोचा जा सकता है - इसे "हैंडल" या "पॉइंटर"। लेकिन यह सूची के बारे में सच नहीं है कि फ़ंक्शन देता है। वह लौटाई गई सूची नई सूची संरचना से बनायी जा सकती है, और आमतौर पर उस सूची को इंगित करने वाला कुछ भी नहीं (कोई परिवर्तनीय) नहीं है। फ़ंक्शन add-to-list कभी भी प्रतीक (चर) foo नहीं देखता है - इसका यह जानने का कोई तरीका नहीं है कि इसे पहले मान के रूप में प्राप्त होने वाली सूची मान foo तक सीमित है। यदि add-to-list इस तरह से डिज़ाइन किए गए थे तो आपको अभी भी अपने लौटे हुए परिणाम को अपनी सूची चर में असाइन करने की आवश्यकता होगी।

IOW, add-to-list अपने आर्ग का मूल्यांकन करता है, क्योंकि यह एक समारोह है, लेकिन यह बहुत स्पष्ट नहीं होता। यह प्रतीक अपने पहले तर्क के मूल्य के रूप में अपेक्षा करता है। और यह उस चर (प्रतीक) के मूल्य की सूची होने की अपेक्षा करता है। यह सूची (संभवतः सूची संरचना को बदलने) के लिए अपनी दूसरी आर्ग के मूल्य को कहते हैं, और यह चर कि सूची में अपना पहला आर्ग का मूल्य है कि का मूल्य निर्धारित करता है।

निष्कर्ष: किसी भी यह आर्ग के रूप में एक प्रतीक जरूरत है क्योंकि अपना काम है कि प्रतीक (नया मान ही सूची मूल्य या नई सूची तत्व के साथ एक ही मूल्य जा रहा है पर जोड़ा के लिए एक नया मान असाइन है सामने)।

और हां, push में मैक्रो या विशेष रूप का उपयोग करने का एक और तरीका होगा। यह वही विचार है: push अपने दूसरे तर्क के रूप में प्रतीक चाहता है। अंतर यह है कि push अपने तर्कों का मूल्यांकन नहीं करता है इसलिए प्रतीक को उद्धृत करने की आवश्यकता नहीं है। लेकिन दोनों मामलों में (Emacs Lisp में) को प्रतीक पर के लिए संवर्धित सूची में सेट करने के लिए कोड को पकड़ने की आवश्यकता है।

+0

मुझे लगता है कि यह सामान्य रूप से एक सार्थक बिंदु है, लेकिन यह सूचियों के मामले में वास्तव में सच नहीं है, वे सिर्फ एक विपक्षी सेल के लिए संकेतक हैं। उदाहरण के लिए, '(मेरी-ऐड-टू-लिस्ट 1 (सूची मूल्य) (setcdr (अंतिम सूची) (cons value nil)) सूची को परिभाषित करें) 'या' (my-add-to-list2 (सूची मान) को परिभाषित करें (setcdr सूची (विपक्ष (कार सूची) (सीडीआर सूची))) (सेटकार सूची मूल्य) सूची) ' – phils

+1

बिंदु यह नहीं था कि आपके पास कोई ऐसा फ़ंक्शन नहीं हो सकता है जो उस सूची में एक मूल्य जोड़ता है जो प्रतीक का मूल्य नहीं है। मुद्दा यह है कि 'ऐड-टू-लिस्ट' का बिंदु एक चर के सूची मूल्य में तत्व जोड़ना है। IOW, 'ऐड-टू-लिस्ट' है * वैरिएबल वैल्यू सेट करने के बारे में *। यह *** नहीं *** एक सूची में तत्व जोड़ने के लिए केवल एक फ़ंक्शन है (इसके नाम के बावजूद)। – Drew

+0

मुझे लगता है कि महत्वपूर्ण अंतर यह है कि * प्रतीक * को पार करके आप उस प्रतीक के मूल्य को बदलने की क्षमता प्राप्त करते हैं * अन्य प्रतीकों के मूल्यों को प्रभावित किए बिना *, जबकि यदि आप मूल्यांकन सूची को पास करते हैं, तो सभी प्रतीकों को इंगित किया जाता है सूची प्रभावित हो सकती है। – phils

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