Python syntax in Lisp and Scheme

Kaz Kylheku kaz at ashi.footprints.net
Wed Oct 15 14:32:31 EDT 2003


kaz at ashi.footprints.net (Kaz Kylheku) wrote in message news:<cf333042.0310141516.5027ee91 at posting.google.com>...
> Matthias Blume <find at my.address.elsewhere> wrote in message news:<m1k777n2i2.fsf at tti5.uchicago.edu>...
> > kaz at ashi.footprints.net (Kaz Kylheku) writes:
> > 
> > > Marcin 'Qrczak' Kowalczyk <qrczak at knm.org.pl> wrote in message news:<pan.2003.10.13.21.26.56.715704 at knm.org.pl>...
> > > > On Mon, 13 Oct 2003 13:51:22 -0700, Kaz Kylheku wrote:
> > > > 
> > > > > Secondly, it would be unoptimizeable. The result of evaluating a
> > > > > lambda expression is an opaque function object. It can only be called.
> > > > 
> > > > This is not true. When the compiler sees the application of a lambda,
> > > > it can inline it and perform further optimizations, fusing together
> > > > its arguments, its body and its context.
> > > 
> > > Kindly keep in mind the overall context of the discussion, which is
> > > HOF's versus macros. The closures being discussed are ones passed down
> > > into functions. Those closures typically cannot be inlined, except
> > > under very special circumstances taken advantage of by a compiler with
> > > very smart global optimizations.
> > 
> > If a macro works in a particular situation, then any equivalent HOF
> > can be inlined there as well.  Granted, not all compilers will
> > actually do so, but the possibility trivially exists.  This does not
> > depend on "very smart" global optimizations.
> 
> That is a case of bringing all of the function into the present
> context so it can be mixed with the closures manually created there.
> 
> A macro controls how much material is inlined and how much isn't.

What I said here is silly because a HOF can also be structured to have
inlined and noninlined parts: an inlined skeleton function that calls
non-inlined functions.

> A macro can have its own binary interface between the expanded
> material and some material in a library that is associated with the
> macro.
> 
> The macro decides what forms need to be made into a closure that is
> passed to the library and which are not.

This is the real point; in a Lisp macro, material from parameters is
usually spun into closures precisely because inlining is not wanted;
it's a compromise which allows some remote function to call back into
the present lexical environment, allowing the macro to generate less
inlined bloat.

In functional languages with lazy evaluation, evey expression is
effectively a closure. When you call some function f with argument x,
that x is effectively a lambda function which returns the value of x
in its original environment.

When the argument to a function is an expression, it need not be
evaluated prior to the call; it may be delayed until the last possible
moment when its value is actually needed, and it may never be
evaluated at all.

So it seems as if higher order functions have the evaluation control
of macros. But delaying evaluation is not the same as control over
evaluation. Moreover, a macro is not just some mechanism for delaying
the evaluation of expressions; it's a mechanism for assigning an
arbitrary meaning to expressions.

A HOF can generate code only by interpolating parameters into a fixed
body. The meaning of everything stays the same. A HOF can trivially
replace a macro under two conditions:

1. The macro is used as an interface to hide lambdas from the user.
This is not necessary if the language has lazy evaluation. Every
expression is already a lambda, capable of being passed to a foreign
environment and evaluated there, with all the hooks to the original
environment.

2. The macro is used as a trivial inlining mechanism, which
substitutes expressions into a template. HOF inlining effectively does
the same thing. Since evaluation is lazy, there is little or no
semantic difference between evaluating parameters and calling a
function, or inserting the unevaluated expressions into the body and
inlining it.

In Common Lisp, we don't have the lazy evaluation semantics, so
certain macro uses that fall under 1. are essential. People who argue
against these always use HOF examples from another programming
language. But CL programmers don't want to switch to another
programming language. You can't switch programming languages while
holding everything else constant.

Certain macro uses in Lisp that seem to fall under 2. are also
essential; some macros that do nothing more than substitute their
arguments into some functional template nevertheless have imperative
semantics, such as conditional or repeated evaluation of some forms.
When Lisp programmers demonstrate these uses, again, they are
countered by examples from a different programming language. ``Gee, if
you only had virtual sequences (or whatever gadget), you wouldn't need
that imperative DO- stuff.'' But now you are no longer talking about
just HOF's, but HOF's plus virtual sequences.

In general, for every macro use, you could design a programming
language feature, such as higher order functions, lazy sequences and
whatnot, and then claim that the macro use is unnecessary when you
have that feature. The problem is that there is no end to this
progression. Macros can implement anything you want (arbitrary syntax
to semantics mapping), and that anything can always be given a name
and codified in some offshoot academic language under a coat of
hard-coded syntax, and you can then claim that you eliminated macros
once and for all for all situations that you (and by implication
everyone else) cares about.




More information about the Python-list mailing list