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 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
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.
str to return 'List([contents of list])'. Finally we override the
| so we can use it as a bind operator.