2010-06-01 8 views
9

एक ज्ञापन क्लोजुरियन के रूप में ज्ञापन, यह recommended to me था कि मैं Project Euler समस्याओं को भाषा सीखने के तरीके के रूप में देखता हूं। यह आपके कौशल को बेहतर बनाने और आत्मविश्वास हासिल करने का एक शानदार तरीका है। मैंने अभी अपना जवाब problem #14 पर पूरा कर लिया है। यह ठीक काम करता है, लेकिन इसे कुशलतापूर्वक चलाने के लिए मुझे कुछ ज्ञापन लागू करना पड़ा। मैं अपने कोड को संरचित करने के तरीके के कारण प्रीपेक्स्ड memoize फ़ंक्शन का उपयोग नहीं कर सका, और मुझे लगता है कि यह मेरे स्वयं के किसी भी तरह से रोल करने का अच्छा अनुभव था। मेरा सवाल यह है कि अगर मेरे कैश को फ़ंक्शन के भीतर ही एन्सेप्लेट करने का कोई अच्छा तरीका है, या यदि मुझे बाहरी कैश को परिभाषित करना है जैसे मैंने किया है। इसके अलावा, मेरे कोड को अधिक बेवकूफ बनाने के लिए कोई सुझाव की सराहना की जाएगी।प्रोजेक्ट यूलर # 14 और क्लोजर

(use 'clojure.test) 

(def mem (atom {})) 

(with-test 
    (defn chain-length  
    ([x] (chain-length x x 0))  
    ([start-val x c] 
     (if-let [e (last(find @mem x))] 
     (let [ret (+ c e)] 
      (swap! mem assoc start-val ret) 
      ret) 
     (if (<= x 1)    
      (let [ret (+ c 1)] 
      (swap! mem assoc start-val ret) 
      ret)     
      (if (even? x)    
      (recur start-val (/ x 2) (+ c 1)) 
      (recur start-val (+ 1 (* x 3)) (+ c 1))))))) 
    (is (= 10 (chain-length 13)))) 

(with-test 
    (defn longest-chain 
    ([] (longest-chain 2 0 0)) 
    ([c max start-num] 
     (if (>= c 1000000) 
     start-num 
     (let [l (chain-length c)] 
      (if (> l max) 
      (recur (+ 1 c) l c) 
      (recur (+ 1 c) max start-num)))))) 
    (is (= 837799 (longest-chain)))) 
+0

बस प्रोजेक्ट यूलर के लिए मुझे उजागर करने के लिए धन्यवाद देना चाहता था। मैं भी क्लोजर सीखने की कोशिश कर रहा हूं। –

+0

बेहद मामूली बिंदु, लेकिन (इंक सी) शायद (+ 1 सी) से अधिक मूर्खतापूर्ण है। –

उत्तर

3

के बाद से आप चाहते हैं कैश chain-length के सभी आमंत्रण के बीच साझा करने के लिए, आप chain-length(let [mem (atom {})] (defn chain-length ...)) के रूप में लिखते थे, ताकि इसमें केवल chain-length को दिखाई जाएगी।

इस मामले में, के बाद से सबसे लंबी चेन पर्याप्त छोटा है, तो आप अनुभवहीन पुनरावर्ती पद्धति का उपयोग करके chain-length को परिभाषित करने और उस पर Clojure के builtin memoize समारोह इस्तेमाल कर सकते हैं।

+0

धन्यवाद! अब जब आपने इसे समझाया है, तो यह स्पष्ट प्रतीत होता है। बेवकूफ रिकर्सन और यादों का उपयोग करने का विचार मेरे दिमाग को पार कर गया लेकिन मैंने सोचा कि यह एक बेहतर सीखने का अनुभव होगा और बूट करने के लिए और अधिक "स्केलेबल" होगा। – dbyrne

1

आप एक clojure में आसपास के वातावरण पर कब्जा कर सकते हैं:

(defn my-memoize [f] 
    (let [cache (atom {})] 
    (fn [x] 
     (let [cy (get @cache x)] 
     (if (nil? cy) 
      (let [fx (f x)] 
      (reset! cache (assoc @cache x fx)) fx) cy))))) 


(defn mul2 [x] (do (print "Hello") (* 2 x))) 
(def mmul2 (my-memoize mul2)) 
user=> (mmul2 2) 
Hello4 
user=> (mmul2 2) 
4 

तुम देखो mul2 funciton केवल एक बार कहा जाता है।

तो 'कैश' क्लोजर द्वारा कब्जा कर लिया गया है और मूल्यों को स्टोर करने के लिए उपयोग किया जा सकता है।

+0

यह अनिवार्य रूप से अंतर्निहित ज्ञापन कार्य सही काम करता है? मुझे नहीं लगता कि यह वर्तमान में मेरे कार्यों को लिखे जाने के तरीके के साथ काम करेगा क्योंकि रिकर्सिव कॉल में हमेशा अलग-अलग पैरामीटर होंगे, और एक कैश किए गए मान को कभी वापस नहीं किया जाएगा। – dbyrne

+0

यह वास्तव में एक मुद्दा नहीं है क्योंकि पैरामीटर में से केवल एक का उपयोग करने की आवश्यकता है। यदि एक्स पहले से ही ज्ञात है तो आप राज्य पैरामीटर के लिए कैश की गई गणना जोड़ सकते हैं। –

2

सादे पुराने memoize का उपयोग करके एक बेवकूफ (?) संस्करण है।

(def chain-length 
    (memoize 
     (fn [n] 
     (cond 
     (== n 1) 1 
     (even? n) (inc (chain-length (/ n 2))) 
     :else  (inc (chain-length (inc (* 3 n)))))))) 

(defn longest-chain [start end] 
    (reduce (fn [x y] 
      (if (> (second x) (second y)) x y)) 
      (for [n (range start (inc end))] 
      [n (chain-length n)]))) 

आप recur उपयोग करने के लिए आग्रह करता हूं है, पर विचार map या reduce पहले। वे अक्सर जो चाहते हैं वह करते हैं, और कभी-कभी इसे बेहतर/तेज़ करते हैं, क्योंकि वे चंकित सीक का लाभ उठाते हैं।

(inc x)(+ 1 x) जैसा है, लेकिन inc लगभग दोगुना तेज़ है।

+0

मैंने आपके संस्करण की कोशिश की, लेकिन (सबसे लंबी श्रृंखला 2 1000000) एक StackOverflowError का कारण बनता है। एक लाख परियोजना यूलर अभ्यास # 14 से है। –

+0

'(सबसे लंबी श्रृंखला 1 1000000) 'आज़माएं और इसे काम करना चाहिए। इसे पहले 1 के मूल्य को कैश करना होगा। –

+0

एक ही त्रुटि। मुझे आश्चर्य होगा कि अगर इसे हल किया गया है, क्योंकि (चेन-लम्बाई 2) के साथ, यह कंड में (श्रृंखला-लंबाई 1) को कॉल करता है, और उसे भी कैश किया जाएगा। यह आपके मशीन पर काम करता है मुझे लगता है? मैंने क्लोजर संस्करण 1.1 और 1.2 दोनों की कोशिश की। –

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