Zoeken…


Syntaxis

  • De ' symbool dat gebruikt wordt in de macroexpand voorbeeld is alleen syntactische suiker voor de quote operator. Je zou in plaats daarvan kunnen hebben geschreven (macroexpand (quote (infix 1 + 2))) .

Opmerkingen

Macro's zijn slechts functies die tijdens het compileren worden uitgevoerd, dwz tijdens de eval stap in een read-eval-print-loop .

Reader-macro's zijn een andere vorm van macro die tijdens het lezen wordt uitgebreid in plaats van tijdens het compileren.

Best practice bij het definiëren van macro.

  • alpha-hernoemen, aangezien macro wordt uitgebreid, kan een bindend naamconflict ontstaan. Bindend conflict is niet erg intuïtief om op te lossen bij gebruik van de macro. Daarom is het, wanneer een macro een binding aan het bereik toevoegt, verplicht om het # aan het einde van elk symbool te gebruiken.

Eenvoudige Infix Macro

Clojure gebruikt voorvoegselnotatie, dat wil zeggen: de operator komt vóór zijn operanden.

Een eenvoudige som van twee getallen zou bijvoorbeeld zijn:

(+ 1 2)
;; => 3

Met macro's kunt u de Clojure-taal tot op zekere hoogte manipuleren. U kunt bijvoorbeeld een macro implementeren waarmee u code kunt schrijven in infix-notatie (bijvoorbeeld 1 + 2 ):

(defmacro infix [first-operand operator second-operand]
    "Converts an infix expression into a prefix expression"
    (list operator first-operand second-operand))

Laten we eens kijken wat de bovenstaande code doet:

  • defmacro is een speciale vorm die u gebruikt om een macro te definiëren.
  • infix is de naam van de macro die we definiëren.
  • [first-operand operator second-operand] zijn de parameters die deze macro verwacht te ontvangen wanneer deze wordt aangeroepen.
  • (list operator first-operand second-operand) is het lichaam van onze macro. Het maakt eenvoudig een list met de waarden van de parameters die aan de infix en retourneert dat.

defmacro is een speciale vorm omdat het zich een beetje anders gedraagt dan andere Clojure-constructen: de parameters worden niet onmiddellijk geëvalueerd (wanneer we de macro aanroepen). Dit is wat ons toestaat om zoiets te schrijven als:

(infix 1 + 2)
;; => 3

De infix breidt de 1 + 2 argumenten uit naar (+ 1 2) , een geldige Clojure-vorm die kan worden geëvalueerd.

Als u wilt zien wat de infix macro genereert, kunt u de operator macroexpand gebruiken:

(macroexpand '(infix 1 + 2))
;; => (+ 1 2)

macroexpand , zoals geïmpliceerd door zijn naam, zal de macro uitbreiden (in dit geval zal het de infix gebruiken om 1 + 2 te transformeren in (+ 1 2) ) maar zal het niet toestaan dat het resultaat van de macro-uitbreiding wordt geëvalueerd door De tolk van Clojure.

Syntaxis citeren en citeren

Voorbeeld uit de standaardbibliotheek ( 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#))))
  • ` syntax-quote genaamd is als (quote) , maar recursief: het zorgt ervoor (let …) , (if …) , enz. om niet te evalueren tijdens macro-uitbreiding maar om uit te voeren zoals is
  • ~ aka unquote annuleert syntax-quote voor enkel formulier in syntax-quote. Dus de waarde van x wordt uitgevoerd bij het uitbreiden van de macro (in plaats van het x symbool uit te voeren)
  • ~@ aka unquote-splicing is als unquote maar neemt lijstargument en breidt het uit, elk lijstitem naar afzonderlijke vorm
  • # voegt een uniek ID toe aan symbolen om naamconflicten te voorkomen. Het voegt dezelfde id toe voor hetzelfde symbool in de syntax-aanhalingstekens, dus and# inside let en and# inside if dezelfde naam krijgen


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow