Reputation: 6527
I'm trying to realize a lazy sequence (which should generate a single string) in the REPL, with no luck. The original code works fine:
(def word_list ["alpha" "beta" "gamma" "beta" "alpha" "alpha" "beta" "beta" "beta"])
(def word_string (reduce str (interpose " " word_list)));
word_string ; "alpha beta gamma beta alpha alpha beta beta beta"
But not wanting to leave well enough alone, I wondered what else would work, and tried removing the reduce
, thinking that str
might have the same effect. It did not...
(def word_string (str (interpose " " word_list)))
word_string ; "clojure.lang.LazySeq@304a9790"
I tried the obvious, using reduce
again, but that didn't work either. There's another question about realizing lazy sequences that seemed promising, but nothing I tried worked:
(reduce str word_string) ; "clojure.lang.LazySeq@304a9790"
(apply str word_string) ; "clojure.lang.LazySeq@304a9790"
(println word_string) ; "clojure.lang.LazySeq@304a9790"
(apply list word_string) ; [\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...]
(vec word_string) ; [\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...]
(apply list word_string) ; (\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...)
(take 100 word_string) ; (\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...)
The fact that some of the variations, gave me the characters in "clojure.lang.LazySeq" also worries me - did I somehow lose the actual string value, and my reference just has the value "clojure.lang.LazySeq"? If not, how do I actually realize the value?
To clarify: given that word_string
is assigned to a lazy sequence, how would I realize it? Something like (realize word_string)
, say, if that existed.
Update: based on the accepted Answer and how str
works, it turns out that I can get the actual sequence value, not just its name:
(reduce str "" word_string) ; "alpha beta gamma beta alpha alpha beta beta beta"
Yes, this is terrible code. :) I was just trying to understand what was going on, why it was breaking, and whether the actual value was still there or not.
Upvotes: 2
Views: 1086
Reputation: 12883
You don't need to do anything special to realize a lazy seq in clojure, you just use it in any place that a seq is expected.
user=> (def word-list ["alpha" "beta" "gamma" "beta" "alpha" "alpha" "beta" "beta" "beta"])
#'user/word-list
user=> (def should-be-a-seq (interpose " " word_list))
#'user/should-be-a-seq
user=> (class should-be-a-seq)
clojure.lang.LazySeq
So we have a seq, if I use it in any case that would go through all of the values in the seq, it will end up fully realized. e.g.
user=> (seq should-be-a-seq)
("alpha" " " "beta" " " "gamma" " " "beta" " " "alpha" " " "alpha" " " "beta" " " "beta" " " "beta")
It's still a seq though, in fact it's still the same object that it was before.
user=> (str should-be-a-seq)
"clojure.lang.LazySeq@304a9790"
As Diego Basch mentioned, calling str on something is just like calling .toString, which for the LazySeq method is apparently just the default .toString that is inherited from Object.
Since it's a seq, you can use it like any seq, whether it's been fully realized previously or not. e.g.
user=> (apply str should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (reduce str should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (str/join should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (str/join (map #(.toUpperCase %) should-be-a-seq))
"ALPHA BETA GAMMA BETA ALPHA ALPHA BETA BETA BETA"
Upvotes: 2
Reputation: 13059
What you want is:
(def word_string (apply str (interpose " " word_list)))
Look at the documentation of str
:
With no args, returns the empty string. With one arg x, returns
x.toString(). (str nil) returns the empty string. With more than
one arg, returns the concatenation of the str values of the args.
So you're calling .toString
on the sequence, which generates that representation instead of applying str
to the elements of the sequence as arguments.
BTW, the more idiomatic way of doing what you want is:
(clojure.string/join " " word_list)
Also, a string is not a lazy sequence. interpose
returns a lazy sequence, and you're calling .toString
on that.
Upvotes: 4