make sequence side-effectfull in Clojure
What I want to do is like following.
(def mystream (stream (range 100)))
(take 3 mystream)
;=> (0 1 2)
(take 3 mystream)
;=> (3 4 5)
(first (drop 1 mystream))
;=> 7
The stream function make sequence side-effectfull like io stream.
I think this is almost impossible. Here is my attempt.(defprotocol Stream (first! [this]))
(defn stream [lst]
  (let [alst (atom lst)]
    (reify Stream
       (first! [this]
         (let [[fs] @alst]
           (swap! alst rest)
           fs)))))
(let [mystream (stream (iterate inc 1))]
  (map #(if (string? %) (first! mystream) %)
       [:a "e" "b" :c "i" :f]))
;=> (:a 1 2 :c 3 :f)
Unfotunately this approach need to implement all function I will u开发者_如何学Cse.
Judging by your followup comment to Maurits, you don't need mutation, but rather simply need to emit a new sequence with the elements in the right place.
For example:
(defn replace-when [pred coll replacements]
  (lazy-seq
    (when (seq coll)
      (if (seq replacements)
        (if (pred (first coll))
          (cons (first replacements) 
                (replace-when pred (rest coll) (rest replacements)))
          (cons (first coll) 
                (replace-when pred (rest coll) replacements)))
        coll))))
user=> (def seq1 [:a :b :c]) #'user/seq1 user=> (def seq2 [:x "i" "u" :y :z "e"]) #'user/seq2 user=> (replace-when string? seq2 seq1) (:x :a :b :y :z :c)
This won't work with the standard take and drop, but you could quite easily write your own to work on a mutable atom, e.g. you could do something like this:
(def mystream (atom (range 100)))
(defn my-take [n stream]
  (let [data @stream
        result (take n data)]
    (reset! stream (drop n data))
    result))  
(my-take 3 mystream)
=> (0 1 2)
(my-take 3 mystream)
=> (3 4 5)
 加载中,请稍侯......
      
精彩评论