2013-04-09 3 views
15

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

(ns sample.core 
    (:gen-class) 
    (:require clojure.set clojure.string)) 

और

(ns sample.core 
    (:gen-class) 
    (:require [clojure.set] 
      [clojure.string])) 

हालांकि, इस repl

(require 'clojure.string 'clojure.test) 

से काम करता है लेकिन एक CLJ फाइल में विफल रहता है

(ns sample.core 
    (:gen-class) 
    (:require 'clojure.string 'clojure.test)) 
... 
Exception in thread "main" java.lang.Exception: lib names inside prefix lists must not contain periods 
    at clojure.core$load_lib.doInvoke(core.clj:5359) 
    at clojure.lang.RestFn.applyTo(RestFn.java:142) 
    .... 

जबकि ये एपियर एक ही पतली करने के लिए जी:

(ns sample.core 
    (:gen-class) 
    (require clojure.set clojure.string)) 

(ns sample.core 
    (:gen-class) 
    (:require clojure.set clojure.string)) 

आम तौर पर मैं इसे समझ नहीं रहा हूं। मैं उपयोग, आयात और आवश्यकता को समझता हूं। लेकिन मैं ":" और [] और '() आदि में चीजों के बीच मतभेदों को समझ नहीं पा रहा हूं। क्या कोई इस विषय को अंतर्ज्ञानी तरीके से प्रकाशित कर सकता है?

+0

