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 <[email protected]> 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 [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
-~----------~----~----~----~------~----~------~--~---