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 clojure@googlegroups.com
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to