# Mutation in Functional Programming

A *pure function* is a function that always evaluates to the same results given
the same inputs, and does not produce any side effects in the process. There are many advantages to using pure functions. In this blog post I will show how we can still effectively use pure functions to handle state. Most of my code examples would be in Python, but I also show equivalent Haskell code for some examples. Only basic knowledge of Haskell syntax and its type system is needed to understand the Haskell code, and I believe that looking at the type signatures of the Haskell functions would help in understanding the Python code too.

As this is my first technical blog post, I might not be very clear in explaining everything. If you have any clarifications, please leave a comment below so that I can improve this post!

We can represent a stack in python using a list.

However this representation involves mutating the list. We want our `push`

and `pop`

functions to be pure instead. To do this, we will represent a stack as an immutable tuple. Any function that does a computation to a stack takes in the current stack and returns a tuple of the new stack and the result of the computation. Here is the definition of `pop_stack`

:

The first element of the returned tuple, `(2, 3)`

, is the new stack, and the second element, `1`

, is the popped-off value. Similarly, we can define `push_stack`

:

`push_stack`

takes in an element, and returns a function that takes in a stack and pushes that element onto the stack. It does not return anything other than the new stack, but we want to keep a consistent structure for the returned value, so we return `None`

for the second tuple element.

Now we’ve created the basic building blocks for manipulating a stack, we can define other functions combining `push`

and `pop`

together. Let’s write `pop_second`

, which pops off the second element of the stack:

This implementation is purely functional but there’s a lot of repetition: we do not need to use all of `x1`

, `x2`

and `x3`

, and we always pass the states `s1`

, `s2`

and `s3`

to the next step of computation. Let’s introduce some abstractions to help us factor out some common patterns. In the following examples, I will write the equivalent Haskell code beside the Python code.

First, we notice that `pop(x)`

and `push`

are both functions that take in a state and return a tuple `(new_state, result)`

. Let’s define a class `StateFn`

that encapsulates a function that acts on a state:

Next, we need a way to compose two state functions together. We will define a method `bind`

, which takes in `fn`

, a function that takes in a value and returns a state function. `bind`

will return a new `StateFn`

, which is the composition of `fn`

with the encapsulated `self.fn`

. The `StateFn`

object that `bind`

returns contain a function that takes in a state, computes `self.fn`

on that state, resulting in a result and a new state. The result is passed to `fn`

, which will return another `StateFn`

. The new state is then passed to the returned `StateFn`

and the result is returned. This may sound a little complicated, but it will be clearer once we see how `bind`

is used.

What if we do not want to keep the result of the computation? For example, `push`

does not return anything other than the new stack, so we can discard its result, `None`

. We do this by defining `then`

, which takes in a `StateFn`

and returns a function that takes in a state, do the computation for `self.fn`

and discards the result, and then use the resulting state to do the computation with the instance of `StateFn`

, finally returning that result.

Finally, if we have a value and want to enclose it in a `StateFn`

object, we define `ret_state`

that does that:

Now that we have these new abstractions, we can define `StateFn`

instances `push`

and `pop`

, which contains functions that act on a stack.

Finally, we need to define a `run_stack`

function that takes in a `StateFn`

and a stack, and applies the function to the stack.

Now we can perform push and pop operations on our stack!

We can easily compose `push`

and `pop`

with `bind`

and `then`

:

Here `inc_top`

composes `pop`

with `push`

that pushes the popped value on top of the stack. `pop_twice`

first performs a pop, discards its result and pops off the stack again. We notice that the functional syntax for `bind`

and `then`

in Python is a bit cumbersome compared to the operator notation in Haskell, so we overload the `>=`

and `>>`

operators in Python:

Now we can write `pop_second`

using our new abstraction!

Notice that Haskell already provides synthetic sugar for `bind`

and `then`

operations, which makes the pure functional code look almost the same as imperative code.

So in our quest for finding a good abstraction for chaining pure functions to manipulate states, we have discovered a specific form of a even higher level of abstraction, *monads*. In Haskell, the `Monad`

typeclass has the following signature:

For another example, lists are instances of monads. We can think of `return a`

as putting `a`

into a list, and `bind`

takes in a function which accepts an element of a list, and returns another list. `bind`

will apply that function to every element of the list and concatenate all the returned lists together. Here are the implementations of the list monad in Python and Haskell:

Monads should satisfy the following axioms:

`return a`

puts the value a into a monad, and`>>=`

takes that value out of the monad and passes it into`k`

, which is the same as applying`k`

to`a`

.`m >>= return`

will take out the value wrapped in`m`

and pass it to`return`

, which will wrap it in a monad again. This is an identity transform.- This basically says that you can compose binds together.

The `StateFn`

and `List`

objects we created are examples of monads, as we defined `bind`

, `then`

, and `ret_{state,lst}`

for each. In fact, we can think of a monad as an interface, any object with these three functions defined can be considered a monad. Many structures in Haskell, such as `Maybe`

and `IO`

are monads. We can define functions on monads assuming that the axioms described above hold, and these functions can be used on any monad. For example, the `filterM`

function behaves like the normal filter function, just that it acts on monads. If you represent a set as a list, you can use `filterM`

on the list, which is a monad, to find the power-set:

As you can see, monads are very general and powerful abstractions. If you want to learn more about them, the monad chapters of Learn You A Haskell and Real World Haskell are great resources.