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