2012-06-11 9 views
5

Ich versuche, ein Makro zu schreiben, das Middleware ähnlich wie in Compojure erstellt.Clojure-Makro, das eine Funktion höherer Ordnung von einer Funktion erstellt

Ich möchte rufen können:

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

Und haben das Ergebnis wie folgt aussehen:

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

ich diese Online-weit haben Führer aus der Lektüre aber es funktioniert nicht aus für mich:

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

Jede Hilfe oder ein Zeiger auf eine bessere Macro Writing Guide wäre toll, danke.

+0

Wie funktioniert es nicht für Sie? –

+0

CompilerException java.lang.RuntimeException: Das erste Argument zu def muss ein Symbol sein, kompilieren: (NO_SOURCE_PATH: 33) – jdoig

+0

Verwenden Sie die Back-Tick, nicht das einfache Zitat – Alex

Antwort

8

Mal sehen, was macroexpand-1 gibt uns:

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

nicht genau das, was wir nach! Das Wichtigste zuerst: Wenn Sie Dinge in einem Makro auflösen möchten, müssen Sie "` "(den Quasi-Anführungszeichen/Syntax-Anführungszeichen-Operator) verwenden, nicht" '". Ich bin mir auch nicht sicher, was Sie mit diesen Dollarzeichen suchen, aber es könnte sein, dass Sie für die praktische Abkürzung der clojure für die Verwendung gensym für die Hygiene gehen. Aber Sie brauchen es sofort nach jedem Bezeichner, mit dem Sie es verwenden (also [f#], nicht [f]$), und Sie benötigen es bei jedem Auftreten des Bezeichners. Und Sie nicht brauchen es mit args. das alles zusammen setzen:

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

Entschuldigung das $ wo Formular kopieren und einfügen von vim. Und du hast Recht es war die # die ich vermisste :) danke. – jdoig

3

Vielleicht ist dies nur eine Makro Übung, aber das spezifische Beispiel eine Middleware-Funktion zu definieren, ist nicht gut - Sie verlieren viel von der Flexibilität, dass das Middleware-Konzept gibt Ihnen. Zum Beispiel, warum sollte dies (f (+ 2 x)) anstelle von (+ 2 (f x)) auswerten? Beide sind sinnvolle Möglichkeiten, diese Funktion zu umschließen, und Ihre Syntax bietet keine Möglichkeit, diese zu beschreiben. Wirklich nur eine Funktionsrückgabe-Funktion zu definieren ist flexibel, einfach und einfach; Dieses Makro bringt wenig auf den Tisch.

+0

Danke amalloy; Ich benutze es als Sprungbrett, um sowohl Makros zu lernen als auch spezifischere Middleware-ähnliche Gebäudefunktionen zu entwickeln, im Gegensatz zu diesem großen, dummen, der nur etwas umhüllt ... Wie du jetzt recht hast, dieses kann nicht kurzschließen, usw. und es ist nicht beschreibend darüber, wie es Dinge wickelt, usw. – jdoig

Verwandte Themen