2010-04-01 19 views
29

के लिए उपयोग किए जा सकते हैं उदाहरण के लिए मैंने सुना है कि लिस्प की मैक्रो प्रणाली बहुत शक्तिशाली है। हालांकि, मुझे कुछ व्यावहारिक उदाहरणों को ढूंढना मुश्किल लगता है जिनके लिए उनका उपयोग किया जा सकता है; चीजें जो उनके बिना हासिल करना मुश्किल होगा।लिस्प के मैक्रोज़ के उदाहरण

क्या कोई कुछ उदाहरण दे सकता है?

उत्तर

2

बस एक अनुमान - डोमेन विशिष्ट भाषाएं।

+0

इस प्रश्न में सीडब्लू महसूस होता है इसलिए मैंने इस तरह पोस्ट किया। –

+1

लेकिन मैक्रोज़ के बारे में क्या है जो उन्हें सामान्य कार्यों पर डोमेन-विशिष्ट भाषाओं को लिखने के लिए बेहतर बनाता है? –

+1

जेट्स: आपको एक के लिए सबकुछ के मूल्यांकन में देरी करने के लिए बहुत सारी उद्धरण (स्वीकार्य रूप से संबंधित सुविधा) की आवश्यकता होगी। मैक्रोज़ आपको संकलन-समय पर मनमाने ढंग से चीजें करने के लिए, इससे बचने देते हैं। – Ken

3

मैक्रोज़ के साथ आप अपना स्वयं का वाक्यविन्यास परिभाषित कर सकते हैं, इस प्रकार आप लिस्प को बढ़ा सकते हैं और इसे
आपके द्वारा लिखे गए प्रोग्राम के लिए उपयुक्त बनाते हैं।

व्यावहारिक उदाहरणों के लिए, बहुत अच्छी, ऑनलाइन पुस्तक Practical Common Lisp देखें।

7. Macros: Standard Control Constructs
8. Macros: Defining Your Own

8

किसी भी "code generation tool" उठाओ। उनके उदाहरण पढ़ें। यही वह कर सकता है।

सिवाय इसके कि आपको एक अलग प्रोग्रामिंग भाषा का उपयोग करने की आवश्यकता नहीं है, मैक्रो का विस्तार कोड जहां मैक्रो का उपयोग किया जाता है, बनाने के लिए एक अलग कमांड चलाएं, या अपनी हार्ड डिस्क पर बैठे अतिरिक्त टेक्स्ट फाइलें हों आपके कंपाइलर के लिए मूल्य।

उदाहरण के लिए, मुझे लगता है कि Cog पढ़ने का मानना ​​है कि कोई भी लिस्प प्रोग्रामर रोने के लिए पर्याप्त होना चाहिए।

37

