Почему я не могу связать + в clojure? - PullRequest
9 голосов
/ 28 февраля 2010

Может кто-нибудь объяснить, почему я могу перепривязать список, но не +?

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

Я бы хотел перепривязать +, чтобы я мог выполнить частичную оценку.

Ответы [ 2 ]

8 голосов
/ 28 февраля 2010

В 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, чтобы избежать путаницы.

6 голосов
/ 28 февраля 2010

Быстрый обходной путь: используйте 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)

Теперь, это определенно не работает (как вы обнаружили) для случая с двумя аргументами. Я не совсем соединяю точки, но. (особая форма) делает меня подозрительным в сочетании с макросом привязки, тогда как пусть это особая форма ...

Метаданные, специально вызывающие arity 2, также кажутся подозрительными.

...