Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Lisp Macros in Mathematica (Re: If Scheme is so good why MIT drops

161 views
Skip to first unread message

fft1976

unread,
Aug 9, 2009, 6:17:11 PM8/9/09
to
On Jul 21, 5:31 am, Xah Lee <xah...@gmail.com> wrote:

> Also, lisp's macros, a feature that gets lispers much ado about
> nothing. In Mathematica (b ~1989), the whole language can be
> considered as a extended lisp macros system. When i learned about
> lisp's macros while practical coding elisp, i find lisp macros are
> rather so trivial, painful to use, and laughable.

Is this true? How do you write some simple Lisp-like macros in
Mathematica? Are Mathematica's macros like Scheme's hygienic macros or
like Lisp's "low-level" macros?

David Bailey

unread,
Aug 11, 2009, 3:59:35 AM8/11/09
to

Although macros can be abused - as they are in many C programs, where
almost everything is a macro - I'd like to see macros supported directly
in Mathematica, because they would offer an efficient way to access
parts of a structure by name - rather than using Part. This gives you
clarity and speed.

I do have a scheme for doing this. It involves defining functions using
a modified version of the := operator, which replaces macro expressions
on the RHS of the function before saving the result in the normal way.
Macros are defined with a Define\[Breve]Macro call prior to the
functions that use them. I considered using $Pre or $PreRead, but these
do not work when programs are read in with Get or in packages.

David Bailey
http://www.dbaileyconsultancy.co.uk

David Bakin

unread,
Aug 11, 2009, 4:00:20 AM8/11/09
to
It is very easy to make what Lisp calls "special forms". You use HoldAll or
related attributes to create your own "special forms", then manipulate the
arguments in their full form (aka S-expressions), evaluating things when you
wish.

As far as I am aware you do not get reader syntax like quotes and
quasiquotes that make Lisp macros easy to write. But depending on what
you're trying to do you may not need them. With Mathematica you get full
pattern matching on arguments (not just destructuring) and rule-based
programming, and everything else that Mathematica provides. You may find
these features are even more effective than quoting and quasiquoting in
writing macros.

BTW, Mathematica does not need a separate defmacro call that basically means
"define this function such that you don't evaluate any arguments, but when I
return the result, you evaluate it". That is because 1) To get the first
part you add the HoldAll attribute to your function name, and 2) Mathematica
automatically evaluates the result returned by any/all functions, until
there's nothing more to evaluate (which is an important difference between
the Lisp REPL and the Mathematica REPL).

-- David

(By the way, I googled for the source of your quotation, and I'm glad you
didn't bother to quote more of his rant on this elist. That guy may have
something interesting to say but it hard to figure out what because
apparently he is like Steve Martin at the airline counter in Planes, Trains,
and Airplanes - unable to say anything unless it is composed of at least 30%
f**k-variations. Painful to read.)

Pillsy

unread,
Aug 12, 2009, 4:34:14 AM8/12/09
to
On Aug 9, 6:17 pm, fft1976 <fft1...@gmail.com> wrote:

> On Jul 21, 5:31 am, Xah Lee <xah...@gmail.com> wrote:

> > Also, lisp's macros, a feature that gets lispers much ado about
> > nothing. In Mathematica (b ~1989), the whole language can be
> > considered as a extended lisp macros system. When i learned about
> > lisp's macros while practical coding elisp, i find lisp macros are
> > rather so trivial, painful to use, and laughable.

> Is this true?

Kinda sorta.

Mathematica evaluation is based on a rule-rewrite system, so
comparisons with more conventional languages like Lisp can be tricky,
but it provides the ability (through the Hold/HoldPattern/HoldComplete
facilities) to prevent code from being evaluated, and Mathematica code
is built out of data structures that you can easily manipulate from
within Mathematica.

You can also specify that functions Hold their arguments. Together,
that gives you something that approximates the Lisp macro system in
theory.

> How do you write some simple Lisp-like macros in
> Mathematica?

With difficulty. I find the absence of quasiquotation makes things
dramatically more difficult, and there's a mix of different functions
(the aforementioned Hold* functions and Unevaluated) that kind of act
like Lisp's QUOTE but not really, and unquoting is also a good deal
trickier. Mathematica's powerful pattern-matching and rule-rewriting
facilities don't close the gap IMO.

On top of that, the documentation that comes with Mathematica isn't
particularly helpful when it comes to doing macro-like things, and
there isn't anything like the reams of good tutorial material there is
on writing Lisp macros.

> Are Mathematica's macros like Scheme's hygienic macros or
> like Lisp's "low-level" macros?

More like Lisp's "low-level" macros, but you have to deal with a
number of Mathematica functions that try (with mixed results) to
prevent name clashes for you and, as often as not, defeat their
efforts. Also, in Mathematica, there apparently aren't any real
gensyms; the closest equivalent, Unique, actually interns the unique
symbols it creates.

Cheers,
Pillsy

David Bailey

unread,
Aug 13, 2009, 3:20:07 AM8/13/09
to
David Bakin wrote:
> It is very easy to make what Lisp calls "special forms". You use HoldAll or
> related attributes to create your own "special forms", then manipulate the
> arguments in their full form (aka S-expressions), evaluating things when you
> wish.
>
> As far as I am aware you do not get reader syntax like quotes and
> quasiquotes that make Lisp macros easy to write. But depending on what
> you're trying to do you may not need them. With Mathematica you get full
> pattern matching on arguments (not just destructuring) and rule-based
> programming, and everything else that Mathematica provides. You may find
> these features are even more effective than quoting and quasiquoting in
> writing macros.
>
> BTW, Mathematica does not need a separate defmacro call that basically means
> "define this function such that you don't evaluate any arguments, but when I
> return the result, you evaluate it". That is because 1) To get the first
> part you add the HoldAll attribute to your function name, and 2) Mathematica
> automatically evaluates the result returned by any/all functions, until
> there's nothing more to evaluate (which is an important difference between
> the Lisp REPL and the Mathematica REPL).
>

If I understand what you mean, then surely this is missing the point.

Let's take a specific example. Suppose you have a vector of data
representing conditions in a reaction vessel, and you define functions
such as:

pH[x_]:=x[[17]];

This is a function, and could be used to access the relevant component
of a vector, but not to change that value. However, if you code in that
style, you will sacrifice a lot of performance for the sake of clarity.

One way to solve that problem, is to define another operator for use in
defining functions instead of SetDelayed (:=). This lets you make
substitutions on the held form of the RHS before the DownValue is
created - so you code pH[vec] but execute vec[[17]] .

Alternatively, you could use $Pre or $PreRead, but since these do not
work on code loaded by Get or Needs, I don't find this approach general
enough.

As I said before, I think a built-in macro mechanism would be a valuable
addition to Mathematica.

David Bailey
http://www.dbaileyconsultancy.co.uk

David Bakin

unread,
Aug 14, 2009, 5:58:09 AM8/14/09
to
David,

I like your ideas. I wouldn't object to better macro facilities in
Mathematica, including what you suggest (if done right) and
quoting/quasiquoting. (I also wouldn't object (in fact, I would applaud)
moving to real lexcial scoping rather than Module, but that's a different
story.) I also understand what you were saying about performance.

The issue, you know, is that Mathematica doesn't have a compiler in the
sense that a (typical) Lisp implementation does. (It has Compile[], but
that isn't really the same.) In a (typical) Lisp system macro expansion is
done after the program is input and before it is run, at the compile phase.
Thus (as I see you know), the macro expansions are done once, then the
generated code is executed multiple times, therefore you don't get a
performance hit from multiple macro expansions. Using Hold*, pattern
matching, and rule replacement as I suggest would mean, in Mathematica, that
it was done repeatedly at interpretation time, so I presume you're right,
there is a performance hit. (I'm not really experienced enough at
Mathematica to know how much of a hit that is.)

Your solutions sound like reasonable workarounds to the lack of a proper
macro facility, to a point. The point being, that if they aren't integrated
fully into the notebook interface, the macro-expanded definition will be
what Mathematica knows about and what it will later tell you if you try to
display the defintion of your functions. Lisp systems don't have that
problem - if you ask later what the value of your function is you'll get the
pre-macro expanded version that you expect.

(Though I think you could work around that problem to some extent with the
use of the pre-output hooks - I forget what they are but I know Mathematica
has them - to rewrite function definitions back to pre-macro-expanded state
before displaying them. Not sure if that would be a full solution, e.g.,
what would be saved to a notebook after you did a macro-expansion via an
alternate to := or the use of $Pre or $PreRead.)
So I'm not sure what the answer is for the original poster. Maybe: Yes, you
can do powerful macro-like things in Mathematica very easily - but they come
with a performance tax you might not expect if you're used to Lisp systems.

0 new messages