Explanation of macros; Haskell macros

Evan Simpson evan at 4-am.com
Tue Oct 7 12:24:05 EDT 2003


mike420 at ziplip.com wrote:
> I think others dropped the ball while trying to explain macros
> to non-Lispers recently.

I may be more familiar than most Pythonistas with the potential and 
difficulties of macros in Python, from my work in building Zope's Script 
objects.

Some background: Python-based Zope Scripts (there are Perl-based ones as 
well) provide the ability to execute Python code in an environment in 
which every object access has to be vetted by a security system.  Early 
versions used Michael Hudson's excellent and dangerous bytecodehacks 
package, and we later switched over to the compiler package.  In both 
cases, we were taking parsed Python code and changing its semantics -- 
slightly in the case of object access, and more blatantly in hijacking 
the print statement.

As I learned to use the compiler package, it became obvious that the 
same technique could be used to create hygenic macros.  For example, it 
wouldn't be difficult to take the following Python snippet:

   MACRO(Printall, i)

...which parses into the AST (slightly abbreviated):

   Discard(CallFunc(Name('MACRO'),
                    [Name('Printall'), Name('i')],
                    None, None) )

...and recognize the pattern Discard(CallFunc(Name('MACRO'), *).  It can 
then be transformed, perhaps into:

   For(AssName('i*', 'OP_ASSIGN'),
       CallFunc(Name('range'), [Name('i')], None, None),
       Stmt([Printnl([Name('i*')], None)]), None)

...thus making the original snippet behave the same as:

   for i_ in range(i):
     print i

...but with none of the potential indentation and variable-clash issues 
that a source code search-and-replace approach would encounter.

Unfortunately, the power of this technique is limited by the syntax of 
Python, since the code to be transformed must first be parsed under 
normal Python syntax rules.  Lisp doesn't suffer from this thanks to its 
"everything is a list" syntax, but among other things it makes it very 
awkward to create macros with code suites.

Suppose we wanted to make a stupid macro that just executes a code suite 
twice.  We could abuse Python syntax in various ways:

   if +"twice":
   while MACRO(twice):
   for twice in MACROS():

...but we can't make the parser accept any of these nicer syntaxes:

   MACRO(twice):
   do twice:
   @twice:

Even if Guido were willing to add syntactical support for macros, such 
as "@macroname(<args>)" and "@macroname:<suite>", a problem remains. 
While it is only moderately difficult to define an AST transformation 
programmatically, I can't imagine what a nice inline template-ish way to 
define macros, such as Lisp provides, would look like in Python.

Cheers,

Evan @ 4-am







More information about the Python-list mailing list