7

के साथ लिस्प कोड को संकलित करना मुझे बाइट कोड या फ़ाइल को उस मामले के लिए एक fasl फ़ाइल में लिस्प कोड की फ़ाइल संकलित करते समय पढ़ने मैक्रोज़ के बारे में समझने में कुछ परेशानी हो रही है। या शायद मैं इसे समझता हूं लेकिन पता नहीं। मैं बस वास्तव में उलझन में हूँ।रीड मैक्रोज़

जब आप रीड मैक्रो का उपयोग करते हैं, तो क्या आपको स्रोत उपलब्ध नहीं होना चाहिए?

यदि आप करते हैं, तो आपको स्रोत कोड निष्पादित करना होगा जो पढ़ने वाले मैक्रो का कार्य करता है। यदि आप नहीं करते हैं, तो जब आप read-char जैसी सामग्री कर सकते हैं तो वे कैसे काम कर सकते हैं?

कि ऐसा करने के लिए, यदि आप पढ़ मैक्रो उपयोग aforedefined चर करना चाहते हैं, तो आप इसे से पहले सभी कोड को क्रियान्वित किया जाना है, इसलिए इस क्रम जो सब कुछ को खराब करता हो जाता है।

यदि आप इससे पहले कोड नहीं चलाते हैं, तो इसके ऊपर परिभाषित सामग्री उपलब्ध नहीं होगी।

फ़ंक्शन मैक्रोज़ को परिभाषित करने वाले फ़ंक्शंस या कंपाइलर मैक्रोज़ के बारे में क्या? मुझे लगता है कि वे तब तक काम नहीं करेंगे जब तक कि आप require या load फ़ाइल या कुछ संकलित नहीं करते हैं। लेकिन अगर वे संकलित किए गए थे, तो वे उनका उपयोग करने में सक्षम नहीं होंगे?

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

संक्षेप में, ऐसा लगता है कि एक पंक्ति को एक रूप में संकलित करने के लिए जहां इसे आगे मैक्रो प्रोसेसिंग के बिना निष्पादित किया जा सकता है या जो भी हो, आपको पिछली पंक्तियों को पढ़ना, संकलित करना और चलाने की ज़रूरत है।

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

क्षमा करें मेरी पर्यटन के लिए, लेकिन मैं लिस्प के लिए नया हूँ और अधिक पता है कि यह कैसे करना चाहते हैं काम करता है।

उत्तर

1

मैक्रोज़ (पढ़ने मैक्रोज़ सहित) कुछ भी नहीं बल्कि कार्य हैं, और इन सभी अन्य कार्यों के समान ही व्यवहार किया जाता है। फ़ंक्शन या मैक्रो संकलित होने के बाद आपको स्रोत कोड को बनाए रखने की आवश्यकता नहीं है।

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

+0

असल में, एसबीसीएल में व्याख्या मोड है, यह डिफ़ॉल्ट रूप से बंद हो गया है: http://www.sbcl.org/manual/Interpreter.html –

+0

सामान्य लिस्प संकलन वृद्धिशील है, लेकिन फ़ाइलों का संकलन थोड़ा अलग परिभाषित किया गया है। –

+0

@Rainer क्या आप विस्तृत कर सकते हैं? मैं इसके साथ परिचित नहीं हूं –

5

यह वास्तव में एक दिलचस्प सवाल है, और ऐसा कुछ है जो लिस्प प्रोग्रामर के साथ बहुत सी शुरुआत करता है। इसके मुख्य कारणों में से एक यह है कि सबकुछ ज्यादातर "अपेक्षित" काम करता है और जब आप लिस्प की अधिक उन्नत सुविधाओं का उपयोग करना शुरू करते हैं तो आप केवल इन चीजों के बारे में सोचना शुरू कर देते हैं।

कोड को ठीक तरह से संकलित करने के लिए, आपके प्रश्न का संक्षिप्त उत्तर है, हां, पिछले कुछ कोड को निष्पादित किया जाना है। कुछ शब्द ध्यान दें, यह कुंजी है। चलिए एक छोटा सा उदाहरण बनाते हैं।निम्नलिखित सामग्री के साथ एक फ़ाइल पर विचार करें:

