1
votes

I am working on a problem to read in a file with lines like:

A abcdefg
B bcdefgh

But I keep getting errors about Lazy Sequence not compatible with Java Charseq ..

I tried:

(def notlazy (doall lyne2))

Then thought I verified:

(realized? notlazy)
true

But still:

(str/split notlazy #" ")
ClassCastException class clojure.lang.LazySeq cannot be cast to class
  java.lang.CharSequence (clojure.lang.LazySeq is in unnamed module of
  loader 'app'; java.lang.CharSequence is in module java.base of loader
  'bootstrap')  clojure.string/split (string.clj:219)

Help please!

2

2 Answers

6
votes

The first argument to str/split must be a CharSequence to be split. Presumably you want to split each input line in the sequence for which you can use map without needing to eagerly evaluate the input sequence:

(map (fn [line] (str/split line #" ")) lyne2)
1
votes

Expanding on the previous result a bit, we have this example. You can reproduce the following using this template project.

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [clojure.java.io :as io]
    [tupelo.string :as str]
    ))

(def data-file
  "A abcdefg
   B    bcdefgh
  ")

(dotest
  ; Version #1
  (let [lines      (line-seq (io/reader (str/string->stream data-file)))
        lines2     (remove str/blank? lines)
        lines3     (map str/trim lines2)
        line-words (mapv #(str/split % #"\s+") lines3) ; "\s+" => "one or more whitespace chars"
        ]
    (spyxx lines)
    (spyxx lines2)
    (spyxx lines3)
    (spyxx line-words))

with result:

--------------------------------------
   Clojure 1.10.2-alpha1    Java 15
--------------------------------------

Testing tst.demo.core
lines       => <#clojure.lang.Cons ("A abcdefg" "   B    bcdefgh" "  ")>
lines2      => <#clojure.lang.LazySeq ("A abcdefg" "   B    bcdefgh")>
lines3      => <#clojure.lang.LazySeq ("A abcdefg" "B    bcdefgh")>
line-words  => <#clojure.lang.PersistentVector [["A" "abcdefg"] ["B" "bcdefgh"]]>

This shows the type of each result along with its value. We use string->stream so we don't need to set up a dummy file to read from.

The following shows how it would typically be written in real code (not as a demo exercise like Version #1). We use the "thread-last" operator, and write a unit test to verify the result:

  ; Version #2
  (let [result (->> data-file
                 (str/string->stream)
                 (io/reader)
                 (line-seq)
                 (remove str/blank?)
                 (map str/trim)
                 (mapv #(str/split % #"\s+"))) ; "\s+" => "one or more whitespace chars"
        ]
    (is= result [["A" "abcdefg"] ["B" "bcdefgh"]])))