使用var-quote语法调用Clojure函数

时间:2013-02-07 23:45:52

标签: clojure eval var

有时候,在查看其他人的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

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

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

编辑:我知道var-quote可以用于获取被let词法绑定所掩盖的var,但在这种情况下似乎并非如此。我正在看的代码。

2 个答案:

答案 0 :(得分:17)

(#'a)始终引用 var a,而(a)可以被本地绑定遮蔽:

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

但是var-quote / function调用的大多数实际用法都没有直接调用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

这对于交互式开发非常有用,您可以在其中更改某些功能,这些功能包含在其他包中的许多其他功能中。

答案 1 :(得分:6)

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

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

隐私本质上是一种自动文档形式,而不是您在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>