2010-02-28 7 views

Répondre

8

Dans Clojure 1.1.0 au moins, + avec deux arguments est inline pour les performances. Votre liaison arrive trop tard. Avec plus d'arguments cela fonctionne différemment.

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

Une solution de contournement est de faire votre propre espace de noms et l'ombre clojure.core/+ avec votre propre fonction.

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

Notez que inline semble se produire encore plus agressive dans l'instantané actuel de Clojure 1.2.0.

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

Il peut être sage d'utiliser un nom de fonction autre que +, par exemple add, pour éviter toute confusion.

+0

Ils doivent avoir pris cette ligne agressive hors de la version finale de Clojure 1.2.0, parce que la dernière expression me donne -4. –

6

solution rapide: utiliser nous au lieu de lier et cela fonctionnera pour vous très bien:

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

Un peu (incomplet) creuser dans la raison:

Prenez un coup d'oeil à la source pour la fonction +:

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

Notez qu'il existe plusieurs définitions de fonctions en ligne pour différents nombres d'arguments. Si vous essayez de lier à nouveau les 0 ou 1 Définitions arity, il fonctionne très bien:

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

Maintenant, cela ne fonctionne pas vraiment (comme vous avez découvert) pour le cas 2-argument. Je ne suis pas tout à fait en train de relier les points, mais le. (forme spéciale) me rend suspicieux combiné avec la liaison étant une macro tandis que let est une forme spéciale ...

Les métadonnées appelant spécialement arity 2 semblent également suspectes.

Questions connexes