2016-10-20 55 views
1

我有一個宏這樣:怎麼辦命名空間解析Clojure中宏

例子:

(defmacro xxz [& fns] `(:body [email protected](map (fn [[e1 e2]] `(~e2 "http://www.google.com")) fns))) 

如果我通過類似(xxz [client/get client/get]),所產生的macroexpand顯示這些符號沒有資格:

(:body (client/get "http://www.google.com"))

這會導致問題時,像這樣的土地的命名空間中沒有client進口。

有誰知道該怎麼辦?

+0

不知道我明白。如果你在ns「sample」中並且調用了(xxz ...),那麼ns「sample」必須有'(:require [some-ns.client:as client])或類似的名稱。 –

回答

2

這聽起來像一個設計監督與語法引用(在我看來),雖然不清楚一般的「修復」是什麼樣子。

這裏是一個更小例子:

yummly.mobile-api.main> (in-ns 'foo) 
#namespace[foo] 
foo> (clojure.core/refer-clojure) 
foo> (require '[org.httpkit.client :as client]) 
nil 

foo> (defmacro xxz [& fns] 
     `([email protected])) 
#'foo/xxz 
foo> (macroexpand-1 '(xxz client/get)) 
(client/get) 

從一個新的命名空間:

foo> (in-ns 'bar) 
#namespace[bar] 
bar> (macroexpand-1 '(foo/xxz client/get)) 
(client/get) 
bar> (foo/xxz client/get) 
CompilerException java.lang.RuntimeException: No such namespace: client, compiling:(*cider-repl api*:87:6) 

語法引號形式(又名`)着眼於表達每一個符號,因爲它是被編譯,如果它沒有找到一個/然後它假定它是爲本地命名空間並追加當前命名空間。它只能在宏定義時出現在實際宏中的符號,而不是(因爲我希望它能夠做到)符號作爲參數傳遞給宏。

如果您在宏中使用完全名稱空間限定符號,那麼如果名稱空間中用戶使用宏的名稱空間已將這些符號映射到任何內容,則無需擔心,因爲它們會拼出符號名稱的完整路徑。如果您不想在宏中使用的符號中輸入完整名稱空間,則可以在ns表達式中的require語句中使用:refer [get],這樣可以節省您輸入名稱並使其成爲正確的命名空間在宏定義評估時展開。

因爲語法報價是生產unhygenic符號,則需要兩個都:需要或:指功能ns部分在命名空間的頂部,在那裏這些命名空間傳遞給函數的每一位客戶。

另一種方法是找到一些方法來確保符號在編譯語法引用時可用於宏。在某些情況下,這可能會很棘手。

+0

'因爲您在宏中使用命名空間限定符號(因爲您應該這樣做),那麼您不需要擔心,如果名稱空間中的人們使用您的宏將這些符號映射到任何內容,因爲它們會拼出符號的完整路徑它的名字。「 - >這正是問題所在。出於某種原因,在這種情況下,我沒有獲得符號的完整路徑。我在macroexpand中獲得'client/get'符號而不是'clj-http.core/get',這是正確的完全限定符號。因此我的問題是:爲什麼它沒有合格? –

+0

這聽起來像是語法引用中的一個錯誤。這不應該這樣工作 –

+0

我認爲這應該被添加到Clojure Jira問題跟蹤器 –