List monad
Martin McBride, 2020-07-02
Tags monad list monad design pattern
Categories functional programming

In the article on the Failure monad we looked at a simple definition of what a monad is:
A monad is a design pattern that allows us to add a context to data values, and also allows us to easily compose existing functions so that they execute in a context aware manner.
In this article we will look at the List monad. This is a monad that allows us to process lists of values, without cluttering our code with looping constructs.
How a List monad is used
As with the Failure monad, our List monad should do three main things:
- Allow us to wrap a value (in this case, a list value) in a List monad.
- Allow us to apply ant existing function to the entire list, using bind().
- Allow us to retrieve the List from a monad.
So a simple use might be like this:
k = List([1, 2, 3]) n = k.bind(neg) print(n) # List([-1, -2, -3])
We will call our monad List
because that is the name that is commonly used for similar monads in other languages. Notice that a List
monad is quite different to a normal Python list
.
List monad implementation
Based on the previous implementation of the Failure monad, here is our List monad:
class List(): def __init__(self, value): self.value = value def get(self): return self.value def bind(self, f): result = list(map(f, self.value)) return List(result) def __str__(self): return 'List(' + ', '.join(map(str, self.value)) + ')' def __or__(self, f): return self.bind(f)
The List monad just wraps a single value, which should be a list or other sequence. This is stored as self.value
.
The bind
function uses map
to apply the supplied function f
to each element in self.value
. The resulting list is wrapped in a new List monad.
We override str
to return 'List([contents of list])'. Finally we override the or
operator |
so we can use it as a bind operator.