No macros in Python

Mike Meyer mwm at mired.org
Mon Dec 16 19:54:38 EST 2002


"Anders J. Munch" <andersjm at inbound.dk> writes:

> "Mike Meyer" <mwm at mired.org> wrote:
> > "Anders J. Munch" <andersjm at dancontrol.dk> writes:
> > > "Mike Meyer" <mwm at mired.org> wrote:
> > > > Macros are a general-purpose mechanism. There are lots of things they
> > > > let you do. Lazy evaluation, infinite lists, CLOS, short-circuit
> > > > booleans, and so on.
> > > No, s-expressions buy you those things, not macros.  Macros don't
> > > provide expressiveness, they provide speed and some convenience, say
> > > to let you write:
> > Since I can do those things with macros and without s-expressions, I
> > disagree. Well, maybe not CLOS.
> Obviously anything that can be done with a function can be done with a
> macro (just delegate to the function;->).  What's interesting is what
> can be done with a macro that can't be done with a function.

Yup.

> How do you do lazy evaluation with macros?  And infinite lists?  Since
> any particular macro expansion can only be of finite length, I presume
> that closures and setc*r are doing the real work.

Yes, closures and list hacking are doing the real work. Infinite lists
can be done with Python as it exists now. Just inherit from list and
redefine __getitem__ to check to memoize the function that calcualtes
the list, using the list itself for storage. The other features ought
to be checked to see if they should change as well, but __getitem__
does the real work.

I can describe how to do lazy evaluation with S-expressions, but that
would seem to defeat the point. Will you accept an ugly kludge that
may work in current python?

class lazyeval:
    """A tool to create a code function from a string and then call it
       with lazy argument evaluations."""

    def __init__(my, code):
        "Create a callable object from code."
        my.code = code

    def __call__(my, args):
        "Invoke code on the dictionary of args strings."

        def getvalue(a):
           if a != undefined:
              return a
           return eval(a, {}, locals)

        locals = args.copy()
        invalid = __class__("")         # An object to be a marker.
        for key in locals.keys():
            locals[key] = undefined
        calls = args.copy()
        for key, value in calls.items():
            calls[key] = "getvalue(%s)" % value
        return eval(my.code % calls)

Of course, this hasn't been tested. But the idea is that you create a
function that will be evaluated lazily by something like:

        func = lazyeval("if %(pred)s: return %(first)s\n  return %(second)s")
        value = func({"pred": "expression",
                      "first": "funcall1()",
                      "second": "funcall2()"})

which will then evaluate expression and only one of funcall1() or funcall2().

Yes, it's ugly as sin, and the returning an eval of a return may cause
all kinds of problems. But that's what not having macros forces you
into.

        <mike
-- 
Mike Meyer <mwm at mired.org>			http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.



More information about the Python-list mailing list