स्रोत कोड परिवर्तन। सभी प्रकार। उदाहरण:

  • नई नियंत्रण बयान: आप थोड़ी देर के बयान की ज़रूरत है? आपकी भाषा में कोई नहीं है? उदार तानाशाह के लिए अगले वर्ष एक शायद जोड़ने का इंतजार क्यों करें। इसे स्वयं लिखें। पाँच मिनट में।

  • छोटा कोड: आपको बीस वर्ग की घोषणाओं की आवश्यकता है जो लगभग समान दिखती हैं - केवल सीमित मात्रा में स्थान अलग हैं। एक मैक्रो फॉर्म लिखें जो अंतर को पैरामीटर के रूप में लेता है और आपके लिए स्रोत कोड उत्पन्न करता है। बाद में इसे बदलना चाहते हैं? एक जगह में मैक्रो बदलें।

  • स्रोत पेड़ में प्रतिस्थापन: आप स्रोत पेड़ में कोड जोड़ना चाहते हैं? एक चर वास्तव में एक समारोह कॉल होना चाहिए? कोड के चारों ओर एक मैक्रो लपेटें जो स्रोत को 'चलता है' और उन स्थानों को बदलता है जहां यह चर पाता है।

  • पोस्टफिक्स सिंटैक्स: आप अपना कोड पोस्टफिक्स फ़ॉर्म में लिखना चाहते हैं? एक मैक्रो का उपयोग करें जो सामान्य रूप से कोड को फिर से लिखता है (लिस्प में उपसर्ग)।

  • संकलन-समय प्रभाव: परिभाषाओं के बारे में विकास पर्यावरण को सूचित करने के लिए आपको कंपाइलर वातावरण में कुछ कोड चलाने की आवश्यकता है? मैक्रोज़ कोड उत्पन्न कर सकता है जो संकलन समय पर चलता है।

  • संकलन समय पर कोड सरलीकरण/अनुकूलन: आप संकलन समय पर कुछ कोड को सरल बनाना चाहते हैं? एक मैक्रो का उपयोग करें जो सरलीकरण करता है - इस तरह आप स्रोत फ़ॉर्म के आधार पर समय संकलित करने के लिए रनटाइम से काम को स्थानांतरित कर सकते हैं।

  • विवरण/कॉन्फ़िगरेशन से कोड जनरेशन: आपको कक्षाओं का एक जटिल मिश्रण लिखना होगा। उदाहरण के लिए आपकी खिड़की में एक वर्ग है, उपपृष्ठों में कक्षाएं हैं, पैन के बीच स्पेस बाधाएं हैं, आपके पास कमांड लूप, मेनू और अन्य चीजों का पूरा समूह है। एक मैक्रो लिखें जो आपकी खिड़की और उसके घटकों के वर्णन को कैप्चर करता है और विवरण से - कक्षाओं और आदेशों को चलाने के लिए बनाता है।

  • सिंटेक्स सुधार: कुछ भाषा वाक्यविन्यास बहुत सुविधाजनक नहीं दिखता है? एक मैक्रो लिखें जो आपके लिए एप्लिकेशन लेखक के लिए अधिक सुविधाजनक बनाता है।

  • डोमेन विशिष्ट भाषाएं: आपको एक ऐसी भाषा की आवश्यकता है जो आपके आवेदन के डोमेन के नजदीक है? मैक्रोज़ के समूह के साथ आवश्यक भाषा रूप बनाएं।

मेटा-भाषाई अमूर्त

मूल विचार: सब कुछ भाषाई स्तर पर है कि (नए रूपों, नई वाक्य रचना, प्रपत्र परिवर्तनों, सरलीकरण, आईडीई समर्थन, ...) अब हो सकता है टुकड़ा द्वारा डेवलपर टुकड़े द्वारा प्रोग्राम किया गया - कोई अलग मैक्रो प्रसंस्करण चरण नहीं।

+0

मैक्रोज़ का उपयोग करने के कारणों की अद्भुत सूची। हमेशा अपने उत्तरों को पढ़ने में खुशी। धन्यवाद। – gsl

2

भाषा के सिंटैक्स को विस्तारित करने के अलावा आप स्वयं को अधिक स्पष्ट रूप से व्यक्त करने की अनुमति देते हैं, यह आपको मूल्यांकन पर नियंत्रण भी देता है। अपनी पसंद की भाषा में अपना खुद का if लिखने का प्रयास करें ताकि आप वास्तव में my_if something my_then print "success" my_else print "failure" लिख सकें और दोनों प्रिंट स्टेटमेंट का मूल्यांकन न हो। पर्याप्त शक्तिशाली मैक्रो सिस्टम के बिना किसी सख्त भाषा में, यह असंभव है। हालांकि, कोई आम लिस्प प्रोग्रामर कार्य को चुनौतीपूर्ण नहीं पाएगा, हालांकि। डिट्टो for -loops, foreach छोरों, आदि के लिए आप सी में इन बातों को व्यक्त नहीं कर सकते, क्योंकि वे विशेष मूल्यांकन अर्थ विज्ञान की आवश्यकता होती है (लोगों को वास्तव में ऑब्जेक्टिव-सी में foreach शुरू करने की कोशिश की, लेकिन यह अच्छी तरह से काम नहीं किया है), लेकिन वे कर रहे हैं इसके मैक्रोज़ के कारण आम लिस्प में लगभग तुच्छ।

3

R, मानक सांख्यिकी प्रोग्रामिंग भाषा में मैक्रोज़ (R manual, chapter 6) है। आप फंक्शन lm() को कार्यान्वित करने के लिए इसका उपयोग कर सकते हैं, जो आपके द्वारा कोड के रूप में निर्दिष्ट मॉडल के आधार पर डेटा का विश्लेषण करता है।

