2012-06-28 86 views
4

我正在扭曲我的老java/python头clojure的方式。请帮我理解clojure的懒惰特性。懒惰评价Clojure发生了什么

=> (def myvar (lazy-seq [1 2 (prn "abc")])) 
#'user/myvar 

以上很容易理解。由于它是一个懒惰的序列,因此不会评估(prn“abc”),因此不会打印任何内容。

=> (def myvar (lazy-seq [1 2 (prn undefined-var)])) 
CompilerException java.lang.RuntimeException: Unable to resolve symbol: undefined-var in this context, compiling:(NO_SOURCE_PATH:1) 

上面会出现一个错误,你可以看到。为什么?

我的(错误的)理解是,由于它很懒,(prn undefined-var)可能在这里合法,即使“undefined-var”尚未定义。

请任何人指出我的理解到正确的方式。

回答

8

上述两个答案都为您提供了有关该主题的良好信息,但我会尽力确定关键问题。当你在REPL写s-expression(+ x 2)发生两件事情:

  1. 解析由它产生形式,如符号,
  2. 的形式evaluation的characteres的the reader

惰性求pospones第二步骤中,但在第一步骤中,当读取器遇到undefined-var它试图将其转换为一个符号,并且发现这样的符号没有被定义。

+1

谢谢帕维尔。它变得更清晰。源代码需要在读者阶段解决以形成表单。该错误仅显示解决过程失败。听起来这与“懒惰”的评估材料无关。而且它也必须是所有lisp方言的通用方法。 –

+0

没错。据我所知,读者几乎是任何列表方言的强制性部分。 –

1

你似乎有正确的认识,它只是那不是怎么懒-seq的功能工作 这里是一个典型的例子:

user> (lazy-seq (cons 4 (range 5))) 
(4 0 1 2 3 4) 

lazy-seq几乎总是需要一个缺点表达式,其中第一个参数 是序列中的第一项,第二个参数是代码 来生成列表的其余部分。人们很少必须直接在日常Clojure中使用lazy-seq ,使用诸如mapreduce,filter, 等形式更常见。

在函数的代码用于生产序列的其余部分也neeeds 能够被编译,你的情况,你可以通过使用eval推迟汇编以及 虽然我会建议不要使用eval这样的事情 其他需要阅读的代码;使伟大的学习虽然;-)

user> (def myvar (lazy-seq (cons 1 (eval '(prn undefined-var))))) ; don't do this at work 
#'user/myvar 
user> myvar 
; Evaluation aborted. 
user> 
9

当Clojure的读者发现

(def myvar (lazy-seq [1 2 (prn undefined-var)])) 

它需要编译它,这就是为什么它引发错误的原因,因为不确定-VAR不定义。在第一种情况下,它编译好了,但是在你使用seq之前它不会被执行。

+0

这只是在Clojure中的情况,因为clojure脚本必须在执行前被编译为java吗?在其他Lisp方言中,可以在懒惰的评估环境中使用undefined var吗? –

+0

嗨,John,很抱歉,我没有其他Lisp的经验。 – DanLebrero

+0

谢谢dAni,你的回答有很大的帮助。但我可以只设置一个为“接受”。帕维尔更适合我的大脑。 –