How to safely print structures that may contain infinite lazy seqs?
148 views
Skip to first unread message
Austin Haas
unread,
Nov 1, 2020, 6:06:39 PM11/1/20
Reply to author
Sign in to reply to author
Forward
Sign in to forward
Delete
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
How can I make sure that a logging function won't try to realize an infinite lazy seq that could be anywhere in the arguments passed to the logging function?
Is there some way to guarantee that lazy seqs won't be realized when converting to a string?
I know I can bind *print-length*, but I don't want to constrain every collection.
And I know that lazy seqs aren't always realized, but that doesn't seem to help if they are infinite:
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
Hi Austin,
Since there is no way to know the length of a lazy-seq without realizing it, I think your only choice is to set a limit on it by binding *print-length* if you are not sure about the sequence.
Other thing you can try is bounded-count like this :
(defn looks-finite? [xs]
(let [limit 1000]
(< (bounded-count limit xs) limit)))
(looks-finite? (map inc (range))) ;; => false
(looks-finite? (map inc (range 100))) ;; => true
I hope that helps.
Juan
Austin Haas
unread,
Nov 2, 2020, 3:31:53 PM11/2/20
Reply to author
Sign in to reply to author
Forward
Sign in to forward
Delete
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
Thanks, Juan.
I don't need to know the length of the seq, though, only that it is lazy. I don't want to realize any lazy seqs. Ideally, I'd like to be able to print any data structure and have all lazy seqs print just like it does in the example I gave above (i.e., "clojure.lang.LazySeq@c5d38b66"), whether it is finite or infinite.
I also don't want to walk through every data structure to check if it contains a lazy seq, but maybe that is the only option.
I've also tried:
(defmethod print-method clojure.lang.LazySeq [q, w] (.write w "#clojure.lang.LazySeq"))
The next step might be to investigate why infinite lazy seqs don't print as clojure.lang.LazySeq, like the finite ones.
Justin Smith
unread,
Nov 2, 2020, 3:37:00 PM11/2/20
Reply to author
Sign in to reply to author
Forward
Sign in to forward
Delete
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
> The next step might be to investigate why infinite lazy seqs don't print as clojure.lang.LazySeq, like the finite ones.
that printing of "clojure.lang.LazySeq@c5d38b66" relies on completely
realizing the input, as it relies on the hash, which relies on the
fully realized value
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
Thanks, Justin!
Yeah, I noticed that range doesn't return an instance of clojure.lang.LazySeq, so I added a print-method for clojure.lang.Iterate. And that one seems to work as expected, but apparently you can't override the print-method for clojure.lang.LazySeq.
But this doesn't seem like a good approach, anyway, because I don't want to change the printing behavior globally.
I think I'm just going to have to forego logging arbitrary things, and maybe implement some optional santization if necessary.
Bret
unread,
Nov 3, 2020, 10:22:54 PM11/3/20
Reply to author
Sign in to reply to author
Forward
Sign in to forward
Delete
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
I'm not 100% happy with this plus it doesn't really answer the original question, but in case it helps in some way ...
Recently, I had a record I was working on that holds a seq that could be a lazy infinite seq that I ended up using this as the major part of print-method implementation:
I played with checking for instance of a number of things that just got too messy for me at the time. So, for now, I just decided it was good enough to basically see 2 items into the seq and indicate if there are more. This could easily be made more variable in places.
Bret
Michiel Borkent
unread,
Nov 7, 2020, 5:39:52 PM11/7/20
Reply to author
Sign in to reply to author
Forward
Sign in to forward
Delete
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Clojure
I wrote a little library for this purpose a while ago: