Clojure's Simple APIs are Beautiful

December 14, 2021

Over the last couple weeks, I’ve re-discovered Clojure because I felt the itch to try some functional programming. I’ve encountered to Clojure’s immutable data-structures and a bit of its standard library during this time. What strikes me as part of the language’s true beauty is the cohesion within individual functions.

Take the zip function from Python as an example. It does it’s job and does it well. I went looking for zip in Clojure and faced disappointment. There is no zip function. “How can there be no zip?”, I wondered. Of course I can implement zip, so I did.

(defn zip
  [& colls]
  (let [items (map first colls)]
    (if (some nil? items)
      nil
      (lazy-seq (cons (into [] items) (apply zip (map rest colls)))))))

(zip [1 2 3] [:a :b :c :d] [\A \B])
;; => ([1 :a \A] [2 :b \B])

Days later I realized Clojure provides zip, in a way I did not expect, through map. The map API supports providing more than one collection, so zip is a map with a container creation function.

(map vector [1 2 3] [:a :b :c :d] [\A \B])
;; => ([1 :a \A] [2 :b \B])

This is beautiful. This is a cohesive API. Extending map to support multiple collections makes so much sense. It’s more general and still has one purpose.