Sök…


Syntax

  • Den ' symbol som används i macroexpand exemplet är bara syntaktiskt socker för quote operatören. Du kunde ha skrivit (macroexpand (quote (infix 1 + 2))) istället.

Anmärkningar

Makron är bara funktioner som körs vid kompileringstid, dvs under eval i en läs-eval-utskriftsslinga .

Läsmakroer är en annan form av makro som utvidgas vid läsningstid snarare än kompileringstid.

Bästa praxis när man definierar makro.

  • alfa-byta namn, Eftersom makro utvidgas kan bindande namnkonflikt uppstå. Bindande konflikt är inte särskilt intuitivt att lösa när man använder makro. Därför är det obligatoriskt att använda # i slutet av varje symbol närhelst ett makro lägger till en bindning till räckvidden.

Enkel infix-makro

Clojure använder prefixnotation, det vill säga: Operatören kommer före sina operander.

Till exempel skulle en enkel summa av två siffror vara:

(+ 1 2)
;; => 3

Makron låter dig manipulera Clojure-språket till en viss grad. Till exempel kan du implementera ett makro som låter dig skriva kod i infixnotation (t.ex. 1 + 2 ):

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

Låt oss dela upp vad koden ovan gör:

  • defmacro är en speciell form som du använder för att definiera ett makro.
  • infix är namnet på den makro som vi definierar.
  • [first-operand operator second-operand] är de parametrar som denna makro förväntar sig att få när den anropas.
  • (list operator first-operand second-operand) är kroppen av vår makro. Det skapar helt enkelt en list med värdena på parametrarna som tillhandahålls till infix och returnerar det.

defmacro är en speciell form eftersom den beter sig lite annorlunda jämfört med andra Clojure-konstruktioner: Parametrarna utvärderas inte omedelbart (när vi kallar makro). Det är detta som gör att vi kan skriva något som:

(infix 1 + 2)
;; => 3

infix makroet utvidgar argumenten 1 + 2 till (+ 1 2) , vilket är en giltig Clojure-form som kan utvärderas.

Om du vill se vad infix makroen genererar, kan du använda macroexpand operatören:

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

macroexpand , som antyds av namnet, kommer att utöka makro (i detta fall kommer den att använda infix makro för att omvandla 1 + 2 till (+ 1 2) ) men tillåter inte att resultatet av makroutvidgningen utvärderas av Clojures tolk.

Syntaxcitationstecken och citationstecken

Exempel från standardbiblioteket ( 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#))))
  • ` kallas syntax-citat är som (quote) , men rekursivt: det får (let …) , (if …) , etc att inte utvärdera under makroutvidgning utan att mata ut som är
  • ~ aka unquote avbryter syntax-offert för enstaka form i syntax-citerad form. Så x : s värde matas ut vid utökning av makro (istället för att mata ut x symbol)
  • ~@ aka unquote-splicing är som unote men tar listargument och utvidgar det, varje listobjekt till separat form
  • # lägger till unik ID till symboler för att förhindra namnkonflikter. Den lägger till samma id för samma symbol i syntaxciterat uttryck, så and# inuti let och and# inuti if kommer att få samma namn


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow