Question

I'm trying to read in a file line by line and concatenate a new string to the end of each line. For testing I've done this:

(defn read-file
[filename]
(with-open [rdr (clojure.java.io/reader filename)]
  (doall (line-seq rdr))))

(apply str ["asdfasdf" (doall (take 1 (read-file filename)))])

If I just evaluate (take 1 (read-file filename)) in a repl, I get the first line of the file. However, when I try to evaluate what I did above, I get "asdfasdfclojure.lang.LazySeq@4be5d1db".

Can anyone explain how to forcefully evaluate take to get it to not return the lazy sequence?

Was it helpful?

Solution

The take function is lazy by design, so you may have to realize the values you want, using first, next, or nth, or operate on the entire seq with functions like apply, reduce, vec, or into.

In your case, it looks like you are trying to do the following:

(apply str ["asdfasdf" (apply str (take 1 (read-file filename)))])

Or:

(str "asdfasdf" (first (read-file filename)))


You can also realize the entire lazyseq using doall. Just keep in mind, a realized lazy seq is still a seq.

(realized? (take 1 (read-file filename))) ;; => false
(type (take 1 (read-file filename))) ;; => clojure.lang.LazySeq

(realized? (doall (take 1 (read-file filename)))) ;; => true
(type (doall (take 1 (read-file filename)))) ;; => clojure.lang.LazySeq


A better option would be to apply your transformations lazily, using something like map, and select the values you want from the resulting seq. (Like stream processing.)

(first (map #(str "prefix" % "suffix")
             (read-file filename)))

Note: map is lazy, so it will return an unrealized LazySeq.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top