Hi,

The problem is that you end up with the front of your worklist being
wrapped in <n-lines> nested calls to lazy-seq, one per each call to
concat.  Then, realizing the first element causes a stack overflow.
This wouldn't happen if you reversed the arguments to concat, but then
you wouldn't get what you want.  Some possibilities (untested):

; probably the shortest, most idiomatic solution?

(defn getstrlist [file]
  (apply concat
    (take-while identity
      (repeatedly #(getline file)))))

;or, using vectors, and written more like your solution:

(defn getstrlist [file]
  (loop [worklst []]
   (if-let [x (getline file)]
      (recur (into worklst x))
     worklst)))

Cheers,
Jason


On Mar 1, 4:53 pm, Zededarian <zededar...@gmail.com> wrote:
> My ultimate goal is to get a list of all the words in a file in
> order.  I have a function that will get a list of all the words on one
> line of this file in order, and I want to efficiently concatenate
> these lists to end up with one large list.  I'm working with about
> 12000 lines right now, but in a perfect world I'd like to scale much
> higher.
>
> I started off just using concat.  Basically my code looks like:
> (defn getstrlist
>   ([file]
>      (loop [x (getline file) worklst '()]
>        (if x
>          (recur (getline file) (concat worklst (splitstr x)))
>          worklst))))
>
> Then in the REPL, if I type (def a (getstrlist FILE)), it works fine.
> But if I try to output a or take (first a), I get a stack overflow
> error.  I don't know why this is.  I remember hearing somewhere that
> Clojure had lazy sequences, so my best guess is that it isn't actually
> concatenating anything, but is storing pointers to the start of all
> the lists on a stack that overflows when I try to evaluate one of
> these pointers.
>
> I know in Scheme I would write this using metalists that keep track of
> the location of their last element:
> (define (concat metalst1 metalst2)
>   (set-cdr! (car metalst1) (cdr metalst2))
>   (set-car! metalst1 (car metalst2))
>   metalst1)
>
> (define (make-metalst lst)
>   (cons (get-end lst) lst))
>
> (define (get-end lst)
>   (if (null? lst)
>       '()
>       (if (null? (cdr lst))
>           lst
>           (get-end (cdr lst)))))
>
> Which would be fairly efficient.  But since Clojure doesn't seem to
> have real lists, I'm not quite sure how I could port this over.  I
> suppose I could implement my own cons pairs like an idiot and do all
> of this manually, but I figure I'm just not understanding the "Clojure
> solution" to this problem.
--~--~---------~--~----~------------~-------~--~----~
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