2009-08-10 9 views
41

रिच हिकी ने ब्लॉग पोस्ट में से एक में यही कहा लेकिन मैं आवेदन का उपयोग करने में प्रेरणा को समझ नहीं पा रहा हूं। कृपया मदद करे।क्लोजर में 'लागू' का उपयोग क्यों करना चाहिए?

Clojure और सीएल के बीच एक बड़ा अंतर यह है कि Clojure एक लिस्प -1 है, इसलिए funcall की जरूरत नहीं है, और लागू केवल तर्कों की एक क्रम से परिभाषित संग्रह करने के लिए एक समारोह लागू करने के लिए प्रयोग किया जाता है। तो, (लागू करें [i]) लिखा जा सकता है (एफ i)।

इसके अलावा, "क्लोजर लिस्प -1" द्वारा उसका क्या अर्थ है और funcall की आवश्यकता नहीं है? मैंने कभी सीएल में प्रोग्राम नहीं किया है।

धन्यवाद

+0

यहाँ लागू समारोह के स्रोत कोड के साथ एक सार है: https://gist.github.com/purplejacket/36de7061061ec9c49734 – Purplejacket

उत्तर

51

आप अगर तर्क की संख्या कार्य करने के लिए पारित करने के लिए संकलन समय (क्षमा करें, Clojure वाक्य रचना कि सभी अच्छी तरह से पता नहीं है, योजना का सहारा) पर ज्ञात नहीं है लागू होते हैं, का प्रयोग करेंगे:

(define (call-other-1 func arg) (func arg)) 
(define (call-other-2 func arg1 arg2) (func arg1 arg2)) 

जब तक संकलन समय पर तर्कों की संख्या ज्ञात होती है, तो आप ऊपर दिए गए उदाहरण में किए गए अनुसार सीधे उन्हें पास कर सकते हैं। लेकिन अगर तर्क की संख्या संकलन समय पर ज्ञात नहीं है, यदि आप ऐसा नहीं कर सकते हैं (अच्छी तरह से, आप की तरह कुछ की कोशिश कर सकते):

(define (call-other-n func . args) 
    (case (length args) 
     ((0) (other)) 
     ((1) (other (car args))) 
     ((2) (other (car args) (cadr args))) 
     ...)) 

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

(define (call-other-n func . args) 
    (apply other args)) 

यह लेता है जो कुछ भी तर्क की संख्या में यह करने के लिए पिछले तर्क के रूप में दी गई सूची में शामिल हैं, और समारोह को पहले तर्क के रूप में पारित उन मूल्यों के साथ लागू कहता है।

2

प्रकार संचालन लागू के लिए सामान्य पैटर्न तर्क का एक सेट, डिट्टो साथ रनटाइम पर प्रदान की एक समारोह गठबंधन करने के लिए है।

मैंने उस विशेष भाषा के लिए उप-समूहों के बारे में आत्मविश्वास रखने में सक्षम होने के लिए क्लोजर के साथ पर्याप्त नहीं किया है, यह बताने के लिए कि उस मामले में लागू होने का उपयोग कड़ाई से जरूरी है या नहीं।

38

शब्द लिस्प -1 और लिस्प-2 शब्द संदर्भित करते हैं कि क्या कार्य चर के समान नामस्थान में हैं या नहीं।

एक लिस्प -2 (यानी, 2 नामस्थान) में, किसी फ़ॉर्म में पहली आइटम का फ़ंक्शन नाम के रूप में मूल्यांकन किया जाएगा - भले ही यह वास्तव में फ़ंक्शन मान के साथ एक चर का नाम हो। तो यदि आप एक परिवर्तनीय फ़ंक्शन को कॉल करना चाहते हैं, तो आपको चर को दूसरे फ़ंक्शन में पास करना होगा।

योजना और क्लोजर की तरह लिस्प -1 में, चर के लिए मूल्यांकन करने वाले चर प्रारंभिक स्थिति में जा सकते हैं, इसलिए आपको इसे फ़ंक्शन के रूप में मूल्यांकन करने के लिए apply का उपयोग करने की आवश्यकता नहीं है।

28

apply मूल रूप से अनुक्रम को अनचाहे करता है और व्यक्तिगत तर्क के रूप में उन्हें कार्य लागू करता है।

