里面的递归让函数

oni*_*nit 7 recursion clojure let

我很困惑如何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))
              )
  )))
)
Run Code Online (Sandbox Code Playgroud)

但是当我尝试将函数声明为无法编译时:

(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)
    )
)
Run Code Online (Sandbox Code Playgroud)

编辑:这是有效的,使用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)
)
)
Run Code Online (Sandbox Code Playgroud)

Ank*_*kur 8

下面是这样一个例子来做你要求的.我只是为了简单而使用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))
Run Code Online (Sandbox Code Playgroud)

首先计算阶乘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
Run Code Online (Sandbox Code Playgroud)


fog*_*gus 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))
Run Code Online (Sandbox Code Playgroud)

正如你可能会注意到我改变从回letl自己,因为这是你想要的leven绑定到.这(l x y)是有问题的,因为它只引用了函数本地的绑定而且无法访问let.

  • 当像这样使用时,功能SOME-NAME是否会失去memoize的好处?你不需要调用函数memoize返回,还是不可能在let语句中有一个递归的memoized函数? (2认同)