[Python-ideas] [RFC] draft PEP: Dedicated infix operators for matrix multiplication and matrix power

Andrew Barnert abarnert at yahoo.com
Sun Mar 23 23:48:04 CET 2014


On Mar 23, 2014, at 3:51, Devin Jeanpierre <jeanpierreda at gmail.com> wrote:

> On Sun, Mar 23, 2014 at 3:40 AM, Sturla Molden <sturla.molden at gmail.com> wrote:
>> On 15/03/14 01:09, Antoine Pitrou wrote:
>> 
>>> Really? That should be up to the third-party library implementing the @
>>> operator for its types, not to the language itself: Python _suggests_
>>> an use case for @, it doesn't mandate it (especially as there's no
>>> appropriate data type in the stdlib).
>> 
>> 
>> array.array is an appropriate type for supporting @ for matrix
>> multiplication.
> 
> I was thinking the function type, as a composition operator. Matrix
> multiplication corresponds exactly with composition of linear
> functions, so it makes some sort of sense. And it has some kind of
> neat similarity to decorators, which generalize function composition.
> 
> If you rename "matmul" to "compose" and "matpow" to something like
> "iterate" (except less confusing), then you've generalized the
> operators a little and given them more potential use cases.

This sounds nice from a purity point of view, but I'm not sure it's a good idea.

First, matrix multiplication only corresponds exactly with function composition if matrix*vector multiplication corresponds exactly with function calling, which is generally not true in programming. You can't assign a matrix to f, then write f(v) to apply the matrix as an operation; you write f @ v.

Meanwhile, Python doesn't even have compose in functools, much less in builtins, and I don't think anyone had seriously proposed it in decades. If we don't even need it in the stdlib, do we really need is as an operator?

Also, is it right-compose or left-compose? (That is, does (f at g)(2) call
f then g, or g then f?) One answer is obvious to people who think mathematically, the other to novices. And even if you argue that the right answer to that is to teach the novices the right way to think about it clearly, reverse composition is still often useful; that's why many languages that have a compose function or operator also have rcompose and/or make it trivial to write as flip(compose).

Also, how exactly do you define compose? This is easy in a language like Haskell, where every function takes one argument and returns one value (which, because of currying, may actually be a function that takes the next argument...), but in Python, where functions can take any number of arguments, with default values and *args and keyword-only arguments and so on, it's a lot less clear. Does the second function need to be a single-argument function, or do tuple returns match to *args, or something different? Different third-party function libraries use different answers to that, sometimes offering more than one under different names, but obviously the operator has to be either compose1 or composestar, and then the other one won't even be in the stdlib?

Meanwhile, looking at languages that care about mathematical purity and about functional composition: you don't write . for matrix multiplication in Haskell, you write `multStd` or, more likely, define *, **, `mult`, or something else more readable. 




More information about the Python-ideas mailing list