Monad

Monad

In functional programming, monads are a way to structure computations as a sequence of steps, where each step not onlyi produces a value but also some extra information about the computation, such as a potential failure, non-determinism, or side effect.

We will see who to implement monad with python only for help python developer too understand.

Properties

Monad (functional programming) - Wikipedia
  • Wrapper Type
  • wrap function
    • alows entry to monad exosystem alsoknow as return, pure, unit
  • Run function

Examples

Monad Maybe

So, We will start with monad monad Maybe for the first example.

why is the utility of Maybe ?
Is great way to generalize exception of None value (we don't like None..).

with Monad Maybe we can chain multip operation with no need to check the result of the value None. We need to check only on end


def add_one(x: int) -> int:
    return x + 1

def double(x: int) -> int:
    return x * 2

result = Maybe(3).bind(add_one).bind(double)
print(result)  # Just 8

result = Maybe(None).bind(add_one).bind(double)
print(result)  # Nothing

result = Maybe(None).bind(add_one).bind(double).orElse(10)
print(result)  # Just 10

result = Maybe(None) | Maybe(1)
print(result) # Just 1

The naif implementation of the monad Maybe can be:

class Maybe:
    def __init__(self, value):
        self._value = value

    def bind(self, func):
        if self._value is None:
            return Maybe(None)
        else:
            return Maybe(func(self._value))

    def orElse(self, default):
        if self._value is None:
            return Maybe(default)
        else:
            return self

    def unwrap(self):
        return self._value

    def __or__(self, other):
        return Maybe(self._value or other._value)

    def __str__(self):
        if self._value is None:
            return 'Nothing'
        else:
            return 'Just {}'.format(self._value)

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        if isinstance(other, Maybe):
            return self._value == other._value
        else:
            return False

    def __ne__(self, other):
        return not (self == other)

    def __bool__(self):
        return self._value is not None

Monad IO

  • Encapsulates IO operations
  • Chains operations without executing them immediately
  • Runs them later in a controlled manner

We mask a error and the implementation of io function to only focus on the what we whant do.

for this example we well print the and of log with filtering level.

if __name__ == "__main__":
    filename = "example.log"

    io_action = (
        read_file(filename)
        .bind(lambda content: tail(content, 10))
        .bind(lambda content: filter_level(content, "ERROR"))
        .bind(print_lines)
    )
    # ---
    io_action.run()

The implementation of the monad is very simple

from typing import Callable, Any

class IOMonad:

    def __init__(self, action: Callable[[], Any]):
        self.action = action  # A function that returns a value

    def bind(self, func: Callable[[Any], "IOMonad"]) -> "IOMonad":
        return IOMonad(action=lambda: func(self.run()).run())

    def run(self) -> Any:
        return self.action()

def read_file(filename: str) -> IOMonad:
    return IOMonad(lambda: open(filename).read().splitlines())

def tail(lines: list, count: int = 10) -> IOMonad:
    return IOMonad(lambda: lines[-count:])

def filter_level(lines: list, level: str) -> IOMonad:
    return IOMonad(lambda: [line for line in lines if level in line])

def print_lines(lines: list) -> IOMonad:
    return IOMonad(lambda: print("\n".join(lines) if lines else "No WARNING messages found."))

conclusion

Monads are a design patternthat allows a user to chain operations while the monad manages secret behind the scenes.

thanks for reading, go further

Haskell Language
The Haskell purely functional programming language home page.
Category theory - Wikipedia

Very good resource to learn hackell and functional programing https://exercism.org/tracks/haskell/exercises