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
.