Re: macro-biology

From: Marco Baringer (mb_at_bese.it)
Date: 05/16/04


Date: Sun, 16 May 2004 14:29:48 +0200

David Steuber <david@david-steuber.com> writes:

> First question. Can a macro only expand into code? Or can I define a
> macro that will expand into XML for printing? This expansion may be
> into a string that I pass to format. The mechanism isn't as important
> as the ability to do so. Here are a couple examples in pseudolisp
> with the output after printing as with princ or format:

a macro can only expand into code, that code will be eval'd. end of
the story (caveat: this assumes you asked lisp to eval the macro form,
if you're just passing a list to macroexpand things are different).

> (xmlify foo :attr1 "string" :attr2 42) =>
> <foo attr1="string" attr2=42/>
>
> (xmlify bar :attr 42 :baz (all your base)) =>
> <bar attr=42>
> <baz>all</baz>
> <baz>your</baz>
> <baz>base</baz>
> </bar>

so you want xmlify to expand into a string? or do you want xmlify to
expand into a form which prints a string? since strings are
self-evaluating common lisp forms both are doable. of course
expanding directly into a, single, string means you can't do things
like this:

(let ((attr "something"))
  (xmlify foo :attr1 attr)) ==>
<foo attr1='something'/>

> I'm also making the grand assumption that I can nest macros like this:
>
> (xmlify abar :attr "blue" (xmlify prop1 :attr1 69 attr2 foo)) =>
> <abar attr="blue">
> <prop1 attr1=69 attr2="foo"/>
> </abar>

well, that depends on what the definition of xmlify is. for functions
all the args are evaluated and their return value is passed to the
function, for macros this not the case, the source code is passed to
the macro as is, and whatever the macro returns is evaluated, if the
macro does not enusre that the args get evaluated then, well, they
won't get evaluated (or macro expanded).

> I'm sorry I don't have a more complete specification yet. Is there a
> better alternative to the above?

just about any of the xml/html/xhtml generating libraries do what you
(seem) to want, and they generally do it by having macrso which expand
into a series of print forms. this allows the "final" result to be
affected by the runtime enviroment, which is very usefull indeed.

> The second question gets a little hairy. I know that macro expansion
> happens at compile time. However, I want to have an alternate
> definition of xmlify in the above examples. The alternate would take
> the exact same stuff, but generate some sort of lisp instead. The
> same examples, again in psuedolisp:
>
> (xmlify foo :attr1 "string" :attr2 42) =>
> (defparameter foo '(:attr1 "string" :attr2 42))
>
> (xmlify bar :attr 42 :baz (all your base)) =>
> (defparameter bar '(:attr 42 :baz (all your base)))
>
> To deal with the fact that macros happen at compile time, I will only
> use one of the definitions of xmlify at a time. One for when I want
> to take a file that I want to turn into XML and the other for use in
> Lisp. The latter version looks like it is trivial to implement. So
> question no. 1 is the more important of the two. However the macro
> arguments will need to be the same for both.

why do you think generating lisp is any easier/harder than generating
strings?

> My requirements as far as I know them are to have fairly easy to edit
> rules files that are really just lisp. However for political reasons,
> those rules also need to be transformable to XML for use in an
> identical application written in another language after being
> prototyped in lisp. Although I don't plan to throw away the lisp
> version. I'll probably maintain both lisp and java versions that get
> the rules from the same source files. Actually, I'll leave it to a
> friend to deal with the Java version ;-)

oh, so you have files with lisp s-exprs which you want to use to
generate xml? why didn't you just say so? :)

just grab one of the many html generating libraries
(http://www.cliki.net/Web) and see what you like best. except for your
:baz (all your base) example they all already do what you want.

<shameless-plug>

yaclml would allow you to do something along these lines:

(deftag bar (&attribute attr baz)
  (wrap-in-tag ("bar" "attr" attr)
    (dolist (b baz)
      (wrap-in-tag ("baz")
        (emit-html (string-downcase b))))))

and here's the macroexpansion of (bar :attr 42 :baz (all your base))

(PROGN (WRITE-STRING "<bar attr=\"42\"><baz>all</baz><baz>your</baz><baz>base</baz></bar>"
                     *YACLML-STREAM*))

a patch to generate readable html output would be greatly appreciated.

</shameless-plug>

> A rules file may look something like this:
>
> (in-package :foo) ; ignored when genning XML
> (xmlify rule1 :attr1 "string" :attr2 42)
> (xmlify rule2 ...)
> ...

since this seems like a pretty custom applicion you could skip the
in-package and manually bind *package* to what you need before
loading.

by using the #\< and #\> as dispatching read macros (and mess with #\=
while you're at it) you may even come up with a syntax which is xml
enough to fool most java programmers. just be sure to call it XML++,
say you read about it in a blog on javablogs.com and charge 2K a seat
for it. :)

hth.

-- 
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
     -Leonard Cohen


Relevant Pages

  • Re: nested backquote question
    ... The goal is a macro that creates macros that validates or alters ... Lisp format doesn't have %s. ... What's the point of simply returning the error message as a string? ... "TEMPERATURE is not between LOW and HIGH" ...
    (comp.lang.lisp)
  • Help needed with macros: Brain turning to jelly
    ... (with-parsetuple-arg 'string buf ... The macro has this input: ... An args foreign address ... Lisp, ...
    (comp.lang.lisp)
  • Re: macro-biology
    ... >> macro that will expand into XML for printing? ... >> into a string that I pass to format. ...
    (comp.lang.lisp)
  • Re: Newbie Coding Challenge
    ... The macro mechanism itself is quite simple. ... is the name of the class to expand the macro and p1 p2 ... ... The macro returns the expanded string. ... public String expand(Stringparms, ...
    (comp.lang.java.help)
  • Re: LISP macros vs Ruby procs ?
    ... That like saying a string is equivalent to an array/list. ... related functions and generate the code for the macro. ... The enabling feature of Lisp which makes its macros possible is ... which means that the external representation of a lisp ...
    (comp.lang.ruby)