On Wed, Dec 14, 2011 at 3:12 AM, Alan Malloy <a...@malloys.org> wrote:
> On Dec 13, 8:37 pm, Cedric Greevey <cgree...@gmail.com> wrote:
>> On Tue, Dec 13, 2011 at 11:25 PM, Alan Malloy <a...@malloys.org> wrote:
>> > On Dec 13, 7:56 pm, Stephen Compall <stephen.comp...@gmail.com> wrote:
>> >> On Tue, 2011-12-13 at 16:28 -0800, Alan Malloy wrote:
>> >> > As you can see, only as many elements are realized as are needed to
>> >> > satisfy the user's request.
>>
>> >> Yes, in the expression (conr (conr (conr '( 1 2 3) 4) 6) 7), all the
>> >> lazy-seqs implied by the conr calls must be forced immediately to yield
>> >> (1 . more).  It is the same problem with repeatedly concatting to the
>> >> end, and with left-fold in a top-down evaluation scheme like Haskell:
>> >> you can run out of stack if you must travel deep to get to the first
>> >> element.
>>
>> > I see. You're making a subtler point than I realized, and you're right
>> > there. Repeated applications of conr need to be resolved all at once,
>> > but conr'ing one item onto an already-realized collection doesn't
>> > cause anything new to be realized until the element itself is needed.
>>
>> One way to mitigate it would be to use a datastructure with a seq and
>> a vector: conr on a seq would produce one of these with the conr'd
>> item the sole element of the vector, and conr on one of these
>> datastructures would conj the item onto the vector. The datastructure
>> would behave as a seq: first on the datastructure would return first
>> on the seq part, and next would return a datastructure with the seq
>> part nexted -- only, if the seq had only one element, instead with
>> (seq the-vector-part) as the seq part and an empty vector part. An
>> invariant would be maintained that the seq part is nil iff the whole
>> thing is empty.
>>
>> Of course, such a datastructure is a queue, and it's not too much more
>> work to turn it into a deque. Adding at both ends in O(1) and
>> peeking/popping at the front is already in there. Peeking/popping at
>> the rear is trickier, because a naive implementation is O(n) if the
>> vector part happens to be empty. Any time the vector part would become
>> empty you'd have to split the data in half between the seq part and
>> the vector part, in a kind of reversal of how ArrayLists and vectors
>> grow in amortized O(1). The invariant would now be that if there are
>> at least two elements both parts are nonempty, if there's one element
>> the vector part is empty, and if there's none the seq part is nil.
>>
>> (And nobody give me any guff about the vector operations actually
>> being O(log_32 n); on present and near-future hardware I don't think
>> log_32 n will get much above 6 or 7, so for all practical purposes it
>> differs from O(1) by a constant factor of overhead. The work being
>> done on finger trees might enable deques with "true" O(1) peeks at
>> both ends, if the trees hold direct references to their end elements
>> in their roots -- but then I'd expect O(log n) adds and pops at both
>> ends, since the depth will need to be walked to do those.)
>
> This queue already exists: clojure.lang.PersistentQueue.

Should be better documented.

Is it a fully fledged deque?

-- 
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