如何在let中解析interned vars?

时间:2015-02-08 02:39:40

标签: clojure

以下代码编译良好:

(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在我的绑定表单中访问运行时信息)

2 个答案:

答案 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