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