(apply + [1 2 3 4 5]) 

कि रिटर्न 15. यह मूल रूप से (+ [1 2 3 4 5]) के बजाय, (+ 1 2 3 4 5) के लिए विस्तारित:

यहाँ एक उदाहरण है।

+7

फिर भी एक और उदाहरण: (लागू + 1 2 [3 4 5]) => 15 – Isaiah

+0

... लेकिन यह विफल रहता है (लागू + 1 2 [3 4 5]) जो अप्रत्याशित था। कोई विचार क्यों? (मैं क्लोजर के लिए पूरी तरह से नया हूं) – ianjs

+0

@ianjs जो असफल नहीं होता ... – justin

0

लागू प्रोटोकॉल के साथ उपयोगी है, खासकर थ्रेडिंग मैक्रोज़ के संयोजन के साथ। मैंने अभी यह खोजा है। चूंकि आप can't use the & macro to expand interface arguments at compile time, आप इसके बजाय एक अप्रत्याशित रूप से आकार वाले वेक्टर लागू कर सकते हैं।

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

(query-tree [this forms] 
    (apply xml-> (text-id-to-tree this) forms))) 

text-id-to-tree इस विशेष रिकॉर्ड है कि एक xml ज़िपर में एक फ़ाइल को पार्स करता है का एक और तरीका है। अन्य फ़ाइल में, मैं किसी विशेष क्वेरी कि query-tree लागू करता है के साथ प्रोटोकॉल का विस्तार, आदेशों की एक श्रृंखला को निर्दिष्ट XML-> मैक्रो के माध्यम से पिरोया जा सकता:

(tags-with-attrs [this] 
    (query-tree this [zf/descendants zip/node (fn [node] [(map #(% node) [:tag :attrs])])]) 

(ध्यान दें: अपने आप में इस क्वेरी का एक बहुत वापस आ जाएगी टैग के लिए "शून्य" परिणाम जिनमें विशेषताएँ नहीं हैं। अद्वितीय मानों की एक साफ सूची के लिए फ़िल्टर करें और कम करें)।

जेएफ, वैसे, clojure.contrib.zip-filter को संदर्भित करता है, और clojure.zip पर ज़िप करता है। XML-> मैक्रो clojure.contrib.zip-filter.xml पुस्तकालय है, जो मैं :use

6

आप apply का प्रयोग कर एक समारोह है कि एक है कि बहस के लिए एक एकल अनुक्रम पर काम करता है के लिए कई तर्क पर काम करता है परिवर्तित करने के लिए से है। आप अनुक्रम से पहले तर्क भी डाल सकते हैं। उदाहरण के लिए, map कई अनुक्रमों पर काम कर सकता है। यह उदाहरण (ClojureDocs से) मैट्रिक्स को स्थानांतरित करने के लिए map का उपयोग करता है।

user=> (apply map vector [[:a :b] [:c :d]]) 
([:a :c] [:b :d]) 

एक डाला तर्क यहाँ vector है। तो apply

user=> (map vector [:a :b] [:c :d]) 

प्यारा करने के लिए फैलता है!

पुनश्च वैक्टर का एक अनुक्रम के बजाय वैक्टर का एक वेक्टर लौटने के लिए vec में पूरी बात लपेट:

user=> (vec (apply map vector [[:a :b] [:c :d]])) 

हम यहां हैं, तो vec(partial apply vector) के रूप में परिभाषित किया जा सकता है, हालांकि यह नहीं है ।

लिस्प -1 और लिस्प -2 के बारे में चिंता: 1 और 2 किसी दिए गए संदर्भ में नामों की संख्या को इंगित कर सकता है। एक लिस्प -2 में, आपके पास एक ही नाम के साथ दो अलग-अलग चीजें (एक फ़ंक्शन और एक चर) हो सकती हैं। इसलिए, जहां भी कोई भी वैध हो सकता है, आपको अपने प्रोग्राम को किसी चीज़ के साथ सजाने की ज़रूरत है जिससे आप इसका मतलब बता सकें। शुक्र है, क्लोजर (या योजना ...) एक नाम को केवल एक चीज़ को इंगित करने की अनुमति देता है, इसलिए ऐसी कोई सजावट आवश्यक नहीं है।

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