2012-04-09 17 views
30

Nota: questo NON riguarda la concorrenza. Riguarda la macro del thread.Macro di filettatura generalizzata in clojure

So che -> mette l'oggetto in seconda posizione e ->> pone l'argomento nell'ultima posizione.

Ora, io sono curioso, proprio come la breve notazione di mano del #(... %) per le funzioni, v'è una breve notazione di mano per le discussioni che mi permette di collocare l'argomento al arbitraria posizione?

L'obiettivo sarebbe che invece di avere una posizione fissa per il thread da eseguire ... Posso scrivere moduli arbitrari e inserire %% in punti speciali, e il %% è dove viene inserito il thread.

Grazie!

+0

Grazie per la domanda. Volevo chiederlo da secoli. A volte devo usare (# (func-adapter arg1% arg2)) per ottenere l'effetto desiderato con -> o - >>. – jbear

risposta

26

Il 'diamante bacchetta' dal Swiss Arrows biblioteca sarebbe fare quello che stai chiedendo:

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

Detto questo, non è qualcosa che si finisce per dover spesso (o sempre nella mia esperienza Clojure)

+9

Mi piace come queste macro abusino della flessibilità dei nomi delle variabili clojure –

+2

Meglio ancora, dalla versione 1.5, Clojure fornisce 'as->' come spiegato in [un'altra risposta] (http://stackoverflow.com/a/17635433/109618). –

+0

Uso 'as->' abbastanza spesso, ma mi piace la concisione e la chiarezza visiva della bacchetta diamantata. Solitamente accade quando le funzioni comuni con aritmetica diversa, come 'map' e' assoc', sono usate all'interno della stessa discussione. – ctpenrose

2

C'era una libreria che ha fornito questa funzione, ma ho dimenticato dove. Potrebbe essere stato nel deprecabile clojure-contrib. Era la macro -$>.

Ma si potrebbe ricavare uno dal nucleo di clojure -> macro a fare quello che stai cercando:

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

E utilizzare $ per indicare il punto di inserimento:

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

Tecnicamente, si potrebbe utilizzare più $ in un unico modulo. Ma questa implementazione soffre di espandere la stessa forma più volte (in cambio della semplicità).

15

Nel caso in cui qualcun altro si imbatta in questo, c'è un motivo per cui esistono i macro forniti, ma uno non lo pone arbitrariamente: il secondo porterebbe a una progettazione API scadente.

La macro -> inserisce l'argomento nella prima posizione. Ciò corrisponde a funzioni che funzionano su argomenti di alcuni argomenti, ad esempio conj, assoc.

La macro ->> inserisce l'argomento nell'ultima posizione. Ciò corrisponde a funzioni che funzionano su sequenze, ad esempio map, reduce.

Progettate bene le vostre API e avrete meno probabilità di aver bisogno di una tale macro.

+2

Ben ragionato, Alex. Sebbene a volte sia necessario suddividere i dati attraverso funzioni che non sono state progettate. Immagino che si possa sempre usare un (# (f a1% a3)) per aggirarlo. – jbear

+0

'nth' è un buon esempio di una funzione di base che funziona su una raccolta ma che non si aspetta come l'ultima arg ma come la prima. –

+0

'nth' inoltre non restituisce una sequenza come le altre, rendendola funzionante quando si scava in una sequenza nidificata. Penso che sia per questo che è strutturato in questo modo. – deterb

32

Esiste ora una macro di threading generalizzata in Clojure dal 1.5 denominata as->.

questo tweet dà un esempio di come funziona: https://twitter.com/borkdude/status/302881431649128448

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

primo 'x' è destinata a "/ tmp" e un file è fatto fuori di esso. 'x' viene rimandato di nuovo al file risultante e una put attraverso la funzione 'file-seq', ecc.

+0

La biblioteca Swiss Arrows è divertente e tutto, ma questa è probabilmente la migliore risposta del 2014, poiché è stata costruita in Clojure dalla versione 1.5. –

+0

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

Problemi correlati