2010-02-28 13 views

Respuesta

8

En Clojure 1.1.0 al menos, + con dos argumentos está inline para el rendimiento. Su enlace sucede demasiado tarde. Con más argumentos, funciona de manera diferente.

Clojure 1.1.0-master-SNAPSHOT 
user=> (binding [+ -] (+ 1 2)) 
3 
user=> (binding [+ -] (+ 1 2 3)) 
-4 

Una solución es hacer que su propio espacio de nombres y la sombra clojure.core/+ con su propia función.

user=> (ns foo (:refer-clojure :exclude [+])) 
nil 
foo=> (defn + [& args] (reduce clojure.core/+ args)) 
#'foo/+ 
foo=> (+ 1 2) 
3 
foo=> (binding [+ -] (+ 1 2)) 
-1 

Tenga en cuenta que la expansión en línea parece ocurrir incluso de manera más agresiva en la instantánea actual de Clojure 1.2.0.

Clojure 1.2.0-master-SNAPSHOT 
user=> (binding [+ -] (+ 1 2)) 
3 
user=> (binding [+ -] (+ 1 2 3)) 
6 

Puede ser más prudente utilizar un nombre de función que no sea +, por ejemplo add, para evitar confusiones.

+0

Deben haber tomado esta agresiva alineación de la versión final de Clojure 1.2.0, porque la última expresión me da -4. –

6

solución rápida: use vamos en lugar de vinculante y esto va a funcionar para usted muy bien:

user=> (let [+ list] (+ 2 3)) 
(2 3) 

un poco (incompleta) clavándose en la razón:

Take un vistazo a la fuente de la función +:

(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))) 

Observe que hay varias definiciones de funciones en línea para diferentes números de argumentos. Si intenta volver a enlazar los 0 o 1 definiciones Arity, funciona muy bien:

user=> (binding [+ (fn [] "foo")] (+)) 
"foo" 
user=> (binding [+ (fn [a] (list a))] (+ 1)) 
(1) 

Ahora, esto definitivamente no funciona (como lo descubrió) para el caso 2-argumento. No estoy conectando los puntos, pero el. (forma especial) me hace sospechoso combinado con el enlace siendo un macro, mientras que let es una forma especial ...

Los metadatos que invocan especialmente arity 2 también parecen sospechosos.

Cuestiones relacionadas