Idomatic Clojure действительно позволяет работать с последовательностями. В Си я склонен думать в терминах переменных или изменения состояния переменной несколько раз. В Clojure я думаю с точки зрения последовательности. В этом случае я бы разбил задачу на три уровня абстракции:
- превратить поток в последовательность байтов.
- превратить последовательность байтов в последовательность символов
- перевод последовательности символов в последовательность строк.
поток в байтах:
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))))))
байтов в символы
(defn bytes-to-chars [bytes]
(map char bytes))
символы в строки [символы]
(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))))))
Это вычисляется лениво, поэтому каждый раз, когда потребуется следующая строка, она будет извлечена из входного потока и построена. Вы могли бы использовать это в сетевом потоке, например, без необходимости сначала буферизовать весь поток, или беспокоиться о том, чтобы чтение кода из этого потока беспокоилось о том, как он построен.
ps: сейчас я не на моем REPL, поэтому, пожалуйста, отредактируйте, чтобы исправить любые ошибки:)