2009-07-22 10 views
6

के संदर्भ में कौन सा फ़ंक्शन सबसे अच्छा है, मैंने 3 फ़ंक्शंस लिखे हैं जो एक सूची में एक-तत्व दिखाई देने की संख्या की गणना करते हैं। मैंने विभिन्न इनपुट की कोशिश की और इसे प्रोफाइल किया लेकिन मुझे अभी भी पता नहीं है कि स्टैक उपयोग दक्षता और समय दक्षता के मामले में कौन सा फ़ंक्शन सबसे अच्छा है। कृपया मेरी मदद करें।स्टैक उपयोग क्षमता और समय

;; Using an accumulator 
    (defn count-instances1 [a-list an-element] 
     (letfn [(count-aux [list-aux acc] 
         (cond 
          (empty? list-aux) acc 
          :else (if (= (first list-aux) an-element) 
            (count-aux (rest list-aux) (inc acc)) 
            (count-aux (rest list-aux) acc))))] 
     (count-aux a-list 0))) 

;; Normal counting 
    (defn count-instances2 [a-list an-element] 
    (cond 
     (empty? a-list) 0 
     :else 
      (if (= (first a-list) an-element) 
       (+ 1 (count-instances2 (rest a-list) an-element)) 
       (count-instances2 (rest a-list) an-element)))) 

;; using loop. does this help at all? 
    (defn count-instances3 [a-list an-element] 
     (loop [mylist a-list acount 0] 
      (if (empty? mylist) 
       acount 
       (if (= (first mylist) an-element) 
       (recur (rest mylist)(inc acount)) 
       (recur (rest mylist) acount))))) 
+3

आपके प्रोफाइलिंग प्रयासों के परिणाम क्या थे? –

+3

नेस्टेड 'defn' शायद आप जो सोचते हैं वह नहीं करता है। 'defn' हमेशा एक अपूर्ण समारोह को परिभाषित करता है। आप 'letfn' (या यहां तक ​​कि' (चलो [एफ (एफएन ...)]) ') का उपयोग कर सकते हैं यदि आप एक आंतरिक कार्य को परिभाषित करना चाहते हैं। –

+0

धन्यवाद ब्रायन। लेकिन मैं लेटफन काम करने के लिए नहीं मिल सकता है। क्या आप लेटफन के साथ अपना प्रश्न संपादित कर सकते हैं? बहुत बहुत धन्यवाद। – unj2

उत्तर

2

पाश/पुनरावृत्ति होना संस्करण सही तरीका है। Joj की सीमाओं के कारण क्लोजर पूंछ कॉल को अनुकूलित नहीं कर सकता है।

+3

यह सही नहीं है। आपको यह कहना चाहिए कि क्लोजर * चुनता है * पूंछ कॉल को अनुकूलित करने के लिए नहीं, क्योंकि एक भाषा (जावा) में हासिल करना बहुत मुश्किल है जो पहले से ही नहीं है। वास्तव में जेवीएम के शीर्ष पर भाषाओं के कुछ कार्यान्वयन (उदाहरण के लिए, एसआईएससी - http://sisc-scheme.org/) हैं जो पूंछ कॉल अनुकूलित करते हैं। –

+0

वास्तव में अजीब बात है। पूंछ कॉल को अनुकूलित क्यों नहीं करना चाहेंगे? यह हमें कई परेशानी बचा लेगा? क्या व्यापार बंद है? – unj2

+3

'recur' अच्छा है क्योंकि यह स्पष्ट है और आप इसे केवल पूंछ की स्थिति से उपयोग कर सकते हैं (संकलक अन्यथा शिकायत करता है) जो उदाहरणों को पकड़ता है जहां आपको लगता है कि आप पूंछ-पुनरावर्ती हैं लेकिन आप नहीं हैं। यह सब स्वचालित रूप से मैक्रो हो सकता है, लेकिन यह 'रिकर' प्रतीक के साथ पूंछ कॉल में आपके फ़ंक्शन नाम को प्रतिस्थापित करने में बहुत परेशानी नहीं है। –

0

अपने कोड लेखन तो संकलक/interperter पूंछ प्रत्यावर्तन के लिए यह अनुकूलित कर सकते हैं, कुछ प्रदर्शन वृद्धि में परिणाम और उपयोग में कमी ढेर चाहिए। मुझे लगता है कि आपका सामान्य गिनती समारोह पूंछ रिकर्सन के लिए अर्हता प्राप्त कर सकता है ताकि कोई बहुत तेज हो। यकीन नहीं है क्योंकि मैं केवल एक शौक के रूप में लिस्प में डबिल हूं।

http://en.wikipedia.org/wiki/Tail_recursion

+0

क्लोजर JVM की सीमाओं के कारण पूंछ कॉल को अनुकूलित नहीं कर सकता है। – Svante

+1

इस पर रिच हिकी की टिप्पणी यह ​​थी कि एक स्पष्ट अपरिवर्तनीय होना बेहतर था जो लगभग हर समय काम करता है (लगभग JVM पर ऐसा करने की जटिलताओं के कारण) –

+0

@Svante - क्लोजर पूंछ कॉल अनुकूलित कर सकते हैं और करता है। आपको बस स्पष्ट होना होगा कि आप इसे 'रिकूर' (जो रिच हिकी द्वारा भाषा डिज़ाइन पसंद था) का उपयोग कर चाहते हैं। अधिकांश समय में JVM पर टीसीओ करना पूरी तरह से संभव है। JVM सीमाएं केवल पारस्परिक सह-पुनरावर्तन को प्रभावित करती हैं (जो वास्तव में एक बहुत ही दुर्लभ मामला है)। – mikera

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