I looked at the source of lazy-seq I found this:
Clojure 1.4.0
user=> (source lazy-seq)
(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
nil
user=>
I was wondering how fn* differs from fn, but I can't seem to find any reference to fn* in the docs. What am I missing, and how is fn* different?
Disclaimer: I'm a long way from a Clojure compiler expert, so take the following with an appropriate quantity of salt.
fn* is an intrinsic version of fn. Much of Clojure is implemented in Clojure, but some of the low-level functions are implemented in Java; fn* is one such.
fn is implemented in terms of fn*. The source is here:
https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L42
fn* is implemented in the compiler:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L47
There are actually two different versions of fn*, referred to in the Java by the symbols FN and FNONCE. The first is a "bare" fn* and the second is fn* with the metadata ^{:once true}, which is the version used by lazy-seq.
^{:once true} is used to let the compiler know that the closure containing the function will only be invoked once, and that it can perform closed-over local clearing. See this mailing list thread for more details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With