Other notes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Bengt Richter

    #16
    Re: Other notes

    On Wed, 29 Dec 2004 13:11:43 -0500, Steve Holden <steve@holdenwe b.com> wrote:
    [color=blue]
    >Mike Meyer wrote:
    >[color=green]
    >> bearophileHUGS@ lycos.com writes:
    >>
    >>[color=darkred]
    >>>@infix
    >>>def interval(x, y): return range(x, y+1) # 2 parameters needed
    >>>
    >>>This may allow:
    >>>assert 5 interval 9 == interval(5,9)[/color]
    >>
    >>
    >> I don't like the idea of turning words into operators. I'd much rather
    >> see something like:
    >>
    >> @infix('..')
    >> def interval(x, y):
    >> return range(x, y + 1)
    >>
    >> assert 5 .. 9 == interval(5, 10)
    >>
    >> This would also allow us to start working on doing away with the magic
    >> method names for current operators, which I think would be an
    >> improvement.
    >>[/color]
    >Well, perhaps you can explain how a change that's made at run time
    >(calling the decorator) can affect the parser's compile time behavior,
    >then. At the moment, IIRC, the only way Python code can affect the
    >parser's behavior is in the __future__ module, which must be imported at
    >the very head of a module.[/color]
    Good point, which I didn't address in my reply. (in fact I said I liked
    @infix('..') for punctuation-char-named ops, but I was too busy with my
    idea to think about that implementation ;-)

    Potentially, you could do it dynamically with a frame flag (to limit the damage)
    which said, check all ops against a dict of overloads and infix definitions while
    executing byte code for this frame. Of course, the compiler would have to defer
    some kinds of syntax error 'til run time. I.e., '..' would have to be translated
    to OP_POSSIBLE_CUS TOM_INFIX or such. I doubt if it would be worth doing.

    OTOH, I think my suggestion might be ;-) I.e., just do a macro-like (not a general
    macro capability for this!!) translation of expressions with dots at both ends and
    no embedded spaces (intial thought, to make things easier) thus:
    x .expr. y => expr(x, y)

    when expr is a simple name, you can use that expression format to call a two-arg function
    of that name, e.g.,

    def interval(x, y): return xrange(x, y+1)
    for i in x .interval. y: print i, # same as for i in interval(x, y): print i,

    but you could also write stuff like

    def GE(x,y): return x is MY_INFINITY or x >= y
    if x .GE. y: print 'x is greater than y'

    The .expr. as expression would allow module references or tapping into general
    expression and attribute magic etc. I.e., (untested)

    from itertools import chain as CHAIN
    for k,v in d1.items() .CHAIN. d2.items(): print k, v

    or if you had itertools imported and liked verbose infix spelling:

    for k,v in d1.items() .itertools.chai n. d2.items(): print k, v

    or define a hidden-attribute access operation using an object's dict

    def HATTR(obj, i):
    try: return vars(obj)[i]
    except KeyError: raise AttributeError( 'No such attribute: %r', i)

    if thing .HATTR. 2 == 'two': print 'well spelled'

    or
    from rational import rat as RAT

    if x .RAT. y > 1 .RAT. 3: do_it()

    or
    your turn ;-)
    [color=blue]
    >[color=green]
    >> As others have pointed out, you do need to do something about operator
    >> precedence. For existing operators, that's easy - they keep their
    >> precedence. For new operators, it's harder.
    >>[/color]
    >Clearly you'd need some mechanism to specify preference, either
    >relatively or absolutely. I seem to remember Algol 68 allowed this.
    >[color=green]
    >> You also need to worry about binding order. At the very least, you
    >> can specify that all new operators bind left to right. But that might
    >> not be what you want.
    >>[/color]
    >Associativit y and precedence will also have to affect the parsing of the
    >code, of course. Overall this would be a very ambitious change.
    >[/color]
    My suggestion if implemented with left-right priority would be easy to
    implement (I think ;-) And you could always override order with parens.

    Regards,
    Bengt Richter

    Comment

    • Bengt Richter

      #17
      Re: Other notes

      On Thu, 30 Dec 2004 03:37:38 GMT, Andrew Dalke <dalke@dalkesci entific.com> wrote:
      [color=blue]
      >Bengt Richter:[color=green]
      >> OTOH, there is precedent in e.g. fortran (IIRC) for named operators of the
      >> form .XX. -- e.g., .GE. for >= so maybe there could be room for both.[/color]
      >[color=green]
      >> Hm, you could make
      >>
      >> x .infix. y[/color]
      >
      >[color=green]
      >> x .op1. y .op2. z => op2(op1(x, y), z)[/color]
      >
      >The problem being that that's already legal syntax[/color]
      D'oh ;-)
      [color=blue]
      >[color=green][color=darkred]
      >>>> class Xyzzy:[/color][/color]
      >... def __init__(self):
      >... self.op1 = self.op2 = self.y = self
      >... self.z = "Nothing happens here"
      >...[color=green][color=darkred]
      >>>> x = Xyzzy()
      >>>> x .op1. y .op2. z[/color][/color]
      >'Nothing happens here'[color=green][color=darkred]
      >>>>[/color][/color][/color]

      Ok, well, that's happened to me before ;-)
      We'll have to find a way to make it illegal, but it's not likely to be quite as clean.

      x ..OP y
      x ./OP y
      x .<OP y
      x .<OP>. y
      X ._OP_. y
      x ..OP.. y # for symmetry ;-)

      X .(OP). y # emphasizes the .expression. returning a function accepting two args

      That might be the best one.

      OTOH some time ago I was thinking of .(statements). as a possible tokenizer-time star-gate into
      a default-empty tokenizer-dynamically-created module which would essentially exec the statements
      in that module and return the value of the last expression as a string for insertion into the token
      source code stream at that point being tokenized.

      Thus e.g. you could have source that said

      compile_time = .(__import__('t ime').ctime()).

      and get a time stamp string into the source text at tokenization time.

      I had also thought obj.(expr) could be syntactic sugar for obj.__dict__[expr]
      but that would also interfere ;-)

      So maybe .(OP). should for infix, and .[stargate exec args]. should be for that ;-)

      Regards,
      Bengt Richter

      Comment

      • Bengt Richter

        #18
        Re: Other notes

        On Thu, 30 Dec 2004 03:55:12 GMT, bokr@oz.net (Bengt Richter) wrote:
        [.. buncha stuff alzheimersly based on x<spaces>.attr not being parsed as x.attr ;-/ ]
        [color=blue]
        > from rational import rat as RAT
        >
        > if x .RAT. y > 1 .RAT. 3: do_it()
        >
        >or
        > your turn ;-)
        >[/color]
        Andrew got there first ;-)
        Still, see my reply to his for more opportunities ;-)

        Regards,
        Bengt Richter

        Comment

        • Bengt Richter

          #19
          Re: Other notes

          On Thu, 30 Dec 2004 04:46:25 GMT, bokr@oz.net (Bengt Richter) wrote:
          [...][color=blue]
          >Ok, well, that's happened to me before ;-)
          >We'll have to find a way to make it illegal, but it's not likely to be quite as clean.
          >
          > x ..OP y
          > x ./OP y
          > x .<OP y
          > x .<OP>. y
          > X ._OP_. y[/color]
          Bzzzt! ;-/
          [color=blue]
          > x ..OP.. y # for symmetry ;-)
          >
          > X .(OP). y # emphasizes the .expression. returning a function accepting two args
          >
          >That might be the best one.[/color]

          Regards,
          Bengt Richter

          Comment

          • Steve Holden

            #20
            Re: Other notes

            Bengt Richter wrote:
            [color=blue]
            > On Wed, 29 Dec 2004 13:11:43 -0500, Steve Holden <steve@holdenwe b.com> wrote:
            >[/color]
            [...][color=blue][color=green]
            >>
            >>Well, perhaps you can explain how a change that's made at run time
            >>(calling the decorator) can affect the parser's compile time behavior,
            >>then. At the moment, IIRC, the only way Python code can affect the
            >>parser's behavior is in the __future__ module, which must be imported at
            >>the very head of a module.[/color]
            >
            > Good point, which I didn't address in my reply. (in fact I said I liked
            > @infix('..') for punctuation-char-named ops, but I was too busy with my
            > idea to think about that implementation ;-)
            >[/color]
            Well, that explains the lack of detail. I realize that you are more
            likely than most to be able to come up with an implementation.
            [color=blue]
            > Potentially, you could do it dynamically with a frame flag (to limit the damage)
            > which said, check all ops against a dict of overloads and infix definitions while
            > executing byte code for this frame. Of course, the compiler would have to defer
            > some kinds of syntax error 'til run time. I.e., '..' would have to be translated
            > to OP_POSSIBLE_CUS TOM_INFIX or such. I doubt if it would be worth doing.
            >[/color]
            Right. I can't say I think deferring syntax errors until runtime is a
            good idea.
            [color=blue]
            > OTOH, I think my suggestion might be ;-) I.e., just do a macro-like (not a general
            > macro capability for this!!) translation of expressions with dots at both ends and
            > no embedded spaces (intial thought, to make things easier) thus:
            > x .expr. y => expr(x, y)
            >
            > when expr is a simple name, you can use that expression format to call a two-arg function
            > of that name, e.g.,
            >
            > def interval(x, y): return xrange(x, y+1)
            > for i in x .interval. y: print i, # same as for i in interval(x, y): print i,
            >
            > but you could also write stuff like
            >
            > def GE(x,y): return x is MY_INFINITY or x >= y
            > if x .GE. y: print 'x is greater than y'
            >
            > The .expr. as expression would allow module references or tapping into general
            > expression and attribute magic etc. I.e., (untested)
            >
            > from itertools import chain as CHAIN
            > for k,v in d1.items() .CHAIN. d2.items(): print k, v
            >
            > or if you had itertools imported and liked verbose infix spelling:
            >
            > for k,v in d1.items() .itertools.chai n. d2.items(): print k, v
            >
            > or define a hidden-attribute access operation using an object's dict
            >
            > def HATTR(obj, i):
            > try: return vars(obj)[i]
            > except KeyError: raise AttributeError( 'No such attribute: %r', i)
            >
            > if thing .HATTR. 2 == 'two': print 'well spelled'
            >
            > or
            > from rational import rat as RAT
            >
            > if x .RAT. y > 1 .RAT. 3: do_it()
            >
            > or
            > your turn ;-)
            >[/color]
            Well, I can see that Fortran programmers might appreciate it :-). And I
            suppose that the syntax is at least regular enough to be lexed with the
            current framework, give or take. It would lead to potential breakage due
            to the syntactic ambiguity between

            module .function. attribute

            and

            module.function .attribute

            though I don't honestly think that most people currently insert
            gratuitous spaces into attribute references.
            [color=blue]
            >[/color]
            [precedence and associativity][color=blue]
            >
            > My suggestion if implemented with left-right priority would be easy to
            > implement (I think ;-) And you could always override order with parens.[/color]

            Now you're just trying to make it easy :-)

            regards
            Steve
            --
            Steve Holden http://www.holdenweb.com/
            Python Web Programming http://pydish.holdenweb.com/
            Holden Web LLC +1 703 861 4237 +1 800 494 3119

            Comment

            • Mike Meyer

              #21
              Re: Other notes

              Steve Holden <steve@holdenwe b.com> writes:
              [color=blue]
              > Mike Meyer wrote:
              >[color=green]
              >> Steve Holden <steve@holdenwe b.com> writes:
              >>[/color]
              > [...][color=green][color=darkred]
              >>>
              >>>Well, perhaps you can explain how a change that's made at run time
              >>>(calling the decorator) can affect the parser's compile time behavior,
              >>>then. At the moment, IIRC, the only way Python code can affect the
              >>>parser's behavior is in the __future__ module, which must be imported
              >>>at the very head of a module.[/color]
              >> By modifying the parsers grammer at runtime. After all, it's just a
              >> data structure that's internal to the compiler.
              >>[/color]
              > But the parser executes before the compiled program runs, was my
              > point. What strange mixture of compilation and interpretation are you
              > going to use so the parser actually understands that ".." (say) is an
              > operator before the operator definition has been executed?[/color]

              Ok, current decorators won't do. Clearly, any support for adding infix
              operators is going to require compiler support.

              <mike
              --
              Mike Meyer <mwm@mired.or g> http://www.mired.org/home/mwm/
              Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.

              Comment

              • Mike Meyer

                #22
                Re: Other notes

                "Terry Reedy" <tjreedy@udel.e du> writes:
                [color=blue]
                > "Mike Meyer" <mwm@mired.or g> wrote in message
                > news:86acrxt0e7 .fsf@guru.mired .org...[color=green]
                >> Steve Holden <steve@holdenwe b.com> writes:[color=darkred]
                >>> Well, perhaps you can explain how a change that's made at run time
                >>> (calling the decorator) can affect the parser's compile time behavior,
                >>> then. At the moment, IIRC, the only way Python code can affect the
                >>> parser's behavior is in the __future__ module, which must be imported
                >>> at the very head of a module.[/color]
                >>
                >> By modifying the parsers grammer at runtime. After all, it's just a
                >> data structure that's internal to the compiler.[/color]
                >
                > Given that xx.py is parsed in its entirety *before* runtime, that answer is
                > no answer at all. Runtime parser changes (far, far from trivial) could
                > only affect the result of exec and eval.[/color]

                and import. I.e., you could do:

                import french
                import python_with_fre nch_keywords

                <mike
                --
                Mike Meyer <mwm@mired.or g> http://www.mired.org/home/mwm/
                Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.

                Comment

                • beliavsky@aol.com

                  #23
                  Re: Other notes

                  Bengt Richter wrote:
                  [color=blue]
                  >OTOH, there is precedent in e.g. fortran (IIRC) for named operators of[/color]
                  the[color=blue]
                  >form .XX. -- e.g., .GE. for >= so maybe there could be room for both.[/color]

                  Yes, but in Fortran 90 "==", ">=" etc. are equivalent to ".EQ." and
                  ".GE.". It is also possible to define operators on native and
                  user-defined types, so that

                  Y = A .tx. B

                  can be written instead of the expression with the F90 intrinsic
                  functions

                  Y = matmul(transpos e(A),B)

                  The Fortran 95 package Matran at
                  http://www.cs.umd.edu/~stewart/matran/Matran.html uses this approach to
                  simplify the interface of the Lapack library and provide syntax similar
                  to that of Matlab and Octave.

                  I don't know if the syntax of your idea clashes with Python, but it is
                  viable in general.

                  Comment

                  Working...