2012-03-13 10 views
10

Chcę napisać makro, które używa funkcji z biblioteki clj-time. W jednej z nazw chciałbym wywołać makro takiego:Dezorientacja obszaru nazw i makra

(ns budget.account 
    (:require [budget.time])) 

(budget.time/next-date interval frequency) 

Następny-data makro będzie zdefiniowany w innym pliku tak:

(ns budget.time 
    (:require [clj-time.core :as date])) 

(defmacro next-date [interval freq] 
    `(~interval ~freq)) 

Jeśli makro były nazywane z następującymi argumentami (budget.time/next-date interval freq) i interwał i freq, gdzie "tygodnie" i "2" repektywnie wtedy makro-rozszerzenie wyglądałoby mniej więcej (clj-time.core/weeks 2)

Ilekroć próbuję to z REPL nie może rozwiązać przestrzeni nazw.

Czy istnieje sposób zmuszenia makro do rozwiązania interwału do argumentów w przestrzeni nazw Clj-Time? Jaki jest najlepszy sposób na zrobienie tego?

Dzięki!

+0

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

Odpowiedz

10

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 .

+1

Czy lepiej jest wymagać clj-time wszędzie lub używać ns-resolve? – user1265564

+1

osobiście widzę, że wymaganie clj-time wszędzie jako opcji czyszczenia. –

Powiązane problemy