2012-01-14 84 views
7

检查符号是否可以解析时,会出现一些奇怪的行为。Clojure:解析声明符号

user=> ok 
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ok in this context, compiling:(NO_SOURCE_PATH:0) 
user=> (resolve 'ok) 
nil 
user=> (if (resolve 'ok) "bla" (def ok 'ok)) 
"bla" 
user=> ok 
#<Unbound Unbound: #'user/ok> 
user=> (def ok 'ok) 
#'user/ok 
user=> ok 
ok 

谁能告诉我这可能来自哪里?这是行为的目的?

+0

您使用的是什么版本的Clojure?我没有在1.2.1上看到这个 – spacemanaki 2012-01-14 18:11:59

+1

@spacemanaki:有趣的是,我只是在1.2.1和1.3中都转载了这件事。 – 2012-01-14 19:24:36

+0

我的错误,对'ok'的第二次引用导致了一个异常,而不是返回一个'#'对象,我没有注意。对我来说,在'if'里面的1.2.1'(解析'ok')确实会导致'ok'被声明。 – spacemanaki 2012-01-14 20:42:48

回答

4

(def ok "whatever")在编译时间处创建名为ok的变量。编译器扫描整个表单进行编译,发现您将定义一个名为ok的var,并在您的表单实际执行之前为您创建(无需绑定)。当def表单实际执行时,表达式的运行时值将被分配给var user/ok。在你的例子中,这绝不会发生,因为var已经创建,并且if分支以另一种方式。

使用bound?作为替代品是一个可怕的想法,因为它测试了一个完全不同的东西:名为var(它必须存在)是否具有永久绑定或线程本地绑定。

+0

听起来合乎逻辑。但是为什么'(if(resolve'x)x(def x'x))'产生'CompilerException java.lang.RuntimeException:无法在此上下文中解析符号:x,编译:(NO_SOURCE_PATH:1)?还是他在创建变量之前尝试评估x? – 2012-01-15 08:10:49

1

因为我只用它在宏里我现在如下

(defmacro bla [x] 
    (if (resolve x) x `(def ~x '~x))) 

而现在它的作品,因为高清是引号形式内部和决心后,评价使用它。