Securing a future for anonymous functions in Python

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Nick Coghlan

    #16
    Re: Securing a future for anonymous functions in Python

    Carl Banks wrote:[color=blue]
    > Nick Coghlan wrote:
    > In much the same way that programmers often spend a lot of time
    > optimizing parts of their program that will yield very minor dividends,
    > while they could have spent that time working on other things that will
    > pay off a lot, many of the wannabe language designers here are spending
    > a lot of time on aspects of the language for which any improvement
    > would only pay small dividends.[/color]

    Whereas I see it as wannabe language designers only being able to tinker at the
    edges of Python, because GvR already got the bulk of the language right.
    Anonymous functions are the major core construct that doesn't 'fit right', so a
    disproportionat e amount of time is spent playing with ideas about them.

    Cheers,
    Nick.

    --
    Nick Coghlan | ncoghlan@email. com | Brisbane, Australia
    ---------------------------------------------------------------

    Comment

    • Bengt Richter

      #17
      Re: Securing a future for anonymous functions in Python

      On Thu, 30 Dec 2004 17:39:06 -0800, Jeff Shannon <jeff@ccvcorp.c om> wrote:
      [color=blue]
      >Bengt Richter wrote:
      >[color=green]
      >> On Thu, 30 Dec 2004 15:15:51 -0800, Jeff Shannon <jeff@ccvcorp.c om> wrote:
      >>[color=darkred]
      >>>Mimicking function-def indentation inside of another function's arglist
      >>>strikes me as an abomination just waiting to happen; in comparison, the
      >>>need to type a name twice seems trivial.[/color]
      >>
      >> Self-restraint can avoid abominations ;-)[/color]
      >
      >It can, but given the prevalence of lambda abominations (such as the
      >many that the Martellibot described among Cookbook submissions), is
      >there any reason to believe that there would be *more* restraint in
      >using a less-constrained feature?? :)[/color]
      Maybe. If people are determined to overcome limitations that needn't exist,
      they are likely to invent horrible hacks ;-)
      [color=blue]
      >[color=green][color=darkred]
      >>>As a result, it seems to me that, rather than generalize lambdas into
      >>>"full" anonymous functions (with most of the negatives and few of the
      >>>positives of lambda), it would be much better to specialize them further
      >>>into inline-closure-creators, where they can serve a valuable purpose
      >>>without quite as much risk of code pollution.[/color]
      >>
      >> (BTW, again, by closure, do you really mean deferred-action-thingie?)[/color]
      >
      >My understanding of "closure" (which may well be wrong, as I've
      >inferred it entirely from past discussions on this newsgroup) is that
      >it's a callable with some or all of its parameters already set; e.g.,
      >
      > def one_and(foo):
      > def closure(arg):
      > return foo(1, arg)
      > return closure
      >
      > incr = one_and(operato r.add)
      >
      >The function one_and() returns a closure, here bound to incr. It is
      >essentially a (partially) deferred action thingy, if you want to use
      >technical terms. ;) I suppose that one could look at it as the
      >environment in which to call a given function, exported for later use...[/color]

      Quoting from "Essentials of Programming Languages" (Friedman, Wand, Haynes):
      (using *xxx yyy etc* for italics)
      """
      In order for a procedure to retain the bindings that its free variables had
      at the time it was created, it must be a *closed* package, independent of
      the environment in which it is used. Such a package is called a closure.
      In order to be self-contained, a closure must contain the procedure body,
      the list of formal parameters, and the bindings of its free variables.
      It is convenient to store the entire creation environment, rather than
      just the bindings of the free variables. We sometimes say the procedure
      *is closed over* or *closed in* its creation environment. We represent
      closures as records.
      """

      So it looks like you infer better than I remember, and attachment to
      faulty memory has led me to resist better inferences ;-/

      Closure is the name for the whole thing, apparently, not just the environment
      the procedure body needs, which was the aspect that I (mis)attached the name to.

      (Representing closures as records doesn't really belong in that paragraph IMO,
      since it is not really part of the definition there, just a choice in that stage
      of exposition in the book, using scheme-oriented examples. But I quoted verbatim.).

      On the subject CLtL finally (after some stuff beyond my current caffeine level) says,
      """
      The distinction between closures and other kinds of functions is somewhat pointless,
      actually, since Common Lisp defines no particular representation for closures and
      no way to distinguish between closures and non-closure functions. All that matters
      is that the rules of lexical scoping be obeyed.
      """
      I guess that clinches it ;-)

      Might be a good python glossary wiki entry.
      [color=blue]
      >
      >My thesis here is that one of the most common (legitimate) uses of
      >lambda is as an adapter, to create an intermediary that allows a
      >callable with a given signature to be used in places where a different
      >signature is expected -- that is, altering the number or order of
      >arguments passed to a given callable (and possibly also capturing the
      >current value of some other variable in the process). I feel that
      >it's more fruitful to focus on this "adapter" quality rather than
      >focusing on the "anonymous function" quality.
      >[/color]
      I see what you are saying (I think), but I think I'd still like a full
      anonymous def, whatever adapter you come up with. And I prefer to be persuaded ;-)

      Regards,
      Bengt Richter

      Comment

      • Steven Bethard

        #18
        Re: Securing a future for anonymous functions in Python

        Jeff Shannon wrote:[color=blue]
        > My thesis here is that one of the most common (legitimate) uses of
        > lambda is as an adapter, to create an intermediary that allows a
        > callable with a given signature to be used in places where a different
        > signature is expected -- that is, altering the number or order of
        > arguments passed to a given callable (and possibly also capturing the
        > current value of some other variable in the process). I feel that it's
        > more fruitful to focus on this "adapter" quality rather than focusing on
        > the "anonymous function" quality.[/color]

        Maybe the 'functional' module proposed in PEP 309[1] could provide such
        functions?

        py> def ignoreargs(func , nargs, *kwd_names):
        .... def _(*args, **kwds):
        .... args = args[nargs:]
        .... kwds = dict((k, kwds[k])
        .... for k in kwds if k not in kwd_names)
        .... return func(*args, **kwds)
        .... return _
        ....
        py> def f(x, y):
        .... print x, y
        ....
        py> ignoreargs(f, 2)(1, 2, 3, 4)
        3 4
        py> ignoreargs(f, 2, 'a', 'b')(1, 2, 3, 4, a=35, b=64)
        3 4

        Steve

        [1] http://python.fyxm.net/peps/pep-0309.html

        Comment

        • Paul Rubin

          #19
          Re: Securing a future for anonymous functions in Python

          bokr@oz.net (Bengt Richter) writes:[color=blue]
          > print either(A == B, (def "A equals B"), (def "A does not equal B"))
          > either(thefile, (def thefile.close() ), (def 0))[/color]

          I'd really rather have some reasonable macro facility, than to resort
          to using anonymous functions and deferred evaluation for common things
          like that.

          Comment

          • Ian Bicking

            #20
            Re: Securing a future for anonymous functions in Python

            John Roth wrote:[color=blue][color=green]
            >> I appreciate some of the motivation, but merely avoiding giving
            >> something a name doesn't seem like a laudible goal.[/color]
            >
            > Actually, it is a laudable goal. It's always easier to understand
            > something when it's right in front of your face than if it's
            > off somewhere else.[/color]

            Naming the function doesn't move it far away. It changes the order (you
            have to define it before you use it), and it introduces a name.
            [color=blue][color=green]
            >> The one motivation I can see for function expressions is
            >> callback-oriented programming ...[/color]
            >
            > Well, that's true, but that's a very global statement:
            > when you pass a function into another routine, it's
            > essentially a callback.[/color]

            Sure, technically. But I'm thinking of real use cases. One I'm
            familiar with is things like map and filter. These are generally better
            handled with list expressions (and MUCH more readable as such, IMHO).
            Another is control structures, ala Ruby or Smalltalk. IMHO, we have all
            the control structures we need -- while, for, if. Most "novel" control
            structures in Ruby or Smalltalk are just another take on iterators. The
            exception being callbacks, and perhaps some other lazy evaluation
            situations (though outside of what I think of as "callbacks" , I can't
            think of any lazy evaluation situations off the top of my head).

            So that's why I think callbacks are important; callbacks in the style of
            Twisted Deferred, GUI events, etc.
            [color=blue][color=green]
            >> Function expressions could get really out of hand, IMHO, and could
            >> easily lead to twenty-line "expression s". That's aesthetically
            >> incompatible with Python source, IMHO.[/color]
            >
            > Anything can get out of hand; there's no way of legislating
            > good style without restricting the language so much that it
            > becomes unusable for anything really interesting. Even then
            > it doesn't work: see COBOL as a really good example of
            > good intentions gone seriously wrong.[/color]

            OK, I should go further -- even a two-line expression (i.e., an
            expression that contains meaningful vertical whitespace) is
            aesthetically incompatible with Python source. Which covers any
            anonymous function that is more powerful than lambda. I'm not arguing
            that it can be abused, but more that it isn't any good even when it's
            not being abused.
            [color=blue]
            > Have you ever programmed in a language that does use
            > anonymous functions extensively like Smalltalk?[/color]

            Yep, I've done a fair amount of Smalltalk and Scheme programming. I
            don't expect Python to act like them. I appreciate the motivation, but
            I don't think their solution is the right one for Python.

            --
            Ian Bicking / ianb@colorstudy .com / http://blog.ianbicking.org

            Comment

            • Scott David Daniels

              #21
              Re: Securing a future for anonymous functions in Python

              David Bolen wrote:[color=blue]
              > So for example, an asynchronous sequence of operations might be like:
              >
              > d = some_deferred_f unction()
              > d.addCallback(l ambda x: next_function() )
              > d.addCallback(l ambda blah: third_function( otherargs, blah))
              > d.addCallback(l ambda x: last_function() )
              >
              > which to me is more readable (in terms of seeing the sequence of
              > operations being performed in their proper order), then something like:
              >
              > def cb_next(x):
              > return next_function()
              > def cb_third(blah, otherargs):
              > return third_function( otherargs, blah)
              > def cb_last(x):
              > return last_function()
              >
              > d = some_deferred_f unction()
              > d.addCallback(c b_next)
              > d.addCallback(c b_third, otherargs)
              > d.addCallback(c b_next)
              >
              > which has an extra layer of naming (the callback functions), and
              > requires more effort to follow the flow of what is really just a simple
              > sequence of three functions being called.[/color]

              But this sequence contains an error of the same form as the "fat":

              while test() != False:
              ...code...

              The right sequence using lambda is:
              d = some_deferred_f unction()
              d.addCallback(n ext_function)
              d.addCallback(l ambda blah: third_function( otherargs, blah))
              d.addCallback(l ast_function)

              And I would write it as:

              def third_function_ fixed_blah(blah ):
              def call_third(othe rargs):
              return third_function( otherargs, blah)
              return call_third

              d = some_deferred_f unction()
              d.addCallback(n ext_function)
              d.addCallback(t hird_function_f ixed_blah, otherargs)
              d.addCallback(l ast_function)

              The name gives you the chance to point out that the argument order is
              tweaked. In many such cases, I use curry (ASPN recipe #52549), which
              should show up in Python as "partial" in the "functional " module
              according to PEP 309 <http://www.python.org/peps/pep-0309.html>
              (accepted but not included). I suppose it will show up in Python 2.5.

              Programming is a quest is for clear, easy-to-read code, not quick,
              easy-to-write code. Choosing a name is a chance to explain what you
              are doing. lambda is used too often in lieu of deciding what to write.

              --Scott David Daniels
              Scott.Daniels@A cm.Org

              Comment

              • Ian Bicking

                #22
                Re: Securing a future for anonymous functions in Python

                David Bolen wrote:[color=blue]
                > Ian Bicking <ianb@colorstud y.com> writes:
                >
                >[color=green]
                >>The one motivation I can see for function expressions is
                >>callback-oriented programming, like:
                >>
                >> get_web_page(ur l,
                >> when_retrieved= {page |
                >> give_page_to_ot her_object(mung e_page(page))})[/color]
                >
                >
                > This is my primary use case for lambda's nowadays as well - typically
                > just to provide a way to convert the input to a callback into a call
                > to some other routine. I do a lot of Twisted stuff, whose deferred
                > objects make heavy use of single parameter callbacks, and often you
                > just want to call the next method in sequence, with some minor change
                > (or to ignore) the last result.
                >
                > So for example, an asynchronous sequence of operations might be like:
                >
                > d = some_deferred_f unction()
                > d.addCallback(l ambda x: next_function() )
                > d.addCallback(l ambda blah: third_function( otherargs, blah))
                > d.addCallback(l ambda x: last_function() )[/color]

                Steven proposed an ignoreargs function, and the partial function offers
                the other side (http://www.python.org/peps/pep-0309.html). So this
                would become:

                d = some_deferred_f unction()
                d.addCallback(i gnoreargs(next_ function, 1))
                d.addCallback(p artial(third_fu nction, otherargs))
                d.addCallback(i gnoreargs(last_ function, 1))

                I'm not sure this is "better" than it is with lambda. It's actually
                considerably less readable to me. Hmm... well, that makes me less
                excited about those...

                --
                Ian Bicking / ianb@colorstudy .com / http://blog.ianbicking.org

                Comment

                • David Bolen

                  #23
                  Re: Securing a future for anonymous functions in Python

                  Scott David Daniels <Scott.Daniels@ Acm.Org> writes:
                  [color=blue]
                  > David Bolen wrote:[color=green]
                  > > So for example, an asynchronous sequence of operations might be like:
                  > > d = some_deferred_f unction()
                  > > d.addCallback(l ambda x: next_function() )
                  > > d.addCallback(l ambda blah: third_function( otherargs, blah))
                  > > d.addCallback(l ambda x: last_function() )
                  > > which to me is more readable (in terms of seeing the sequence of
                  > > operations being performed in their proper order), then something like:
                  > > def cb_next(x):
                  > > return next_function()
                  > > def cb_third(blah, otherargs):
                  > > return third_function( otherargs, blah)
                  > > def cb_last(x):
                  > > return last_function()
                  > > d = some_deferred_f unction()
                  > > d.addCallback(c b_next)
                  > > d.addCallback(c b_third, otherargs)
                  > > d.addCallback(c b_next)
                  > > which has an extra layer of naming (the callback functions),
                  > > and
                  > > requires more effort to follow the flow of what is really just a simple
                  > > sequence of three functions being called.[/color]
                  >
                  > But this sequence contains an error of the same form as the "fat":[/color]

                  "this" being which of the two scenarios you quote above?
                  [color=blue]
                  > while test() != False:
                  > ...code...[/color]

                  I'm not sure I follow the "error" in this snippet...
                  [color=blue]
                  > The right sequence using lambda is:
                  > d = some_deferred_f unction()
                  > d.addCallback(n ext_function)
                  > d.addCallback(l ambda blah: third_function( otherargs, blah))
                  > d.addCallback(l ast_function)[/color]

                  By what metric are you judging "right"?

                  In my scenario, the functions next_function and last_function are not
                  written to expect any arguments, so they can't be passed straight into
                  addCallback because any deferred callback will automatically receive
                  the result of the prior deferred callback in the chain (this is how
                  Twisted handles asynchronous callbacks for pending operations).
                  Someone has to absorb that argument (either the lambda, or
                  next_function itself, which if it is an existing function, needs to be
                  handled by a wrapper, ala my second example).

                  Your "right" sequence simply isn't equivalent to what I wrote.
                  Whether or not next_function is fixable to be used this way is a
                  separate point, but then you're discussing two different scenarios,
                  and not two ways to write one scenario.

                  -- David

                  Comment

                  • Scott David Daniels

                    #24
                    Re: Securing a future for anonymous functions in Python

                    David Bolen wrote:[color=blue]
                    > Scott David Daniels <Scott.Daniels@ Acm.Org> writes:[color=green]
                    >> while test() != False:
                    >> ...code...[/color]
                    > I'm not sure I follow the "error" in this snippet...[/color]

                    The code is "fat" -- clearer is:
                    while test():
                    ...code...
                    [color=blue][color=green]
                    >>The right sequence using lambda is:
                    >> d = some_deferred_f unction()
                    >> d.addCallback(n ext_function)
                    >> d.addCallback(l ambda blah: third_function( otherargs, blah))
                    >> d.addCallback(l ast_function)[/color]
                    > By what metric are you judging "right"?[/color]

                    By a broken metric that requires you to mis-understand the original code
                    in the same way that I did. It was an idiotic response that required
                    more careful reading than I am doing this morning. The thing I've seen
                    in too much code (and though I saw in your code) is code like:

                    requires_functi on(lambda: function())

                    rather than:

                    requires_functi on(function)

                    It happens quite often, and I'm sure you've seen it. But I got your
                    code wrong, and for that I apologize.

                    --Scott David Daniels
                    Scott.Daniels@A cm.Org

                    Comment

                    • Simo Melenius

                      #25
                      Of closures and expressing anonymous functions [Was: Re: Securing afuture for anonymous functions in Python]

                      bokr@oz.net (Bengt Richter) writes:
                      [color=blue]
                      > Closure is the name for the whole thing, apparently, not just the
                      > environment the procedure body needs, which was the aspect that I
                      > (mis)attached the name to.[/color]

                      Which brings me to the point where I'd welcome more flexibility in
                      writing to variables outside the local scope. This limitation most
                      often kicks in in closed-over code in function objects, although it's
                      a more general issue in Python's scoping.

                      As we know, you can't write to variables that are both non-local and
                      non-global (globals you can declare "global"). Now that effectively
                      makes free variables read-only (although, the objects they point to
                      can _still_ be mutated).

                      Allowing write access to variables in a closed-over lexical scope
                      outside the innermost scope wouldn't hurt because:

                      1) if you need it, you can already do it -- just practice some
                      cumbersome tricks make suitable arrangements (e.g. the classical
                      accumulator example uses an array to hold the counter value instead
                      of binding it directly to the free variable;

                      2) if you don't need or understand it, you don't have to use it;

                      3) and at least in function instances: if you accidentally do, it'll
                      change the bindings within your closure only which is definitely
                      less dangerous than mutating objects that are bound inside the
                      closure.

                      It must be noted, however, that such behaviour would change the way of
                      hiding nested variable names:

                      Now it's safe (though maybe lexically confusing) to use the same
                      variable names in inner functions. This could happen with common names
                      for temporary variables like "i", "x", "y".

                      On the other hand, one could introduce a way to declare variables from
                      global scope or from local scope, with default from lexical scope. (If
                      you want to explicitly hide an outer binding, you'd declare "local
                      foo", for example. You can already do "global foo".)
                      [color=blue]
                      > I see what you are saying (I think), but I think I'd still like a
                      > full anonymous def, whatever adapter you come up with. And I prefer
                      > to be persuaded ;-)[/color]

                      I elaborated on this one in a post a few days ago. Indeed, it is
                      mostly a minor issue that _can_ be worked around(1). The problem is
                      that it eventually becomes irritating, when repeated all the time, to
                      name functions even if the name isn't used elsewhere.

                      It also creates an implicit dependency from the function call (one of
                      whose arguments points to the once-named function) to the once-named
                      function. That is, when you refactor some of your code, you must keep
                      two things paired all the time in your cut+paste maneuvers.


                      br,
                      S

                      (1) Everything can be worked around. In contrast: you can work around
                      the lack of a syntactic language by typing in machine code manually.
                      Sound stupid? Yes, it was done decades ago. How about using C to write
                      a "shell script" equivalent that you need, as a workaround to the
                      problem of lacking a shell? Stupid? Yes, but less -- it's been done.
                      How about writing callbacks by passing in a function pointer and a
                      data pointer, if you don't want to use a language like Python that
                      automates that task for you? Stupid? Yes, but not much -- it's been
                      done all the time. How about implementing an _anonymous_ function by
                      naming it, if you can't do it otherwise?

                      Comment

                      • Simo Melenius

                        #26
                        Re: Securing a future for anonymous functions in Python

                        Ian Bicking <ianb@colorstud y.com> writes:
                        [color=blue]
                        > But I do think there's other ways to approach this. Function
                        > expressions could get really out of hand, IMHO, and could easily lead
                        > to twenty-line "expression s". That's aesthetically incompatible with
                        > Python source, IMHO.[/color]

                        You can already write unaesthetic hundred-line Python functions, if
                        you want to. Python's syntax doesn't yet impose a restriction on the
                        number of sequential statements :-) It sounds artificial to impose
                        such restrictions on these hypothetical "inline blocks", even if by
                        only allowing them to be plain expressions.

                        IMHO, the most pythonic way to write an "inline-block" is by reusing
                        existing keywords, using Python-like start-of-blocks and ending it by
                        indentation rules:

                        map (def x:
                        if foo (x):
                        return baz_1 (x)
                        elif bar (x):
                        return baz_2 (x)
                        else:
                        global hab
                        hab.append (x)
                        return baz_3 (hab),
                        [1,2,3,4,5,6])

                        and for one-liners:

                        map (def x: return x**2, [1,2,3,4,5,6])

                        As a side-effect, we also

                        - got rid of the "lambda" keyword;

                        - strenghtened the semantics of "def": a "def" already defines a
                        function so it's only logical to use it to define anonymous
                        functions, too;

                        - unified the semantics: function is always a function, and functions
                        return values by using "return". When learning Python, I learned the
                        hard way that "lambda"s are expressions, not functions. I'd pay the
                        burden of writing "return" more often in exchange for better
                        consistency.


                        my two cents,
                        br,
                        S

                        Comment

                        • Steven Bethard

                          #27
                          Re: Securing a future for anonymous functions in Python

                          Simo Melenius wrote:[color=blue]
                          > map (def x:
                          > if foo (x):
                          > return baz_1 (x)
                          > elif bar (x):
                          > return baz_2 (x)
                          > else:
                          > global hab
                          > hab.append (x)
                          > return baz_3 (hab),
                          > [1,2,3,4,5,6])[/color]

                          I think this would probably have to be written as:

                          map (def x:
                          if foo(x):
                          return baz_1(x)
                          elif bar(x):
                          return baz_2(x)
                          else:
                          global hab
                          hab.append(x)
                          return baz_3(hab)
                          , [1,2,3,4,5,6])

                          or:

                          map (def x:
                          if foo(x):
                          return baz_1(x)
                          elif bar(x):
                          return baz_2(x)
                          else:
                          global hab
                          hab.append(x)
                          return baz_3(hab)
                          ,
                          [1,2,3,4,5,6])

                          Note the placement of the comma. As it is,
                          return baz_3(hab),
                          returns the tuple containing the result of calling baz_3(hab):

                          py> def f(x):
                          .... return float(x),
                          ....
                          py> f(1)
                          (1.0,)

                          It's not horrible to have to put the comma on the next line, but it
                          isn't as pretty as your version that doesn't. Unfortunately, I don't
                          think anyone's gonna want to revise the return statement syntax just to
                          introduce anonymous functions.

                          Steve

                          Comment

                          • Simo Melenius

                            #28
                            Re: Securing a future for anonymous functions in Python

                            Steven Bethard <steven.bethard @gmail.com> writes:
                            [color=blue]
                            > Simo Melenius wrote:[color=green]
                            > > map (def x:
                            > > if foo (x):
                            > > return baz_1 (x)
                            > > elif bar (x):
                            > > return baz_2 (x)
                            > > else:
                            > > global hab
                            > > hab.append (x)
                            > > return baz_3 (hab),
                            > > [1,2,3,4,5,6])[/color]
                            >
                            > I think this would probably have to be written as:[/color]
                            ....[color=blue]
                            > return baz_3(hab)
                            > , [1,2,3,4,5,6])
                            > or:[/color]
                            ....[color=blue]
                            > return baz_3(hab)
                            > ,
                            > [1,2,3,4,5,6])
                            >
                            > Note the placement of the comma. As it is,
                            > return baz_3(hab),
                            > returns the tuple containing the result of calling baz_3(hab):[/color]

                            That one didn't occur to me; creating a one-item tuple with (foo,) has
                            been odd enough for me: only few times I've seen also the parentheses
                            omitted.

                            I did ponder the unambiguousness of the last line, though. One could
                            suggest a new keyword like "end", but keyword bloat is bad.

                            (Of course, if we trade the "lambda" keyword for another, new keyword
                            we're not exactly _adding_ keywords... :))
                            [color=blue]
                            > It's not horrible to have to put the comma on the next line, but it
                            > isn't as pretty as your version that doesn't. Unfortunately, I don't
                            > think anyone's gonna want to revise the return statement syntax just
                            > to introduce anonymous functions.[/color]

                            There might not be a return statement: the anonymous function might
                            conditionally return earlier and have side-effects at the end of the
                            block (to implicitly return None). So the block-ending would need to
                            fit after any statement and be strictly unambiguous.


                            br,
                            S

                            Comment

                            • Doug Holton

                              #29
                              Re: Securing a future for anonymous functions in Python

                              Steven Bethard wrote:
                              [color=blue]
                              > Simo Melenius wrote:
                              >[color=green]
                              >> map (def x:
                              >> if foo (x):
                              >> return baz_1 (x)
                              >> elif bar (x):
                              >> return baz_2 (x)
                              >> else:
                              >> global hab
                              >> hab.append (x)
                              >> return baz_3 (hab),
                              >> [1,2,3,4,5,6])[/color]
                              >
                              >
                              > I think this would probably have to be written as:[/color]

                              Right the comma plus other things make this difficult for a parser to
                              handle correctly. Other people have already come up with working solutions.

                              We have a special way to pass a multiline closure as a parameter to a
                              function. Put it outside the parameter list.

                              First, the single-line way using curly braces:

                              newlist = map({x as int | return x*x*x}, [1,2,3,4,5,6])

                              Then the multi-line way. I had to add an overload of map to support
                              reversing the order of parameters (list first, then the closure):

                              newlist = map([1,2,3,4,5,6]) def (x as int):
                              return x*x*x

                              for item in newlist:
                              print item

                              Comment

                              • Bengt Richter

                                #30
                                Re: Securing a future for anonymous functions in Python

                                On 01 Jan 2005 00:56:30 +0200, Simo Melenius <firstname.last name@iki.fi-spam> wrote:
                                [color=blue]
                                >Steven Bethard <steven.bethard @gmail.com> writes:
                                >[color=green]
                                >> Simo Melenius wrote:[color=darkred]
                                >> > map (def x:
                                >> > if foo (x):
                                >> > return baz_1 (x)
                                >> > elif bar (x):
                                >> > return baz_2 (x)
                                >> > else:
                                >> > global hab
                                >> > hab.append (x)
                                >> > return baz_3 (hab),
                                >> > [1,2,3,4,5,6])[/color]
                                >>
                                >> I think this would probably have to be written as:[/color]
                                >...[color=green]
                                >> return baz_3(hab)
                                >> , [1,2,3,4,5,6])
                                >> or:[/color]
                                >...[color=green]
                                >> return baz_3(hab)
                                >> ,
                                >> [1,2,3,4,5,6])
                                >>
                                >> Note the placement of the comma. As it is,
                                >> return baz_3(hab),
                                >> returns the tuple containing the result of calling baz_3(hab):[/color]
                                >
                                >That one didn't occur to me; creating a one-item tuple with (foo,) has
                                >been odd enough for me: only few times I've seen also the parentheses
                                >omitted.
                                >
                                >I did ponder the unambiguousness of the last line, though. One could
                                >suggest a new keyword like "end", but keyword bloat is bad.[/color]
                                ISTM you don't need "end" -- just put the def expression in parens,
                                and let the closing paren end it, e.g.:

                                map((def x:
                                if foo (x):
                                return baz_1 (x)
                                elif bar (x):
                                return baz_2 (x)
                                else:
                                global hab
                                hab.append (x)
                                return baz_3 (hab)), [1,2,3,4,5,6])
                                [color=blue]
                                >
                                >(Of course, if we trade the "lambda" keyword for another, new keyword
                                >we're not exactly _adding_ keywords... :))
                                >[color=green]
                                >> It's not horrible to have to put the comma on the next line, but it
                                >> isn't as pretty as your version that doesn't. Unfortunately, I don't
                                >> think anyone's gonna want to revise the return statement syntax just
                                >> to introduce anonymous functions.[/color]
                                >
                                >There might not be a return statement: the anonymous function might
                                >conditionall y return earlier and have side-effects at the end of the
                                >block (to implicitly return None). So the block-ending would need to
                                >fit after any statement and be strictly unambiguous.[/color]
                                Just use parens as necessary or when in doubt ;-)

                                Regards,
                                Bengt Richter

                                Comment

                                Working...