我注意到Clojure的ns函数有一些奇怪的行为。我认为它的论点顺序并不太在意,但显然它可能非常挑剔。
在一个文件中,我有
(ns ^{:doc "Foobar"
:author "me"}
foo.bar)
但如果我把它写成
(ns foo.bar ^{:doc "Foobar"
:author "me"})
我收到以下错误
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
在其他文件中,我在ns之后放了foo.bar,只要元数据不是ns的最后一个参数,它运行正常。这有点烦人,因为在其他文件中,我有一些像(:require foo.baz),显然必须在foo.bar之后,否则它会抛出另一个异常。 ns的规则究竟是什么?我希望我对ns的所有调用都是一致的,而现在我无法弄清楚如何做到这一点。
答案 0 :(得分:3)
这不是关于ns
,而是关于Clojure的词法语法。
^{...}
语法使读者将给定的地图附加到阅读以下表格的结果中。所以,在你的例子中,
^{:doc ... :author ...} foo.bar
实际上是以带有给定元数据的单个符号foo.bar
读入的。很明显,如果^{...}
是结尾括号之间的最后一个东西,那么读者就没有任何东西可以附加这个元数据,所以它会抛出异常(在读取时,所以在任何宏扩展之前)等)。
在Clojure中,将各种def
形式的符号名称放在元数据中的元数据(除了那些纯粹用于主机互操作的形式,如definterface
)转移到定义的东西。基本宏(ns
,defn
,defmacro
)也支持属性映射参数和单独的docstring参数:
(ns foo.core
"Quite a magnificent namespace, and very well-documented."
{:author "Alice Perr"}
(:require [foo.protocols :refer [PFoo]]))
(defn fooify
"Return a PFoo wrapper for x."
{:added "0.0.1"}
[x]
(reify PFoo
...))