2009/4/23 Christophe Grand <christo...@cgrand.net>:
>
> *Warning this message contains mutable state and may hurt functional
> sensibilities.*
>
> Ugly hack:
>
> (defn my-split-with [pred coll]
>  (let [s (atom coll)
>        p #(when-let [r (pred %)] (swap! s rest) r)]
>    [(take-while p coll) (drop-while pred (lazy-seq @s))]))

Cheater ! ;-)

But there's still the problem of having the user being able to check
the second argument before having exhausted (if possible) the first...
and then having an infinite loop: e.g. (first (second (my-split-with
true? (repeat true))).
And maybe calling swap! for each matched elem may be expensive ?
(That's a real question, I don't have any real idea, just a guess ...)

But wait ... the more I think about it, the more it appears to me
(though I can not prove it formally) that the problem requires
side-effect to be solved, either via the use of mutation, either via
the use of multiple threads for coordinating the feeding of 2 separate
sequences ?

If I'm correct, then maybe your solution is not that hacky, provided
that having to choose between manipulating a state and manipulating
multiple threads with BlockingQueues, ... the most efficient, simple
and bug free version will certainly be the local mutation of state.

With these minor enhancements, your version can also be
 * very efficient because there will be at most one swap! call (but
maybe the overhead I added by adding composition stages is worse than
calling swap! each time ?)
 * much more robust if the user tries to consume from the second seq
while not having finished consuming from the first (he will get an
exception)

Here is the final version, renamed safe-split-with for the occasion:

(defn rests [coll]
  (lazy-seq
    (if-let [s (seq coll)]
      (cons s (rests (rest s)))
      (list ()))))


(defn safe-split-with [pred coll]
  (let [s (atom nil)
         p #(if-let [r (pred (first %))] true (do (reset! s (second %)) false))]
    [(map first (take-while p (map vector coll (rests coll))))
     (lazy-seq (if-let [s @s]
                      s
                      (throw (IllegalStateException. "Tried to check
seq of elems of coll non matching pred before having exhausted seq of
elems matching pred."))))]))

; test:
(doseq [c (safe-split-with true? [true true false false])] (println c))

; test exception:
(println (second (safe-split-with true? [true true false false])))

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