2012-04-09 14 views
30

Hinweis: Es handelt sich NICHT um Nebenläufigkeit. Hier geht es um das Thread-Makro.Verallgemeinertes Threading-Makro in Clojure

Ich weiß, dass -> das Objekt an der 2. Position setzt und ->> das Argument an der letzten Position setzt. Jetzt

, ich bin neugierig, ähnlich wie die verkürzte Schreibweise von #(... %) für Funktionen gibt es eine verkürzte Schreibweise für Threads, die ich das Argument an beliebigen Standort platzieren können?

Das Ziel wäre, dass statt einer festen Stelle für den Thread durchlaufen ... Ich kann beliebige Formen schreiben und %% an besonderen Orten einfügen, und die %% ist, wo der Thread eingefügt wird.

Danke!

+0

Danke für die Frage. Ich wollte das schon ewig fragen. Manchmal muss ich (# (func-adapter arg1% arg2)) verwenden, um den gewünschten Effekt mit -> oder - >> zu erhalten. – jbear

Antwort

26

der ‚Diamant Zauberstab‘ von Swiss Arrows Bibliothek würde das tun, was Sie fragen nach:

(-<> 0 
(* <> 5) 
(vector 1 2 <> 3 4)) 
; => [1 2 0 3 4] 

Das heißt, es ist nicht etwas, das man oft am Ende brauchen (oder jemals in meiner Clojure Erfahrung)

+9

Ich mag, wie diese Makros die Flexibilität von clojure Variablennamen missbrauchen –

+2

Besser noch, ab Version 1.5, Clojure bietet 'as->' wie in [eine andere Antwort] erklärt (http://stackoverflow.com/a/17635433/109618). –

+0

Ich benutze 'as->' ziemlich oft, aber ich mag die Prägnanz und visuelle Klarheit des Diamantstabs. Gewöhnlich passiert es, wenn allgemeine Funktionen mit unterschiedlichen Eigenschaften wie "map" und "assoc" innerhalb desselben Threads verwendet werden. – ctpenrose

2

Es gab eine Bibliothek, die diese Funktion zur Verfügung stellte, aber ich vergaß wo. Es könnte in dem veralteten clojure-contrib sein. Es war das -$> Makro.

Aber man konnte man von clojure Kern -> macro ableiten, um das zu machen Sie suchen:

(defmacro -$> 
    ([x] x) 
    ([x form] (if (seq? form) 
       (with-meta (map #(if (= %1 '$) x %1) form) (meta form)) 
       (list form x))) 
    ([x form & more] `(-$> (-$> ~x ~form) [email protected]))) 

und $ verwenden, um die Einfügemarke anzuzeigen:

user=> (-$> 2 str (identity $) (println $)) 
2 
nil 

Technisch könnte man Verwenden Sie mehrere $ in einer Form. Diese Implementierung leidet jedoch daran, dass dieselbe Form mehrmals erweitert wird (im Austausch für die Einfachheit).

15

Für den Fall, dass jemand darüber stolpert, gibt es einen Grund dafür, dass die bereitgestellten Makros existieren, aber eine willkürliche Platzierung nicht: Letzteres würde zu einem schlechten API-Design führen.

Das Makro -> platziert das Argument in der ersten Position. Dies entspricht Funktionen, die an einem Subjektargument arbeiten, z. B. conj, assoc.

Der Makro ->> platziert das Argument an der letzten Position. Dies entspricht Funktionen, die an Sequenzen arbeiten, z. B. map, reduce.

Entwerfen Sie Ihre APIs gut und Sie werden weniger wahrscheinlich ein solches Makro benötigen.

+2

Gut durchdacht, Alex. Manchmal müssen Sie jedoch Daten mit Funktionen verknüpfen, die Sie nicht entworfen haben. Ich denke, man kann immer ein (# (f a1% a3)) verwenden, um es zu umgehen. – jbear

+0

'nth' ist ein gutes Beispiel für eine Kernfunktion, die auf einer Sammlung funktioniert, aber sie nicht als das letzte Argument, sondern als das erste erwartet. –

+0

'nth' gibt auch keine Sequenz wie die anderen zurück, was es gut macht, wenn man sich in verschachtelte Sequenzen vertieft. Ich denke, deshalb ist es so strukturiert. – deterb

32

Es gibt jetzt ein verallgemeinertes Threading-Makro in Clojure seit 1.5 genannt as->.

Dieser tweet gibt ein Beispiel dafür, wie es funktioniert: https://twitter.com/borkdude/status/302881431649128448

(as-> "/tmp" x 
     (java.io.File. x) 
     (file-seq x) 
     (filter (memfn isDirectory) x) 
     (count x)) 

First ‚x‘ „/ tmp“ gebunden ist und eine Datei wird aus ihm gemacht. 'x' wird erneut zur resultierenden Datei zurückgebogen und durch die 'Datei-Seq'-Funktion usw. gesetzt.

+0

Die Swiss Arrows Bibliothek macht Spaß und alles, aber das ist wahrscheinlich die beste Antwort seit 2014, da sie seit der Version 1.5 in Clojure eingebaut ist. –

+0

Github-Codebeispiele hier: https://github.com/search?q=as-%3E+extension%3A.clj&type=Code&ref=searchresults –