2010-02-28 18 views

Antwort

8

In Clojure 1.1.0 mindestens, + mit zwei Argumente ist für die Leistung inline. Deine Bindung passiert zu spät. Mit mehr Argumenten funktioniert es anders.

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

Eine Abhilfe ist, einen eigenen Namensraum zu machen und clojure.core/+ mit Ihrer eigenen Funktion Schatten.

Beachten Sie, dass das Inlining im aktuellen Snapshot von Clojure 1.2.0 anscheinend noch aggressiver abläuft.

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

Es kann sein, weiseste einen Funktionsnamen andere als + zu verwenden, z.B. add, um Verwirrung zu vermeiden.

+0

Sie müssen das aggressive Inlining aus dem endgültigen Build von Clojure 1.2.0 genommen haben, weil der letzte Ausdruck mir -4 gibt. –

6

Schnell Abhilfe: Verwenden Sie lassen statt Bindung und das wird gut für Sie arbeiten:

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

Eine kleine (unvollständige) in den Grund zu graben:

Nehmen ein Blick auf die Quelle für die + Funktion:

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

Beachten Sie, dass es mehrere Inline-Funktionsdefinitionen für unterschiedliche Anzahlen von Argumenten gibt. Wenn Sie versuchen, die 0 oder 1 arity Definitionen erneut zu binden, es funktioniert ganz gut:

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

Nun, dies auf jeden Fall funktioniert nicht (wie Sie entdeckt) für den 2-Argument Fall. Ich verbinde die Punkte nicht ganz, aber die. (spezielles Formular) macht mich verdächtig kombiniert mit Bindung als Makro, während es eine spezielle Form ist ...

Die Metadaten, die besonders arity 2 aufrufen, erscheinen ebenfalls verdächtig.

Verwandte Themen