The Cons in iterate's return value

155 views
Skip to first unread message

Mars0i

unread,
Apr 16, 2014, 12:45:01 PM4/16/14
to clo...@googlegroups.com
The docstring for iterate says that it returns a lazy sequence, but it returns a Cons wrapped around a LazySeq.  This means, for example, that realized? can't be applied to what iterate returns.  Is this a problem with the iterate docstring?  Or should realized? be applicable to Conses?  I assume that there's a good reason that iterate returns a Cons instead of a LazySeq.

Clojure 1.6.0
user=> (doc iterate)
-------------------------
clojure.core/iterate
([f x])
  Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
nil

user=> (def xs (iterate inc 0))
#'user/xs

user=> (class xs)
clojure.lang.Cons

user=> (class (rest xs))
clojure.lang.LazySeq

user=> (realized? (rest xs))
false

user=> (realized? xs)
ClassCastException clojure.lang.Cons cannot be cast to clojure.lang.IPending  clojure.core/realized? (core.clj:6883)

user=> (take 5 xs)
(0 1 2 3 4)

user=> (realized? (rest xs))
true

user=> (realized? xs)
ClassCastException clojure.lang.Cons cannot be cast to clojure.lang.IPending  clojure.core/realized? (core.clj:6883)

user=> (doc realized?)
-------------------------
clojure.core/realized?
([x])
  Returns true if a value has been produced for a promise, delay, future or lazy sequence.
nil

gianluca torta

unread,
Apr 16, 2014, 3:39:24 PM4/16/14
to clo...@googlegroups.com
this issue on core.typed
http://dev.clojure.org/jira/browse/CTYP-96

in particular the comment:
"This is starting to make me rethink what a clojure.core docstring means exactly by a "lazy sequence"

cheers,
Gianluca

Ambrose Bonnaire-Sergeant

unread,
Apr 16, 2014, 3:56:42 PM4/16/14
to clojure
Ah so it seems a "lazy sequence" implements IPending?

Thanks,
Ambrose


--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

John Mastro

unread,
Apr 16, 2014, 4:28:02 PM4/16/14
to clo...@googlegroups.com
> I assume that there's a good reason that iterate returns a Cons
> instead of a LazySeq.

IIUC, this particular case arises because iterate's body is implemented
as

    (cons x (lazy-seq (iterate f (f x))))

rather than

    (lazy-seq (cons x (iterate f (f x))))

Can anyone comment on whether there's a reason to prefer one over the
other?

--
John Mastro

Mikera

unread,
Apr 16, 2014, 11:24:57 PM4/16/14
to clo...@googlegroups.com
The difference is that the former is slightly less lazy - the Cons cell containing x is constructed immediately rather than being deferred as part of the lazy seq.

This probably performs slightly better in some circumstances, and since you already have x as a value it probably makes sense to do this eagerly since no arbitrary computation is being done (f doesn't need to be called yet in either case).

Mars0i

unread,
Apr 16, 2014, 11:35:14 PM4/16/14
to clo...@googlegroups.com
On Wednesday, April 16, 2014 2:39:24 PM UTC-5, gianluca torta wrote:
this issue on core.typed
http://dev.clojure.org/jira/browse/CTYP-96

in particular the comment:
"This is starting to make me rethink what a clojure.core docstring means exactly by a "lazy sequence"

Even if we interpreted "lazy sequence" so that a Cons containing a LazySeq would count as a lazy sequence, making the docstring for iterate correct, the docstring for realized? would be wrong. 

Thanks for the JIRA reference.  That issue was resolved, I gather because it only concerned the return type of iterate itself.  

Mikera wrote:
"The difference is that the former ... probably performs slightly better in some circumstances, and since you already have x as a value it probably makes sense to do this eagerly since no arbitrary computation is being done (f doesn't need to be called yet in either case)."

But then should realized? be able to deal with a Cons containing a LazySeq?

(Is this an issue worthy of JIRA? I've never submitted there, and am not sure I know enough to do so.  Willing to try to figure it out.)

A. Webb

unread,
Apr 17, 2014, 11:36:13 AM4/17/14
to clo...@googlegroups.com


On Wednesday, April 16, 2014 10:35:14 PM UTC-5, Mars0i wrote:

But then should realized? be able to deal with a Cons containing a LazySeq?

(Is this an issue worthy of JIRA? I've never submitted there, and am not sure I know enough to do so.  Willing to try to figure it out.)

No, realized? works as intended on a single object. If you want to know if there is an unrealized portion remaining of a sequence, just roll your own function to step through it, being careful not to force realization of unrealized portions while doing so. Untested example:

(defn seq-realized?
  "Returns false if there is an unrealized tail in the sequence,
  otherwise true."
  [s]
  (if (instance? clojure.lang.IPending s)
    (if (realized? s)
      (if (seq s)
        (recur (rest s))
        true)
      false)
    (if (seq s)
      (recur (rest s))
      true)))

Mars0i

unread,
Apr 17, 2014, 5:48:37 PM4/17/14
to clo...@googlegroups.com


On Thursday, April 17, 2014 10:36:13 AM UTC-5, A. Webb wrote:
On Wednesday, April 16, 2014 10:35:14 PM UTC-5, Mars0i wrote:

But then should realized? be able to deal with a Cons containing a LazySeq?

(Is this an issue worthy of JIRA? I've never submitted there, and am not sure I know enough to do so.  Willing to try to figure it out.)

No, realized? works as intended on a single object. If you want to know if there is an unrealized portion remaining of a sequence, just roll your own function to step through it, being careful not to force realization of unrealized portions while doing so. Untested example:

Very nice--thanks.

But there's still a conflict between the docstrings for iterate and realized?, right?  If it's true that iterate "Returns a lazy sequence", then it's false that realized? "Returns true if a value has been produced for a ... lazy sequence", since it throws an exception on what iterate returns.
Reply all
Reply to author
Forward
0 new messages