为什么在Clojure中需要在(require '[...]])中使用单引号?

10

我看到在使用 (ns ...) 时不需要加引号,因为 ns 是一个宏。

然而,在 (require '[...]) 中为什么需要加引号呢?我曾经认为 Clojure 的向量是一种避免使用引号的花哨方式,但现在我在这里看到了一个。

我们使用 (require 'clojure.string),因此 require 看起来像是一个函数,但是当作为参数传递向量时,我们不需要将其引用。

输入图片说明

如果没有加引号,错误消息也会令人困惑。


相关的,几乎重复:http://stackoverflow.com/q/32783187/124319 - coredump
2个回答

9
这是因为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,并在传递之前为你加上引号,因此你不必自己添加。


5
该领域是:引用向量本质上是引用向量形式内的每个子形式。
user> (= '[a b c] ['a 'b 'c])
=> true

require表单可以采用引用命名空间的带引号符号形式,也可以采用带引号符号的带有进一步限制的带引号符号向量形式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接