PEP 312 - Making lambdas implicit worries me, surely it's just the name 'lambda' that is bad...

Stephen Horne intentionally at blank.co.uk
Sun Mar 2 13:41:25 CET 2003


As the title says, making lambdas implicit worries me - just because a
parser will not find them ambiguous, it doesn't mean I won't!

I'm going to be called a hypocrite by anyone who remembers my
contribution to the integer division thread - but surely the real
problem with 'lambda' is it's name. It really needs something that is
short yet more easily understood. Replacing this name (in stages, over
several Python versions) might be a better solution.

I'd propose 'fn' - a fairly obvious abbreviation for 'function' (at
least mathemeticians seem to think so). While it still may not be
entirely obvious what is going on to some, it seems better than
'lambda' - at least to me. It's also *much* easier to look up a
keyword in the manual than yet another use of the colon.

In an example like...

  x = function_name (a = b, c : b + c)

Is it even obvious that the 'b, c : b + c' is a significant construct?
- I don't think so. What I see is 'a = b' as one parameter and 'c : b
+ c' as possibly someone mistyping a ':' for an '='.


In a related issue, I'd quite like to be able to embed short
imperative sequences in an expression sometimes. I added this facility
to a little language I wrote some time ago (no - you won't have seen
it), and it turned out to be one of the most used facilities.

A major use was abbreviation, in contexts where temporary variables
could not otherwise be declared because of the way fragments of code
are assembled (Zope has a similar issue, I believe).

A typical example may be...

  { local a := <some_long_expression>; a * a }

Instead of...

  <some_long_expression> * <some_long_expression>

The language already supported '{' and '}' for C-like grouping of
statements, so it seemed natural to allow it's use in an expression
and take the result of the last item as the overall result.

Admittedly, this abbreviation purpose can be solved using lambdas in
Python - e.g.

  (lambda a : a * a) (<some_long_expression>)

or even

  (lambda a = <some_long_expression>: a * a) ()

but there have been other uses - e.g. people seem to prefer

  { local t := 0; for (local i : list) { t += i; }; t }

to...

  reduce (local t, 0, local i, list, i + t)

Personally, I find the former less readable. The trouble is that
people tend not to know the latter, whereas they know the building
blocks of the former.

If you're wondering about the reduce syntax, the language doesn't have
lambdas or - for that matter - user defined functions as it doesn't
need them given its very limited applications. Things like 'reduce'
were added when I decided they were a good idea, though I still get
funny looks. The odd syntax works because the interpreter works
directly on the abstract syntax tree - it doesn't need lambdas because
the parameters to built-in functions are basically the unevaluated
subexpressions.


How is this a related issue? - Well, one thing I dislike about lambdas
is that you can't use imperative code in them. On (admittedly rare)
occasions, I've wanted to do just that. Just because the function is
declared in an expression context, that doesn't mean that the body of
the function has to be a simple expression. Keeping things readable
tends to mean the body should be a simple expression, but not quite
always.

Actually, I've always thought that having separate 'def' and 'lambda'
syntaxes is a bit redundant. In lisp (and a few others) you'd use the
'lambda' form to do both jobs, rather like (in current Python)
writing...

  sum = lambda a, b : a + b

This could be modified to allow indentation to structure imperative
statements in the body of the function (ie slightly generalising
current indentation rules to allow the Haskell off-side rule). The
following needs a fixed-pitch font to read, I'm afraid...

  total = fn p_list : l_total = 0
                      for i in p_list :
                        l_total += i
                      return l_total

  print total ([1, 2, 3])

A switch-like structure might then look something like...

  cases := [  fn : do_stuff
                   do_stuff
                   do_stuff
            , fn : do_stuff
                   do_stuff
           ]

  cases [x] ()
     

The off-side rule in Haskell acts much like parentheses, to override
precedence. Thus...

  a =     b
        * c
      +   d
        * e

Would mean...

  a = (b * c) + (d * e)

Whereas...

  a =     b
      *   c
        + d
      *   e

Would mean...

  a = b * (c + d) * e

My Haskell is very rusty, though, so there's a very good chance I'm
wrong. Even so, this general pattern would theoretically work - except
for the rather obvious fact that existing Python code doesn't expect
the precedence rules to suddenly change for multiline expressions.
Damn. Still, it could be set up to work only for selected initial
keywords, such as a replacement-for-lambda such as 'fn'.

-- 
steve at ninereeds dot fsnet dot co dot uk




More information about the Python-list mailing list