2012-06-11 17 views
5

Sto provando a scrivere una macro che sviluppi middleware simile a quella usata in compojure.Macro Clojure che crea una funzione di ordine superiore da una funzione

voglio essere in grado di chiamare:

(def-middleware plus-two [x] 
    (+ 2 x)) 

E avere il risultato assomigliare:

(defn plus-two [f] 
(fn [x] 
    (f (+ 2 x))) 

ho fino a questo punto dalla lettura guide on-line, ma non è il lavoro fuori per me:

(defmacro def-middleware [fn-name args & body] 
    '(defn ~fn-name [f] 
    (fn ~args 
     (f [email protected])))) 

Qualsiasi aiuto o un puntatore a una migliore guida per la scrittura di macro sarebbe fantastico, grazie.

+0

Come funziona per te? –

+0

CompilerException java.lang.RuntimeException: il primo argomento di def deve essere un simbolo, la compilazione: (NO_SOURCE_PATH: 33) – jdoig

+0

usa il back-tick, non la virgoletta singola – Alex

risposta

8

Vediamo cosa macroexpand-1 ci dà:

user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x)))) 
(defn 
~fn-name 
[f] 
$ 
(fn ~args$ (f (clojure.core/unquote-splicing body)))) 

Non esattamente ciò che stiamo cercando! Per prima cosa: se si desidera rimuovere unquote in una macro, è necessario utilizzare "` "(l'operatore quasiquote/syntax-quote), non" '". Inoltre, non sono sicuro di cosa stai cercando con quei segni di dollaro, ma è che stai andando per la scorciatoia pratico del clojure per l'utilizzo di gensym per l'igiene. Ma ne hai bisogno subito dopo ogni identificatore con cui lo usi (quindi [f#], non [f]$) e ne hai bisogno su ogni occorrenza dell'identificatore. E tu non ne hai bisogno con args. Mettendo insieme tutto questo:

user=> (defmacro def-middleware [fn-name args & body] `(defn ~fn-name [f#] (fn ~args (f# [email protected])))) 
#'user/def-middleware 
user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x)))) 
(clojure.core/defn 
plus-two 
[f__594__auto__] 
(clojure.core/fn [x] (f__594__auto__ (+ 2 x)))) 
nil 
user=> 
+0

Ci scusiamo per il modulo $ dove copiare e incollare da vim. E hai ragione era il # mi mancava :) grazie. – jdoig

3

Forse questo è solo un esercizio di macro, ma l'esempio specifico di definire una funzione middleware non è buona - si perde un sacco di flessibilità che il concetto middleware ti dà. Ad esempio, perché questo dovrebbe valutare (f (+ 2 x)) anziché (+ 2 (f x))? Entrambi sono modi sensati per avvolgere questa funzione e la sintassi non consente di descrivere quest'ultima. In realtà, la semplice definizione di una funzione-ritorno-funzione è flessibile, semplice e facile; questa macro porta poco in tavola.

+0

Grazie amalloy; Lo sto usando come un trampolino di lancio per imparare le macro e anche per costruire funzioni di costruzione del middleware più specifiche rispetto a questo grande e stupido che avvolge solo qualcosa ... Come hai ragione, com'è attualmente, questo non può cortocircuitare, ecc. e non è descrittivo su come avvolge le cose, ecc. – jdoig

Problemi correlati