Python syntax in Lisp and Scheme

Bengt Richter bokr at oz.net
Wed Oct 15 22:57:14 EDT 2003


On Wed, 15 Oct 2003 00:04:21 +1300, Paul Foley <see at below.invalid> wrote:

>On Tue, 14 Oct 2003 01:26:54 -0400, David Mertz wrote:
>
>> Matthew Danish <mdanish at andrew.cmu.edu> wrote previously:
>> |On Wed, Oct 08, 2003 at 03:59:19PM -0400, David Mertz wrote:
>> |> |Come on.  Haskell has a nice type system.  Python is an application of
>> |> |Greespun's Tenth Rule of programming.
>> |> Btw. This is more nonsense.  HOFs are not a special Lisp thing.  Haskell
>> |> does them much better, for example... and so does Python.
>
>> |Wow.  The language with the limited lambda form, whose Creator regrets
>> |including in the language, is ... better ... at HOFs?
>> |You must be smoking something really good.
>
>> I guess a much better saying than Greenspun's would be something like:
>> "Those who know only Lisp are doomed to repeat it (whenver they look at
>> another language)."  It does a better job of getting at the actual
>> dynamic.
>
>Is there anyone who knows only Lisp?
>
>Those who know Lisp repeat it for a reason -- and it isn't because
>it's all they know!  [Besides, Greenspun's 10th isn't about _Lispers_
>reinventing Lisp; it's about _everybody else_ reinventing Lisp]
>
>> In point of fact, Python could completely eliminate the operator
>> 'lambda', and remain exactly as useful for HOFs. Some Pythonistas seem
>> to want this, and it might well happen in Python3000.  It makes no
>> difference... the alpha and omega of HOFs is that functions are first
>> class objects that can be passed and returned.  Whether they happen to
>> have names is utterly irrelevant, anonymity is nothing special.
>
True, but if you are forced to bind to a name in order to get hold of some
first class functions but not others, then some are IMO "more equal than others."
And unless you allow assignments in expressions, def foo():... will be excluded,
because it assigns/binds foo in the def evaluation context, whereas lambda doesn't.

For simple functions, things look a lot the same, e.g.,

 >>> def show():
 ...     def foo(x): return x+1
 ...     bar = lambda x: x+1
 ...     return foo,bar
 ...
 >>> import dis
 >>> dis.dis(show)
   2           0 LOAD_CONST               1 (<code object foo at 009033A0, file "<stdin>", line 2>)
               3 MAKE_FUNCTION            0
               6 STORE_FAST               0 (foo)
 
   3           9 LOAD_CONST               2 (<code object <lambda> at 009034A0, file "<stdin>", line 3>)
              12 MAKE_FUNCTION            0
              15 STORE_FAST               1 (bar)
 
   4          18 LOAD_FAST                0 (foo)
              21 LOAD_FAST                1 (bar)
              24 BUILD_TUPLE              2
              27 RETURN_VALUE
              28 LOAD_CONST               0 (None)
              31 RETURN_VALUE
 >>> foo,bar = show()
 >>> dis.dis(foo)
   2           0 LOAD_FAST                0 (x)
               3 LOAD_CONST               1 (1)
               6 BINARY_ADD
               7 RETURN_VALUE
               8 LOAD_CONST               0 (None)
              11 RETURN_VALUE
 >>> dis.dis(bar)
   3           0 LOAD_FAST                0 (x)
               3 LOAD_CONST               1 (1)
               6 BINARY_ADD
               7 RETURN_VALUE
 
The difference in the code generated seems to be mainly that lambda is guaranteed to have
a return value expression at the end, so there is no return case to solve by default boilerplate,
and it is left out.

Lambda is an expression, so this is possible with Python's syntax:

 >>> (lambda
 ... x
 ... :
 ... x
 ... +
 ... 1
 ... )
 <function <lambda> at 0x008FDE70>

(because indentation is ignored inside brackets). This obviously now precludes lambda bodies that
are dependent on indented code suites, and makes it (so far) impossible to put def foo():pass
inside expression brackets. But this is surface stuff w.r.t. the definition of the code body IMO.

The name part does make a difference, however, because it amounts to a forced assignment (note that
that you get MAKE_FUNCTION followed by STORE_FAST whether you assign a lambda expression "manually"
or do it by def. You get identical code (see above), but with lambda you don't have to have
a STORE_FAST LOAD_FAST to get the use of your function as "first class").

>True enough.  Naming things is a pain though.  Imagine if you couldn't
>use numbers without naming them: e.g., if instead of 2 + 3 you had to
>do something like
>
>  two = 2
>  three = 3
>  two + three
>
>Bleargh!  It "makes no difference" in much the same way that using
>assembler instead of Python "makes no difference" -- you can do the
>same thing either one, but one way is enormously more painful.
>
I think it makes a semantic difference, not just convenience.

>[Mind you, Python's lambda is next to useless anyway]

Well, even so, I would miss it, unless it's given a full life as a nameless def():
I don't think we can know if YAGNI will apply, since there is no current opportunity
for beautiful use cases to evolve or even viably to be conceived.

Regards,
Bengt Richter




More information about the Python-list mailing list