यहां बताया गया है कि यह कैसे काम करता है: lm(Y ~ aX + b, data)a और b पैरामीटर ढूंढने का प्रयास करेगा जो आपके डेटा को सर्वोत्तम रूप से फिट करते हैं। अच्छा हिस्सा यह है कि आप aX + b के लिए किसी भी रैखिक समीकरण को प्रतिस्थापित कर सकते हैं और यह अभी भी काम करेगा। आंकड़े गणना को आसान बनाने के लिए यह एक शानदार विशेषता है, और यह केवल इतना सुंदर काम करता है क्योंकि lm() समीकरण का विश्लेषण कर सकता है, जो वास्तव में लिस्प मैक्रोज़ करता है।

4

कुछ भी जो आप आमतौर पर प्री-प्रोसेसर में करना चाहते थे?

एक मैक्रो मैंने लिखा, खेल वस्तुओं ड्राइविंग के लिए राज्य मशीनों को परिभाषित करने के लिए है।

(progn 
(defclass ray-ai (ai) nil (:default-initargs :current 'ground)) 
(defmethod gen-act ((ai ray-ai) (state (eql 'ground))) 
      (macrolet ((transit (state) 
         (list 'setf (list 'current 'ai) (list 'quote state)))) 
       (flet ((object() 
         (object ai))) 
       (let* ((o (object)) (r (range o))) 
        (loop for p in *players* 
         if (line-of-sight-p o p r) 
         do (progn (setf (target o) p) (transit seek))))))) 
    (defmethod gen-act ((ai ray-ai) (state (eql 'seek))) 
      (macrolet ((transit (state) 
         (list 'setf (list 'current 'ai) (list 'quote state)))) 
       (flet ((object() 
         (object ai))) 
       (let* ((o (object)) 
         (target (target o)) 
         (r (range o)) 
         (losp (line-of-sight-p o target r))) 
        (when losp 
        (let ((dir (find-direction o target))) 
         (setf (movement o) (object-speed o dir)))) 
        (unless losp (transit ground))))))) 

एक में पूरे राज्य मशीन पीढ़ी द्वारा encapsulating:

(def-ai ray-ai 
    (ground 
    (let* ((o (object)) 
      (r (range o))) 
    (loop for p in *players* 
      if (line-of-sight-p o p r) 
      do (progn 
       (setf (target o) p) 
       (transit seek))))) 
    (seek 
    (let* ((o (object)) 
      (target (target o)) 
      (r (range o)) 
      (losp (line-of-sight-p o target r))) 
    (when losp 
     (let ((dir (find-direction o target))) 
     (setf (movement o) (object-speed o dir)))) 
    (unless losp 
     (transit ground))))) 

से इसे पढ़ने के लिए है: यह (मैक्रो का उपयोग) की तुलना में यह है उत्पन्न कोड को पढ़ने के लिए कोड को पढ़ने के लिए आसान है मैक्रो, मैं यह भी सुनिश्चित कर सकता हूं कि मैं केवल परिभाषित राज्यों का संदर्भ लेता हूं और चेतावनी देता हूं कि यह मामला नहीं है।

+8

कूपल्ड आप थोड़ा अधिक विशिष्ट क्यों हैं कि यह "अच्छा कोड नहीं" क्यों है? मैं अपने कोड की आलोचना करने से खुश हूं, लेकिन "अच्छा नहीं है" की तुलना में थोड़ा अधिक रचनात्मक कुछ सराहना की जाएगी। मुझे यकीन है कि अगर आपका टिप्पणी बॉक्स बहुत छोटा है तो मेरा ईमेल पता है। – Vatine

1

मैक्रोज़ भाषा सुविधाओं तक पहुंच प्रदान करने में आवश्यक हैं। उदाहरण के लिए, TXR Lisp में, मेरे पास एक सीमित फ़ंक्शन कैप्चर करने के लिए sys:capture-cont नामक एक एकल फ़ंक्शन है। लेकिन यह स्वयं ही उपयोग करने के लिए अजीब है। तो इसके आसपास मैक्रोज़ लपेटे गए हैं, जैसे suspend, या obtain and yield जो पुन: प्रारंभ करने योग्य, निलंबित निष्पादन के लिए वैकल्पिक मॉडल प्रदान करते हैं। उन्हें here लागू किया गया है।

एक और उदाहरण जटिल मैक्रो defstruct है जो संरचना प्रकार को परिभाषित करने के लिए वाक्यविन्यास प्रदान करता है। यह lambda -s और अन्य सामग्री जो make-struct-type फ़ंक्शन को पास किया गया है, में इसके तर्कों को संकलित करता है। कार्यक्रमों OOP संरचनाओं को परिभाषित करने के लिए सीधे make-struct-type उपयोग किया है, वे बदसूरत होगा:

1> (macroexpand '(defstruct foo bar x y (z 9) (:init (self) (setf self.x 42)))) 
(sys:make-struct-type 'foo 'bar '() 
         '(x y z)() 
         (lambda (#:g0101) 
         (let ((#:g0102 (struct-type #:g0101))) 
          (unless (static-slot-p #:g0102 'z) 
          (slotset #:g0101 'z 
            9))) 
         (let ((self #:g0101)) 
          (setf (qref self x) 
          42))) 
        ()) 

ओह! उस पर बहुत कुछ चल रहा है। उदाहरण के लिए, हम 9 को स्लॉट z में स्लॉट नहीं करते हैं क्योंकि (विरासत के कारण) हम वास्तव में व्युत्पन्न संरचना की मूल संरचना हो सकते हैं, और व्युत्पन्न संरचना में, z एक स्थैतिक स्लॉट (उदाहरणों द्वारा साझा किया जा सकता है) हो सकता है। हम व्युत्पन्न कक्षा में z के लिए निर्धारित मूल्य को क्लॉबरिंग करेंगे।

एएनएसआई कॉमन लिस्प में, मैक्रो का एक अच्छा उदाहरण loop है, जो समांतर पुनरावृत्ति के लिए एक संपूर्ण उप-भाषा प्रदान करता है। एक एकल loop आमंत्रण एक संपूर्ण जटिल एल्गोरिदम व्यक्त कर सकता है।

मैक्रोज़ हमें सिंटैक्स के बारे में स्वतंत्र रूप से सोचने देते हैं जो हम एक भाषा सुविधा में चाहते हैं, और अंतर्निहित कार्यों या इसे लागू करने के लिए आवश्यक विशेष ऑपरेटरों को। इन दोनों में जो भी विकल्प हम करते हैं, मैक्रोज़ उन्हें हमारे लिए पुल करेंगे। मुझे चिंता करने की ज़रूरत नहीं है कि make-struct उपयोग करने के लिए बदसूरत है, इसलिए मैं तकनीकी पहलुओं पर ध्यान केंद्रित कर सकता हूं; मुझे पता है कि मैक्रो अलग-अलग व्यापार-बंद कैसे बना सकता है इस पर ध्यान दिए बिना। मैंने डिजाइन निर्णय लिया कि सभी संरचना प्रारंभिक प्रकार को पंजीकृत कुछ कार्यों द्वारा किया जा रहा है। ठीक है, इसका मतलब है कि मेरे मैक्रो को स्लॉट-डिफ़ाइनिंग सिंटैक्स में सभी प्रारंभिकताओं को लेना है, और अज्ञात कार्यों को संकलित करना है, जहां स्लॉट प्रारंभिक निकायों को निकायों में उत्पन्न कोड द्वारा किया जाता है।

मैक्रोज़ सिंटैक्स के बिट्स के लिए कंपाइलर हैं, जिसके लिए फ़ंक्शंस और विशेष ऑपरेटर लक्ष्य भाषा हैं।

कभी-कभी लोग (गैर-लिस्प लोग, आमतौर पर) इस तरह से मैक्रोज़ की आलोचना करते हैं: मैक्रोज़ कोई क्षमता नहीं जोड़ता है, केवल सिंटैक्टिक चीनी।

सबसे पहले, सिंटेक्टिक चीनी एक क्षमता है।

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

यदि आपके पास sys:capture-cont नहीं है, तो आप suspend मैक्रो के साथ अपने व्यवहार को केवल हैक नहीं कर सकते हैं। लेकिन अगर आपके पास मैक्रोज़ नहीं है, तो आपको को एक नई सुविधा के लिए पहुंचने के लिए बहुत ही असुविधाजनक करना है जो लाइब्रेरी फ़ंक्शन नहीं है, अर्थात् कुछ नए वाक्यांश संरचना नियमों को एक पार्सर में हार्ड-कोडिंग करना मुश्किल है।

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