2012-10-18 18 views
7

मुझे उलझन में है कि कैसे भिन्न और अलग-अलग प्रकार को बाध्य करते हैं।अंदर घुसपैठ

(def leven 
    (memoize (fn [x y] 
    (cond (empty? x) (count y) 
     (empty? y) (count x) 
     :else (min (+ (leven (rest x) y) 1) 
        (+ (leven x (rest y)) 1) 
        (+ (leven (rest x) (rest y)) (if (= (first x) (first y)) 0 1)) 
      ) 
))) 
) 

लेकिन जब मैं समारोह की घोषणा करने की कोशिश यह संकलन करने में विफल रहता है जाने के रूप में: तकनीक अंकुर द्वारा पता चला है का उपयोग कर, यह काम करता है:

(def leven 
    (let [l (memoize (fn [x y] 
    (cond (empty? x) (count y) 
      (empty? y) (count x) 
      :else (min (+ (l (rest x) y) 1) 
         (+ (l x (rest y)) 1) 
         (+ (l (rest x) (rest y)) (if (= (first x) (first y)) 0 1)) 
       ) 
    ) 
    ))] 
    (l x y) 
    ) 
) 

संपादित क्यों यह काम करता है किसी ने मुझे बता सकते हैं।

(defn leven [x y] 
(let [l (memoize (fn [f x y] 
(cond (empty? x) (count y) 
     (empty? y) (count x) 
     :else (min (+ (f f (rest x) y) 1) 
        (+ (f f x (rest y)) 1) 
        (+ (f f (rest x) (rest y)) (if (= (first x) (first y)) 0 1)) 
      ) 
) 
)) 
magic (partial l l)] 
(magic x y) 
) 
) 

उत्तर

7

नीचे जो कुछ आपने पूछा है, उसके लिए ऐसा उदाहरण है। मैं सिर्फ सादगी की खातिर भाज्य उपयोग कर रहा हूँ और भाज्य में println जोड़ा यकीन Memoization ठीक

(let [fact (memoize (fn [f x] 
         (println (str "Called for " x)) 
         (if (<= x 1) 1 (* x (f f (- x 1)))))) 
     magic (partial fact fact)] 
    (magic 10) 
    (magic 11)) 

पहले 10 के भाज्य की गणना और फिर 11 जिस स्थिति में यह नहीं फिर से भाज्य 10 के लिए जब तक बुलाना चाहिए काम कर रहा है 1 जैसा कि याद किया गया है।

Called for 10 
Called for 9 
Called for 8 
Called for 7 
Called for 6 
Called for 5 
Called for 4 
Called for 3 
Called for 2 
Called for 1 
Called for 11 
39916800 
+0

बहुत रोचक। तो आप मूल रूप से केवल एक तर्क के रूप में कार्य में गुजर रहे हैं ताकि संकलक परिभाषित न किए जाने के बारे में भ्रमित न हो। मैं अब यह कोशिश नहीं कर सकता, लेकिन मैं बाद में इस दृष्टिकोण को आजमाने की कोशिश कर रहा हूं। – onit

6

let प्रपत्र नाम क्रमिक रूप से बांधता है तो अपने दूसरे समारोह परिभाषा नाम l जब आप इसे का उल्लेख करने की कोशिश मौजूद नहीं है। आप या तो letfn (कुछ मामूली mods के साथ) का उपयोग कर सकते हैं या निर्धारित फ़ंक्शन एक नाम देने और बदले में इतनी तरह के बजाय कि देखें,:

(def leven 
    (let [l (memoize (fn SOME-NAME [x y] 
    (cond 
     (empty? x) (count y) 
     (empty? y) (count x) 
     :else (min (+ (SOME-NAME (rest x) y) 1) 
       (+ (SOME-NAME x (rest y)) 1) 
       (+ (SOME-NAME (rest x) (rest y)) (if (= (first x) (first y)) 0 1))))))] 
l)) 

तो हो सकता है जैसा कि मैंने let से लौटने बदल l ही होने के लिए चूंकि आप leven से बाध्य हैं। (l x y) समस्याग्रस्त था क्योंकि यह केवल कार्य के लिए स्थानीय बाइंडिंग को संदर्भित करता था और let तक पहुंच योग्य नहीं था।

+2

क्या फ़ंक्शन कुछ-नाम उस तरह उपयोग किए जाने पर ज्ञापन के लाभ खो देता है? क्या आपको फ़ंक्शन ज्ञापन रिटर्न को कॉल करने की आवश्यकता नहीं है, या क्या एक लेट स्टेटमेंट में रिकर्सिव मेमोनाइज्ड फ़ंक्शन होना संभव नहीं है? – onit

+1

@onit परिभाषा 'लेवेन' को 'कुछ नाम' को पहले तर्क के रूप में स्थानांतरित करके ज्ञापन के लाभ प्राप्त करने के लिए संशोधित किया जा सकता है: '(एफएन [SOME-NAME xy]' और फिर कॉल को 'SOME' में बदलकर -NAME' से '(कुछ नाम कुछ नाम ...) 'और अंत में वापसी मूल्य' l' को' (आंशिक ll) 'के रूप में बदलकर। –

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