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