Maybe Python? Explaining Haskell (to myself) with Python.

Do you miss functional stuff in Python? I personally don't :)

But recently I started reading a lot of stuff on functional programming and it definitely has some advantages over good old OOP. Can't say that I like to see it in Python, but it definitely helps to stretch one's mind.

In this post, I'll try to implement something similar to Maybe type & related functions (see Haskell's Data.Maybe) in Python.

What is Maybe?

As it's said in Haskell docs:

The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.

We can illustrate it by the following division function: divide(float, float) -> Maybe float (pseudo PyHaskell notation :) ). Maybe float here because in Python if we try to divide by 0 we'll get runtime error ZeroDivisionError.
In Python typing module for type hints, there is such type annotation: Optional[T]

Implementation

So let's approach it with division function from the example.

In this example, we won't actually get None value, instead ZeroDivisionError will be thrown. So let's update it to handle the exception.

So we can see now how we can generalize it to be used with any function, that throws an exception.

Or better with a decorator:

Related functions

As you can see there are several related functions in Data.Maybe docs
Let's start with isJust & isNothing:

Then maybe but as we already have decorator function called maybe we'll call it maybe_fn:

And all the rest:

Updates

After posting to Reddit I got several comments (special thanks to subtly_homoerotic & frankreyes) on the post, noting that there is a problem.

Let's assume we have following function (don't ask me how my brain created it or where can you utilize it in the real world):

If we'll try to utilize our @maybe decorator to the function we'll get to the point where we won't be able to distinguish between normal function execution (i.e function returns None intentionally) and some exceptional case (ZeroDivisionError happened)

To resolve the issue we'll add one more class Just and update our maybe decorator:

So this way we'll be able to distinguish Just(None) and plain None and thus separate intentional None return value and "empty" None value.

Finally, we'll have to rewrite functions to utilize Just value:

What it's all about?

I cannot say that it'll help you in everyday work with Python. Neither it will give you a good grasp of Haskell knowledge. But it definitely can help you with an understanding of some Haskell concepts and ideas (though they are easy to understand in Haskell docs). At least it helped me :).