clojure什么时候删除变量?
When does clojure remove a variable?
我正在查看 memoize
的来源。
来自 C++/Python 等语言,这部分让我印象深刻:
(let [mem (atom {})] (fn [& args] (if-let [e (find @mem args)] ...
我意识到 memoize
returns 一个函数,但是为了存储状态,它使用了本地 "variable" mem
。但是 after memoize
returns 这个函数,不应该让那个外部 let 从作用域中消失。函数怎么还引用了mem
.
为什么 Clojure 不删除那个外部变量,它是如何管理变量名的。假设我创建了另一个记忆函数,然后 memoize
使用另一个 mem
。这个名字和之前的 mem
不冲突吗?
P.S.: 我在想一定有很多事情发生在那里,阻止了那件事,所以我给自己写了一个更简单的版本,那就是像 http://ideone.com/VZLsJp ,但仍然像 memoize
.
如果没有线程可以访问对象,则对象是可回收的,这是 JVM 语言的惯例。如果一个线程引用了 memoize
返回的函数,并且该函数引用了 mem
中的原子,那么该原子仍然可以传递地访问。
But after memoize returns the function, shouldn't that outer let vanish from scope. How can the function still refer to the mem.
这就是所谓的closure。如果一个函数是使用其环境中的名称定义的,它会在之后保留对该值的引用 - 即使定义环境已经消失并且该函数是唯一可以访问的东西。
Like suppose, I make another memoized function, then memoize uses another mem. Doesn't that name clash with the earlier 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
在每个返回的函数中引用不同的原子。
我正在查看 memoize
的来源。
来自 C++/Python 等语言,这部分让我印象深刻:
(let [mem (atom {})] (fn [& args] (if-let [e (find @mem args)] ...
我意识到 memoize
returns 一个函数,但是为了存储状态,它使用了本地 "variable" mem
。但是 after memoize
returns 这个函数,不应该让那个外部 let 从作用域中消失。函数怎么还引用了mem
.
为什么 Clojure 不删除那个外部变量,它是如何管理变量名的。假设我创建了另一个记忆函数,然后 memoize
使用另一个 mem
。这个名字和之前的 mem
不冲突吗?
P.S.: 我在想一定有很多事情发生在那里,阻止了那件事,所以我给自己写了一个更简单的版本,那就是像 http://ideone.com/VZLsJp ,但仍然像 memoize
.
如果没有线程可以访问对象,则对象是可回收的,这是 JVM 语言的惯例。如果一个线程引用了 memoize
返回的函数,并且该函数引用了 mem
中的原子,那么该原子仍然可以传递地访问。
But after memoize returns the function, shouldn't that outer let vanish from scope. How can the function still refer to the mem.
这就是所谓的closure。如果一个函数是使用其环境中的名称定义的,它会在之后保留对该值的引用 - 即使定义环境已经消失并且该函数是唯一可以访问的东西。
Like suppose, I make another memoized function, then memoize uses another mem. Doesn't that name clash with the earlier 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
在每个返回的函数中引用不同的原子。