Is __mul__ sufficient for operator '*'?

Mick Krippendorf mad.mick at gmx.de
Tue Oct 20 05:23:43 CEST 2009


Muhammad Alkarouri schrieb:
> Traceback (most recent call last):
>   File "<pyshell#83>", line 1, in <module>
>     x*7
> TypeError: unsupported operand type(s) for *: 'Maybe' and 'int'
> 
> The farthest I can go in this is that I presume that __mul__ (as
> called by operator *) is supposed to be a bound method while I am
> returning a lambda function. Is this correct? And How can I make the
> implementation support such operators?

It does not so much depend on the function being bound, but on the fact
that Python expects Maybe.__mul__ to be present already when it tries to
execute '*'. You could always add this, though:

    def __mul__(self, other):
        return Maybe.__getattribute__(self, "__mul__")(other)

but of course you'd have to do it for every operator you want to use on
your Maybe objects. Your use of __getattribute__ OTH suggests you're
trying to avoid exactly that. I'd rather go for a monadic implementation
with unit, bind and lift operations, e.g:

----8<--------8<--------8<--------8<--------8<----

class Monad(object):
    # unit:
    def __init__(self, value):
        self.value = value
    # bind:
    def __rshift__(self, function):
        return function(self.__class__)(self.value)
    def __str__(self):
        return "%s(%s)" % (self.__class__.__name__, self.value)

def lift(f):
    def lift_unit(m):
        def lift_bind(x):
            return m(f(x))
        return lift_bind
    return lift_unit

class idem(Monad):
    def __call__(self, value):
        return value

class Nothing(object):
    def __rshift__(self, function):
        return Nothing
    def __str__(self):
        return "Nothing"
Nothing = Nothing()

class Maybe(Monad):
    def __new__(cls, value=Nothing):
        if value is Nothing:
            return Nothing
        return super(Monad, cls).__new__(cls)

if __name__ == "__main__":

    x = Maybe(9)
    print x >> lift(lambda v: v * 7)
    print x >> lift(lambda v: v * 7) >> idem

    y = Maybe(Nothing)
    print y >> lift(lambda v: v * 7)
    print y >> lift(lambda v: v * 7) >> idem

----8<--------8<--------8<--------8<--------8<----

While I can see how this monadic stuff is usefull in Haskell et al.,
I'm still not sure how to apply it to Python. And for the impenetrable
mathematical language in which Monads are usually presented, well...


HTH,
Mick.



More information about the Python-list mailing list