(print 'a) 

(defmacro bar (x) `(print ,x)) 

(bar 'b) 

आप पहले से ही पता लगा है, अगर आप इस फाइल पर COMPILE-FILE चलाने के लिए, जिसके परिणामस्वरूप .fasl फ़ाइल बस निम्नलिखित कोड की संकलित संस्करण में शामिल होंगे:

(print 'a) 
(print 'b) 

"लेकिन", आप पूछ सकते हैं, "संकलन के दौरान DEFMACRO फ़ॉर्म निष्पादित क्यों किया गया था, लेकिन PRINT फ़ॉर्म नहीं था?"। उत्तर हाइपरपेक अनुभाग 3.2.3 में समझाया गया है।

आम तौर पर, शीर्ष स्तर संकलन फ़ाइल के साथ संकलित एक फ़ाइल में प्रदर्शित होने के रूपों केवल मूल्यांकन किया जाता है जब जिसके परिणामस्वरूप संकलित फ़ाइल भरी हुई है, और नहीं है जब फ़ाइल संकलित किया गया है: यह निम्नलिखित वाक्य में शामिल है। हालांकि, यह आमतौर पर है कि फ़ाइल में कुछ रूपों का मूल्यांकन समय संकलित करने के लिए किया जाना चाहिए ताकि फ़ाइल के शेष को सही ढंग से पढ़ और संकलित किया जा सके।

एक ऐसा फॉर्म है जिसका उपयोग किसी फॉर्म का मूल्यांकन करने पर ठीक से नियंत्रित करने के लिए किया जा सकता है। इस उद्देश्य के लिए आप EVAL-WHEN का उपयोग करते हैं। वास्तव में, यह बिल्कुल ठीक है कि लिस्प कंपाइलर DEFMACRO को लागू करता है। आप देख सकते हैं कि कैसे अपने लिस्प REPL से निम्न लिखकर यह लागू करता है:

(macroexpand '(defmacro bar (x) `(print ,x))) 

जाहिर है अलग लिस्प कार्यान्वयन इस अलग ढंग से लागू होगा, लेकिन कुंजी महत्वपूर्ण बात यह है कि यह एक के रूप में परिभाषा लपेटता है: (eval-when (:compile-toplevel :load-toplevel :execute) ...)। यह संकलक को बताता है कि फाइल को संकलित करते समय फॉर्म का मूल्यांकन किया जाना चाहिए, लेकिन फ़ाइल लोड होने पर भी। अगर ऐसा नहीं होता है, तो आप उसी फ़ाइल में मैक्रो का उपयोग करने में सक्षम नहीं होंगे जैसा कि इसे परिभाषित किया गया था। अगर फ़ाइल का संकलन तब किया गया था जब फ़ाइल संकलित की गई थी, तो आप इसे लोड करने के बाद एक अलग फ़ाइल में मैक्रो का उपयोग करने में सक्षम नहीं होंगे।

+2

संकलित फ़ाइल में केवल दो प्रिंट स्टेटमेंट नहीं हैं, इसमें मैक्रो परिभाषा भी शामिल है। –

+1

संकलन समय और रनटाइम पर एक कंपाइलर मैक्रो चलाना वास्तव में संकलक मैक्रोज़ के लिए अपेक्षित चीज़ों के बारे में है। हालांकि, यह मैक्रोज़ पढ़ने के पते (जो मैं देखता हूं) पता नहीं करता है। कंपाइलर मैक्रोज़ सरल कार्य होते हैं (वे वास्तविक वस्तुओं को पैरामीटर के रूप में लेते हैं ताकि सैद्धांतिक रूप से वे रनटाइम तक विस्तार में देरी कर सकें) लेकिन मैक्रोज़ पाठ पर निर्भर करते हैं। वो कैसे काम करते है? –

+0

@ सेठ कार्नेगी संकलन वृद्धिशील है। प्रत्येक रूप को संसाधित किया जाता है क्योंकि उन्हें पढ़ा जाता है (इस संदर्भ में संसाधित या तो संकलित या मूल्यांकन किया जाता है, या दोनों)। इसका मतलब है कि पहला फॉर्म पाठक व्यवहार को संशोधित कर सकता है, और फिर यह नया व्यवहार बाद के रूपों को प्रभावित करेगा जैसा कि उन्हें पढ़ा जाता है। –

4

फ़ाइलों का संकलन कॉमन लिस्प में परिभाषित किया गया है: संकलन CLHS Section 3.2.3 File Compilation

जबकि: पढ़ने मैक्रो का उपयोग एक रूप का इस्तेमाल करते हैं, तो आप उस मैक्रो कार्यान्वयन संकलक के लिए उपलब्ध पढ़ा करना है।

आमतौर पर ऐसी निर्भरताओं को defsystem सुविधा के साथ संभाला जाता है, जहां सिस्टम की विभिन्न फाइलों (किसी प्रोजेक्ट की तरह कुछ) के बीच निर्भरता का वर्णन किया जाता है। किसी निश्चित फ़ाइल को संकलित करने के लिए, एक और फ़ाइल (अधिमानतः संकलित संस्करण) को संकलित लिस्प में लोड किया जाना चाहिए।

