2015-02-08 45 views
3

下面的代码编译细:如何解决let中的interned vars?

(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) 

看起来实习生在这种情况下不会执行unti l let完成后。我唯一的工作,而不是使用当地人是为了突变原子或使用alter-var-root

为什么intern工作在let,et al。就像它在do中那样?有没有办法迫使实习生在let内部完成,以便上面的例子编译? (顺便说一句,宏不是一种选择,因为我想要访问使用ns-map我约束力的形式运行信息)

+2

一个很好的问题,但这里唯一令人惊讶的是赤裸裸的'do'编译。隐式'do'的合约是按顺序执行的,不是按顺序编译的。解决方案是提前“申报”。 – 2015-02-08 05:10:22

+1

@ A.Webb当在顶层时,'(do x y z)'编译x,运行x;编译y,运行y;编译z,运行z。这是必要的,以便允许宏发出包装在“do”中的多个表单并将它们视为独立的顶级表达式。 – amalloy 2015-02-08 19:59:38

回答

3

你不能写,因为只有do得到特殊待遇导致其子窗体每个编译和评估顺序,而不是全部编译,然后进行全部评估。但是,真的,这是一种奇怪的方式来做你想做的事情:这些手动拨打intern是非常不寻常的。为什么不简单地把当地人放进你的let,然后实习你想保留哪一个? let具有您需要的属性,因为之前定义的符号在下一个绑定中可见。

(let [e 1, f (+ e 1)] 
    (intern *ns* 'e e) 
    (intern *ns* 'f f)) 
2

@amalloy的另一个答案回答了问题的“为什么”部分,并提出了一种解决方法。如果由于某种原因,它仍然是重要的参考一个实习的VAR值,resolve功能,可用于:

(let [] 
    (intern *ns* 'e 1) 
    (intern *ns* 'f (+ @(resolve 'e) 1))) 
;; => #'user/f 
e 
;; => 1 
f 
;; => 2