So, I'm trying to understand functional programming, particularly as
it relates to the seq abstraction, and I'm hitting a slight difficulty
as I'm playing around - something that seems as if it ought to be
simple, is not.

I'm playing with copying one seq into another. I've found several
different ways to do it, but the most obvious one, in my opinion, is
missing.

Here's the straight-up, high performance tail recursive version that
was my first thought:

(defn copy-seq-r [source]
  (loop [so-far '() to-go source]
    (if (nil? to-go)
      so-far
      (recur (cons (first to-go) so-far)
             (rest to-go)))))

The obvious problem with this is that because seqs are last-in first-
out, this returns the seq in reverse order. Obviously not what we
wanted. And using (reverse) or consing the (last) is awful for
performance.

The next implementation is simpler, and uses recursion quite
elegantly:

(defn copy-seq [source]
    (if (nil? source)
      '()
      (cons (first source) (copy-seq (rest source)))))

The obvious fault with this is that it's non tail-recursive and blows
the stack with seqs of greater than 200-300 elements.

This can be fixed by making the cons a lazy-cons. This creates a
lazily-called function that closes over the source parameter, thus
removing the call from the stack. This works fine in Clojure, and
seems to be the best solution for actual use in a program. (One
question... Is the reference to the lazy function maintained after the
function is realized? I don't want to have thousands seqs hanging
around in memory while they're not needed. Also, I'm not 100% sure of
the semantics of lazy-cons... the above code implemented with lazy-
cons IS O(n) in both time and space, correct? Or does lazy-cons do
something different than I'm thinking of)

However, there is a sense in which using lazy-cons feels rather like a
cheat. It feels like there ought to be a straightforward functional
way to copy a seq/list, in order, in O(n) time, without using
laziness. Or is this seemingly simple task an impossibility due to the
nature of the singly-linked list? That's beginning to be what I'm
thinking. What would one do in a language like Scheme, without lazy-
cons?

(Of course, another solution in Clojure would be to copy to a vec
instead of a list and then seq it... But I'm more interested in the
theory, here).

Thanks in advance for the help - I know this is probably a stupid
question, but I'm curious and want to make sure the way I'm thinking
about lists and seqs is correct.

--~--~---------~--~----~------------~-------~--~----~
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 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to