Infix application of binary functions
It could help readability if binary (arity of 2) functions could be applied infix with some syntax. For example, borrowing from Haskell, the backtick could be reintroduced for this purpose. Good examples for this are isinstance and hasattr: if some_object `isinstance` Iterable: ... elif some_object `hasattr` '__iter__': ... It is already possible[1] to make infix functions, but the solution is a hack and requires functions to be marked as infix. (The use of backticks is just an example borrowing from Haskell and might not be optimal, although a benefit is that it isn't very noisy.) [1] http://code.activestate.com/recipes/384122-infix-operators/
On Wed, Jul 21, 2010 at 3:37 PM, Dag Odenhall
It could help readability if binary (arity of 2) functions could be applied infix with some syntax. For example, borrowing from Haskell, the backtick could be reintroduced for this purpose.
Good examples for this are isinstance and hasattr:
if some_object `isinstance` Iterable: ... elif some_object `hasattr` '__iter__':
Already proposed (by me) and rejected by the BDFL: http://mail.python.org/pipermail/python-ideas/2007-January/000054.html Cheers, Chris -- http://blog.rebertia.com
Then what about: obj $isinstance Iterable or obj $isinstance$ Iterable or obj *isinstance Iterable or obj isinstance? Iterable These don't use the backtick charackter (wich on some setups even is a unicode char not from 7bit ascii). -panzi On 07/22/2010 01:17 AM, Chris Rebert wrote:
On Wed, Jul 21, 2010 at 3:37 PM, Dag Odenhall
wrote: It could help readability if binary (arity of 2) functions could be applied infix with some syntax. For example, borrowing from Haskell, the backtick could be reintroduced for this purpose.
Good examples for this are isinstance and hasattr:
if some_object `isinstance` Iterable: ... elif some_object `hasattr` '__iter__':
Already proposed (by me) and rejected by the BDFL:
http://mail.python.org/pipermail/python-ideas/2007-January/000054.html
Cheers, Chris
Already proposed (by me) and rejected by the BDFL:
http://mail.python.org/pipermail/python-ideas/2007-January/000054.html
Ah, thanks. He only rejects the backtick however, not infix application itself.
On 07/22/2010 01:17 AM, Chris Rebert wrote:
On Wed, Jul 21, 2010 at 3:37 PM, Dag Odenhall
wrote: It could help readability if binary (arity of 2) functions could be applied infix with some syntax. For example, borrowing from Haskell, the backtick could be reintroduced for this purpose.
Good examples for this are isinstance and hasattr:
if some_object `isinstance` Iterable: ... elif some_object `hasattr` '__iter__':
Already proposed (by me) and rejected by the BDFL:
http://mail.python.org/pipermail/python-ideas/2007-January/000054.html
On Wed, Jul 21, 2010 at 4:33 PM, Mathias Panzenböck
wrote: Then what about: <snip> obj *isinstance Iterable
How would the parser distinguish that from multiplication?
or obj isinstance? Iterable
That would look odd for non-interoggative binary functions: z = x cartesianProduct? y
These don't use the backtick charackter (wich on some setups even is a unicode char not from 7bit ascii).
Not using backtick definitely makes the proposal more viable. (Personally I <3 backtick though.) Cheers, Chris
tor 2010-07-22 klockan 01:33 +0200 skrev Mathias Panzenböck:
Then what about: obj $isinstance Iterable or obj $isinstance$ Iterable or obj *isinstance Iterable or obj isinstance? Iterable
These don't use the backtick charackter (wich on some setups even is a unicode char not from 7bit ascii).
I like the question mark, although it is only useful for predicates. I haven't considered if infix is useful for anything other than predicates, though. Another possibility is a keyword, maybe "of": obj isinstance of Iterable or obj hasattr of '__iter__' But better then would be a keyword that already exists and makes sense for this use. A character such as the question mark is probably best, just noting the possibility of a keyword for completeness sake. An example of a non-predicate infix might be str.format: 'Hello {}' str.format? 'World' Here, the question mark makes less sense.
This can be done in Python today:
class Infix(object): ... def __init__(self, func): ... self.func = func ... self.arg1 = self.arg2 = self.not_set = object() ... ... def __radd__(self, arg1): ... self.arg1 = arg1 ... if self.arg2 is self.not_set: ... return self ... else: ... return self.func(self.arg1, self.arg2) ... ... def __add__(self, arg2): ... self.arg2 = arg2 ... if self.arg1 is self.not_set: ... return self ... else: ... return self.func(self.arg1, self.arg2) ... @Infix ... def add(one, two): ... return one + two ... @Infix ... def mul(one, two): ... return one * two ... @Infix ... def power(one, two): ... return one ** two ... 1 + add + 1 2 2 + mul + 2 4 3 + power + 3 27
Enjoy. -- Carl Johnson
Thought about it some more. Here’s a more general formula: class InfixArity(object): def __init__(self, arity): self.arity = arity self.args = [] def __call__(self, func): self.func = func return self def __add__(self, arg): self.args.append(arg) if len(self.args) < self.arity: return self else: return self.func(*self.args) __radd__ = __add__ Infix = lambda func: InfixArity(2)(func) And of course, one can use __mul__ or __div__ or whatever to taste. "1 // add // 2” doesn’t make me instantly vomit in my mouth. ;-) -- Carl Johnson
Last time, I swear! I caught a bug in the last version. Since I
mutated my instances (not very Haskell-like!!), you couldn’t use the
same function more than once. Here’s a new version that lets you use
the same function again:
class InfixArity(object):
def __init__(self, arity):
self.arity = arity
def __call__(self, func):
self.func = func
return self
def __add__(self, arg):
return InfixHelper(self.func, self.arity, arg)
__radd__ = __add__
__floordiv__ = __rfloordiv__ = __add__
__truediv__ = __rtruediv__ = __add__
class InfixHelper(object):
def __init__(self, func, arity, firstarg):
self.func = func
self.arity = arity
self.args = [firstarg]
def __add__(self, arg):
self.args.append(arg)
if len(self.args) < self.arity:
return self
else:
return self.func(*self.args)
__radd__ = __add__
__floordiv__ = __rfloordiv__ = __add__
__truediv__ = __rtruediv__ = __add__
Infix = lambda func: InfixArity(2)(func)
I imagine it would be possible to make an n-arity class that could
work like “average // 1 // 2 // 3 // 4 // done” or maybe one that has
you use a different operator for the last argument, but I leave that
as an exercise for the reader.
-- Carl Johnson
On Wed, Jul 21, 2010 at 5:49 PM, Carl M. Johnson
Thought about it some more. Here’s a more general formula:
class InfixArity(object): def __init__(self, arity): self.arity = arity self.args = []
def __call__(self, func): self.func = func return self
def __add__(self, arg): self.args.append(arg) if len(self.args) < self.arity: return self else: return self.func(*self.args)
__radd__ = __add__
Infix = lambda func: InfixArity(2)(func)
And of course, one can use __mul__ or __div__ or whatever to taste. "1 // add // 2” doesn’t make me instantly vomit in my mouth. ;-)
-- Carl Johnson
This can be done in Python today:
Quoting myself from the original post: It is already possible[1] to make infix functions, but the solution is a hack and requires functions to be marked as infix. [1] http://code.activestate.com/recipes/384122-infix-operators/
Dag Odenhall
This can be done in Python today:
Quoting myself from the original post:
It is already possible[1] to make infix functions, but the solution is a hack and requires functions to be marked as infix.
I don't see how “add a new punctuation character to the syntax in every place where this is to be used” is less of a hack. For reference you might want to read over the debates that preceded the introduction of ‘@’ to the language. There is *very strong* resistance to adding syntax that uses arbitrary punctuation characters. IMO that resistance is for good reason: punctuation beyond what Python already supports today rarely improves readability, and usually worsens it. -- \ “All television is educational television. The question is: | `\ what is it teaching?” —Nicholas Johnson | _o__) | Ben Finney
participants (5)
-
Ben Finney
-
Carl M. Johnson
-
Chris Rebert
-
Dag Odenhall
-
Mathias Panzenböck