18

有时,在查看其他人的 Clojure 代码时,我会看到一个通过定义的函数defn,然后使用 var-quote 语法调用,例如:

user> (defn a [] 1)
#'user/a
user> (a)   ; This is how you normally call a function
1
user> (#'a) ; This uses the var-quote syntax and produces the same result
1

对于我的生活,我无法弄清楚这两种调用函数的方式之间的区别。我在评估文档中找不到任何内容来说明当呼叫的操作员是 var 时会发生什么,这可能表明为什么首选第二种形式。binding他们似乎都对分配和语法引用做出了相同的反应。

那么,有人可以提供一个代码示例来说明两者之间的区别(a)(#'a)

编辑:我知道 var-quote 可用于获取被let词法绑定遮蔽的 var,但在我正在查看的代码中似乎并非如此。

4

2 回答 2

21

(#'a)总是指var a,而(a)可以被本地绑定遮蔽:

user> (defn a [] 1)
#'user/a
user> (let [a (fn [] "booh")] [(a) (#'a)])
["booh" 1]

但是 var-quote / function call 的大多数实际用途并不是直接调用 var-quote 表达式,而是缓存它的值,以便高阶构造在传入时引用 var a 的当前值而不是它的值:

(defn a [] 1)
(defn my-call [f] (fn [] (+ 1 (f))))
(def one (my-call a))
(def two (my-call #'a))
(defn a [] 2)

user> (one)
2
user> (two)
3

这对于交互式开发非常有用,在这种开发中,您正在更改一些包装在其他包中的一堆其他功能中的功能。

于 2013-02-08T00:25:05.057 回答
7

第二种形式允许您规避 clojure 设置的隐私限制。

因此,例如,如果您开发了一个带有私有函数的库,但想从单独的命名空间测试它们,则不能直接引用它们。但是您可以使用 var quote 语法来获取它们。这对此非常有用。

隐私是 clojure 本质上是一种自动文档形式,与您在 Java 中看到的隐私相反。你可以绕过它。

user> (defn- a [] 1)
#'user/a
user> (ns user2)
nil
user2> (user/a)
CompilerException java.lang.IllegalStateException: var: #'user/a is not public,    compiling:(NO_SOURCE_PATH:1) 
user2> (#'user/a)
1
user2> 
于 2013-02-08T10:50:17.153 回答