What happened to Clojure's lazy assessment

I am twisting my old java / python clojure head. Please help me understand the lazy clojure feature.

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

The above is easy to understand. Since this is a lazy sequence, (prn "abc") will not be evaluated, so nothing is printed.

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

The above will cause an error, as you can see. Why?

My (wrong) understanding is that since it is lazy, (prn undefined -var) can be legally here, even "undefined -var" is not yet defined.

Please indicate my understanding correctly.

+4
source share
3 answers

Both of the above answers will provide you with good information on this, but I will try to identify the key problem here. When you write s-expression in REPL, for example (+ x 2) , two things happen:

  • reader analysis of characters that give forms, such as characters,
  • evaluation forms.

A deferred evaluation cancels the second step, but at the first stage, when the reader encounters undefined-var , he tries to convert it to a character and finds that such a character is not defined.

+8
source

When the clojure reader finds

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

It must compile it, which is why it throws an error since undefined -var is not defined. In the first case, it compiles fine, but it fails until you use seq.

+9
source

You seem to have the correct understanding, it's just not how the lazy-seq function works here is a typical example:

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

lazy-seq almost always takes a cons statement, where the first argument is the first element in the sequence, and the second argument is the code to compose the rest of the list. Faithful people rarely have to use lazy-seq directly on Clojure day, using forms like map reduce , filter , etc. much more common.

the code in the function to create the rest of the sequence also contains to be able to compile, in your case you can also delay compilation using eval , although I would recommend not using eval for such things in code that needs to be read by others; does for a lot of learning though; -)

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

All Articles