为什么我们需要Clojure中的’in(require'[…]])?

Why do we need ' in (require '[…]]) with Clojure?

我看到我们不需要'(ns ...)',因为ns是一个宏。
但是,为什么在(require '[...])中需要'?我以为Clojure的向量是避免'的一种奇特方法,但现在我在这里看到了。

我们使用(require 'clojure.string),所以require似乎是一个函数,但是当作为参数给出时,我们不引用向量。

enter


这是因为require是作为函数而非宏实现的,因此需要带引号的libspec。未引用的libspec将按以下方式求值:

1
2
user=> [clojure.set :as s]
CompilerException java.lang.ClassNotFoundException: clojure.set

因此产生错误。

但是,ns被实现为宏,并且完全控制是否或何时进一步评估其参数,因此您无需引用libspec。您可以查看ns的宏扩展,看看扩展时会发生什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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,并在将其传递给要求之前将其引用给您,因此您不必这样做。


利基是:引用向量本质上是引用向量形式内的每个子形式。

1
2
user> (= '[a b c] ['a 'b 'c])
=> true

require格式可以采用带引号的符号(引用名称空间),也可以采用带引号的矢量构成进一步的限制。