fetch(url).then(do this).then(do that) or you’ve used the
async/await syntax. You might have noticed that you cannot get a value out of the Promise. As soon as you write
await your function has to be
async (has to be a Promise itself). Or when you use
.then() you cannot get the value out of the
then. This is because the value only exist after your Promise (the computation) has be resolved, e.g. an API call has been made and the result has arrived.
async to your function definition in order to use
await, in Haskell you have to specify the Monad type in the type annotation. For instance
String -> IO String is a function that takes a name for an environment variable e.g.
$HOME and gives you the contents of that variable. This operation happens to be of type
IO String and not just
String because the contents the environment variable is dependent on your system and can change over time. But pure functions by definition always provide the same output for the same input. Therefore you get back an
IO String which basically means that as soon as the containing IO operation has been executed you will get back the contents of the environment variable. This is actually pure, because you always get back the same IO computation given the same input. Now, if you have a function like
String -> String then you can be sure that there will be no side effects and no IO computation involved. And most of your functions can look like that, which allows you very easy reasoning of what kind of things can happen in your program, just by reading the type definition.
In this post I want to show you how easy it is to write your own Monad instance in Phyton. I have chosen to implement a list Monad, because it provides easy intuition and has much similarities with the Haskell implementation. We start by writing a Functor and Applicative instance for list in Python.
This is how Functor is defined in Haskell. Although it is named class you can think of it as an interface. This interface states that in order for something to be a Functor it has to implement the
map) function. A Functor is also often called “mappable”, because it is something we can map over like a list.
In Python we can use type hints to implement the Functor interface for list.
As you can see the implementation of the list Functor is very straight forward. The
fmap function simply takes a list
fa and applies the function given in the second argument of
fmap to every element of the list. As you can see we are now able to apply lambda functions to every list element and chain the results by repeated
fmap calls. There is also a builtin function in python for
[f(x) for x in fa] simply called
map. The same code, using the existing implementation, in Haskell would look like:
(++"0") <$> (show) <$> (+ 1) <$> [1,2,3], where
fmap as operator.
Next thing we are going to implement is Applicative. The interface for Applicative in Haskell looks as follows:
We have to implement two functions. The first one is very simple. Given a type
a lets say Integer, we simply have to put it into our structure, e.g.
Int -> [Int]. And the second function states, that given two Applicative, e.g. two lists, and one containing a list with a function, we simply apply the functions of that list to every element of the other list.
This is very similar to the implementation of Applicative for lists in Haskell
fs <*> xs = [f x | f <- fs, x <- xs] and
[(++"0")] <*> ([(show)] <*> ([(+ 1)] <*> [1,2,3])) yields the same result.
The Monad interface requires us to implement two functions. The
return is very similar to
pure, we just have to lift a value into the Monad, e.g. put a value into a list. The second function
>>= also called bind, takes a function that converts an
m b e.g. from
a -> [b] in case of lists.
Now lets compare our Python list Monad implementation with the Haskell implementation.
As we can see the implementation is very similar, the bind function consists of
map, also called
flatmap. And this is how we can use the monadic bind function in Haskell
[1,2,3] >>= \x -> [(x+1)] >>= \x -> [(show x)] >>= \x -> [x ++ "0"]. Here you can find the full implementation of Functor, Applicative and Monad for list in Python: