recursion clojure let

Recursion dentro de la funcion de dejar



clojure let (2)

A continuación se muestra un ejemplo de cómo hacer lo que ha pedido. Estoy usando factorial solo por simplicidad y he imprimido en factorial para asegurarme de que la memorización funciona bien

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

Primero calcule el factorial de 10 y luego 11, en cuyo caso no debería volver a llamar factorial de 10 a 1 como se ha memorizado.

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

Estoy confundido en cuanto a cómo def y dejo variables de vinculación de manera diferente. ¿Puede alguien explicarme por qué esto funciona?

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

Pero cuando trato de declarar la función como deja que no compile:

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

EDITAR: Esto funciona, usando la técnica mostrada por Ankur.

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


La forma let enlaza los nombres secuencialmente, por lo que en su segunda definición de función, el nombre l no existe cuando intenta hacer referencia a él. Puede usar letfn (con algunos mods menores) o darle un nombre a la función definida y en su lugar referirse a eso, así:

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

Como puedes notar, cambio el retorno del let to be l , ya que eso es lo que quieres leven . El (lxy) era problemático porque se refería a enlaces solo locales a la función y no accesibles para el let .