以下代码编译良好:
(intern *ns* 'a 1) ;#'user/a
(intern *ns* 'b (+ a 1)) ;#'user/b
它还会编译为do
:
(do
(intern *ns* 'c 1)
(intern *ns* 'd (+ c 1)))
然而,let
(或我尝试的任何其他绑定形式,包括fn
)的编译失败:
(let []
(intern *ns* 'e 1)
(intern *ns* 'f (+ e 1)))
;CompilerException java.lang.RuntimeException: Unable to resolve symbol: ‘e in this context, compiling:(NO_SOURCE_PATH:2:5)
看起来直到let
完成后才会在这种情况下执行实习生。我唯一的工作而不是使用locals是改变原子或使用alter-var-root
。
intern
为什么不在let
内工作?与do
中的方式相同?有没有办法强制实习生在一个let内完成,以便上面的例子编译? (顺便说一下,宏不是一个选项,因为我想使用ns-map
在我的绑定表单中访问运行时信息)
答案 0 :(得分:3)
你不能这样写,因为只有do
获得特殊处理,导致其子表单按顺序编译和评估,而不是一次编译,然后全部评估。但实际上,这是一种奇怪的方式来做你想要做的事情:这些对intern
的手动调用是非常不寻常的。为什么不简单地将本地人放入您的let
,然后将实习生放在您要保留的位置? let
具有您需要的属性,因为先前定义的符号在下一个绑定中可见。
(let [e 1, f (+ e 1)]
(intern *ns* 'e e)
(intern *ns* 'f f))
答案 1 :(得分:2)
@amalloy的另一个答案回答了问题的“原因”部分并提出了解决方法。如果由于某种原因,引用interned var的值仍然很重要,可以使用resolve
函数:
(let []
(intern *ns* 'e 1)
(intern *ns* 'f (+ @(resolve 'e) 1)))
;; => #'user/f
e
;; => 1
f
;; => 2