The Holy Java

Building the right thing, building it right, fast

From Stateful Iteration in Python to Stateless Clojure

Posted by Jakub Holý on March 19, 2013

I have a piece of Python code that leverages a stateful object and was wondering how to reimplement it in the inherently stateless Clojure, without resorting to its facilities for managing state. It turns out to be simple and beautiful.

The core of the code is a for loop that transform a list of maps, while also using input from another iterator-like object, a Palette. The Palette has the method next() that remembers the last color used and returns the next one. Here it is:

class Palette:
    last_idx = 0
    colors = ["C04000", ...]

    def next(self):
        self.last_idx = (self.last_idx + 1) % len(self.colors)
        return self.colors[self.last_idx]

graph_items = []

for idx, item in enumerate(item_maps):
    graph_items.append({
            "itemid": item['itemid'],
            "color": palette.next(),
            "sortorder": idx
            })

In Clojure, we would rather have no such state (for reasons I won’t discuss now). However, when writing idiomatic Clojure, we actually don’t need to.

We will use the fact that map – the function that can transform collection items – can take not just one but any number of collections, iterating over all of them in parallel. Instead of using the stateful palette.next(), we will create an infinite sequence of (repeating) colors and pass it into map together with the items collection. We want also the index of the items so we pass in a third sequence, the range from 0 to infinity. The map function will be thus called with (the current index, the current item, the current color).

Using infinite sequences is quite common (and elegant) in Clojure.

This is what the code could look like:

;; An infinite sequence of the colors (starting
;; again with the 1st one, when all exhausted)
(def palette (cycle ["C04000" "..."]))

(defn make-graph-items [items]
  (map
   (fn [idx item color] {"itemid" (item "itemid"), "color" color, "sortorder" idx})
       (range) items palette))

(def graph-items (make-graph-items items))

Conclusion

Statelessness is not scary. It is fun.

Disclaimer: I am only learning both Python and Clojure.

About these ads

8 Responses to “From Stateful Iteration in Python to Stateless Clojure”

  1. Bob Shock said

    Very cool! I had a similar experience converting a stateful Sudoku solver from Java and Ruby to Clojure and Scala. The stateless code was easier to read (eventually) and also made it really easy to save the progression of the solution. Solving most of the 4clojure puzzles also helped me make the transition to a state-free mindset!

  2. francisga said

    Disclaimer: I love both Python and Clojure. however you can use an ‘infinite sequence’ style of programming quite readily in Python, too, using iterators and generators in itertools. Here is some Python equivalent to your Clojure (including lazy evaluation):
    from itertools import count, izip, cycle
    graph_items = ({‘itemid':item[‘itemid’], ‘color':color, ‘sortorder':idx} for item,color,idx in izip(items, cycle(colors), count())

  3. geek42 said

    you could try using yield instead of your state hold code

    • Could you elaborate a little, please? With yield I wouldn’t need to be appending to a collection but still would need to somehow get the next color.

  4. geek42 said

    and of course your Palette could be replaced by

    import itertools
    colors = [“C04000″, …]

    Palette = itertools.cycle(colors)

    BTW, i am a clojure love, i show this not for justifying python

Sorry, the comment form is closed at this time.

 
%d bloggers like this: