Here’s a way to avoid recursive helper functionsâ€¦

By using loop in Clojure.

Sometimes recursive helper functions seem needed, like `fibonacci-iter`

:

```
(defn- fibonacci-iter [a b count]
(if (= count 0)
b
(recur (+ a b) a (- count 1))))
(defn fibonacci [n]
(fibonacci-iter 1 0 n))
```

Code language: Clojure (clojure)

(I ported this to Clojure from Structure and Interpretation of Computer Programs, licensed CC BY-SA-4.0)

That `fibonacci-iter`

helper function is only needed for recursion.

For example, the public `(defn fibonacci [n]`

only needs an argument `n`

for the index of the Fibonacci number.

`(fibonacci 1)`

returns `1`

`(fibonacci 2)`

returns `1`

`(fibonacci 3)`

returns `2`

`(fibonacci 4)`

returns `3`

`(fibonacci 5)`

returns `5`

etcâ€¦

But `fibonacci-iter`

needs arguments to keep track of the recursion.

`(defn- fibonacci-iter [a b count]`

### Arguments in each recursion

a | b | count |
---|---|---|

1 | 0 | 5 |

1 | 1 | 4 |

2 | 1 | 3 |

3 | 2 | 2 |

5 | 3 | 1 |

8 | 5 (returns this, ending recursion) | 0 |

These arguments tell it when to end the recursion, and what to return:

```
(defn- fibonacci-iter [a b count]
(if (= count 0)
b
(recur (+ a b) a (- count 1))))
```

Code language: Clojure (clojure)

With loop in Clojure, you don’t need `fibonacci-iter`

:

```
(defn fibonacci [n]
(loop [a 1
b 0
count n]
(if (= count 0)
b
(recur (+ a b) a (- count 1)))))
```

Code language: Clojure (clojure)

`loop`

is like inlining `fibonacci-iter`

, but it lets you set an initial value for the arguments:

```
(defn fibonacci [n]
(loop [a 1 ;; a has an initial value of 1
b 0 ;; b has an initial value of 0
count n] ;; count has an initial value of n
(if (= count 0)
b
(recur (+ a b) a (- count 1)))))
```

Code language: Clojure (clojure)

And once this calls `recur`

on line `7`

, those initial values don’t apply anymore.

It sets `a`

, `b`

, and `count`

to whatever it passes to `recur`

:

```
(defn fibonacci [n]
(loop [a 1 ;; a is the 1st argument of recur on line 7
b 0 ;; b is the 2nd argument of recur on line 7
count n] ;; count is the 3rd argument of recur on line 7
(if (= count 0)
b
(recur (+ a b) a (- count 1))))) ;; goes back to line 2
```

Code language: Clojure (clojure)

This is a simple example.

But it helps more when the function is bigger.

Here’s an example function where `loop`

helps more.

This function, `expire-n`

, removes expired keys from a data store:

### Helper Function

```
;; Recursive helper function
(defn- iter-keys-expired [time n store expired-store]
(if
(or (<= (count expired-store) (* 0.25 n)) (= (count expired-store) (count store)))
expired-store
(recur n time store
(union
expired-store
(->> expired-store
(apply dissoc store)
has-exp
(take n)
(expired time))))))
(defn expire-n [time n store]
(let [keys-expired
(iter-keys-expired time n store (->> store
has-exp
(take n)
(expired time)))]
(apply dissoc store keys-expired)))
```

Code language: Clojure (clojure)

### Loop, No Helper Function

```
(defn expire-n [store time n]
(let [keys-expired
;; loop replaces recursive helper function
(loop [expired-store (->> store
has-exp
(take n)
(expired time))]
(if
(or (<= (count expired-store) (* 0.25 n)) (= (count expired-store) (count store)))
expired-store
(recur (union
expired-store
(->> expired-store
(apply dissoc store)
has-exp
(take n)
(expired time))))))]
(apply dissoc store keys-expired)))
```

Code language: Clojure (clojure)

The loop Clojure form is more useful in `expire-n`

than in `fibonacci`

, because `expire-n`

is more complex.

Calling `iter-keys-expired`

makes you look above `expire-n`

to see what it does.

Loop makes recursion easier to understand.

## Leave a Reply