2010-07-06 14 views
11

सब, मैं क्लोजर भाषा पर एक नज़र डालना शुरू कर रहा हूं, और कुछ ऐसा करने के बारे में कुछ प्रश्न हैं जो मैं करने की कोशिश कर रहा हूं। व्यापक उद्देश्य अनुक्रम फ़ंक्शन every? से all? को उपनाम करना है। मुझे यकीन है कि एक फ़ंक्शन या मैक्रो है जो उपनाम (या उन पंक्तियों के साथ कुछ) करता है लेकिन मैं देखना चाहता था कि कुछ बुनियादी संरचनाओं के साथ यह संभव था कि मैं अब तक जानता हूं। मेरा दृष्टिकोण all? नामक एक फ़ंक्शन को परिभाषित करने वाला था जो every? कार्यान्वयन के लिए अपने तर्क लागू करता है।क्लोजर मेटाप्रोग्रामिंग प्रश्न (शुरुआत के लिए!)

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

1) कीवर्ड के साथ नामित कार्यों को परिभाषित करने से त्रुटियां फेंकता है। जाहिर है यह clojure.lang.IObj चाहता है।

user=> (defn :foo "bar")  
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to clojure.lang.IObj (NO_SOURCE_FILE:0) 

वहाँ एक IObj, या अन्य साधनों के लिए एक खोजशब्द कास्ट करने के लिए कुछ प्रदान किया गया मान के साथ एक नव परिभाषित समारोह के नाम पर parameterize करने के लिए एक समारोह है? (रूबी में, define_method अन्य तकनीकों के साथ यह करता है)

irb(main)> self.class.instance_eval do 
irb(main)* define_method(:foo) { "bar" } 
irb(main)> end 
=> #<Proc> 
irb(main)> foo 
=> "bar" 

2) एक समारोह में सभी तर्कों को एक चर में एकत्रित करें। यहां तक ​​कि (+ 1 2 3 4) जैसे बुनियादी कार्य भी तर्कों की एक परिवर्तनीय मात्रा लेते हैं। फ़ंक्शन बॉडी में हैंडलिंग के लिए सूची में सबकुछ एकत्र करने के लिए कोई भी तरीका नहीं है, मैंने अब तक की सभी फ़ंक्शन परिभाषा तकनीकों को तर्क दिया है। एक बार फिर, मैं क्या कर रहा हूं रूबी में ऐसा किया जाता है:

irb(main)> def foo(*args) 
irb(main)> p args 
irb(main)> end 
=> nil 
irb(main)> foo(1, 2, 3) 
[1, 2, 3] 
=> nil 

किसी भी मदद के लिए धन्यवाद जो आप मुझे प्रदान कर सकते हैं!

उत्तर

17

