Idomatic Clojure really gives itself the ability to work with sequences. In C, I tend to think in terms of variables or changing the state of a variable a bunch of times. In Clojure, I think in terms of sequences. In this case, I would break the problem into three levels of abstraction:
- turn a stream into a sequence of bytes.
- turn a sequence of bytes into a sequence of characters
- translate a sequence of characters into a sequence of strings.
stream in bytes:
defn byte-seq [rdr] "create a lazy seq of bytes in a file and close the file at the end" (let [result (. rdr read)] (if (= result -1) (do (. rdr close) nil) (lazy-seq (cons result (byte-seq rdr))))))
bytes to characters
(defn bytes-to-chars [bytes] (map char bytes))
chars-to-strings [chars]
(defn chars-to-strings [chars] (let [length-str (take-wile (#{1234567890} %) chars) length (Integer/parseInt length-str) length-of-lengh (inc (count length-str)) str-seq (drop length-of-length chars)] (lazy-seq (cons (take length str-seq) (recur (drop (+ length-of-length length) chars))))))
This is evaluated lazily, so every time the next line is needed, it will be pulled out of the input stream and constructed. you could use this in a network stream, for example, without having to first buffer the entire stream or worry that reading code from this stream worries about how it is built.
ps: im not on my REPL at the moment, so please edit to fix any erros :)
Arthur ulfeldt
source share