2011-10-18 9 views
31

क्लोजर में पुनरावृत्ति के लिए "पूंछ की स्थिति" की सटीक परिभाषा क्या है। मुझे लगता है कि यह एक लूप एस-अभिव्यक्ति में आखिरी वस्तु होगी, लेकिन नीचे दिए गए उदाहरण में मुझे ऐसा लगता है कि एस-एक्सप्रेशन जो शुरू होता है (अगर ...) पूंछ की स्थिति में है (या [लूप कुंजीशब्द] [बाइंडिंग स्टेटस] [अगर स्टेटमेंट])।क्लोजर: रिकूर ​​के लिए पूंछ की स्थिति क्या है?

(= __ 
    (loop [x 5 
     result []] 
    (if (> x 0) 
     (recur (dec x) (conj result (+ 2 x))) 
     result))) 

कोड http://www.4clojure.com/problem/68

निकट से संबंधित सवाल से लिया: How can I call recur in an if conditional in Clojure?

उत्तर

56

पूंछ स्थिति एक स्थिति है जो एक अभिव्यक्ति से कोई मान होता है। पूंछ की स्थिति में फॉर्म के मूल्यांकन के बाद मूल्यांकन किए जाने वाले कोई और रूप नहीं हैं।

से The Joy of Clojure

(defn absolute-value [x] 
    (if (pos? x) 
     x  ; "then" clause 
     (- x))) ; "else" clause 

यह एक एकल पैरामीटर और नाम यह x लेता है इस उदाहरण पर विचार। यदि एक्स पहले से ही एक सकारात्मक संख्या है, तो एक्स लौटा है; अन्यथा एक्स के विपरीत वापस आ गया है। यदि फॉर्म फ़ंक्शन की पूंछ स्थिति में है क्योंकि जो कुछ भी लौटाता है, तो पूरे फ़ंक्शन वापस आ जाएगा। "तब" खंड में एक्स फ़ंक्शन की पूंछ स्थिति में भी है। लेकिन "अन्य" खंड में एक्स फ़ंक्शन की पूंछ स्थिति में नहीं है क्योंकि x का मान फ़ंक्शन पर पास किया गया है, सीधे वापस नहीं किया गया है। एक और खंड (- x) के रूप में अन्य खंड पूंछ की स्थिति में है। क्योंकि उनमें से या तो अगर बयान से लौटाया जा सकता है

अभिव्यक्ति

(if a 
    b 
    c) 

दोनों b और c में

इसी तरह, पूंछ की स्थिति में हैं।

अब आप अपने उदाहरण

(loop [x 5 
     result []] 
    (if (> x 0) 
    (recur (dec x) (conj result (+ 2 x))) 
    result))) 

(if ...) रूप (loop ...) फार्म और दोनों (recur ...) फार्म और result प्रपत्र की पूंछ स्थिति में है में (if ...) प्रपत्र की पूंछ स्थिति में हैं। क्योंकि (+ 1 ...)(recur tail) के बाद मूल्यांकन किया जाएगा

प्रश्न में दूसरी ओर है कि आप लिंक किए गए

(fn [coll] (let [tail (rest coll)] 
      (if (empty tail) 
       1 
       (+ 1 (recur tail))))) 

recur पर पूंछ की स्थिति में नहीं है। इसलिए क्लोजर कंपाइलर एक त्रुटि देता है।

पूंछ की स्थिति महत्वपूर्ण है क्योंकि आप पूंछ की स्थिति से recur रूप का उपयोग कर सकते हैं। कार्यात्मक प्रोग्रामिंग भाषा आमतौर पर लूप द्वारा प्रक्रियात्मक प्रोग्रामिंग भाषाओं को पूरा करने के लिए रिकर्सन का उपयोग करती है। लेकिन रिकर्सन समस्याग्रस्त है, क्योंकि यह स्टैक स्पेस का उपभोग करता है और गहरी रिकर्सन स्टैक ओवरफ्लो समस्याओं (धीमी होने के अतिरिक्त) का कारण बन सकता है। यह समस्या आमतौर पर पूंछ कॉल अनुकूलन (टीसीओ) द्वारा हल की जाती है, जो कॉलर से दूर होती है जब रिकर्सिव कॉल किसी फ़ंक्शन/फ़ॉर्म की पूंछ स्थिति में होती है।

क्योंकि क्लोजर JVM पर होस्ट किया गया है और JVM पूंछ कॉल अनुकूलन का समर्थन नहीं करता है, इसे रिकर्सन करने के लिए एक चाल की आवश्यकता है। recur फॉर्म वह चाल है, यह क्लोजर कंपाइलर को पूंछ कॉल अनुकूलन के समान कुछ करने की अनुमति देता है। इसके अलावा, यह सत्यापित करता है कि recur वास्तव में पूंछ की स्थिति में है। लाभ यह है कि आप यह सुनिश्चित कर सकते हैं कि अनुकूलन वास्तव में होता है।

+0

धन्यवाद, महान विवरण, मेरे भ्रम की स्थिति यह थी कि मैं अंतिम के मामले में एस-अभिव्यक्ति में एक पद के रूप में पूंछ स्थिति के बारे में सोच रहा था बल्कि उसके बाद मूल्यांकन। आपके स्पष्टीकरण के प्रकाश में ऐसा लगता है कि एक लूप में एकाधिक पुनरावर्ती रूपों का उपयोग करना संभव है (उदाहरण के लिए अंतिम IF s-exp की दोनों शाखाओं में) सही है? – tjb

+0

हां यह पूरी तरह से संभव है। मुझे भी इस बात से बहुत भ्रमित होना याद है। इसके अलावा मैंने यह पढ़ना जारी रखा कि जेवीएम पर टीसीओ की कमी के कारण पुनरावृत्ति कितनी महत्वपूर्ण थी ... मुझे इनमें से किसी के बारे में पहली बात समझ नहीं आई थी (उदाहरण के लिए टीसीओ क्या है ...) और मेरा सिर था कताई ... – Paul

+0

हाँ, यह काफी उलझन में है, और मैंने इसे कहीं भी समझाया कोई भी दस्तावेज कभी नहीं देखा। हो सकता है कि मैं सुझाव दूंगा कि वे आपके उत्तर के आधार पर पुनरावृत्ति दस्तावेज में कुछ जोड़ते हैं। – tjb

24

बस पॉल से उत्कृष्ट उत्तर को पूरक करने के लिए, क्लोजर (ed1) का जॉय एक टेबल (तालिका 7.1) प्रदान करता है जो दिखाता है कि पूंछ की स्थिति विभिन्न रूपों/अभिव्यक्तियों में कहां है, जिसे मैंने नीचे पुन: प्रस्तुत किया है। जहां शब्द "पूंछ" प्रत्येक प्रपत्र/अभिव्यक्ति में होता है के लिए देखो:

 
|---------------------+-------------------------------------------+---------------| 
| Form    | Tail Position        | recur target? | 
|---------------------+-------------------------------------------+---------------| 
| fn, defn   | (fn [args] expressions tail)    | Yes   | 
| loop    | (loop [bindings] expressions tail)  | Yes   | 
| let, letfn, binding | (let [bindings] expressions tail)   | No   | 
| do     | (do expressions tail)      | No   | 
| if, if-not   | (if test then tail else tail)    | No   | 
| when, when-not  | (when test expressions tail)    | No   | 
| cond    | (cond test test tail ... :else else tail) | No   | 
| or, and    | (or test test ... tail)     | No   | 
| case    | (case const const tail ... default tail) | No   | 
|---------------------+-------------------------------------------+---------------| 
संबंधित मुद्दे