mrocklin / multipledispatch

Multiple dispatch
https://multiple-dispatch.readthedocs.io/en/latest/
Other
801 stars 71 forks source link

Commutative dispatching #110

Open asmeurer opened 4 years ago

asmeurer commented 4 years ago

I want to define multiple dispatching for a function f(x, y) that I know should always be commutative (f(x, y) == f(y, x)). Does multipledispatch support this? Basically, I only want to define f(type_A, type_B) and have it automatically define f(type_B, type_A).

mrocklin commented 4 years ago

The dumb way to do this is the following:

@dispatch((A, B), (B, A))
def f(x, y):
    ...

There may also be another way to do it (I'm no longer up to date on this library)

asmeurer commented 4 years ago

Looking at the code, I don't think this is implemented. But I wonder if it can be done simply by subclassing Dispatcher like

from itertools import permutations

class CommutativeDispatcher(Dispatcher):
    def add(self, signature, func):
        for perm in permutations(signature):
            super().add(perm, func)

and then also redefine dispatch to use CommutativeDispatcher.

The dumb way to do this is the following:

Does that work? I thought tuple meant union. So wouldn't that also define f(A, A) and f(B, B)?

mrocklin commented 4 years ago

Does that work? I thought tuple meant union. So wouldn't that also define f(A, A) and f(B, B)?

Yes, you're correct. So maybe you want ...

@dispatch(A, B)
@dispatch(B, A)
def f(x, y):
    ...

As you say, making a wrapper would not be hard.

asmeurer commented 4 years ago

Yes, that's what I want. Except I don't want to type it twice for each type, because I know that f is always commutative.

Actually, maybe it will be better make a wrapper at the dispatcher level, rather than Dispatcher.

(I haven't tested this)

def commutative_dispatcher(*types):
    def inner(f):
        for perm in permutations(types):
            f = dispatch(*perm)(f)
        return f
    return inner

(functions that return functions don't compose so easily in Python. I think we need monads or something ;-)