Suche…
Syntax
- Das
'
Symbol im macroexpand Beispiel verwendet wird , ist nur syntaktischer Zucker für dasquote
Operator. Sie hätten(macroexpand (quote (infix 1 + 2)))
schreiben können.
Bemerkungen
Makros sind nur Funktionen, die zur Kompilierzeit ausgeführt werden, dh während des eval
Schritts in einer Read-Eval-Print-Schleife .
Reader-Makros sind eine andere Form von Makros, die zur Lesezeit und nicht zur Kompilierzeit erweitert werden.
Best Practice beim Definieren eines Makros.
- Alpha-Umbenennung, Da sich ein Konflikt mit dem Namen der Bindungsnamen für das Expandieren ergibt. Bindungskonflikte lassen sich bei Verwendung des Makros nicht sehr intuitiv lösen. Wenn ein Makro dem Gültigkeitsbereich eine Bindung hinzufügt, ist es daher obligatorisch, das
#
am Ende jedes Symbols zu verwenden.
Einfaches Infix-Makro
Clojure verwendet die Präfixnotation, dh: Der Operator steht vor seinen Operanden.
Eine einfache Summe aus zwei Zahlen wäre zum Beispiel:
(+ 1 2) ;; => 3
Mithilfe von Makros können Sie die Clojure-Sprache bis zu einem gewissen Grad bearbeiten. Sie könnten beispielsweise ein Makro implementieren, mit dem Sie Code in Infix-Notation schreiben können (z. B. 1 + 2
):
(defmacro infix [first-operand operator second-operand]
"Converts an infix expression into a prefix expression"
(list operator first-operand second-operand))
Brechen wir auf, was der Code oben macht:
-
defmacro
ist ein spezielles Formular, mit dem Sie ein Makro definieren. -
infix
ist der Name des Makros, das wir definieren. -
[first-operand operator second-operand]
sind die Parameter, die dieses Makro erwartet, wenn es aufgerufen wird. -
(list operator first-operand second-operand)
ist der Körper unseres Makros. Es erstellt einfach einelist
mit den Werten der Parameter, die für dasinfix
Makro bereitgestellt werden, und gibt diese zurück.
defmacro
ist eine spezielle Form, da sie sich im Vergleich zu anderen Clojure-Konstrukten etwas anders verhält: Ihre Parameter werden nicht sofort ausgewertet (wenn wir das Makro aufrufen). Das erlaubt uns etwas zu schreiben:
(infix 1 + 2)
;; => 3
Das infix
Makro erweitert die 1 + 2
Argumente in (+ 1 2)
Dies ist eine gültige Clojure-Form, die ausgewertet werden kann.
Wenn Sie sehen möchten, was das infix
Makro generiert, können Sie den macroexpand
Operator verwenden:
(macroexpand '(infix 1 + 2))
;; => (+ 1 2)
macroexpand
der Name impliziert, erweitert macroexpand
das Makro (in diesem Fall wird das infix
Makro verwendet, um 1 + 2
in (+ 1 2)
umzuwandeln). Das Ergebnis der Makroerweiterung wird jedoch nicht von bewertet Clojures Dolmetscher
Zitieren und Aufheben von Anführungszeichen
Beispiel aus der Standardbibliothek ( core.clj: 807 ):
(defmacro and
"Evaluates exprs one at a time, from left to right. If a form
returns logical false (nil or false), and returns that value and
doesn't evaluate any of the other expressions, otherwise it returns
the value of the last expr. (and) returns true."
{:added "1.0"}
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
-
`
aufgerufenes Syntax-Zitat ist wie(quote)
, aber rekursiv: Es bewirkt(let …)
,(if …)
usw., dass es während der Makroerweiterung nicht ausgewertet wird, sondern wie es ausgegeben wird -
~
aka unquote bricht das Syntaxzitat für ein einzelnes Formular in einem Syntax-Anführungszeichen ab. Derx
-Wert wird also beim Erweitern des Makros ausgegeben (anstatt dasx
Symbol auszugeben) -
~@
aka unquote-splicing ist wie unquote, nimmt aber Listenargumente auf und erweitert es, wobei jedes Listenelement in eine separate Form gebracht wird -
#
fügt den Symbolen eine eindeutige ID hinzu, um Namenskonflikte zu vermeiden. Es fügt die gleiche ID für dasselbe Symbol in einem Ausdruck mit Syntax-Anführungszeichen an, alsoand#
inlet
undand#
inif
,if
derselbe Name erhalten wird