[gambit-list] Black hole documentation

Per Eckerdal per.eckerdal at gmail.com
Sun Jul 12 14:42:06 EDT 2009


> Hi Per,
>
> First question I have is :
>
> Can you elaborate on why you decided to model black hole on
> syntax-rules vs other approaches like R6RS syntax-case for instance.
> My knowledge of those approaches is very light but it seems that if
> R6RS decided to scrap syntax-rules and go for another approach there
> must be good reasons. Can you comment on that? It would help a lot in
> getting an idea of the strengths and weaknesses of black hole.
>
> Also, I read that syntax-rules doesn't support any kind of
> non-hygienic macros. Is that the case for black hole or did you extend
> it to support non-hygienic macros?

-- First, my thought about syntax-rules vs. syntax-case

It's true that syntax-rules doesn't support any kind of non-hygienic  
macros. All variables that the macro uses must be passed explicitly as  
parameters to the macro. I have not made any extension to this kind of  
macro. BH does not even support SRFI-46, but that should be really  
simple to implement when needed.

The reason I wanted to support syntax-rules are mostly pragmatic; I  
wanted to be able to use other people's R5RS code. Also, I wanted to  
make it easy for people who are writing code in Black Hole to write it  
in a reasonably portable way.

Syntax-rules macros are based on pattern matching, and are turing  
complete. However, many useful operations that are possible to do in  
Scheme are impossible to do in syntax-rules macros; string operations  
for instance.

In essence, syntax-rules is a tool for writing macros that is easy to  
learn and it's easy to write correct macros in it. Most macros are  
very simple, and syntax-rules excels in those cases. My impression is  
that syntax-rules was put in R5RS without very much thought, but it  
was still in many ways an improvement over R4RS macros (non-hygienic,  
I think). R5RS' specification of syntax-rules is rather hairy at  
corner cases, and implementations claiming full R5RS compliance often  
have slightly different behavior.

But, syntax-rules macros are 1) not able to break hygiene in any way  
2) not able to execute arbitrary Scheme code. Syntax-case is, as I  
understand it, but honestly, I don't know very much about syntax-case,  
able to do both of these things. It seems people who don't like R6RS  
often criticize syntax-case for breaking the principle of lexical  
scope, and for being overly complex.

-- How this relates to Black Hole

Black Hole's macro system is not modelled on syntax-rules, it is based  
on syntactic closures, and syntax-rules is implemented in terms of  
syntactic closures. Implementing syntax-rules took only about a day,  
and it should be possible to implement syntax-case as well. I just  
haven't done it.

Chicken's macro system is based on explicit renaming, which might  
actually be a better choice than syntactic closures, because I have  
heard that ER is faster than SC, not sure though. So far, I haven't  
had any performance problems, but I am going to have to change a  
rather large part of the hygiene core to be able to implement let- 
syntax properly, and that might make it slower. (At the moment, it's  
not always possible to use define-syntax directly inside let-syntax)

The reason I chose syntactic closures over explicit renaming is that I  
think it's easier to write SC macros than explicit renaming macros.  
Also, I would guess that it's easier to implement syntax-rules in SC  
than in ER. SC is basically a little bit higher level than ER.

There is one more thing that I ought to mention. Because syntax-rules  
doesn't allow execution of arbitrary code, syntax-rules is very  
convenient for the module system/compiler/interpreter writer. Allowing  
execution of arbitrary code introduces all kinds of strange problems,  
and the only really good solution to those problems that I know of is  
called the syntactic tower. The syntactic tower requires all modules  
to have a potentially unbounded number of instances; one for each  
compilation phase (run-time, compilation time, compilation-compilation  
time, and so on). Implementing this is rather tricky if you want to do  
it efficiently.

At the moment, BH does not implement the syntactic tower; there is  
only one set of globals. Because of this, macros using global state  
become quite fragile. That's why syntax-rules is the recommended way  
of writing macros; it's impossible to run into these problems if you  
use them. Also, if you need more powerful macros, you can always use  
sc-macro-transformer (syntactic closure macros).

I have found a way to implement the syntactic tower in a way that  
doesn't inhibit the performance of the code after it's macro expanded,  
but it's somewhat complex and I haven't found the time to do it yet.  
It's rather high on the to do list though.

/Per




More information about the Gambit-list mailing list