brokensandals.net -> Technical -> Thinking functionally about a simple function

From 2011-11-15.

I had a very simple function to write: given a list of timestamped objects (some having duplicate timestamps) sorted by time, modify the first object at every timestamp in a certain way.

In Ruby I might write:

prev_time = nil
new_objects = objects.map do |object|
  result = (prev_time == object.time ? object : modify(object))
  prev_time = object.time
  result
end

But the project is coded in Clojure, which discourages such imperative code (by making it so ugly you feel silly and a little guilty for writing it). I didn’t immediately see a not-annoyingly-verbose way to implement this.

I was just failing to think functionally; if I view the problem as having:

then this can just be solved with map, provided we can generate a list of the values for the second parameter. Obviously they stand in a simple relationship to those for the first, so that should be easy; here, it’s just the first list, shifted to the right one position.

(defn modify-if-necessary [object prev-object]
  (if (= (:time object) (:time prev-object))
      object
      (modify object)))

(map modify-if-necessary objects (cons nil objects))