2016-10-20 59 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问题跟踪器 –