अब, अगर आप पढ़ने मैक्रो निर्धारित करना चाहते हैं और है एक ही फाइल में अपनी अंकन का उपयोग रूपों, तो आप फिर से यकीन है कि संकलक के बारे में पढ़ा स्थूल और इसके कार्यान्वयन जानता है बनाने की जरूरत है। फ़ाइल कंपाइलर में संकलन पर्यावरण है। यह डिफ़ॉल्ट रूप से इस वातावरण में एक ही फ़ाइल के संकलित कार्यों को लोड नहीं करता है।

संकलक को फ़ाइल में कुछ कोड के बारे में जागरूक बनाने के लिए यह सामान्य लिस्प को संकलित करता है EVAL-WHEN। एक पढ़ा मैक्रो उदाहरण पर

आइए नज़र:

(set-syntax-from-char #\] #\)) 

(defun reader-example (stream char) 
    (declare (ignore char)) 
    (let ((class (read stream t nil t)) 
     (args (read-delimited-list #\] stream t))) 
    (apply #'make-instance 
      class 
      args))) 

(set-macro-character #\[ 'reader-example) 

(defclass example() 
    ((name :initarg :name))) 

(defvar *examples* 
    (list [example :name e1] 
     [example :name e2] 
     [example :name e3])) 

आप ऊपर स्रोत लोड करते हैं, तो सब कुछ ठीक है। लेकिन अगर हम एक फाइल कंपाइलर का उपयोग करते हैं तो यह पहले लोड किए बिना संकलित नहीं होता है। उदाहरण के लिए फ़ाइल कंपाइलर को पथनाम के साथ फ़ंक्शन COMPILE-FILE पर कॉल करके बुलाया जाता है।

(set-syntax-from-char #\] #\)) 

ऊपर संकलन समय पर निष्पादित नहीं किया जाएगा:

अब फ़ाइल संकलन। नया वाक्यविन्यास परिवर्तन संकलन समय पर उपलब्ध नहीं होगा।

(defun reader-example (stream char) 
    (declare (ignore char)) 
    (let ((class (read stream t nil t)) 
     (args (read-delimited-list #\] stream t))) 
    (apply #'make-instance 
      class 
      args))) 

उपरोक्त फ़ंक्शन संकलित हो जाता है, लेकिन लोड नहीं होता है। यह कार्यान्वयन बाद के चरणों में संकलक के लिए उपलब्ध नहीं है।

(set-macro-character #\[ 'reader-example) 

फिर, उपरोक्त फॉर्म निष्पादित नहीं किया गया है - इसके लिए कोड उत्पन्न होता है।

(defclass example() 
    ((name :initarg :name))) 

कंपाइलर कक्षा को नोट करता है, लेकिन बाद में इसके उदाहरण नहीं बना सकता है।

(defvar *examples* 
    (list [example :name e1] 
     [example :name e2] 
     [example :name e3])) 

कोड से ऊपर एक त्रुटि से चलाता है, के बाद से पढ़ने के लिए मैक्रो संकलन समय पर उपलब्ध नहीं है - जब तक यह पहले लोड किया गया है।

  • एक अलग फाइल में पढ़ने मैक्रो के क्रियान्वयन रख दिया और यकीन है कि यह संकलित और जो पढ़ा मैक्रो का उपयोग करता है किसी भी फ़ाइल से पहले भरी हुई है बनाने:

    अब दो आसान समाधान कर रहे हैं।

  • कोड जो संकलन समय पर प्रभाव की जरूरत है चारों ओर एक EVAL-WHEN डाल:

उदाहरण:

(EVAL-WHEN (:compile-toplevel :load-toplevel :execute) 
    (do-something-also-at-compile-time)) 

ऊपर संकलक द्वारा देखा जाएगा और यह भी तो मार डाला। अब आपको यह सुनिश्चित करना होगा कि कोड में संकलन समय पर वह सब कुछ है (सभी आवश्यक परिभाषाएं)।

कहने की जरूरत नहीं है: जितनी ज्यादा हो सके संकलन निर्भरताओं को कम करने के लिए यह अच्छी शैली है। आमतौर पर आवश्यक कार्यक्षमता को एक अलग फ़ाइल में रखें और सुनिश्चित करें कि यह फ़ाइल संकलित हो जाती है और संकलन लिस्पी में लोड हो जाती है इससे पहले कि आप इसका उपयोग करने वाली फ़ाइल संकलित करें।