Makra zwracają listę, która jest następnie analizowana w przestrzeni nazw, z której jest wywoływana, a nie przestrzeni nazw, w której została zdefiniowana. Jest to funkcja inna niż funkcje, które oceniają w przestrzeni nazw, w której zostały zdefiniowane. Jest to , ponieważ makra zwracają kod, który ma zostać uruchomiony, zamiast go uruchamiać.
jeśli pójdę do innej przestrzeni nazw, na przykład hello.core
i rozwinąć wezwanie do następnej daty uzyskać:
hello.core> (macroexpand-1 '(next-date weeks 2))
(weeks 2)
potem po rozszerzeniu, tydzień został rozwiązany z hello.core, w którym jest oczywiście nie zdefiniowane. aby to naprawić, potrzebujemy zwróconego symbolu do przenoszenia informacji o przestrzeni nazw.
Na szczęście można jawnie rozwiązać symbol w przestrzeni nazw z ns-resolve
. Zajmuje nazw i symbolu i próbuje odnaleźć go w przestrzeni nazw powracającego zero, jeśli nie znalazł
(ns-resolve 'clj-time.core (symbol "weeks"))
#'clj-time.core/weeks
obok makra weźmie symbol i numer więc możemy zrezygnować z jawne wywołanie symbol
(ns-resolve 'clj-time.core 'weeks)
#'clj-time.core/weeks
więc teraz wystarczy funkcję, która rozwiązuje funkcję, a następnie tworzy listę funkcji rozwiązany następnie przez liczbę,
(defmacro next-date [interval freq]
(list (ns-resolve 'clj-time.core interval) freq))
W powyższym makro wszystkich robi to zrobić wywołanie funkcji, która jest natychmiast nazwie, więc nie trzeba nawet makra dla tego:
(defn next-date [interval freq]
((ns-resolve 'clj-time.core interval) freq))
(next-date 'weeks 2)
#<Weeks P2W>
nie-makro wersja wymaga zacytować interwał ponieważ nie trzeba go oceniać, zanim będzie można go przejrzeć. To, co tutaj naprawdę kupuje makro, nie musi zawierać cytatu, a to kosztem wymagania od wszystkich rozmówców, aby wymagali clj-time
oczywiście moglibyśmy również wymagać czasu clj-time wszędzie, ale to nie jest tak naprawdę punkt .
Dlaczego trzeba pisać makro. Czy nie można tego zrobić za pomocą zwykłej funkcji? Pamiętaj: nigdy nie powinieneś pisać makra, gdy funkcja będzie działać. – viebel