Hi, I've read that lisp macros enable one to do things "undoable" in most other languages. I was wondering what some examples of these undoable things are, and how they would be implemented using macros. -ted
Ted> Hi, I've read that lisp macros enable one to do things "undoable" in Ted> most other languages. I was wondering what some examples of these Ted> undoable things are, and how they would be implemented using macros.
I don't know about claiming things to be "impossible" in general, but Lisp does have an extremely powerful macro facility that is part of the language definition. Lisp macros are generally used to extend the Lisp language as needed.
The main thing to know is that Lisp macros are written in Lisp: they can therefore use the full power of Lisp to process the macro arguments and generate the code for the macro's expansion. This also means that the macro writer has full control over the syntax of the macro.
> Hi, I've read that lisp macros enable one to do things "undoable" in > most other languages. I was wondering what some examples of these > undoable things are, and how they would be implemented using macros.
Macros can change the syntax of the language or implement a sub-language, both of which are translated into the regular language before compilation and/or evaluation. This is due to the lack of structure to Lisp forms, the flexibility in evaluation rules, and the uniformity of representation of language elements.
Ted Sandler <tedsand...@worldnet.att.net> writes: > Hi, I've read that lisp macros enable one to do things "undoable" in > most other languages. I was wondering what some examples of these > undoable things are, and how they would be implemented using macros. > -ted
Ted Sandler <tedsand...@worldnet.att.net> writes: > Hi, I've read that lisp macros enable one to do things "undoable" in > most other languages. I was wondering what some examples of these > undoable things are, and how they would be implemented using macros. > -ted
I don't think anything is "undoable" in any language, but some things are so difficult they just don't get done.
I also don't think it's possible to produce a Common Lisp macro and say, "There, you see, _no_ other language can do _that_".
If you want to learn about CL macros you should try to get "On Lisp" by Paul Graham. Amazon.co.uk had copies last time I looked. It is packed with examples of macros which would be difficult or _nigh_ impossible to write any other way.
In article <uy9q95ffc....@spacy.Boston.MA.US>, Christopher Stacy wrote: >The main thing to know is that Lisp macros are written in Lisp: >they can therefore use the full power of Lisp to process the macro >arguments and generate the code for the macro's expansion. >This also means that the macro writer has full control over >the syntax of the macro.
No, the macro invocation always looks like
(my-macro-name arguments)
LISP has control over the syntax, the writer has control over the shape of the trees involved. ;)
k...@ashi.footprints.net (Kaz Kylheku) writes: > In article <uy9q95ffc....@spacy.Boston.MA.US>, Christopher Stacy wrote: > >The main thing to know is that Lisp macros are written in Lisp: > >they can therefore use the full power of Lisp to process the macro > >arguments and generate the code for the macro's expansion. > >This also means that the macro writer has full control over > >the syntax of the macro.
> No, the macro invocation always looks like
> (my-macro-name arguments)
> LISP has control over the syntax, the writer has control over > the shape of the trees involved. ;)
Kaz, I don't see what the "No" here means. How does what you said differe from what Chris said?
In article <3B3EB873.22656...@worldnet.att.net>, Ted Sandler wrote: >Hi, I've read that lisp macros enable one to do things "undoable" in >most other languages. I was wondering what some examples of these >undoable things are, and how they would be implemented using macros.
An example of the power of LISP macros is the Common LISP Object System (CLOS); an entire object oriented programming system that can be implemented using macros. It polymorphism through generic functions, multiple inheritance, and implementations of it even support meta-class programming. The (defclass ...) construct of CLOS is (implemented as) a macro for defining a class. Consider that when LISP macros were invented, OOP didn't exist. When OOP came along, entire programming language families hit a brick wall and died. LISP programmers just wrote OOP systems in LISP and merrily carried on. This inspires a kind of confidence in LISP that it will be able to acquire any language feature that anyone comes up with in the forseeable future.
LISP programs execute by the evaluation of forms, which you can think of as trees. Every language feature is some kind of form: function definitions, loops and so on.
Most programming languages parse constructs and turn them into some kind of internal tree structure which is evaluated (interpreter mode) or processed to produce a translation.
In LISP, you basically write these trees directly, thanks to its minimal syntax. And these trees can be also treated as data; so there is a blur in the systemic distinction between code and data.
Macros are procedures which, at run time, construct trees which are then evaluated.
When you call an ordinary LISP function, all of the arguments are evaluated, and then the functions's parameters are bound to the resulting values. When the function is done, it produces some value, or multiple values.
Some built-in forms are special, in that they don't evaluate their parmeters. For example, a form for declaring a variable obviously cannot evaluate the variable name being declared. Or a form which iterates over some items, an on each iteration binds a name to each item in turn, also cannot evaluate that name.
Unlike functions, LISP macros allow you to create your own forms that behave just like special forms. So you can introduce new language constructs. If you want a new kind of loop you can create a macro which provides it, completely seamlessly.
Macros receive their parameters unevaluated, and compute a form, usually by carrying out some computation and then substituting parameters into a template. The constructed form is returned and then evaluated. Because this is done at run time, there is considerable power and flexibility in what macros can do. The same macro can compute something different each time; slightly different or even radically different. For example, suppose that your newly invented language construct needs to be able to invent a symbol for internal use. When invoked, your macro can use the LISP (gensym) function to generate a unique new symbol, which you can stick into appropriate places in the returned form.
One feature of macros that helps them seamlessly emulate built-in forms is called destructuring. Rather than taking only flat parameter lists, macros can take nested parameter lists, so that
(mymacro (a (b c (d e)) f))
can be a valid macro call in which the arguments a, b, c, d, ... are mapped to parameters. Thus macros can emulate language features that have this type of rich, nested syntax. Within each parameter nesting, you can have all the bells and whistles of a full LISP parameter list: optional parameters, keyword parameters and all that.
Here is a very simple macro example which shows some of the features: destructuring, substituting into a template to produce a form, using (gensym) to invent a needed symbol. The purpose of this macro is to introduce a very simple language feature; a loop construct which executes a sequence of forms N times, where N is a parameter. We implement our new kind of loop, which we will call ``ntimes'' in terms of the Common LISP ``dotimes' loop:
The special dot syntax in the macro parameter list means that the first argument to the macro will be known as ``count'', and ``forms'' will represent the entire list of remaining arguments. Of course, all the arguments are unevaluated, which is important because the forms are program statements that we want to execute in the loop, and they need to be incorporated verbatim into the loop product we are trying to build.
The first thing the macro does is create a lexical environment with local variables via let, in which a local variable called counter is bound to the value produced by calling (gensym). In other words, the value of counter is a unique symbol (symbols are values in LISP). In this let environment there is but one form that is evaluated; this will be the return value of the macro, which will be subject to a second evaluation. This is where we specify the template and substitute things into it to build up the loop:
`(dotimes (,counter ,count) ,@forms)))
The backtick means that the entire form is quoted: evaluation is suppresed, except for things preceded by , and ,@. These introduce parameters which are evaluated and interpolated into the form. The value of counter is a unique symbol, so ,counter causes that unique symbol to be put into the tree. ,count expands to the form that the user specified which determines the loop count. That form is pinned into our tree. (See, this is like Christmas!). Lastly, ,@forms means expand the value of ``forms'' into a list which is spliced into place. ``forms'' evaluates to the unevaluated list of forms.
So now you can write something like
(ntimes 3 (format t "Hello, ") (format t " world~%"))
to print a message three times. This expands into
(dotimes (<UNIQUE-SYM> 3) (format t "Hello, ") (format t " world~%"))
(dotimes is itself probably a macro, so more expansion takes place, but we aren't interested in that).
Now perhaps making a simpler loop based on an existing construct is not exactly ``undoable'' in other languages, even using primitive C token preprocessing. But note the differences. This is completely seamless, and does things at run time, like compute a unique name for a variable. The only way the user can know that ntimes is a macro is to peek at the definition or to perform:
(macro-expand '(ntimes 3 'blah))
to intercept the product. In other words, macro processing in LISP is not a hacked together text processing kludge like in some other languages, but a bona fide tree transformation mechanism.
In article <sfwsng2nch2....@world.std.com>, Kent M Pitman wrote: >k...@ashi.footprints.net (Kaz Kylheku) writes:
>> In article <uy9q95ffc....@spacy.Boston.MA.US>, Christopher Stacy wrote: >> >The main thing to know is that Lisp macros are written in Lisp: >> >they can therefore use the full power of Lisp to process the macro >> >arguments and generate the code for the macro's expansion. >> >This also means that the macro writer has full control over >> >the syntax of the macro.
>> No, the macro invocation always looks like
>> (my-macro-name arguments)
>> LISP has control over the syntax, the writer has control over >> the shape of the trees involved. ;)
>Kaz, I don't see what the "No" here means. >How does what you said differe from what Chris said?
It depends on what you mean by syntax: whether you think of the configuration of trees as syntax, or whether you think of the actual form of the program text as syntax. I think of the trees as internal representation, which has a rigid mapping to an outside syntax imposed by LISP (which is a good thing). To me, syntax is actually how the input characters of the source program combine into tokens, and tokens into constructs.
If you had full control over the the macro syntax, you should be able to make it callable as (for instance):
[ arg1 | arg2 | arg3 ] mymacro
So clearly, you don't have full control over syntax. For that, you have to write a full blown parser.
k...@ashi.footprints.net (Kaz Kylheku) writes: > In article <sfwsng2nch2....@world.std.com>, Kent M Pitman wrote: > >k...@ashi.footprints.net (Kaz Kylheku) writes:
> >> In article <uy9q95ffc....@spacy.Boston.MA.US>, Christopher Stacy wrote: > >> >The main thing to know is that Lisp macros are written in Lisp: > >> >they can therefore use the full power of Lisp to process the macro > >> >arguments and generate the code for the macro's expansion. > >> >This also means that the macro writer has full control over > >> >the syntax of the macro.
> >> No, the macro invocation always looks like
> >> (my-macro-name arguments)
> >> LISP has control over the syntax, the writer has control over > >> the shape of the trees involved. ;)
> >Kaz, I don't see what the "No" here means. > >How does what you said differe from what Chris said?
> It depends on what you mean by syntax: whether you think of the > configuration of trees as syntax, or whether you think of the > actual form of the program text as syntax.
Chris has been programming in Lisp for nearly as long as I have, and I know he's not confused on that point. That's why I asked. You're just misunderstanding his use of the term "syntax".
I also use the term "syntax" to mean "tree structure".
So does the ANSI CL spec.
> I think > of the trees as internal representation, which has > a rigid mapping to an outside syntax imposed by LISP > (which is a good thing).
Well, one can cons a tree that has no syntax at all by that definition of syntax. For this reason, I always encourage people to understand that Lisp "syntax" is defined on objects, not on text.
> To me, syntax is actually how > the input characters of the source program combine into > tokens, and tokens into constructs.
This is fine except it's inappropriate to think the term "syntax" as uniquely implying this interpretation. The normal use of syntax in the community I deal in is "expression syntax", i.e., tree shape.
We usually refer to what you call syntax as "READ syntax" or "reader syntax", but mostly we just assume that any attempt to refer to text syntax is mere metaphor for the underlying text. Most code is indeed typed in, but when one asks "What is the syntax of with-open-file?" one is *not* generally asking where the whitespace goes, and to the extent one is asking where the parens go, one is generally using that as a convenient notational metaphor for asking where the list groupings are.
> If you had full control over the the macro syntax, you > should be able to make it callable as (for instance):
> [ arg1 | arg2 | arg3 ] mymacro
Again, I'd encourage you to use the term "read syntax" here.
There IS a legitimate expression syntax issue here as well, which is what I thought you might be referring to (but apparently not) and which did come up in the InterLisp dialect. The question of whether you can write [expression] syntax like
(x * y)
and have the symbol * get control. That's also something you can't do in Lisp, so it's technically true even at the expression level that macros aren't totally in control of their syntax. But even there, we as language designers rationalize this by saying there is an overarching desire to have a language whose syntax has certain commonalities, and macros do have the ability to grab control of the expression syntax to the extent that any part of the language, even builtins, do. That is, no system-provided operator can do that either.
> So clearly, you don't have full control over syntax. > For that, you have to write a full blown parser.
What you say, given your choice of meaning for syntax, is not wrong. However, you're likely to confuse a lot of Lisp programmers if you insist that this unqualified usage of the word syntax uniquely means your own meaning. I recommend using the term "read[er] syntax" to make your meaning clear and avoid a lot of interpersonal confusion.
>>> No, the macro invocation always looks like >>> (my-macro-name arguments)
Kaz> If you had full control over the the macro syntax, you Kaz> should be able to make it callable as (for instance): Kaz> [ arg1 | arg2 | arg3 ] mymacro Kaz> So clearly, you don't have full control over syntax. Kaz> For that, you have to write a full blown parser.
Your statement is very misleading in the context of the original question, because with macros, the thing that you are calling "arguments" are not evaluated according to the normal rules of Lisp function calls. Macros do not need to have the shape that your example shows, except in the sense that a macro invocation looks like a list with the name in the CAR. (Also, unlike your example, those "arguments" need not be a single thing -- additional syntax can be invented, such as in the LOOP macro) Don't forget that you can also define reader-macros, which are "full blown parsers" that are invoked by a single character, and needn't look like a list at all.
k...@ashi.footprints.net (Kaz Kylheku) writes: > Macros are procedures which, at run time, construct trees > which are then evaluated.
Run time rather than compile time? I'd been meaning to reply on this thread with examples from Scheme macros, but if CL macros are expanded and evaluated at run time, they're very different beasts, even beyond the whole "hygienic" issue.
> In article <3B3EB873.22656...@worldnet.att.net>, Ted Sandler wrote: > >Hi, I've read that lisp macros enable one to do things "undoable" in > >most other languages. I was wondering what some examples of these > >undoable things are, and how they would be implemented using macros.
> Macros are procedures which, at run time, construct trees > which are then evaluated.
[snip]
> Macros receive their parameters unevaluated, and compute a form, > usually by carrying out some computation and then substituting > parameters into a template. The constructed form is returned and > then evaluated. Because this is done at run time,
My understanding is that macros are expanded at compile time and the above statements are only true in the case that you are calling compile at runtime. While this has great uses it is not the most common way macros are used (like the defclass example for instance, that all happens at compile time)
> > Macros receive their parameters unevaluated, and compute a form, > > usually by carrying out some computation and then substituting > > parameters into a template. The constructed form is returned and > > then evaluated. Because this is done at run time,
> My understanding is that macros are expanded at compile time and the above > statements are only true in the case that you are calling compile at > runtime. While this has great uses it is not the most common way macros are > used (like the defclass example for instance, that all happens at compile > time)
No, macros are expanded at macroexpand time.
Cheeky? Yes, but there's no smiley there because in all seriousness there is a separate macroexpand time. It occurs as a sub-time of either compile time _or_ eval time.
-- Duane Rettig Franz Inc. http://www.franz.com/ (www) 1995 University Ave Suite 275 Berkeley, CA 94704 Phone: (510) 548-3600; FAX: (510) 548-8253 du...@Franz.COM (internet)
Ted Sandler <tedsand...@worldnet.att.net> writes in comp.lang.lisp:
> Hi, I've read that lisp macros enable one to do things "undoable" in > most other languages. I was wondering what some examples of these > undoable things are, and how they would be implemented using macros.
I'm going to give you an actual example, but first some background:
In terms of a program's potential behavior, all programming languages are provably equivalent. It may require extensive effort, but you can do OOP with inheritance in BASIC. In that sense there's no "undoable" thing in any language.
However, in terms of a programming language's ability to extend itself, there are obvious differences. For example, the BASIC I used when I first learned some programming had a fixed set of math operations. I couldn't add my own. I could make a program *behave* as if it had other operations, but calling a BASIC subroutine required more code than just doing, say, SIN(X).
When I moved on to Forth, I was delighted that now I could write my own functions, and they were then as convenient to use as the ones built into the language. From a theoretical standpoint, this didn't enable anything previously "undoable". For me, however, it did.
Previously, I had read a magazine article that described a BASIC program to make mazes. I read and reread the article, but somehow couldn't get the algorithm into my head. It was too complicated.
After learning some Forth, I was able to go back and understand the algorithm, because now my mind had a more convenient language to express it in. I wrote my own Forth program to generate mazes and was very proud of myself.
Lisp macros make Lisp different from other languages in a way analagous to how Forth is different from BASIC. They allow the user to extend the language in ways previously undoable, giving convenient expression to concepts that the language designers might not have anticipated.
I'll give you an example. Suppose you're looping through an alphabetized table of words and their definitions. There may be more than one definition per word, but you want these grouped by word.
BRL (my Scheme-based web system) has macros useful for such situations. You use the sql-repeat macro or brl-repeat macro to iterate through the results. Within that, you can use (group-beginning? word) to test if you're at the beginning of a group.
You see, functions can only tell you something about the value of a variable. A function would be useless here, because it would only be passed the current value of word, not its previous value. (Side note: group-beginning? can take any expression as its argument, not just a variable.)
In languages without macros, you could work around this problem by defining another variable, e.g. priorword, that you set to the value of word at the end of each iteration, then compare word and priorword. For simple problems, this is not a big deal. However, as things get more complex, the additional code obscures the core problem being solved. Even more code is needed for the equivalent of group-ending?.
Not long ago, a coworker was struggling with creating a complex HTML report from a database using ASP/VBscript. He had been trying for days, but it still wasn't working. He showed me what he was doing, but urged me not to sink too much time into it.
It was a good deal trickier than your usual HTML report. It took me 3 or 4 tries to get a BRL solution working. "Another victory for BRL," my coworker declared as I gave him the code.
What really surprised me was that, this experienced programmer was not able to expand the BRL program I gave him into functionally equivalent VBscript. Probably some little bug kept him tripped up, and the excess code made it difficult to track down. Given enough time, I'm sure he would have been able to get it. For practical purposes, i.e. time constraints, the macro enabled something "undoable" in another language.
>> > Macros receive their parameters unevaluated, and compute a form, >> > usually by carrying out some computation and then substituting >> > parameters into a template. The constructed form is returned and >> > then evaluated. Because this is done at run time,
>> My understanding is that macros are expanded at compile time and the above >> statements are only true in the case that you are calling compile at >> runtime. While this has great uses it is not the most common way macros are >> used (like the defclass example for instance, that all happens at compile >> time)
>No, macros are expanded at macroexpand time.
>Cheeky? Yes, but there's no smiley there because in all seriousness >there is a separate macroexpand time. It occurs as a sub-time of either >compile time _or_ eval time.
The important thing is that *if* a function is compiled, all the macros within the function definition will have been expanded at compile time.
In some implementations (e.g. CMUCL), there isn't even an interpreter. EVAL works by compiling the form and then calling the resulting function. So, while a traditional interpreter will generally delay expanding a macro until it's is encountered during execution (which allows them to access dynamic bindings in the containing form), these compiler-only implementations will expand all the macros in an expression before executing anything.
With a typical interpreter, this will return 2, but in a compiler-only system it will return 1.
-- Barry Margolin, bar...@genuity.net Genuity, Burlington, MA *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups. Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
In article <nm9bsmqxdr8....@kindness.mit.edu>, brle...@my-deja.com wrote: >Ted Sandler <tedsand...@worldnet.att.net> writes in comp.lang.lisp:
>> Hi, I've read that lisp macros enable one to do things "undoable" in >> most other languages. I was wondering what some examples of these >> undoable things are, and how they would be implemented using macros.
>I'm going to give you an actual example, but first some background:
>In terms of a program's potential behavior, all programming languages >are provably equivalent. It may require extensive effort, but you can >do OOP with inheritance in BASIC. In that sense there's no "undoable" >thing in any language.
But note that doing OOP with inheritance in BASIC may require the use of BASIC to write an interpreter for an OOP language, and then writing the OOP program in that language. One can then no longer say that BASIC made OOP programming possible, because that same OOP language can be implemented without using BASIC.
LISP macros allow you to code such interpreters without making a sharp systemic division between LISP and the new language. Functions and data pass between LISP and the newly constructed language freely and seamlessly; for instance one does not give up LISP programming when using the Common LISP Object System. The system is built up in LISP and then mixes right in. Basic data types become members of classes, objects can be put into lists, functions can now be generic, and so on.
But one would likely have to abandon BASIC in using the OOP language written in BASIC, or at the very best have some awkward glue to translate between the two, always making it painfully clear which level one is working in.
Barry Margolin <bar...@genuity.net> writes: > The important thing is that *if* a function is compiled, all the macros > within the function definition will have been expanded at compile time.
> In some implementations (e.g. CMUCL), there isn't even an interpreter.
Minor nitpicking ahead...
Actually, CMU CL does have 2 interpreters, one very simplistic one that can only handle very trivial forms like function application, progn, setq, etc., but doesn't depend on (part of) the compiler, and another interpreter that works directly on the internal representation of the first pass of the compiler (called IR1). This can handle all legal forms, but requires (the first pass) of the compiler to be present. The simplistic interpreter hands off complex forms to the normal interpreter.
The simplistic interpreter is important for runtime-only images which leave out the compiler, but need a way to get the compiled code running.
So while CMU CL doesn't do a full compile for interpreted code, it does a full IR1 conversion for complex forms first, and this obviously includes the macro-expansion phase, thereby making interpreter and compiler equivalent in this regard.
MCL is an example of a system that AFAIK really is a compiler-only system.
> With a typical interpreter, this will return 2, but in a compiler-only > system it will return 1.
In CMU CL, it will return 1, too, as explained above...
Regs, Pierre.
-- Pierre R. Mai <p...@acm.org> http://www.pmsf.de/pmai/ The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein
> MCL is an example of a system that AFAIK really is a compiler-only > system.
Actually, MCL also has a very simplistic interpreter for doing things like SETQ and function calls. But anything more complicated gets handed off to the compiler.
-- Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu
> > If you had full control over the the macro syntax, you > > should be able to make it callable as (for instance):
> > [ arg1 | arg2 | arg3 ] mymacro
> > So clearly, you don't have full control over syntax. > > For that, you have to write a full blown parser.
> Can't you do that with reader macros?
Not in the general case of trying to mix Lisp code and other code. For readmacros to get a foothold, you must have a piece of syntax that introduces the special syntax and you must know when you are released from it. So, you can make a syntax like:
& arg1 arg2 arg3 $ fn
or something like that where it reads forms up to a $ and then one form after, constructing (fn arg1 arg2 arg3). But you can't just have
1 2 3 +
like in PostScript if you expect to mix it with Lisp, because what would you do in the case of
(- 1 2 3 +)
Would that mean
(- (+ 1 2 3))
or
(- 1 (+ 2 3))
or
(- 1 2 (+ 3))
or
(- 1 2 3 (+))
The Lisp Machine, for example, used a funny non-ascii character I'll represent as $ here to do:
#$ a*b-c*d $
So you could switch in and out of infix mode. You could do similarly for some sort of RPN notation if you wanted. But the thing you can't do is just say that a given operator reads its arguments backwards because by the time you encounter the operator, you've already disposed of the things to its left.
> > > If you had full control over the the macro syntax, you > > > should be able to make it callable as (for instance):
> > > [ arg1 | arg2 | arg3 ] mymacro
> > > So clearly, you don't have full control over syntax. > > > For that, you have to write a full blown parser.
> > Can't you do that with reader macros?
> Not in the general case of trying to mix Lisp code and other code. > For readmacros to get a foothold, you must have a piece of syntax > that introduces the special syntax and you must know when you are > released from it. So, you can make a syntax like:
> & arg1 arg2 arg3 $ fn
> or something like that where it reads forms up to a $ and then one form > after, constructing (fn arg1 arg2 arg3). But you can't just have
> 1 2 3 +
> like in PostScript if you expect to mix it with Lisp, because what > would you do in the case of
> (- 1 2 3 +)
> Would that mean
> (- (+ 1 2 3))
> or
> (- 1 (+ 2 3))
> or
> (- 1 2 (+ 3))
> or
> (- 1 2 3 (+))
> The Lisp Machine, for example, used a funny non-ascii character I'll > represent as $ here to do:
> #$ a*b-c*d $
> So you could switch in and out of infix mode. You could do similarly > for some sort of RPN notation if you wanted. But the thing you can't > do is just say that a given operator reads its arguments backwards > because by the time you encounter the operator, you've already disposed > of the things to its left.
The INFIX package available in the AI.Repository (and somewhere else, I suppose) allows you to do
#I( a*b-c*d / sin(x) )
and more. THe original version used #\$ as delimiters (a la' TeX), but that conflicted with a use of #\$ in MCL, so it was changed to #I().
Cheers
-- Marco Antoniotti ======================================================== NYU Courant Bioinformatics Group tel. +1 - 212 - 998 3488 719 Broadway 12th Floor fax +1 - 212 - 995 4122 New York, NY 10003, USA http://bioinformatics.cat.nyu.edu "Hello New York! We'll do what we can!" Bill Murray in `Ghostbusters'.
> > > If you had full control over the the macro syntax, you > > > should be able to make it callable as (for instance):
> > > [ arg1 | arg2 | arg3 ] mymacro
> > > So clearly, you don't have full control over syntax. > > > For that, you have to write a full blown parser.
> > Can't you do that with reader macros?
> Not in the general case of trying to mix Lisp code and other code. > For readmacros to get a foothold, you must have a piece of syntax > that introduces the special syntax and you must know when you are > released from it. So, you can make a syntax like:
> & arg1 arg2 arg3 $ fn
> or something like that where it reads forms up to a $ and then one form > after, constructing (fn arg1 arg2 arg3). But you can't just have
> 1 2 3 +
You can't have 1 2 3 +, but you can have #[1 2 3 +].
> like in PostScript if you expect to mix it with Lisp, because what > would you do in the case of
> (- 1 2 3 +)
It's an error(using my read-macro). An argument to plus must be a number. It would give an error.
> So you could switch in and out of infix mode. You could do similarly > for some sort of RPN notation if you wanted. But the thing you can't > do is just say that a given operator reads its arguments backwards > because by the time you encounter the operator, you've already disposed > of the things to its left.
I am probably not understanding you, because this is easy to do: