Jestem zdezorientowany co do tego, jak zdefiniować i pozwolić wiązać zmienne inaczej. Czy ktoś może mi wyjaśnić, dlaczego to działa:

(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)))))))

Ale kiedy próbuję zadeklarować funkcję, ponieważ niech się nie skompiluje:

(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)))

EDYCJA: To działa, używając techniki pokazanej przez Ankura.

(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
onit 18 październik 2012, 16:46

2 odpowiedzi

Najlepsza odpowiedź

Poniżej znajduje się taki przykład, aby zrobić to, o co prosiłeś. Używam silni tylko dla uproszczenia i dodałem println w silni, aby upewnić się, że zapamiętywanie działa poprawnie

(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))

Najpierw oblicz silnię 10, a potem 11, w którym to przypadku nie powinno się ponownie wywoływać silni od 10 do 1, ponieważ została ona zapamiętana.

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
8
Ankur 18 październik 2012, 20:46

Formularz let wiąże nazwy sekwencyjnie, więc w drugiej definicji funkcji nazwa l nie istnieje, gdy próbujesz się do niej odwoływać. Możesz użyć letfn (z kilkoma pomniejszymi modyfikacjami) lub nadać zdefiniowanej funkcji nazwę i zamiast tego odwołać się do niej, na przykład:

(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))

Jak możesz zauważyć, zmieniłem zwrot z let na sam l, ponieważ do tego chcesz leven być powiązany. (l x y) był problematyczny, ponieważ odnosił się do powiązań tylko lokalnych dla funkcji i niedostępnych dla let.

6
Nathan Hughes 18 październik 2012, 17:05