On Sun, Nov 23, 2008 at 2:34 PM, André Thieme <[EMAIL PROTECTED]>wrote:
> > On 23 Nov., 13:38, "[EMAIL PROTECTED]" <[EMAIL PROTECTED]> > wrote: > > > I have agents whose state is a vector (used as a buffer) of messages. > > There are a couple of transformation functions, e.g. tagging messages, > > removing messages from the vector etc. which are implemented with map > > and filter. In addition when messages are appended to the vector, conj > > is used and messages end up at the end of the vector. Later I noticed > > that the order was screwed because some intermediate tagging (using > > map) returned a secuence as the new agent's state and later additions > > with conj prepended messages at the front. This motivated me to ask > > for the simplest and most efficient way to get a vector back because > > that's what I wanted. Now I use a list instead of a vector and use > > reverse when necessary. > > A typical design pattern in functional programming languages is, > to write ones own map function. Was it easier to solve your problem > by doing it with lists compared to something like: > > user> (defn vmap [function vector] > (loop [[f & r :as v] vector result []] > (if (nil? v) > result > (recur r (conj result (function f)))))) > #'user/vmap > user> (vmap inc [10 20 30]) > [11 21 31] > ? > > Although I would agree that something like vmap should be in the > core language itself. Maybe if there would be a datatype > clojure.lang.LazyConj vs. the now existing clojure.lang.LazyCons. > And then a (lazy-conj ...) function would also be needed. > This could then build lazy lists and also vectors, and on top of that > one could build vmap, or replace map with it. > Wouldn't it be be less brittle to define an operation that always adds an element to the end of a sequence instead of relying on conj and some (undocumented?) knowledge how it works for (seqs over) particular datatypes? For example, if you define something like (defmulti enqueue (fn [coll elt] (class coll))) (defmethod enqueue LazilyPersistentVector [coll elt] (conj coll elt)) (defmethod enqueue :default [coll elt] (concat coll [elt])) you get stacks using cons/first/rest and queues using enqueue/first/rest in a nice, symmetrical way. user> (def queue (enqueue (enqueue (enqueue [] 1) 2) 3)) #'user/queue user> (first queue) 1 user> (rest queue) (2 3) user> (def stack (cons 3 (cons 2 (cons 1 [])))) #'user/stack user> (first stack) 3 user> (rest stack) (2 1) If you are dealing with long queues, performance might certainly be a concern with this approach. But unless you have a server with a really heavy workload I don't think it should be a problem for message queues (and you can still use vmap for performance reasons, but the program stays correct even if you accidentially use map somewhere). Matthias --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] 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 -~----------~----~----~----~------~----~------~--~---
