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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en