需要解释Clojure的ns函数中的奇怪行为

时间:2013-05-24 00:10:34

标签: syntax clojure namespaces

我注意到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的所有调用都是一致的,而现在我无法弄清楚如何做到这一点。

1 个答案:

答案 0 :(得分:3)

这不是关于ns,而是关于Clojure的词法语法。

^{...}语法使读者将给定的地图附加到阅读以下表格的结果中。所以,在你的例子中,

^{:doc ... :author ...} foo.bar

实际上是以带有给定元数据的单个符号foo.bar读入的。很明显,如果^{...}是结尾括号之间的最后一个东西,那么读者就没有任何东西可以附加这个元数据,所以它会抛出异常(在读取时,所以在任何宏扩展之前)等)。

在Clojure中,将各种def形式的符号名称放在元数据中的元数据(除了那些纯粹用于主机互操作的形式,如definterface)转移到定义的东西。基本宏(nsdefndefmacro)也支持属性映射参数和单独的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
    ...))