Bengt Richter wrote: > On Thu, 26 Jan 2006 17:47:51 +0100, Claudio Grondi <[EMAIL PROTECTED]> 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 -- http://mail.python.org/mailman/listinfo/python-list