我发现我们不需要'(ns ...)
,因为ns是一个宏。
但是,为什么我们需要'(require '[...])
?我认为Clojure的矢量是避免'的一种奇特方式,但现在我在这里看到了一个。
我们使用(require 'clojure.string)
所以require
似乎是一个函数,但是当作为参数给出时,我们不引用向量。
来自非引用的错误消息也令人困惑。
答案 0 :(得分:6)
这是因为require
是作为函数而不是宏实现的,因此它需要引用的libspec。不带引号的libspec将按如下方式进行评估:
user=> [clojure.set :as s]
CompilerException java.lang.ClassNotFoundException: clojure.set
因此产生错误。
但是,ns
是作为宏实现的,并且可以完全控制是否或何时进一步评估其参数,因此您不需要引用libspec。您可以查看ns的宏展开,看看展开时会发生什么:
user=> (use 'clojure.pprint)
nil
user=> (pprint (macroexpand '(ns foo (:require [clojure.set :as s]))))
(do
(clojure.core/in-ns 'foo)
(clojure.core/with-loading-context
(clojure.core/refer 'clojure.core)
(clojure.core/require '[clojure.set :as s]))
(if
(.equals 'foo 'clojure.core)
nil
(do
(clojure.core/dosync
(clojure.core/commute
@#'clojure.core/*loaded-libs*
clojure.core/conj
'foo))
nil)))
nil
正如您所看到的,ns
只是按原样使用libspec并在将其传递给require之前为您引用,因此您不必这样做。
答案 1 :(得分:2)
利基是:引用一个向量基本上引用了向量形式中的每个子形式。
user> (= '[a b c] ['a 'b 'c])
=> true
require
表单可以使用带引号的符号,引用命名空间,也可以使用带引号的符号向量进行进一步的限制。