2013-03-16 11 views
5

योजना को बेहतर ढंग से समझने के लिए, मैं अजगर में एक छोटी योजना जैसी भाषा लिखने की कोशिश कर रहा हूं।योजना में वाक्यविन्यास वस्तुओं का उद्देश्य क्या है?

समस्या यह है कि मैं वाक्य रचना वस्तुओं पर अटक कर रहा हूँ। मैं उन्हें लागू नहीं कर सकता क्योंकि मैं वास्तव में समझ में नहीं आता कि वे क्या हैं और वे कैसे काम करते हैं।

उन्हें समझने की कोशिश करने के लिए, मैं DrRacket में वाक्य रचना की वस्तुओं के साथ एक सा आसपास निभाई।

मैं क्या लगता है कर लिया है से, #'(+ 2 3) का मूल्यांकन, '(+ 2 3) के मूल्यांकन से अलग नहीं है मामला है कि वहाँ एक शाब्दिक + चर शीर्ष स्तर के नाम स्थान में एक पीछा में छोड़कर, जिसमें मामले (eval '(+ 2 3)) अभी भी रिटर्न 5, लेकिन (eval #'(+ 2 3)) बस एक त्रुटि फेंकता है।

उदाहरण के लिए:

(define (top-sym) 
    '(+ 2 3)) 
(define (top-stx) 
    #'(+ 2 3)) 
(define (shadow-sym) 
    (define + *) 
    '(+ 2 3)) 
(define (shadow-stx) 
    (define + *) 
    #'(+ 2 3)) 

(eval (top-sym)), (eval (top-stx)), और (eval (shadow-sym)) सभी 5, (eval (shadow-stx)) एक त्रुटि फेंकता है, जबकि वापसी। उनमें से कोई भी उनमें से 6 लौटाता है।

अगर मुझे बेहतर नहीं पता था, तो मुझे लगता है कि सिंटैक्स ऑब्जेक्ट्स के बारे में विशेष बात यह है कि (एक छोटी सी तथ्य से कि वे बेहतर त्रुटि रिपोर्टिंग के लिए कोड का स्थान संग्रहीत करते हैं) यह है कि वे एक त्रुटि फेंकते हैं कुछ परिस्थितियों जहां उनके प्रतीक समकक्षों ने संभावित रूप से अवांछित मूल्य वापस कर दिया होगा।

तो कहानी है कि सरल थे, वहाँ नियमित सूचियों और प्रतीकों से अधिक वाक्य रचना वस्तुओं का उपयोग करने के लिए कोई वास्तविक लाभ होगा।

तो मेरे सवाल है: उन्हें ऐसी क्या खास बात है कि मैं वाक्य रचना वस्तुओं के बारे में क्या याद आ रही है?

+0

क्या आपने देखा है: http://docs.racket-lang.org/reference/syntax-model.html#%28part._stxobj-model%29 अभी तक? – dyoo

+0

@dyoo मैंने कई बार पढ़ा है और यही कारण है कि मुझे लगता है कि मैं उन्हें समझ गया, जब तक मैंने उपर्युक्त परीक्षणों की कोशिश नहीं की। उस पृष्ठ से, मैंने सोचा होगा कि '(eval (छाया-stx)) '''' वापस आना चाहिए। – Matt

+2

बस स्पष्ट करने के लिए, जब आप सिंटैक्स ऑब्जेक्ट्स के बारे में पूछते हैं, तो यह वास्तव में एक विशिष्ट रैकेट चीज है: यह सामान्य रूप से एक योजना की बात नहीं है। सिंटैक्स ऑब्जेक्ट एक डेटा प्रकार है जो रैकेट के भाषा आधारभूत संरचना के केंद्र में है। – dyoo

उत्तर

11

सिंटेक्स वस्तुओं अंतर्निहित रैकेट संकलक के लिए शाब्दिक संदर्भ के लिए भंडार हैं।

#lang racket/base 
(* 3 4) 

संकलक एक वाक्य रचना उद्देश्य यह है कि कार्यक्रम की संपूर्ण सामग्री का प्रतिनिधित्व प्राप्त करता है: वस्तुतः, जब हम कार्यक्रम की तरह दर्ज करें।

#lang racket/base 

(define example-program 
    (open-input-string 
    " 
    #lang racket/base 
    (* 3 4) 
    ")) 

(read-accept-reader #t) 
(define thingy (read-syntax 'the-test-program example-program)) 
(print thingy) (newline) 
(syntax? thingy) 

नोट कार्यक्रम में *thingy के भीतर एक वाक्य रचना वस्तु के रूप में एक संकलन समय प्रतिनिधित्व किया है कि: यहाँ हम देखते हैं कि वाक्य रचना वस्तु की तरह दिखता है क्या यह बताने के लिए एक उदाहरण है। यह अभी तक कोई बाध्यकारी जानकारी है: और पल में, thingy में * पता नहीं कहाँ से आता है। संकलन के दौरान विस्तार की प्रक्रिया के दौरान यह है कि संकलक *#lang racket/base के * के संदर्भ के रूप में * को संबद्ध करता है।

यदि हम संकलन समय पर चीजों के साथ बातचीत करते हैं तो हम इसे और अधिक आसानी से देख सकते हैं। (नोट: मैं जानबूझकर eval के बारे में बात करने से परहेज कर रहा हूं क्योंकि मैं संकलन-समय बनाम रन-टाइम के दौरान क्या होता है, इस बारे में चर्चा को मिश्रित करना चाहता हूं।

#lang racket/base 
(require (for-syntax racket/base)) 

;; This macro is only meant to let us see what the compiler is dealing with 
;; at compile time. 

(define-syntax (at-compile-time stx) 
    (syntax-case stx() 
    [(_ expr) 
    (let() 
     (define the-expr #'expr) 
     (printf "I see the expression is: ~s\n" the-expr) 

     ;; Ultimately, as a macro, we must return back a rewrite of 
     ;; the input. Let's just return the expr: 
     the-expr)])) 


(at-compile-time (* 3 4)) 

हम यहाँ एक मैक्रो, at-compile-time इस्तेमाल करेंगे, हमें संकलन के दौरान चीजों की राज्य निरीक्षण जाने के लिए:)

यहाँ हमें क्या इन वाक्यविन्यास वस्तुओं कर के और अधिक का निरीक्षण करने देने के लिए एक उदाहरण है। यदि आप इस कार्यक्रम को ड्रैकेट में चलाते हैं, तो आप देखेंगे कि ड्रैकेट पहले प्रोग्राम को संकलित करता है, और फिर इसे चलाता है। चूंकि यह प्रोग्राम संकलित करता है, जब यह at-compile-time के उपयोग को देखता है, तो संकलक हमारे मैक्रो का आह्वान करेगा।

तो संकलन समय में, हम जैसे कुछ दिखाई देगा:

I see the expression is: #<syntax:20:17 (* 3 4)> 

कार्यक्रम एक छोटा सा संशोधन करते हैं, और अगर हम पहचानकर्ता के identifier-binding निरीक्षण कर सकते हैं देखें:

#lang racket/base 
(require (for-syntax racket/base)) 

(define-syntax (at-compile-time stx) 
    (syntax-case stx() 
    [(_ expr) 
    (let() 
     (define the-expr #'expr) 
     (printf "I see the expression is: ~s\n" the-expr) 
     (when (identifier? the-expr) 
     (printf "The identifier binding is: ~s\n" (identifier-binding the-expr))) 

     the-expr)])) 


((at-compile-time *) 3 4) 

(let ([* +]) 
    ((at-compile-time *) 3 4)) 

I see the expression is: #<syntax:21:18 *> 
The identifier binding is: (#<module-path-index> * #<module-path-index> * 0 0 0) 
I see the expression is: #<syntax:24:20 *> 
The identifier binding is: lexical 
12 
7 

: हम DrRacket में इस कार्यक्रम चलाते हैं, तो हम निम्न उत्पादन देखेंगे (वैसे: हम आउटपुट को at-compile-time से आगे क्यों देखते हैं? क्योंकि संकलन रनटाइम से पहले पूरी तरह से किया जाता है! कार्यक्रम अगर हम पहले से संकलन और raco make का उपयोग करके बाईटकोड बचाने के लिए, हम नहीं देखना होगा संकलक लागू किया जा रहा है जब हम कार्यक्रम चलाते हैं।)

समय संकलक at-compile-time का उपयोग करता है तक पहुँच जाता है से, यह करने के लिए जानता है उपयुक्त व्याख्यात्मक बाध्यकारी जानकारी पहचानकर्ताओं को संबद्ध करें। जब हम पहली मामले में identifier-binding का निरीक्षण किया, संकलक जानता है कि यह एक विशेष मॉड्यूल (इस मामले में, #lang racket/base, जो कि module-path-index व्यापार के बारे में है) से संबद्ध है,। लेकिन दूसरे मामले में, यह जानता है कि यह लेक्सिकल बाध्यकारी है: संकलक पहले से ही (let ([* +]) ...) के माध्यम से चला गया है, और इसलिए यह जानता है कि * का उपयोग let द्वारा बाध्यकारी सेट पर वापस देखें।

रैकेट संकलक वाक्य रचना वस्तुओं का उपयोग करता है बंधन अपने मैक्रो के रूप में ग्राहकों को जानकारी, उस तरह का संवाद करने के लिए। वाक्य रचना वस्तुओं में बाध्यकारी जानकारी, प्रासंगिक नहीं हो सकता है क्योंकि समय से हम वाक्य रचना वस्तुओं का मूल्यांकन, उनके बाइंडिंग बातों का उल्लेख हो सकता है:


eval उपयोग करने के लिए निरीक्षण करने के लिए सामान की इस तरह के मुद्दों से भरा है की कोशिश कर रहा वह अस्तित्व में नहीं है! यह मौलिक कारण है कि आप अपने प्रयोगों में त्रुटियों को देख रहे थे।

फिर भी, यहां एक उदाहरण है कि एस भाव और वाक्य रचना वस्तुओं के बीच अंतर पता चलता है:

#lang racket/base 

(module mod1 racket/base 
    (provide x) 
    (define x #'(* 3 4))) 

(module mod2 racket/base 
    (define * +) ;; Override! 
    (provide x) 
    (define x #'(* 3 4))) 

;;;;;;;;;;;;;;;;;;;;;;;;;;; 

(require (prefix-in m1: (submod "." mod1)) 
     (prefix-in m2: (submod "." mod2))) 

(displayln m1:x) 
(displayln (syntax->datum m1:x)) 
(eval m1:x) 

(displayln m2:x) 
(displayln (syntax->datum m2:x)) 
(eval m2:x) 

इस उदाहरण को ध्यान से इतना है कि वाक्य रचना वस्तुओं की सामग्री केवल करने के लिए मॉड्यूल बाध्य बातों का उल्लेख निर्माण किया है, जो उस समय मौजूद होगा जब हम eval का उपयोग करेंगे। हम उदाहरण थोड़ा परिवर्तन हो, तो

(module broken-mod2 racket/base 
    (provide x) 
    (define x 
    (let ([* +]) 
     #'(* 3 4)))) 

तो चीजें बुरी तरह तोड़ जब हम evalx कि broken-mod2 से बाहर आता है करने के लिए प्रयास करते हैं, के बाद से वाक्य रचना वस्तु एक शाब्दिक बाध्यकारी है कि द्वारा अस्तित्व में नहीं है बात कर रहा है समय हम evaleval एक कठिन जानवर है।

+0

वैसे, मैथ्यू फ्लैट विशेष रूप से क्लोजर/वेस्ट 2013 में इस विषय के बारे में एक बात करेंगे। उनकी बात http://clojurewest.org/sessions#flatt में बहुत अधिक उदाहरण होंगे जिन्हें स्पष्टीकरण में मदद करनी चाहिए। – dyoo

+0

धन्यवाद! क्या बात ऑनलाइन देखने योग्य होगी? – Matt

+0

@ मैट: मुझे विश्वास है, लेकिन मुझे बिल्कुल यकीन नहीं है। क्लोजर/वेस्ट 2012 में InfoQ http://clojurewest.org/news/2012/5/11/clojurewest-video-schedule.html द्वारा होस्ट किया गया एक वीडियो संग्रह है, इसलिए मुझे उम्मीद है कि वे इस वर्ष भी वही करेंगे। – dyoo

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