मैं, बुलेट बिंदुओं में जवाब देंगे के बाद से सवाल अलग मुद्दों में बड़े करीने से विभाजित किया जा सकता है देखते हैं।

  • कुछ जो परोक्ष क्या पालन करने के लिए है में निहित है, लेकिन जो शायद अपने आप में एक गोली समर्थन करती: शीर्ष-स्तरीय वस्तुओं def & कं द्वारा बनाई गई (और विशेष रूप से defn द्वारा) Vars हैं। तो आप वास्तव में क्या करना चाहते हैं Var; कार्य केवल नियमित मूल्य होते हैं जिनके पास वास्तव में नाम नहीं होते हैं (सिवाय इसके कि उनके नाम उनके शरीर के भीतर स्थानीय रूप से बाध्य हो सकते हैं; हालांकि, इस मुद्दे को हाथ से करने के लिए कुछ भी नहीं है)।

  • वहाँ वास्तव में एक "aliasing मैक्रो" उपलब्ध Clojure में - clojure.contrib.def/defalias:

    (use '[clojure.contrib.def :only [defalias]]) 
    (defalias foo bar) 
    ; => foo can now be used in place of bar 
    

    (def foo bar) पर इस का लाभ यह है कि यह मेटाडाटा से अधिक (जैसे docstring के रूप में) प्रतियां; यह वर्तमान सिर में मैक्रोज़ के साथ भी काम करता प्रतीत होता है, हालांकि मुझे एक बग याद है जो पिछले संस्करणों में इसे रोकता था।

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

    (defn foo [...] ...) 
    
  • defn लिखना चाहिए के निर्माण को कम एक सहायक मैक्रो है नई समारोह होल्डिंग प्रोग्रामर def & fn वाक्य रचना के मिश्रण का इस्तेमाल करने की अनुमति देकर Vars। इसलिए defn उपनाम बनाने के लिए आवश्यक पूर्ववर्ती मानों (जो कार्य हो सकता है) के साथ वर्र्स बनाने के लिए प्रश्न से बाहर है; defalias या इसके बजाय बस def का उपयोग करें।

  • निम्न सिंटैक्स एक variadic समारोह बनाने के लिए, का उपयोग करें:

    (fn [x y & args] ...) 
    

    x और y स्थितीय तर्क की आवश्यकता होगी; फ़ंक्शन (उनमें से किसी भी संख्या) को पारित किए गए बाकी तर्क एक सीक में एकत्र किए जाएंगे और args नाम के तहत उपलब्ध होंगे। यदि आवश्यक नहीं है तो आपको "आवश्यक स्थितित्मक तर्क" निर्दिष्ट करने की आवश्यकता नहीं है: (fn [& args] ...)

    एक वार एक variadic समारोह के आयोजन बनाने के लिए,

    (defn foo [x y & args] ...) 
    
  • का उपयोग कुछ तर्कों (जैसा कि उपरोक्त उदाहरण में या शायद args seq के रूप में आप एक seqable वस्तु में इकट्ठे हो गया गया है करने के लिए एक समारोह को लागू करने के एक वेक्टर & ग), का उपयोग apply:

    (defn all? [& args] 
        (apply every? args)) 
    
  • आप उपनाम बनाने के लिए एक समारोह लिखने के लिए चाहते हैं - के रूप में करने का विरोध किया। एक मैक्रो - आपको फ़ंक्शन intern, with-meta, meta - और संभवतः resolve/ns-resolve पर फ़ंक्शन की जांच करने की आवश्यकता होगी, इस पर निर्भर करता है कि फ़ंक्शन प्रतीक या वर्र्स स्वीकार करना है या नहीं। मैं पाठक को एक अभ्यास के रूप में विवरण भरने छोड़ दूंगा। :-)

+1

बस पिछले अनुच्छेद में दिए गए डिज़ाइन को महसूस करने वाले 'इंटर्न-एलियास' फ़ंक्शन के साथ एक गिस्ट पोस्ट किया गया। मैं एक सेकंड में एक डॉकस्ट्रिंग जोड़ दूंगा। यह मेटा को मूल से उपनाम में प्रतिलिपि बनाता है, वर्तमान के अलावा नामस्थानों में उपनाम बनाने का समर्थन करता है, दोनों प्रतीकों और वर्रों को मूल और सी के रूप में स्वीकार करता है। Http://gist.github.com/464970 –

+0

देखें, दोस्त आओ। कम से कम अन्य लोगों को मौका दें! क्या आपकी खुफिया स्तर को वापस * सामान्य * तक कम करने के लिए आप कुछ प्रकार की दवा नहीं ले सकते हैं? हमारे पास वापस आओ, भाई, हम आपको याद करते हैं। : पी – Rayne

+0

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

6

आपको बस इतना करना है कि हर किसी को बांधना है? सभी के लिए काम करते हैं? प्रतीक है, जो डीईएफ़ के माध्यम से किया जाता है:

(def all? every?) 

थोड़ा इस बारे में अधिक के लिए, Clojure macro to create a synonym for a function

+0

मैं इस तरह की एक सुविधा के कार्यान्वयन की खोज कर रहा था, लेकिन मुझे यह करने का त्वरित तरीका जानने में खुशी हुई, धन्यवाद! –

3

लगता है कि मैं यहाँ मौजूदा स्पष्टीकरण के लिए बहुत कुछ जोड़ सकते हैं, शायद तर्क संग्रह और destructuring पर रूबी ट्रैवेलर्स शब्दकोश में रिक्त स्थान के एक जोड़े को भरने को छोड़कर नहीं है:

(defn foo [& args]     ; Ruby: def foo(*args) 
    (println args))  
user=> (foo 1 2 3) 
(1 2 3) 

(defn foo [& args] 
    (+ args)) 
user=> (foo 1 2 3) 
java.lang.ClassCastException  ; + takes numbers, not a list 

(defn foo [& args] 
    (apply + args))     ; apply: as Ruby proc.call(*args) 
user=> (foo 1 2 3) 
6 

(defn foo [& args] 
    (let [[a b & other] args]  ; Ruby: a, b, *other = args 
    (println a b other))) 
user=> (foo 1 2 3) 
1 2 (3) 
+0

समानार्थी के लिए धन्यवाद। :] –

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