Lisp-like macros in Python?

Discussion in 'Python' started by sturlamolden, May 1, 2007.

  1. sturlamolden

    sturlamolden Guest

    Hello

    The Lisp crowd always brags about their magical macros. I was
    wondering if it is possible to emulate some of the functionality in
    Python using a function decorator that evals Python code in the stack
    frame of the caller. The macro would then return a Python expression
    as a string. Granted, I know more Python than Lisp, so it may not work
    exactly as you expect.

    Any comments and improvements are appreciated.

    Regards,
    Sturla Molden




    __codestore__ = {}

    def macro(func):

    """
    Lisp-like macros in Python
    (C) 2007 Sturla Molden

    @macro decorates a function which must return a Python
    expression
    as a string. The expression will be evaluated in the context
    (stack frame)
    of the caller.
    """

    def macro_decorator(*args,**kwargs):
    global __codestore__
    import sys
    pycode = '(' + func(*args,**kwargs) + ')'
    try:
    ccode = __codestore__[pycode]
    except:
    ccode = compile(pycode,'macrostore','eval')
    __codestore__[pycode] = ccode
    frame = sys._getframe().f_back
    try:
    retval = eval(ccode,frame.f_globals,frame.f_locals)
    return retval
    except:
    raise
    macro_decorator.__doc__ = func.__doc__
    return macro_decorator


    # Usage example

    def factorial(x):

    """ computes the factorial function using macro expansion """

    @macro
    def fmacro(n):

    """ returns '1' or 'x*(x-1)*(x-2)*...*(x-(x-1))' """

    if n == 0:
    code = '1'
    else:
    code = 'x'
    for x in xrange(1,n):
    code += '*(x-%d)' % (x)
    return code

    return fmacro(x)
     
    sturlamolden, May 1, 2007
    #1
    1. Advertisements

  2. The 'magical macros' of lisp are executed at compile time, allowing
    arbitrary code transformations without the loss of run time
    efficiency. If you want to hack this together in python you should
    write a preprocessor that allows python code *to be run in future*
    inter spaced with python code *to be executed immediately* and
    replaces the executed code with it's output. The immediately executed
    code should be able to make use of any existing code or definitions
    that are marked as to be compiled in the future.

    This is should be quite do-able in python(I think I haven't really
    looked at it) because it has a REPL and everything that implies, but
    you'd have to implement lispy macros as some kind of def_with_macros
    which immediately produces a string which is equivalent to the macro
    expanded function definition and then evaluates it.

    Good luck in doing anything useful with these macros in a language
    with non-uniform syntax however.
     
    Chris Russell, May 1, 2007
    #2
    1. Advertisements

  3. Pascal Costanza, May 1, 2007
    #3
  4. sturlamolden

    Duane Rettig Guest

    I don't know python, but check out

    http://www.cl-user.net/asp/libs/clpython
     
    Duane Rettig, May 1, 2007
    #4
  5. sturlamolden

    Andy Freeman Guest

    How about something that can't be done with a function, such as the
    functionality of the "with" statement that was added to python 2.5?

    Yes, it has to handle a suite of statements.

    It would be nice if it handled both the "{as target}" and no target
    forms.

    Also, it shouldn't rely on magic names - if it needs a variable for
    its purposes, it should guarantee that said variable and/or use can
    not be one that affects how the rest of the user's program behaves.

    There's a fair amount of relevant discussion in http://www.python.org/dev/peps/pep-0343/
    ..
     
    Andy Freeman, May 1, 2007
    #5
  6. sturlamolden

    John Nagle Guest

    I used LISP back when LISP macros were popular.
    You don't want to go there. It degrades readability
    without improving the language.

    Check out the original "MIT loop macro", used to put
    something comparable to a FOR statement into early versions
    of LISP.

    http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/iter/loop/mit/0.html

    Note that it's at version 829. And that was with MIT people fixing it.
    That thing was a trouble spot for a decade or more.

    Scheme added a "do" statement as part of the language, which
    was the right answer. The "loop macro" was, at long last, retired
    around 1991.

    There are lots of "l33t" features one can put in a language,
    but in the end, they're mostly not that helpful.

    The people who advocate "l33t features" usually need to do more
    maintenance programming on the code of others, to get more of a sense
    of gives real, operational trouble in a programming language.
    Really. After you've fixed the bad code of others, then you're
    entitled to talk about language design.

    As someone who's programmed in all too many languages and with
    a background in formal proof systems, I would make few changes to
    Python as a language. (And most of the things I'd change involve
    removing less-used features that constrain implementations.)
    The language is fine. The problems are elsewhere.
    The CPython implementation is way too slow and some of the libraries
    are flakey. That's what needs attention.

    John Nagle
     
    John Nagle, May 1, 2007
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.