# Mastering Clojure Iteration: A Practical Guide

You're working with a collection in Clojure and need to iterate over it. You reach for... wait, which one?

* `for`
    
* `map`
    
* `doseq`
    
* `run!`
    

In my experience, while the official documentation exists, it's often unclear **when** to use each construct. This guide breaks down the differences with practical examples, so you can make the right choice every time.

**TLDR:** Always use `run!` and `doseq` for side-effects, and `map` and `for` for lazy data transformations

### **1.** `map` - Transform Collections

**Purpose:** Transform each element of a collection into something else.

**Returns:** A lazy sequence of transformed values.

**When to use:**

* You want to convert one collection into another
    
* You're applying a transformation function
    
* You **need the result** for further processing
    

**Characteristics:**

* **Lazy** - only computes values when needed
    
* **Returns a sequence** - the transformed collection
    
* **Pure** - no side effects expected
    

```clojure
;; Transform numbers to their squares
(map #(* % %) [1 2 3 4])
;; => (1 4 9 16)

;; Extract user IDs
(map :user-id users)
;; => ("alice" "bob" "charlie")

;; Transform with a function
(map str/upper-case ["hello" "world"])
;; => ("HELLO" "WORLD")
```

**When NOT to use map:**

The key insight is that `map` is lazy, so side effects inside `map` can lead to surprising results.

If you're doing side effects, you probably want `doseq` or `run!` instead.

```clojure
;; This creates a lazy sequence but doesn't execute
(def squares (map #(do (println "Computing" %)
                       (* % %))
                  [1 2 3]))
;; => No output yet!

;; Realizing the sequence triggers computation
(doall squares)
;; Computing 1
;; Computing 2
;; Computing 3
;; => (1 4 9)
```

### **2.** `for` - List Comprehensions

**Purpose:** Build a collection with complex iteration logic (filters, multiple bindings, let bindings).

**Returns:** A lazy sequence.

**When to use:**

* You need complex iteration with multiple sequences
    
* You want to filter while iterating
    
* You need `let` bindings inside the iteration
    
* You're translating a mathematical set notation
    

**Characteristics:**

* **Lazy** - only computes when realized
    
* **Returns a sequence** - the generated collection
    
* **Declarative** - reads like "for each X in Y, produce Z"
    

```clojure
;; Cartesian product with filter
(for [x [1 2 3]
      y [4 5 6]
      :when (even? (+ x y))]
  [x y])
;; => ([1 5] [2 4] [2 6] [3 5])

;; Multiple bindings with let
(for [user users
      :let [email (:email user)
            domain (second (str/split email #"@"))]
      :when (= domain "example.com")]
  (:name user))
;; => ("Alice" "Bob")

;; Nested iteration
(for [feed feeds
      item (:items feed)]
  (process-item feed item))

;; Perfect for generating a deck of cards
(def suits #{:hearts :diamonds :clubs :spades})
(def ranks ["2" "3" "4" "5" "6" "7" "8" "9" "10" "J" "Q" "K" "A"])

(defn make-deck
  "Create a 52-card deck"
  []
  (shuffle
   (for [suit suits
         rank ranks]
     {:suit suit :rank rank})))
```

**Rule of thumb:** Use `for` when you need `:when`, `:let`, or multiple sequences. Use `map` for simple one-to-one transformations.

Generally, follow the same rules as `map` Don’t use this when you need to generate side effects.

```clojure
;; Unnecessarily verbose
(for [user users]
  (:email user))

;; Better - Use map
(map :email users)

;; weird with side effects
=> (doall (map println [1 2 3]))
1
2
3
(nil nil nil)
```

### **3.** `doseq` - Imperative Iteration for Side Effects

**Purpose:** Execute side effects for each element in a collection.

**Returns:** `nil` (you're not using the return value).

**When to use:**

* You're doing I/O (printing, file writes, network calls)
    
* You're mutating state (atoms, databases)
    
* You need multiple operations per item
    
* You need destructuring or complex bindings
    

**Characteristics:**

* **Eager** - executes immediately
    
* **Returns nil** - signals "I'm doing side effects"
    
* **Imperative** - like a `for` loop in other languages
    

```clojure
;; doseq - Best for performing side effects for each result

;; Destructuring with complex logic with :keys
(doseq [{:keys [name email role]} users]
  (when (= role "admin")
    (send-admin-notification name email)))

;; Multiple operations per item
(doseq [order orders]
  (send-confirmation-email order)
  (update-inventory order)
  (log-transaction order))

;; Nested iteration
(doseq [feed feeds]
  (println "Processing" (:feed-id feed))
  (doseq [item (:items feed)]
    (save-to-db item)))
```

### **4.** `run!` - Concise Side Effects

**Purpose:** Apply a **single side-effecting function** to each element.

**Returns:** `nil`.

**When to use:**

* You're calling one side-effect producing function per item
    
* You don't need destructuring
    
* You want concise code
    

**Characteristics:**

* **Eager** - executes immediately
    
* **Returns nil** - signals side effects
    
* **Concise** - one-liner for simple cases
    

`run!` is more concise for when you're just calling a single function

```clojure
;; doseq - verbose
(doseq [alert alerts]
  (println alert))

;; Better with run! - concise
(run! println alerts)

;; Send email to each user
(run! send-email users)

;; Save each document
(run! save-to-db documents)

;; Close each connection
(run! #(.close %) connections)
```

#### **When You Shouldn’t Use** `run!`

```clojure
;; Multiple operations - better with doseq
(doseq [user users]
  (send-email user)
  (log-activity user)
  (update-db user))

;; Destructuring
;; With run! you need a wrapper
(run! (fn [{:keys [name email]}]
        (send-email name email))
      users)

;; Better with doseq!
(doseq [{:keys [name email]} users]
  (send-email name email))

;; Conditional logic
;; With run! you need the logic in the function
(run! (fn [user]
        (when (active? user)
          (send-notification user)))
      users)

;; doseq is clearer
(doseq [user users]
  (when (active? user)
    (send-notification user)))
```

### **Summary**

| **Construct** | **Returns** | **Eager/Lazy** | **Primary Use** | **Side Effects?** |
| --- | --- | --- | --- | --- |
| `map` | Transformed sequence | Lazy | Transform data | ❌ No (pure) |
| `for` | Generated sequence | Lazy | Complex collection building | ❌ No (pure) |
| `doseq` | `nil` | Eager | Multiple side effects per item | ✅ Yes |
| `run!` | `nil` | Eager | Single function call per item | ✅ Yes |

Understanding the different iteration constructs in Clojure is crucial for writing efficient and effective code.

Use `map` and `for` when transforming data with lazy evaluation and pure functions. For producing side effects, `doseq` and `run!` are better suited, providing eager execution and clear intent for side-effecting operations.

I hope this helps on your Clojure journey. It has definitely helped in mine.

Further Reading Resources:

* [Clojure’s for](https://clojure.org/guides/learn/flow#_clojures_for)
    
* [Clojure map documentation](https://clojuredocs.org/clojure.core/map)
    
* [Clojure doseq documentation](https://clojuredocs.org/clojure.core/doseq)
    
* [Clojure doall documentation](https://clojuredocs.org/clojure.core/doall)
    
* [Iteration for Side Effects - Clojure Guides](https://clojure.org/guides/learn/flow#_iteration_for_side_effects)
    
* [Clojure run! documentation](https://clojuredocs.org/clojure.core/run!)
