2017-06-21 6 views
6

zum Beispiel der Luminus Webseite states dassWarum werden Compojure-Routen als Makros definiert?

Compojure Route Definitionen sind nur Funktionen, die Anfrage Karten akzeptieren und Antwortkarten zurückgeben ...

(GET "/" [] "Show something") 
... 

Aber compojure Routen sind nicht Funktionen

(defmacro GET "Generate a `GET` route." 
    [path args & body] 
    (compile-route :get path args body)) 

Man kann die Funktion make-route verwenden, die zwar Funktionen zurückgibt, aber keine Destrukturierung erlaubt. Als eine Funktion können Sie die spezielle Syntax von compojure nicht zum Zerstören verwenden (d. H. Den Vektor), aber stoppt dies jegliche Form der Destrukturierung? Erhöht das Makro von ihnen eine Leistungssteigerung?

(make-route :get "/some_path" some_handler) 

Konnte die destruktive Syntax nicht mit einem Makro-Wrapper an die Funktion übergeben werden?

Antwort

7

Ein Grund, warum Makros verwendet werden, ist, dass der Benutzer Funktions- und Symbolnamen schreiben kann, ohne alles angeben zu müssen. Nehmen Sie dieses Beispiel from the Clojure Cookbook:

; Routing 
(defroutes main-routes 
    (GET "/" [] (index)) 
    (GET "/en/" [] (index)) 
    (GET "/fr/" [] (index-fr)) 
    (GET "/:greeting/" [greeting] (view greeting))) 

Alle der index* Symbole sowie view und greeting müßte zitiert werden, wenn GET eine Funktion sind:

; Routing 
(defroutes main-routes 
    (GET "/" [] '(index)) 
    (GET "/en/" [] '(index)) 
    (GET "/fr/" [] '(index-fr)) 
    (GET "/:greeting/" '[greeting] '(view greeting))) 

Da Funktionsargumente ausgewertet werden, bevor die Funktion aufgerufen wird, , (index)et al würde ausgewertet werden, sobald das Formular gelesen wurde. Auch die greeting arg wird bei jeder HTTP-Anfrage geändert, so dass es offensichtlich nicht vorher bekannt ist.

Das Makro kümmert sich auch um alle Destrukturierungszauber, die mit einer normalen Funktion (normalerweise) nicht möglich sind.

Die Sache, die oft verwirrend ist (und nicht gut für Anfänger erklärt), ist, dass eine Zeile wie:

(GET "/:greeting/" [greeting] (view greeting)) 

nicht normal „Clojure Code“ ist. Stattdessen ist es eine Art Kurzschrift (domänenspezifische Sprache oder DSL, um präzise zu sein), die das GET Makro aufnehmen und als Anweisungen verwenden wird, um "legalen" Clojure-Code zu generieren. Die DSL ist normalerweise viel kürzer, einfacher, & bequemer für einen Menschen als der endgültige generierte Code, genauso wie Clojure ist viel kürzer, einfacher, & bequemer als die Java-Bytecode von der Clojure-Compiler oder der Maschine Assembler-Code schließlich produziert produziert von der JVM.

Kurz gesagt, jedes Makro ist ein "Pre-Compiler", der das DSL in Clojure umwandelt, das dann vom Clojure-Compiler zur Erzeugung von Java-Bytecode aufgenommen wird.

auch sagen, dass es konnte neu angeordnet werden, um alle Makro Magie in die defroutes Makro zu setzen, so dass die GET Symbol weder eine Funktion noch ein Makro war, sondern nur eine Art von Markierung wie die :get Schlüsselwort in der Implementierung. Als Benutzer sind diese Arten von Implementierungsdetails normalerweise nicht wichtig.

aktualisieren

Am besten ist es Makros nur zu verwenden, wenn eine Funktion nicht funktionieren oder ist sehr umständlich. Der entscheidende Faktor ist in der Regel, wenn man nackte (nicht notierte) Symbole verwenden, aber nicht im Voraus auswerten möchte. Core Clojure selbst verwendet Makros für viele Konstrukte, die in anderen Sprachen "eingebaut" sind, einschließlich defn, , or, when und andere.

Beachten Sie auch, dass ein Makro kann einige Dinge eine Funktion kann, wie ein Parameter zu einer Funktion höherer Ordnung wie filter.

Zusammenfassend definiert eine Funktion ein Verhalten. Ein Makro definiert eine Spracherweiterung.

+0

Wenn GET eine Funktion wäre, würde '(Gruß anzeigen)' überhaupt keinen Sinn ergeben. Du müsstest etwas mehr schreiben wie '(GET" /: Gruß "(fn [req] (let-request [Gruß] req] (Gruß anzeigen))))', was umständlich, aber nicht unmöglich ist. – amalloy

+0

Der Funktionsansatz müsste für die meisten Funktionen "eval" verwenden, weshalb die Makrolösung sehr bevorzugt ist. –

+0

@AlanThompson - reine Neugier. Ich bin kein großer Fan von Makros, da ich glaube, dass sie oft verunstalten, was wirklich passiert. Immer interessiert, wenn Projekte sie stark verwenden (Designentscheidungen usw.). Gerade gefunden "Bidi" - der Datenstruktur Ansatz spricht zu mir auf einer spirituellen Ebene. – beoliver

Verwandte Themen