Кто-либо может объяснить, почему я могу снова переплести список, но не +?
(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
Возможно, будет разумнее использовать имя функции, отличное от +
, например добавить
, чтобы избежать путаницы.
Быстрое решение: используйте 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, это сработает нормально:
user=> (binding [+ (fn [] "foo")] (+))
"foo"
user=> (binding [+ (fn [a] (list a))] (+ 1))
(1)
Теперь это определенно не работает (как вы обнаружили) для случая с двумя аргументами. Я не совсем понимаю, но. (специальная форма) вызывает у меня подозрение в сочетании с привязкой, являющейся макросом, тогда как let - это особая форма ...
Метаданные, специально вызывающие arity 2, также кажутся подозрительными.