I trying clojure i am trying to figure out how to implement the following algorithm,
I am reading from an input stream i want to continue reading until it is not a delimiter character.
i can do this in java with a while loop but i can't seem to figure out how to do it in clojure?
while read readChar != delimiter do some processing.... end while
Following is the syntax of the 'while' statement. The while statement is executed by first evaluating the condition expression (a Boolean value), and if the result is true, then the statements in the while loop are executed. The process is repeated starting from the evaluation of the condition in the while statement.
Clojure collections "collect" values into compound values. There are four key Clojure collection types: vectors, lists, sets, and maps.
Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and unlike most Lisps where the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences.
I don't know Clojure, but it looks that, like Scheme, it supports "let loops":
(loop [char (readChar)]
(if (= char delimiter)
'()
(do (some-processing)
(recur (readChar)))))
Hope this is enough to get you started. I referred to http://clojure.org/special_forms#toc9 to answer this question.
NOTE: I know that Clojure discourages side-effects, so presumably you want to return something useful instead of '().
Working on Clojure 1.3.0, and for what it's worth, you can write while loops in Clojure now by doing something akin to
(while truth-expression
(call-some-function))
The loop approach will work fine in clojure however loop/recur are considered low level operations and higher order functions usually preferred.
Normally this sort of problem would be solved by creating a sequence of tokens (characters in your example) and applying on or more of clojure's sequence functions (doseq, dorun, take-while, etc.)
The following example reads the first username from /etc/passwd on unix like systems.
(require '[clojure.java [io :as io]])
(defn char-seq
"create a lazy sequence of characters from an input stream"
[i-stream]
(map char
(take-while
(partial not= -1)
(repeatedly #(.read i-stream)))))
;; process the sequence one token at a time
;; with-open will automatically close the stream for us
(with-open [is (io/input-stream "/etc/passwd")]
(doseq [c (take-while (partial not= \:) (char-seq is))]
;; your processing is done here
(prn c)))
I came up with this in the spirit of line-seq
. It's fully lazy and exhibits more of Clojure's functional nature than loop
.
(defn delim-seq
([#^java.io.Reader rdr #^Character delim]
(delim-seq rdr delim (StringBuilder.)))
([#^java.io.Reader rdr #^Character delim #^StringBuilder buf]
(lazy-seq
(let [ch (.read rdr)]
(when-not (= ch -1)
(if (= (char ch) delim)
(cons (str buf) (delim-seq rdr delim))
(delim-seq rdr delim (doto buf (.append (char ch))))))))))
Full paste.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With