Pure Functions & Recursion

Malina Tran
Tech and the City
Published in
3 min readJul 20, 2016
Me and recursion at the Oakland Museum of California

All of the functions, with a few exceptions, found in Clojure are pure functions. This renders them as stable and reliable. A function qualifies as a pure function if:

  • It will always return the same result if given the same arguments. This is also known as referential transparency. This means that pure functions rely on their own arguments and immutable values to determine their return value. You can bet that mathematical functions or are considered to be referentially transparent .
  • It doesn’t produce any side effects. What this means is that a function does not change the association between its name and value within a given scope. Side effects are harmful because they introduce uncertainty to the code. Consequently, this leads to difficulty tracing and debugging should an issue arise. In languages like Ruby and JavaScript, when an object gets passed around, sometimes there are unintended changes. This leads to anxiety-driven development (just kidding — I think).

At the core of a functional programming language is immutable data structures. What this means (and how this differs from object-oriented programming) is that the data is never changed. Rather, you create new data from existing data. The beauty with Clojure is that you only have to consider the relationship between a function’s input and output. But, how do you actually work with immutable data?

This was one of my main challenges when endeavoring upon Clojure and writing a tic-tac-toe game. Recursion, in the context of computer science, is when a function being defined is applied within its own definition. It can get a little trippy. In reality, you can create an infinite recursion when you hold two mirrors parallel to each other and create a series of nested images (see image above).

In many recursive functions, you will use `recur` to continue calling on the function if it does not meet a base case. Here’s an example from my tic-tac-toe game:

(Note: Medium using GitHub gists is the best thing ever, especially when code snippets aren’t syntactically highlighted — an absolute necessity for Clojure code).

I want to take some time to break down this code block. The purpose of the function is to get the values of the cells belonging to one column. By comparing each cell’s value, we can determine if there is a winner (in other words, if each cells has the same value, e.g. “X” or “O”). But that doesn’t happen in this function. From lines 2–4, you can see that I’m taking advantage of multi-arity, which allows us to have a variable number of arguments for a single function. The reason I’m using multi-arity in this function is to set default values of `index` (to be 0) and `cells` (to be an empty vector) without needing to do so when I invoke the method.

In line 5, I am setting the variables to the arguments and will proceed to loop through this function until we reach the base case in line 9. Here, the vector of `cells` will be returned if the number of cells equals the length (which, in a 3x3 board, will be 3). Otherwise, we call `recur` and pass in the same number of arguments to the function. Each time, however, we are adding the value of the index to `cells` through `cons` (using `get` to get the value of the element by index). And each time we call `recur`, we are changing the index value to increase by the length number (which is 3).

This is just one way that recursive iteration can be implemented in Clojure.

I’ve been implementing a couple of recursion functions and I must say, it was a little intimidating at first. But once you start testing your function’s output, and writing the code to implement, you’ll start to recognize its patterns.

--

--