jeudi 25 mai 2023

Is my modified python monad still a monad?

I recently learned how monads work and how they can be used to take more control over side effects. I wrote a few to calculate the time of composed functions, and to ofc take care of logging. One annoying thing I noticed is that I had to repeatedly write .bind(func) instead of simply .func, which is a slight annoyance.

So I then tried to include that in my logger monad and this is what I ended up with:

class IterBetter:
    def __init__(self, value: Iterable[T], log: List[str] = None):
        self.value = value
        self.log = log or []
        self.original_type = type(value)
        
    # convenience methods
    def __repr__(self):
        return f"{self.value}"
    
    def __getitem__(self, index):
        return self.value[index]
    
    def __setitem__(self, index, value):
        self.value[index] = value
    
    
    @staticmethod
    def bindify(f):
        
        def wrapper(self, func):
            result, msg = f(self, func)
            return IterBetter(result, self.log + [msg])
        
        return wrapper
    
    @bindify
    def newmap(self, func):
        msg = f"Mapping {func} over {self.value}"
        mapped = self.original_type(map(func, self.value))
        return mapped, msg
    
    @bindify
    def newfilter(self, func):
        msg = f"Filtering {func} over {self.value}"
        filtered = self.original_type(filter(func, self.value))
        return filtered, msg

Now you can write something like

mylst = IterBetter([1, 2, 3, 4, 5])
newlst = (
    mylst
    .newmap(lambda x: x + 1)
    .newfilter(lambda x: x % 2 == 0)
    .newmap(lambda x: x * 3)
)

Which is very nice imo, it's definitely more convenient than python's built-in maps and filers (but comprehensions exist, so this isn't all that practical).

However... Why would we want to use a design like that for the class? Like what's the advantage of returning a log message instead of just appending it to the log list? Either way we have to change the original log.

And is this modified implementation still a monad?

Aucun commentaire:

Enregistrer un commentaire