See the source of clojure.contrib.duck-streams/read-lines
http://clojuredocs.org/clojure_contrib/clojure.contrib.duck-streams/read-lines

For the second question: Use read-lines directly.

If you want a lazy-seq that doesn't close the stream when it's empty,

; untested
(defn take-bytes [rdr]
    (lazy-seq (cons (.take rdr) (take-bytes rdr))))

which will produce an "infinite" sequence.

Jonathan

On Thu, May 19, 2011 at 11:50 AM, timc <timgcl...@gmail.com> wrote:

> Hello
> I wonder if I could ask for advice on how to construct a lazy sequence. My
> application might be of interest to some of you.
>
> The context for this is that I have an embedded system with very limited
> facilities for proper debugging.
> I have inserted a 'trace' facility in the embedded code that is able to
> emit binary bytes that I can capture over a serial comm channel.
> So, what I get is a stream of bytes that is a sort of mini-language.
>
> For example, I might get the values as in this seq:
>
>   (def bSeq [1 20 30 4 1 7 8 5 60 5 70])
>
> where the 'sentences' of this language are as follows:
>
> 1 a b (that is, a 1 is followed by two values),
> 4 (that is, a 4 is on its own)
> 5 x (that is, a 5 is followed by one value),  and so on.
>
> Now, examining this stream of values is tedious to say the least, so I want
> to parse it and print meaningful versions of the sentences (after all, I
> know what they really mean :).
> So, I construct a set of specifications for the sentences, like this:
>
> (defstruct Spec :nArgs :fmt)
>
> (def specs {
>     1 (struct Spec 2 "[1] a=%d b=%d\n")
>     4 (struct Spec 0 "[4]\n")
>     5 (struct Spec 1 "[5] z=%d\n")
>     })
>
> The map of Specs is keyed by the value that starts the sentence.
> The Spec itself comprises :nArgs (how many values follow)
> and :fmt (a string for the format function, expecting :nArgs values, which
> will render the sentence in a useful way).
>
> I want to do the parsing of the byte sequence as follows, using the magic
> of reduce:
>
> (reduce parser {} bSeq)
>
> where the parser function is this:
>
>   (defn parser [m a]
>     (if (empty? m)
>       (if-let [spec (specs a)]
>         (if (zero? (spec :nArgs))
>           (do
>             (print (format (spec :fmt)))
>             {})
>           {:spec spec :args []})
>         (throw (Error. (format "Input %d has no format spec" a))))
>       (let [newArgs (conj (m :args) a)]
>         (if (= ((m :spec) :nArgs) (count newArgs))
>           (do
>             (print (apply format ((m :spec) :fmt) newArgs))
>             {})
>           (assoc m :args newArgs)))))
>
> To explain a bit: the args to parser are m, a map with keys:
>   :spec -- the spec of the sentence that is currently being parsed
>   :args -- a vector of the args to this sentence
> or the empty map if the next thing expected is the start value of a
> sentence;
> and a the next value in the sequence.
>
> Lo and behold, this produces formatted output like this:
>
> [1] a=20 b=30
> [4]
> [1] a=7 b=8
> [5] z=60
> [5] z=70
>
> So far so good, but here comes the real question of this post.
> The data arrives from the serial port in variable sized byte arrays at
> unpredictable moments in time; these are placed in a queue, like this:
>
> (def inputQ (java.util.concurrent.LinkedBlockingQueue.))
> (defn inputArrives [byteArray] (.put inputQ byteArray))
>
> It is of course very easy to read the things out of the queue by means of
> (.take inputQ), and then read the bytes one-by-one; of course this may block
> waiting for more inputs.
>
> So - how do I make a function that returns a lazy sequence that internally
> is getting the byte arrays off this queue and feeding the bytes contained
> therein to the caller of the lazy sequence - one byte at a time?
>
> And - a similar question (easier to answer I imagine) how do I construct a
> lazy sequence from the bytes read from a file (possibly with some
> translation between reading the raw bytes from the file and handing them
> over to the caller of the lazy sequence)?
>
> Of course, I could (and have) implemented all the above in a much more
> procedural kind of way, but it is so much more elegant (and easier to
> understand) with a lazy sequence :)
>
> Looking forward to some remarkable, simple solutions :)
>
> Regards, Tim
>
> PS Thinking about this makes me wonder about the existence, or
> non-existence of a 'super-reduce' function that could do context-free
> grammar parsing.
> Is such a thing possible? Is there-such a thing as a lazy back-trackable
> sequence? Now that I've asked - I'm not even sure what that means :))
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to