我对def如何以不同的方式绑定变量感到困惑。有人可以向我解释为什么会有效:
(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)
)
)
编辑:这是有效的,使用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)
)
)
答案 0 :(得分:7)
下面是这样一个例子来做你要求的。我只是为了简单而使用factorial,并在factorial中添加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
答案 1 :(得分:6)
let
形式按顺序绑定名称,因此在第二个函数定义中,当您尝试引用它时,名称l
不存在。你可以使用letfn
(带有一些小的mod)或者给定义的函数命名,而是改为引用它,如下所示:
(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
无法访问。