2016-05-06 9 views
2

Ich bin mir nicht sicher, dass dies der beste Ort zum Posten ist, aber warum nicht 2) funktioniert? Führt das Threading-Makro das Ergebnis von seq nicht in (map str)?Clojure threading Makro

;; 1 
(map str (seq (str (* 8 8)))) -> ("6" "4") 

;; 2 
(defn a [x y] 
    (-> (* x y) 
     str 
     seq 
     (map str))) 


(a 8 8) -> Don't know how to create ISeq from: clojure.core$str 

Antwort

6

Sie verwenden die thread-first Makro, die jede Form wie das zweite Element des nächsten fügt, wie folgt aus:

(-> (* x y) str seq (map str)) 
(-> (str (* x y)) seq (map str)) 
(-> (seq (str (* x y))) (map str)) 
(map (seq (str (* x y))) str) 

Was Sie wollen, ist das thread-last Makro:

(defn a [x y] 
    (->> (* x y) str seq (map str))) 

(a 8 8) ;=> ("6" "4") 
3

wie Elogent darauf hinweist, dass das Makro die Argumente falsch platziert. In der Regel, wenn die Arbeit mit Makros (und Schreiben von ihnen vor allem) es hilft über macroexpand-1 und kombinieren es mit clojure.pprint/pprint zu wissen, eine klare Sicht zu bekommen, was läuft eigentlich:

user> (clojure.pprint/pprint 
     (macroexpand-1 
     '(-> (* x y) 
      str 
      seq 
      (map str)))) 
(map (seq (str (* x y))) str) 
nil 

Was wir nicht recht sehen aussehen Recht. Also das nächste Geige wir mit ihm, bis er sich ausdehnt, was wir erwarten:

user> (clojure.pprint/pprint 
     (macroexpand-1 
     '(->> (* x y) 
       str 
       seq 
       (map str)))) 
(map str (seq (str (* x y)))) 
nil 

Es gibt eine Vielzahl von Threading-Makros sind mit Situationen wie dieser zu helfen, vor allem as->, die Sie mit dem Gewinde Wert geben einen expliziten Namen können, wenn Sie müssen Funktionen einzufädeln, die das erste und das letzte Argument für den wichtigen Beitrag bei abwechselnder Verwendung:

user> (as-> (* 7 42) x 
     (str x) 
     (seq x) 
     (map str x)) 
("2" "9" "4") 
+0

Sehr nützlich, danke für den Tipp! – jeemar

1

Hier ist eine Alternative, die gut zu wissen, (von rechts gelesen hat, nach links):

(defn a [x y] 
    ((comp (partial map str) seq str *) 
    x y)) 

Dies kann in Kontexten nützlich sein, in denen Sie die anzuwendenden Transformationen von den Daten unterscheiden möchten, auf die sie angewendet werden (ich würde es begrüßen, wenn Kritik zu diesem Thema vorliegt).

+1

Ihre Absicht ist gut, aber da Sie die Transformation und die Daten bereits in die "a" -Funktion integrieren, gewinnen Sie hier nichts. –

1

Sie könnten auch die Verwendung des it-> Threading-Formulars von the Tupelo library in Erwägung ziehen, das entwickelt wurde, um Thread-First-Thread-Last-Sorgen zu vermeiden. Betrachten Sie diesen Code:

(ns clj.core 
    (:use tupelo.core)) 

(defn a [x y] 
    (it-> (* x y) 
     (str it) 
     (seq it) 
     (map str it))) 

(spyx (a 8 8)) 

(defn -main []) 

Welche produziert:

(a 8 8) => ("6" "4") 

Der it-> Makro verwendet den Platzhalter it explizit zu wählen, wo das Ergebnis jeder aufeinanderfolgenden Form zu platzieren. Dies ist eine einfache Möglichkeit, den Code zu vereinfachen und diese Art von Fehlern zu vermeiden.

+0

Danke für den Vorschlag. Es sieht aus wie eine hübsche süße Bibliothek. – jeemar