with-redefs在地图中使用的函数

kon*_*onr 4 clojure

我想知道下面的片段中发生了什么.为什么在不强制评估序列的情况下不正确地重新定义函数?

user> (defn foo [] (map vector (range 3)))
#'user/foo
user> (defn bar [] (map #(vector %) (range 3)))
#'user/bar
user> (foo)
([0] [1] [2])
user> (bar)
([0] [1] [2])
user> (with-redefs [vector (fn [_] "what does the fox say?")] (foo))
("what does the fox say?" "what does the fox say?" "what does the fox say?")
user> (with-redefs [vector (fn [_] "what does the fox say?")] (bar))
([0] [1] [2])
user> (with-redefs [vector (fn [_] "what does the fox say?")] (vec (bar)))
["what does the fox say?" "what does the fox say?" "what does the fox say?"]
user> 
Run Code Online (Sandbox Code Playgroud)

谢谢!

jbm*_*jbm 6

不同之处在于,当您调用foovector,作为参数map被评估(在这种情况下意味着将其解析为函数对象),并且不需要再次解析.即使在您的代码退出后,也会使用相同的函数对象with-redefs.

bar,但是,它是不是vector这是一个参数map,而是一个匿名函数的引用vector的名字.结果是,虽然匿名函数只被评估一次,但vector每次调用匿名函数时都会解析.因为map是懒惰的,所以在代码已经退出之后就会发生这种情况with-redefs(除了你的力量评估时).

关键点在于函数调用 - 就像(map vector (range 3))- 每个参数都被评估,调用函数得到那些评估的结果.这意味着map调用foo获得重新定义vector,而map调用bar获取一个函数,在调用它时仍需要按vector名称查找.

有关评估的Clojure.org 页面提供了有关如何将符号解析为对象的一些详细信息.这也是后期绑定的一个例子.