Clojure 在映射内部使用的函数上使用redefs

Clojure 在映射内部使用的函数上使用redefs,clojure,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

我想知道下面的片段中发生了什么。为什么在不强制对序列求值的情况下不能正确地重新定义函数

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> 

谢谢

不同之处在于,当调用
foo
时,
vector
作为
map
的一个参数,将被计算一次(在本例中,这意味着将其解析为函数对象),而无需再次解析。即使您的代码使用redefs退出
,也会使用相同的函数对象

然而,在
bar
中,
vector
不是
map
的参数,而是一个匿名函数,它按名称引用
vector
。结果是,虽然匿名函数只计算一次,
vector
将在每次调用匿名函数时解析。因为
map
是惰性的,所以这是在代码已经使用redefs退出
之后发生的(除了您的力评估时)

关键的一点是,在函数调用中,如
(映射向量(范围3))
,每个参数都会被计算,调用函数会得到这些计算的结果。这意味着
map
调用
foo
将获得重新定义的
向量
,而
map
调用
bar
将获得一个函数,调用该函数时仍需按名称查找
vector

org提供了一些关于如何将符号解析为对象的详细信息。这也是一个例子