2012-03-13 11 views
10

clj-timeライブラリの関数を使用するマクロを作成します。 1つの名前空間では私はこのようなマクロを呼び出すしたいと思います:名前空間の混乱とマクロ

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

(budget.time/next-date interval frequency) 

次の日のマクロは、このような別のファイルに定義されます:マクロは、次の引数で呼び出された場合

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

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

(budget.time/next-date interval freq)とintervalとfreqここで、「週」と「2」はそれぞれマクロ展開と同じです(clj-time.core/weeks 2)

私が試したときはいつでもこれはREPLからネームスペースを解決できません。

マクロにclj-time名前空間の引数の間隔を解決させる方法はありますか?これを行う最善の方法は何ですか?

ありがとうございます!

+0

マクロを書く必要があるのはなぜですか。これは通常の機能ではできませんでしたか?覚えておいて欲しいのは、関数の実行時にマクロを書くべきではないということです。 – viebel

答えて

10

マクロは、それが定義されている名前空間ではなく、呼び出された名前空間で評価されるリストを返します。これは定義されている名前空間で評価される関数とは異なります。これはです。マクロを実行する代わりに、実行するコードが返されるためです。展開後、数週間は、それがである、hello.coreから解決され、その後

hello.core> (macroexpand-1 '(next-date weeks 2)) 
(weeks 2) 

:私はインスタンスhello.coreのために、別のネームスペースに移動し、私が得る次の日への呼び出しを展開する場合

もちろん定義されていません。これを修正するには、返されたシンボルが名前空間の情報を保持する必要があります。

は、ns-resolveという名前空間のシンボルを明示的に解決できます。それは名前空間と記号を取り、我々はsymbolへの明示的な呼び出しで済ますことができますので、あなたのマクロは、シンボルと番号を取るされる次のそれは

(ns-resolve 'clj-time.core (symbol "weeks")) 
#'clj-time.core/weeks 

を発見していない場合は、名前空間の復帰はnilでそれを見つけようとします

(ns-resolve 'clj-time.core 'weeks) 
#'clj-time.core/weeks 

ので、今、あなただけの

(defmacro next-date [interval freq] 
    (list (ns-resolve 'clj-time.core interval) freq)) 
、機能を解決した後、番号が続く解決機能のリストを作成する機能を必要とする上記のマクロで

それがないすべてはあなたも、このマクロは必要ありませんので、すぐに呼び出される関数の呼び出しを行います:

(defn next-date [interval freq] 
    ((ns-resolve 'clj-time.core interval) freq)) 
(next-date 'weeks 2) 
#<Weeks P2W> 

非マクロバージョンがあるため間隔を引用する必要がありますあなたがそれを見る前に評価される必要はありません。マクロが実際にここに買ったのは、すべての発信者にclj-timeを要求する代償として、見積もりを含める必要はありません。

もちろん、どこでもclj-timeが必要ですが、 。

+1

どこでもclj-timeを要求するか、ns-resolveを使用する方が良いですか? – user1265564

+1

個人的には、クリーナーオプションとしてどこでもclj-timeが必要です。 –