2017-02-05 144 views
0

我正在查看memoize的来源。 从像C++/Python这样的语言的到来,这部分打我辛苦: (let [mem (atom {})] (fn [& args] (if-let [e (find @mem args)] ...clojure什么时候删除变量?

我意识到memoize返回功能,但对于存储状态,它采用的是当地的“变量” mem。但memoize还原函数,不应该从外部让范围消失。功能如何仍然可以参考mem

为什么Clojure不删除该外部变量,以及它如何管理变量名称。就像假设,我做了另一个memoized函数,然后memoize使用另一个mem。这个名字是不是与早期的mem相冲突?

P.S:我在想,一定有很多的东西可以在那里发生的事情,是防止,所以我写了自己是一个容易的版本,即是这样http://ideone.com/VZLsJp,但目前仍然可以工作,如memoize

+0

@Flimzy,谢谢你的好评:D –

回答

5

如果没有线程可以访问它们,那么对象是垃圾收集的,按照通常的JVM语言。如果线程引用了memoize返回的函数,并且该函数具有对mem中原子的引用,则传递原子仍然可以访问。

但是memoize函数返回后,不应该从外部让范围消失。函数如何仍然可以引用mem。

这就是所谓的closure。如果一个函数是使用其环境中的名称来定义的,那么它会在后面保留对该值的引用 - 即使定义环境已经消失,并且函数是唯一可以访问的东西。

就像假设我做了另一个memoized函数,然后memoize使用另一个mem。这个名字是不是与早期的MEM冲突?

不,可能会让程序员混淆。有多个范围,每个都声明自己的名字mem是非常有可能的,并且lexical scoping的常规规则用于确定在读取mem时的含义。有一些棘手的边界情况,如

(let[foo 2] 
    (let[foo (fn[] foo)] ;; In the function definition, foo has the value from the outer scope 
    ;; because the second let has not yet bound the name 
    (foo))) ;; => 2. 

,但一般的想法很简单 - 一个名称的值是最接近的程序文本的地方所定义的,一个是使用 - 无论是在本地范围或最接近的外部范围。 memoize的不同调用创建不同的闭包,因此名称mem引用每个返回函数中的不同原子。

+1

谢谢!学到新东西:在Clojure关闭。 :) –

+1

以防万一,[Python也有关闭](http://stackoverflow.com/a/4020443/4534687)! –

相关问题