Using non-ascii symbols
Claudio Grondi
claudio.grondi at freenet.de
Fri Jan 27 09:47:15 CET 2006
Bengt Richter wrote:
> On Thu, 26 Jan 2006 17:47:51 +0100, Claudio Grondi <claudio.grondi at freenet.de> wrote:
>
>
>>Rocco Moretti wrote:
>>
>>>Terry Hancock wrote:
>>>
>>>
>>>>One thing that I also think would be good is to open up the
>>>>operator set for Python. Right now you can overload the
>>>>existing operators, but you can't easily define new ones.
>>>>And even if you do, you are very limited in what you can
>>>>use, and understandability suffers.
>>>
>>>
>>>One of the issues that would need to be dealt with in allowing new
>>>operators to be defined is how to work out precedence rules for the new
>>>operators. Right now you can redefine the meaning of addition and
>>>multiplication, but you can't change the order of operations. (Witness
>>>%, and that it must have the same precedence in both multiplication and
>>>string replacement.)
>>>
>>>If you allow (semi)arbitrary characters to be used as operators, some
>>>scheme must be chosen for assigning a place in the precedence hierarchy.
>>
>>Speaking maybe only for myself:
>>I don't like implicit rules, so I don't like also any precedence
>>hierarchy being in action, so for safety reasons I always write even
>>8+6*2 (==20) as 8+(6*2) to be sure all will go the way I expect it.
>>
>
> Maybe you would like the unambiguousness of
> (+ 8 (* 6 2))
> or
> 6 2 * 8 +
> ?
>
> Hm, ... ISTM you could have a concept of all objects as potential operator
> objects as now, but instead of selecting methods of the objects according
> to special symbols like + - * etc, allow method selection by rules applied
> to a sequence of objects for selecting methods. E.g., say
> a, X, b, Y, c
> is a sequence of objects (happening to be contained in a tuple expression here).
> Now let's define seqeval such that
> seqeval((a, X, b, Y, c))
> looks at the objects to see if they have certain methods, and then calls some of
> those methods with some of the other objects as arguments, and applies rules of
> precedence and association to do something useful, producing a final result.
>
> I'm just thinking out loud here, but what I'm getting at is being able to write
> 8+6*2
> as
> seqeval((8, PLUS, 6, TIMES, 2))
> with the appropriate definitions of seqeval and PLUS and TIMES. This is with a view
> to having seqeval as a builtin that does standard processing, and then having
> a language change to make white-space-separated expressions like
> 8 PLUS 6 TIMES 2
> be syntactic sugar for an implicit
> seqeval((8, PLUS, 6, TIMES, 2))
> where PLUS and TIMES may be arbitrary user-defined objects suitable for seqeval.
> I'm thinking out loud, so I anticipate syntactic ambiguities in expressions and the need to
> use parens etc., but this would in effect let us define arbitrarily named operators.
> Precedence might be established by looking for PLUS.__precedence__. But as usual,
> parens would control precedence dominantly. E.g.,
> (8 PLUS 6) TIMES 2
> would be sugar for
> seqeval((seqeval(8, PLUS, 6), TIMES, 2)
>
> IOW, we have an object sequence expression analogous to a tuple expression without commas.
> I guess generator expressions might be somewhat of a problem to disambiguate sometimes, we'll see
> how bad that gets ;-)
>
> One way to detect operator objects would be to test callable(obj), which would allow
> for functions and types and bound methods etc. Now there needs to be a way of
> handling UNARY_PLUS vs PLUS functionality (obviously the name bindings are just mnemonic
> and aren't seen by seqeval unless they're part of the operator object). ...
>
> A sketch:
>
> >>> def seqeval(objseq):
> ... """evaluate an object sequence. rules tbd."""
> ... args=[]
> ... ops=[]
> ... for obj in objseq:
> ... if callable(obj):
> ... if ops[-1:] and obj.__precedence__<= ops[-1].__precedence__:
> ... args[-2:] = [ops.pop()(*args[-2:])]
> ... ops.append(obj)
> ... continue
> ... elif isinstance(obj, tuple):
> ... obj = seqeval(obj)
> ... while len(args)==0 and ops: # unary
> ... obj = ops.pop()(obj)
> ... args.append(obj)
> ... while ops:
> ... args[-2:] = [ops.pop()(*args[-2:])]
> ... return args[-1]
> ...
> >>> def PLUS(x, y=None):
> ... print 'PLUS(%s, %s)'%(x,y)
> ... if y is None: return x
> ... else: return x+y
> ...
> >>> PLUS.__precedence__ = 1
> >>>
> >>> def MINUS(x, y=None):
> ... print 'MINUS(%s, %s)'%(x,y)
> ... if y is None: return -x
> ... else: return x-y
> ...
> >>> MINUS.__precedence__ = 1
> >>>
> >>> def TIMES(x, y):
> ... print 'TIMES(%s, %s)'%(x,y)
> ... return x*y
> ...
> >>> TIMES.__precedence__ = 2
> >>>
> >>> seqeval((8, PLUS, 6, TIMES, 2))
> TIMES(6, 2)
> PLUS(8, 12)
> 20
> >>> seqeval(((8, PLUS, 6), TIMES, 2))
> PLUS(8, 6)
> TIMES(14, 2)
> 28
> >>> seqeval(((8, PLUS, 6), TIMES, (MINUS, 2)))
> PLUS(8, 6)
> MINUS(2, None)
> TIMES(14, -2)
> -28
> >>> seqeval((MINUS, (8, PLUS, 6), TIMES, (MINUS, 2)))
> PLUS(8, 6)
> MINUS(14, None)
> MINUS(2, None)
> TIMES(-14, -2)
> 28
> >>> list(seqeval((i, TIMES, j, PLUS, k)) for i in (2,3) for j in (10,100) for k in (5,7))
> TIMES(2, 10)
> PLUS(20, 5)
> TIMES(2, 10)
> PLUS(20, 7)
> TIMES(2, 100)
> PLUS(200, 5)
> TIMES(2, 100)
> PLUS(200, 7)
> TIMES(3, 10)
> PLUS(30, 5)
> TIMES(3, 10)
> PLUS(30, 7)
> TIMES(3, 100)
> PLUS(300, 5)
> TIMES(3, 100)
> PLUS(300, 7)
> [25, 27, 205, 207, 35, 37, 305, 307]
>
> Regards,
> Bengt Richter
At the first glance I like this concept much and mean it is very
Pythonic in the sense of the term as I understand it. I would be glad to
see it implemented if it does not result in any side effects or other
problems I can't currently anticipate.
Claudio
More information about the Python-list
mailing list