为什么我不能在clojure中绑定+?

时间:2010-02-28 18:58:50

标签: binding clojure evaluation partial

任何人都可以解释为什么我可以重新列出列表而不是+?

(binding [list vector]
  (list 1 3))
(binding [list +]
  (list 1 3))
(binding [+ list]
  (+ 1 3))

我想重新绑定+所以我可以进行部分评估。

2 个答案:

答案 0 :(得分:8)

至少在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,以避免混淆。

答案 1 :(得分:6)

快速解决方法:使用代替绑定,这对你很有用:

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的元数据似乎也很可疑。