谁能解释为什么我可以重新绑定列表但不能+?
(binding [list vector]
(list 1 3))
(binding [list +]
(list 1 3))
(binding [+ list]
(+ 1 3))
我想重新绑定 + 以便我可以进行部分评估。
谁能解释为什么我可以重新绑定列表但不能+?
(binding [list vector]
(list 1 3))
(binding [list +]
(list 1 3))
(binding [+ list]
(+ 1 3))
我想重新绑定 + 以便我可以进行部分评估。
至少在 Clojure 1.1.0 中,+
内联了两个参数以提高性能。你的绑定发生得太晚了。有了更多的论点,它的工作方式就不同了。
Clojure 1.1.0-master-SNAPSHOT
user=> (binding [+ -] (+ 1 2))
3
user=> (binding [+ -] (+ 1 2 3))
-4
clojure.core/+
一种解决方法是使用自己的函数创建自己的命名空间和影子。
user=> (ns foo (:refer-clojure :exclude [+]))
nil
foo=> (defn + [& args] (reduce clojure.core/+ args))
#'foo/+
foo=> (+ 1 2)
3
foo=> (binding [+ -] (+ 1 2))
-1
请注意,在 Clojure 1.2.0 的当前快照中,内联似乎更加激进。
Clojure 1.2.0-master-SNAPSHOT
user=> (binding [+ -] (+ 1 2))
3
user=> (binding [+ -] (+ 1 2 3))
6
使用 以外的函数名可能是最明智的+
,例如add
,以避免混淆。
快速解决方法:使用let而不是绑定,这对您很有效:
user=> (let [+ list] (+ 2 3))
(2 3)
稍微(不完整)挖掘原因:
看一下 + 函数的源代码:
(defn +
"Returns the sum of nums. (+) returns 0."
{:inline (fn [x y] `(. clojure.lang.Numbers (add ~x ~y)))
:inline-arities #{2}}
([] 0)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (add x y)))
([x y & more]
(reduce + (+ x y) more)))
请注意,对于不同数量的参数,有几个内联函数定义。如果您尝试重新绑定 0 或 1 arity 定义,它工作得很好:
user=> (binding [+ (fn [] "foo")] (+))
"foo"
user=> (binding [+ (fn [a] (list a))] (+ 1))
(1)
现在,对于 2 参数的情况,这绝对不起作用(正如您所发现的)。我没有把这些点联系起来,但是 . (特殊形式)让我怀疑绑定是一个宏,而 let 是一种特殊形式......
特别提到 arity 2 的元数据似乎也很可疑。