संभावित डुप्लिकेट [एनएस फॉर्म में आवश्यकता क्यों आवश्यक फ़ंक्शन से अलग व्यवहार करती है] (http://stackoverflow.com/questions/3719929/why-does-require-in-the-ns-form-behave- अलग-अलग-आवश्यकता-फ़ंक्शन) –

+1

एचएम, वास्तव में [] और प्रतिकृति और clj कोड के बीच अंतर के बारे में नहीं पूछता है। –

उत्तर

12

यहां मुद्दा सूक्ष्म और संभावित रूप से मैक्रोज़ के बारे में कुछ समझने के बिना ग्रोक करना मुश्किल है।

मैक्रोज़ सिंटैक्स में उसी तरह से हेरफेर करते हैं जो कार्य मूल्यों में हेरफेर करता है। वास्तव में, मैक्रोज़ सिर्फ एक हुक के साथ काम करते हैं जो उन्हें संकलन समय पर मूल्यांकन करने का कारण बनता है। वे डेटा शाब्दिक पारित होते हैं जिन्हें आप स्रोत कोड में देखते हैं और मूल्यांकन शीर्ष-डाउन होते हैं। के एक समारोह और एक मैक्रो एक ही शरीर है कि बनाने ताकि आप अंतर देख सकते हैं करते हैं:

(defmacro print-args-m [& args] 
    (print "Your args:") 
    (prn args)) 

(defn print-args-f [& args] 
    (print "Your args:") 
    (prn args)) 

(print-args-m (+ 1 2) (str "hello" " sir!")) 

; Your args: ((+ 1 2) (str "hello" " sir!")) 

(print-args-f (+ 1 2) (str "hello" " sir!")) 

; Your args: (3 "hello sir!") 

मैक्रो उनकी वापसी मान से बदल रहे हैं। आप macroexpand

(defmacro defmap [sym & args] 
    `(def ~sym (hash-map [email protected]))) ; I won't explain these crazy symbols here. 
           ; There are plenty of good tutorials around 

(macroexpand 
    '(defmap people 
    "Steve" {:age 53, :gender :male} 
    "Agnes" {:age 7, :gender :female})) 

; (def people 
; (clojure.core/hash-map 
;  "Steve" {:age 53, :gender :male} 
;  "Agnes" {:age 7, :gender :female})) 

इस बिंदु पर के साथ इस प्रक्रिया का निरीक्षण कर सकते हैं, मैं शायद व्याख्या करनी चाहिए कि ' निम्न प्रपत्र का कारण बनता है होना करने के लिए quote डी। इसका मतलब है कि संकलक फॉर्म को पढ़ेगा, लेकिन इसे निष्पादित नहीं करेगा या प्रतीकों को हल करने का प्रयास करेगा और आगे भी। यानी 'conj एक प्रतीक का मूल्यांकन करता है, जबकि conj किसी फ़ंक्शन का मूल्यांकन करता है। (eval 'conj)(eval (quote conj)) के समतुल्य conj के बराबर है।

इस बात को ध्यान में रखते हुए, पता है कि आप नामस्थान के रूप में प्रतीक को हल नहीं कर सकते हैं जब तक कि इसे किसी भी तरह से आपके नामस्थान में जादुई रूप से आयात नहीं किया जाता है। यह require फ़ंक्शन करता है। यह प्रतीक लेता है और वे नामस्थानों को मेल खाता है, जो उन्हें वर्तमान नामस्थान में उपलब्ध कराते हैं।

(macroexpand 
    '(ns sample.core 
    (:require clojure.set clojure.string))) 

; (do 
; (clojure.core/in-ns 'sample.core) 
; (clojure.core/with-loading-context 
;  (clojure.core/refer 'clojure.core) 
;  (clojure.core/require 'clojure.set 'clojure.string))) 

देखें कि यह कैसे प्रतीकों clojure.set और हमारे लिए clojure.string उद्धृत किया:

देखते हैं क्या ns मैक्रो के लिए विस्तारित करते हैं? कितना सुविधाजनक! लेकिन :require के चरण में require का उपयोग करते समय क्या सौदा है?

(macroexpand 
'(ns sample.core 
    (require clojure.set clojure.string))) 

; (do 
; (clojure.core/in-ns 'sample.core) 
; (clojure.core/with-loading-context 
;  (clojure.core/refer 'clojure.core) 
;  (clojure.core/require 'clojure.set 'clojure.string))) 

ऐसा लगता है कि जो कोई भी ns मैक्रो लिखा था, काफी अच्छा हमें यह दोनों तरीकों से करते हैं के लिए गया था के बाद से इस परिणाम वास्तव में पहले की तरह ही है। Neato!

संपादित करें: tvachon केवल :require का उपयोग कर के बाद से यह केवल आधिकारिक तौर पर समर्थित प्रपत्र

है लेकिन क्या ब्रैकेट के साथ सौदा है के बारे में सही है?

(macroexpand 
    '(ns sample.core 
    (:require [clojure.set] 
       [clojure.string]))) 

; (do 
; (clojure.core/in-ns 'sample.core) 
; (clojure.core/with-loading-context 
; (clojure.core/refer 'clojure.core) 
; (clojure.core/require '[clojure.set] '[clojure.string]))) 

बाहर कर देता है वे भी उद्धृत किया जाए, ठीक जैसे हम अगर हम require को स्टैंडअलोन कॉल लिख रहे थे करना चाहते हैं।

यह भी पता चला है कि ns परवाह नहीं है कि हम इसे सूची (माता-पिता) या वैक्टर (ब्रैकेट) के साथ काम करने के लिए देते हैं या नहीं। यह तर्कों को चीजों के अनुक्रम के रूप में देखता है। उदाहरण के लिए, इस काम करता है:

(ns sample.core 
    [:gen-class] 
    [:require [clojure.set] 
      [clojure.string]]) 

require, के रूप में टिप्पणी में amalloy से कहा, वैक्टर और सूचियों के लिए अलग अलग अर्थ विज्ञान है, तो उन अप मिश्रण नहीं है!

अंत में, निम्नलिखित कार्य क्यों नहीं करते?

(ns sample.core 
    (:require 'clojure.string 'clojure.test)) 

खैर, ns के बाद से है हमारे हमारे लिए के हवाले से, इन प्रतीकों दो बार उद्धृत करने के लिए, जो केवल एक बार उद्धृत किया जा रहा से शब्दार्थ अलग है और यह भी शुद्ध पागलपन है।

conj ; => #<core$conj [email protected]> 
'conj ; => conj 
''conj ; => (quote conj) 
'''conj ; => (quote (quote conj)) 

मुझे उम्मीद है कि यह मदद करता है, और मैं निश्चित रूप से मैक्रोज़ लिखने के तरीके सीखने की सलाह देता हूं। वे बहुत मजेदार हैं।

+2

'(: आवश्यकता (clojure.set) (clojure.string)) 'बिल्कुल काम नहीं करता है। यह एक नो-ऑप है, जो * देखो * जैसा होता है जैसे यह काम करता है क्योंकि आपने दो नामस्थानों को चुना है जो पहले से ही आवश्यक हैं। इसे कुछ गैर-मौजूद नामस्थानों पर आज़माएं: यह चुपचाप सफल होता है; मौजूदा नामस्थानों पर यह चुपचाप कुछ भी नहीं करता है। यहां माता-पिता का उपयोग करना एक उपसर्ग सूची इंगित करता है, जैसा कि '(: आवश्यकता (क्लोजर सेट स्ट्रिंग)) '; आपके द्वारा दिया गया वाक्यविन्यास केवल वैक्टर के साथ काम करता है। – amalloy

+0

अच्छी तरह से देखा गया। मैं प्रतिबिंबित करने के लिए पोस्ट संपादित करेंगे। –

+0

महान उत्तर, और टीडीटी संदर्भ के लिए +1, यदि यह – Hendekagon

4

टी एल; डॉ:

 
(ns sample.core 
    (:gen-class) 
    (:require clojure.set clojure.string)) 

और

 
(ns sample.core 
    (:gen-class) 
    (:require [clojure.set] 
      [clojure.string])) 

दोनों ठीक हैं - दूसरे संस्करण सिर्फ सबसे लचीला वाक्य रचना require समर्थन की एक विशेष मामला है। इसे भी लिखा जा सकता है:

 
(ns sample.core 
    (:gen-class) 
    (:require [clojure set string])) 

सामान्य रूप से, यह अंतिम रूप इस विशेष आवश्यकता के लिए सबसे अच्छा अभ्यास है।


(require 'clojure.string 'clojure.test)

इसके अलावा एक CLJ फाइल में काम करता है - इस प्रयास करें:

 
(ns sample.core 
    (:gen-class)) 
(require 'clojure.string 'clojure.test) 

भ्रम है कि यहाँ है अपने टूटे उदाहरण में आप में "उद्धृत प्रतीकों" का उपयोग करने की कोशिश कर रहे :requirens मैक्रो का खंड। शायद यह सबसे सहज ज्ञान नहीं है, लेकिन यहां बताया गया है कि यह कैसे टूट जाता है:

अन्य मॉड्यूल, require और ns की आवश्यकता के दो तरीके हैं।

require एक समारोह है कि उद्धृत रूपों की एक सूची लेता है ("के हवाले से" होने से बचाने के clojure प्रतीकों आप require के पास जिस तरह से यह अन्य सभी प्रतीकों करता है को देखने की जरूरत है)।

ns एक मैक्रो है जो :require विकल्प का समर्थन करता है। यह इस विकल्प का मूल्य लेता है और, कवर के तहत, इसे require फ़ंक्शन पर कॉल में बदल देता है। आपको :require विकल्प के मान को उद्धृत करने की आवश्यकता नहीं है क्योंकि ns एक मैक्रो है और इसलिए प्रतीकों को उद्धृत करने में सक्षम है।

यह अभी भी अस्पष्ट नहीं हो सकता है, लेकिन मैं स्पष्ट करने के लिए क्लोजर दस्तावेज़ों को बदलने का सुझाव देता हूं - एक बार जब आप पूरी तरह से क्लोजर की बेहतर समझ लेंगे तो आप पूरी तरह से समझ लेंगे।

क्लोजर स्रोत फ़ाइलों में आपको हमेशा पुस्तकालयों की आवश्यकता के लिए ns खंड का उपयोग करना चाहिए - require केवल REPL में उपयोग किया जाना चाहिए।


अपने पिछले दो उदाहरणों में आप सही है कि

 
(ns sample.core 
    (:gen-class) 
    (require clojure.set clojure.string)) 

काम करता है, लेकिन यह एक दुर्घटना है - शायद इस तथ्य का एक परिणाम है कि

 
(name :require) 
=> "require" 

(name 'require) 
=> "require" 

प्रलेखित वाक्य रचना है

 
(ns sample.core 
    (:gen-class) 
    (:require clojure.set clojure.string)) 

और केवल एक ही गारंटी है कि भविष्य में तोड़ना न पड़े।

+0

"क्लोजर स्रोत फ़ाइलों में आपको हमेशा पुस्तकालयों की आवश्यकता के लिए एनएस क्लॉज का उपयोग करना चाहिए - आवश्यकता केवल आरईपीएल में उपयोग की जानी चाहिए।" क्यूं कर? –

+2

कोई तकनीकी कारण नहीं - पूरी तरह से शैली और पठनीयता में से एक। 'Ns' का उपयोग लगातार यह सुनिश्चित करता है कि अन्य प्रोग्रामर आसानी से देख सकें कि फ़ाइल द्वारा कौन सी नेमस्पेस की आवश्यकता पूरी फाइल के माध्यम से खोदने के बिना की जाती है। यह एक छोटा क्लीनर भी है, क्योंकि आपको मैन्युअल रूप से फॉर्म से बचने की आवश्यकता नहीं है। – tvachon

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