Szukaj…
Składnia
- Symbol
'
użyty w przykładzie makrozwinięcia to po prostu cukier syntaktyczny dla operatoraquote
. 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 tworzylist
z wartościami parametrów dostarczonych do makrainfix
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 symbolux
) -
~@
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ęcand#
insidelet
and#
insideif
otrzymają tę samą nazwę