इस रिक्रिएशन कोड को कैसे समझें?


12

मैंने इस कोड को मैनुअल An Introduction to Programming in Emacs Lispकी मदद से रिकर्स का प्रदर्शन करते हुए पाया condकि पंक्तियों की दर्ज संख्या के आधार पर कंकड़ की संख्या ज्ञात करने के लिए, अर्थात यदि पंक्तियाँ = 2, तो कंकड़ 3 होनी चाहिए, यदि 4 पंक्तियाँ तो यह 10 कंकड़ होनी चाहिए वहाँ।

(defun triangle-using-cond (number)
  (cond ((<= number 0) 0)
        ((= number 1) 1)
        ((> number 1)
         (+ number (triangle-using-cond (1- number))))))

तर्क 4 पास करने के बाद 10 का मूल्यांकन:

(triangle-using-cond 4)

मैनुअल ने स्पष्ट रूप से नहीं बताया कि इस उदाहरण कोड में प्रत्येक चरण में क्या होता है विशेष रूप से और मैं यह पता नहीं लगा सका कि यहां पुनरावृत्ति कैसे काम करती है। क्या आप मुझे मैकेनिक्स को चरण-दर-चरण समझने में मदद कर सकते हैं कि प्रत्येक उदाहरण में क्या होता है?


मैं किसी और को "रिकर्सन" शब्द के साथ आपकी मदद करने दूंगा (क्योंकि मुझे लगता है कि वह इस संदर्भ में कुछ अलग होने के नाते) या बेहतर तरीके से समझाता है कि मैं क्या लिखने वाला हूं: (क) यदि संख्या इससे कम या बराबर है से 0, फिर 0; (बी) यदि संख्या 1 के बराबर है, तो 1; (c) यदि संख्या 1 से अधिक है, तो फ़ंक्शन द्वारा दिए गए मान में संख्या को उस संख्या के साथ जोड़ें, triangle-using-condजो संख्या जो भी है, उससे 1 कम है। परिस्थितियाँ a, b और फिर c के क्रम में जाती हैं - जो भी पहले मैच करता है, वह वह स्थान है जहाँ हिरन रुकता है।
मुकदमा

हमेशा की तरह इंटरप्रिटेटर अंतरतम से बाहरीतम तक का मूल्यांकन करता है। इस प्रकार, 1-4 = 3। अब पुनरावर्ती कॉल होगा (triangle-using-cond 3), लेकिन यह एक ही पुनरावर्ती कॉल के साथ फिर से समाप्त होगा जब तक कि यह 1 सशर्त हिट नहीं करता है, है ना? आगे क्या होगा?
डॉक्टरेट

ओह, मैं देखता हूं - चरण 3 में फ़ंक्शन खुद को पुन: उपयोग करता है - ठीक है, अच्छा बिंदु।
मुकदमा

मुझे आश्चर्य है कि इसका परिणाम क्या होगा (triangle-using-cond 3)?
डॉक्टरेट

2
nb फ़ंक्शन 1-का एक विशेष रूप से भ्रामक नाम है, खासकर यदि आप एक कॉल पढ़ते हैं जैसे कि यह इन्फिक्स नोटेशन था। यह अपने तर्क को एक घटाता है; तर्क को माइनस नहीं करें।
फिल्स

जवाबों:


14

"प्रिंटफ़ डीबगिंग" का उपयोग करना

आप फ़ंक्शन परिभाषा को संशोधित करके Emacs को समझने में आपकी मदद कर सकते हैं:

(defun triangle-using-cond (number)
  (message (format "called with %d" number))
  (cond ((<= number 0) 0)
        ((= number 1) 1)
        ((> number 1)
         (+ number (triangle-using-cond (1- number))))))

बस बफर (message ...)को मुद्रित करने के लिए कहीं और जोड़ दें *Messages*

एडबग का उपयोग करना

फ़ंक्शन परिभाषा के अंदर कहीं भी बिंदु रखें और C-u C-M-xइसे "इंस्ट्रूमेंट" पर हिट करें। फिर फ़ंक्शन का मूल्यांकन करें, उदाहरण के बाद बिंदु को रखकर (triangle-using-cond 3)और मार C-x C-e

अब आप एडबग मोड में हैं। फ़ंक्शन के माध्यम से कदम रखने के लिए स्पेस बार मारो। प्रत्येक अभिव्यक्ति के मध्यवर्ती मूल्यों को प्रतिध्वनि क्षेत्र में दिखाया गया है। एडबग मोड से बाहर निकलने के लिए बस हिट करें q। इंस्ट्रूमेंटेशन को हटाने के लिए, परिभाषा के अंदर कहीं भी बिंदु डालें और परिभाषा C-M-xका पुनर्मूल्यांकन करने के लिए हिट करें।

मानक Emacs डीबगर का उपयोग करना

M-x debug-on-entry triangle-using-cond, तब, जब triangle-using-condआह्वान किया जाता है, तो आपको Emacs डीबगर (बफर *Backtrace*) में रखा जाता है ।

मूल्यांकन के माध्यम से कदम d(या cकिसी भी निर्बाध मूल्यांकन के माध्यम से छोड़ने के लिए)।

मध्यवर्ती स्थिति (चर मान, आदि) देखने के लिए आप eकभी भी उपयोग कर सकते हैं । आपको मूल्यांकन करने के लिए एक सेक्सप दर्ज करने के लिए कहा जाता है, और मूल्यांकन परिणाम मुद्रित होता है।

जब आप डीबगर का उपयोग करते हैं, तो स्रोत कोड की एक प्रतिलिपि किसी अन्य फ़्रेम में दिखाई देती है, इसलिए आप अनुसरण कर सकते हैं कि क्या चल रहा है।

आप स्रोत कोड में मनमाने स्थानों पर डिबगर (अधिक या कम ब्रेकप्वाइंट) दर्ज करने के लिए स्पष्ट कॉल भी सम्मिलित कर सकते हैं। आप डालने (debug)या (debug nil SOME-SEXP-TO-EVALUATE)। बाद के मामले में, जब डिबगर दर्ज किया SOME-SEXP-TO-EVALUATEजाता है, तो मूल्यांकन किया जाता है और परिणाम मुद्रित किया जाता है। (याद रखें कि आप इस तरह के कोड को स्रोत कोड में डाल सकते हैं और इसका C-M-xमूल्यांकन करने के लिए उपयोग कर सकते हैं, फिर पूर्ववत करें - आपको संपादित फ़ाइल को सहेजने की आवश्यकता नहीं है।)

Using Debuggerअधिक जानकारी के लिए Elisp मैन्युअल, नोड देखें।

एक पाश के रूप में पुनरावृत्ति

वैसे भी, एक लूप के रूप में पुनरावृत्ति के बारे में सोचो। दो समाप्ति के मामलों को परिभाषित किया गया है: (<= number 0)और (= number 1)। इन मामलों में फ़ंक्शन एक साधारण संख्या देता है।

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

पुनरावर्ती मामला परिणाम इसलिए है:

(+ number (+ (1- number) (+ (1- (1- number)) ... 1)

उदाहरण के लिए लें (triangle-using-cond 4)। चलो अंतिम अभिव्यक्ति जमा करते हैं:

  • पहले पुनरावृत्ति में numberहै 4, इसलिए (> number 1)शाखा का पालन किया जाता है। हम एक अभिव्यक्ति का निर्माण शुरू करते हैं (+ 4 ...और फ़ंक्शन को कॉल करते हैं (1- 4), अर्थात (triangle-using-cond 3)

  • अब numberहै 3, और परिणाम है (+ 3 (triangle-using-cond 2))। कुल परिणाम अभिव्यक्ति है (+ 4 (+ 3 (triangle-using-cond 2)))

  • numberहै 2, अब तो अभिव्यक्ति है(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))

  • numberहै 1अब, और हम ले (= number 1)शाखा, एक उबाऊ में जिसके परिणामस्वरूप 1। पूरी अभिव्यक्ति है (+ 4 (+ 3 (+ 2 1)))। बाहर के अंदर से मूल्यांकन कि और आपको मिलता है: (+ 4 (+ 3 3)), (+ 4 6), या बस 10


3
एडबग और भी बेहतर होगा। =)
मालाबार

कैसे निशान का उपयोग कर मुद्रित करने के लिए message (...), C-x C-eबस मार अंतिम परिणाम (10) और कुछ नहीं दिखाता है? क्या मैं कुछ भूल रहा हूँ?
डॉक्टरेट

@ मलबारबा, कैसे लगाएं Edebugकार्रवाई?
डॉक्टरेट

1
@doctorate ने C-u C-M-xइसे edebug करने के लिए फ़ंक्शन के अंदर बिंदु के साथ मारा । फिर फ़ंक्शन को सामान्य रूप से चलाएं।
मालाबार

@ बफर (message ...)को सामान प्रिंट करें *Message*
21

6

SICP से प्रक्रिया अनुप्रयोग के लिए प्रतिस्थापन मॉडल इस तरह कोड को समझने के लिए एल्गोरिथ्म की व्याख्या कर सकते हैं।

मैंने इसे सुविधाजनक बनाने के लिए कुछ कोड भी लिखे। lispy-flattenसे lispy पैकेज करता है। यहाँ आवेदन lispy-flattenकरने का परिणाम है (triangle-using-cond 4):

(cond ((<= 4 0)
       0)
      ((= 4 1)
       1)
      ((> 4 1)
       (+ 4 (triangle-using-cond (1- 4)))))

आप उपरोक्त अभिव्यक्ति को सरल बना सकते हैं:

(+ 4 (triangle-using-cond 3))

फिर एक बार और समतल करें:

(+ 4 (cond ((<= 3 0)
            0)
           ((= 3 1)
            1)
           ((> 3 1)
            (+ 3 (triangle-using-cond (1- 3))))))

अंतिम परिणाम:

(+ 4 (+ 3 (+ 2 1)))

3

यह Emacs / Elisp के लिए विशिष्ट नहीं है, लेकिन अगर आपके पास गणित की पृष्ठभूमि है, तो पुनरावृत्ति गणितीय प्रेरण की तरह है । (या यदि आप नहीं करते हैं: तो जब आप प्रेरण सीखते हैं, तो यह पुनरावृत्ति की तरह है!)

आइए परिभाषा के साथ शुरू करें:

(defun triangle-using-cond (number)
  (cond ((<= number 0) 0)
        ((= number 1) 1)
        ((> number 1)
         (+ number (triangle-using-cond (1- number))))))

जब numberहै 4, न तो के पहले दो की स्थिति, पकड़ तो यह तीसरी शर्त के अनुसार मूल्यांकन कर रहा है:
(triangle-using-cond 4)के रूप में मूल्यांकन किया जाता है
(+ number (triangle-using-cond (1- number))), अर्थात् के रूप में
(+ 4 (triangle-using-cond 3))

इसी तरह
(triangle-using-cond 3)से मूल्यांकन किया जाता है
(+ 3 (triangle-using-cond 2))

इसी तरह (triangle-using-cond 2)से मूल्यांकन किया जाता है
(+ 2 (triangle-using-cond 1))

लेकिन (triangle-using-cond 1)दूसरी शर्त यह है कि इसका मूल्यांकन किया जाए 1

पुनरावर्तन सीखने वाले किसी व्यक्ति के लिए सलाह का एक टुकड़ा: बचने की कोशिश करें

पुनरावर्ती कॉल काम करने के बजाय पुनरावर्ती कॉल के दौरान क्या होता है, इस बारे में सोचने की कोशिश करने की सामान्य शुरुआत करने वाला गलती करता है (कभी-कभी आवर्ती छलांग कहा जाता है)।

यदि आप अपने आप को समझाने की कोशिश कर रहे हैं कि क्या (triangle-using-cond 4)सही उत्तर वापस आएगा, तो बस मान लें कि (triangle-using-cond 3)वह सही उत्तर लौटाएगा, और सत्यापित करें कि क्या यह उस स्थिति में सही होगा। बेशक आपको आधार मामले को भी सत्यापित करना होगा।


2

आपके उदाहरण के लिए गणना चरण निम्नानुसार होंगे:

(4 +               ;; step 1
   (3 +            ;; step 2
      (2 +         ;; step 3
         (1))))    ;; step 4
=> 10

0 स्थिति वास्तव में कभी नहीं मिली है क्योंकि 1 इनपुट के रूप में पहले से ही पुनरावृत्ति को समाप्त करता है।


(1)एक वैध अभिव्यक्ति नहीं है।
rekado

1
यह ठीक के साथ मूल्यांकन करता है M-x calc। :-) गंभीरता से, मेरा मतलब है कि गणना दिखाने के लिए, न कि लिस्प मूल्यांकन।
पपरिका

ओह, मैंने यह भी नहीं देखा कि यह आपके उत्तर के (4 +बजाय (+ 4... :)
20

0

मुझे लगता है कि यह बहुत आसान है, आपको इसके तहत emacs की जरूरत नहीं है, यह सिर्फ प्राथमिक स्कूल गणित है।

f (0) = 0

f (1) = 1

f (n) = f (n-1) + n जब n> 1

so f (5) = 5 + f (4) = 5 + 4 + f (3) = 5 + 4 + 3 + 2 + 1 + 0 0

अब यह स्पष्ट है।


इस फ़ंक्शन के मामले में, हालांकि, f (0) को कभी नहीं बुलाया जाता है।
रेकडो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.