Szukaj…


Składnia

  • Symbol ' użyty w przykładzie makrozwinięcia to po prostu cukier syntaktyczny dla operatora quote . Mógłbyś napisać (macroexpand (quote (infix 1 + 2))) zamiast tego.

Uwagi

Makra to tylko funkcje, które działają w czasie kompilacji, tj. Podczas kroku eval w pętli read-eval-print .

Makra czytnika to kolejna forma makra, która jest rozszerzana w czasie odczytu, a nie w czasie kompilacji.

Najlepsza praktyka przy definiowaniu makra.

  • zmiana nazwy alfa, ponieważ makro jest rozwinięte, może wystąpić konflikt nazw. Konflikt wiążący nie jest zbyt intuicyjny do rozwiązania podczas korzystania z makra. Dlatego za każdym razem, gdy makro dodaje powiązanie do zakresu, obowiązkowe jest użycie znaku # na końcu każdego symbolu.

Simple Infix Macro

Clojure używa notacji przedrostkowej, to znaczy: Operator jest przed operandami.

Na przykład prosta suma dwóch liczb to:

(+ 1 2)
;; => 3

Makra pozwalają w pewnym stopniu manipulować językiem Clojure. Na przykład możesz zaimplementować makro, które pozwala pisać kod w notacji infix (np. 1 + 2 ):

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

Podzielmy się tym, co robi powyższy kod:

  • defmacro to specjalna forma używana do definiowania makra.
  • infix to nazwa definiowanego przez nas makra.
  • [first-operand operator second-operand] to parametry, które makro spodziewa się otrzymać po wywołaniu.
  • (list operator first-operand second-operand) jest ciałem naszego makra. Po prostu tworzy list z wartościami parametrów dostarczonych do makra infix i zwraca to.

defmacro jest specjalną formą, ponieważ zachowuje się nieco inaczej niż inne konstrukcje Clojure: jego parametry nie są natychmiast oceniane (kiedy wywołujemy makro). To pozwala nam napisać coś takiego:

(infix 1 + 2)
;; => 3

Makro infix rozwinie argumenty 1 + 2 w (+ 1 2) , który jest prawidłowym formularzem Clojure, który można ocenić.

Jeśli chcesz zobaczyć, co infix makro generuje, można użyć macroexpand operatora:

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

macroexpand , jak sugeruje jego nazwa, spowoduje rozwinięcie makra (w tym przypadku użyje makra infix do przekształcenia 1 + 2 w (+ 1 2) ), ale nie pozwoli na ocenę wyniku rozwinięcia makra przez Tłumacz Clojure'a.

Cytowanie i cofanie składni

Przykład ze standardowej biblioteki ( 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#))))
  • ` nazwany syntax-quote jest podobny do (quote) , ale rekurencyjny: powoduje, że (let …) , (if …) itp. nie ocenia podczas ekspansji makr, ale wyświetla tak jak jest
  • ~ aka unquote anuluje cytat składni dla pojedynczego formularza w formularzu cytowanym przez składnię. Więc wartość x jest wyprowadzana podczas rozwijania makra (zamiast wypisywania symbolu x )
  • ~@ aka unquote-splicing jest jak quote, ale pobiera argument listy i rozwija go, każdy element listy do osobnego formularza
  • # dołącza unikalny identyfikator do symboli, aby zapobiec konfliktom nazw. Dołącza ten sam identyfikator dla tego samego symbolu w wyrażeniu cytowanym w składni, więc and# inside let and# inside if otrzymają tę samą nazwę


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow