Loop Code Recur All Articles
Algorithms & Problem Solving

Live Clojure Cookbooks: Ready-to-Use Recipes for Everyday Functional Programming

By Loop Code Recur Algorithms & Problem Solving
Live Clojure Cookbooks: Ready-to-Use Recipes for Everyday Functional Programming

There's a certain type of Clojure tutorial that starts with "first, let's discuss the philosophical implications of immutability..." — and by paragraph three, you've closed the tab and opened Slack. Look, we love theory here at Loop Code Recur, but sometimes you just need a recipe. Something you can copy, paste, tweak, and ship before your stand-up.

So here's our take on a live cookbook: working recipes for the problems Clojure devs actually hit, with the algorithmic thinking explained just enough to make them stick.

Recipe 1: Deep-Merge Nested Config Maps

The problem: you've got a base config and an environment override, and merge only handles the top level.

(defn deep-merge [a b]
  (if (and (map? a) (map? b))
    (merge-with deep-merge a b)
    b)))

That's it — recursion doing the heavy lifting. Notice the structure: base case (not both maps? take b), recursive case (merge maps, recursing on conflicts). Once you see this shape, you'll spot it everywhere. It's the same skeleton as traversing a tree, because... it is traversing a tree.

Recipe 2: Flatten a Deeply Nested Structure (Without flatten)

Core's flatten nukes everything into a flat list. Often you only want to flatten one level, or flatten while keeping certain things intact:

(defn flatten-once [coll]
  (mapcat #(if (sequential? %) % [%]) coll))

(flatten-once [1 [2 3] 4 [5]])
;; => (1 2 3 4 5)

mapcat is the unsung hero of Clojure — it's map followed by concat, which is honestly how half of data pipelines work anyway.

Recipe 3: Group Records by a Computed Key

Every API response ever: a list of records you need bucketed. Maybe you're grouping customers by state code for a US-wide rollout, or orders by week:

(->> orders
     (group-by (comp :state :shipping-address))
     (map (fn [[state os]] [state (count os)]))
     (into (sorted-map)))

The (comp :state :shipping-address) bit is the move to internalize — composing key extractors keeps your transformations declarative. sorted-map gives you alphabetical output for free, which matters when someone's eyeballing a report.

Recipe 4: Write Your Own reduce (Yes, Really)

You use reduce daily. But writing it yourself is a five-minute exercise that permanently upgrades your intuition:

(defn my-reduce [f init coll]
  (loop [acc init
         remaining coll]
    (if (seq remaining)
      (recur (f acc (first remaining))
             (next remaining))
      acc)))

loop/recur is Clojure's iteration workhorse — recur rebinds the loop locals without consuming stack, so this handles millions of elements without a stack overflow. Once you've written this, reduce, transduce, and iterate all stop feeling like magic.

Recipe 5: Sliding Window Over a Sequence

Computing a moving average, diffing consecutive items, rate-limit checks — all sliding window problems:

(defn sliding-pairs [coll]
  (map vector coll (rest coll)))

(sliding-pairs [10 12 9 15])
;; => ([10 12] [12 9] [9 15])

Two lines. The lazy rest means this never materializes the whole sequence in memory — great for log processing where "the log" is 4GB of Tuesday.

How to Use This Cookbook

Don't memorize these. Instead, notice the patterns:

That's four patterns covering maybe 80% of day-to-day Clojure data wrangling. Keep this page bookmarked, paste the recipe, adjust the shape of your data, and move on with your life.

And when you're ready to go deeper — say, turning recipe #4 into a full understanding of transducers, or recipe #5 into a rate limiter running in production — you know where to find us. One iteration at a time.