On Sat, January 11, 2014 9:22 pm, Alex Baranosky wrote:
> There is a class of problems where you want to track some state as you
process a seq

This is an interesting exercise.  I find said class of problem comes up
fairly frequently and I usually end up with something scary-looking using
reduce or lazy-seq that I'm never quite satisfied with.  I often feel
there's some missing flow control mechanism just out of reach.

As another point of comparison here's a straightforward imperative version
(of the simplified problem):

    (defn unique [words]
      (let [occurrences (java.util.HashMap.)]
        (for [word words]
          (let [n (get occurrences word 0)]
            (.put occurrences word (inc n))
            (if (zero? n) word (str word "_" n))))))

i.e. "if a tree falls in the woods..." style mutation. :-)

> and transduce.lazy/map-state enables you to do that
(https://github.com/brandonbloom/transduce)

The imperative solution led me towards something like the "for"-like form
of map-state.  A macro that's a hybrid of "for" and "loop" such that it
takes both for and loop style bindings:

    (defn unique [words]
      (for-loop [word words] [occurrences {}]
        (let [n (get occurences word 0)]
          (yield (if (zero? n) word (str word "_" n))
            (assoc occurrences word (inc n))))))

Imagine "yield" is somewhat like "recur" in that it takes new values to
bind for the next iteration but its first argument is the sequence element
to return for the current step.  Like recur yield must be in the tail call
position.

The above might expand into this:

    (defn uniquify [words format]
      ((fn uniquify* [occurrences words]
        (lazy-seq
          (let [[word & rest] words
                n (get occurrences word 0)]
            (when word
              (cons (if (zero? n) word (str word "_" n))
                    (uniquify* (assoc occurrences word (inc n))
                               rest))))))
       {} words))



-- 
-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to