[plt-scheme] Reproviding "else"

From: Neil Toronto (ntoronto at cs.byu.edu)
Date: Mon Mar 16 18:08:30 EDT 2009

Ryan Culpepper wrote:
> On Mar 16, 2009, at 3:19 PM, Neil Toronto wrote:
>> The attached example language module "cond-lang.ss" implements a very 
>> small language, reproviding a few bits of Scheme and providing a new 
>> cond macro. When "cond-test.ss" uses that macro, the compiler gives an 
>> error:
>>    compile: unbound identifier (and no #%top syntax transformer
>>    is bound) in: else
>> It's not just else, though: you can't use as a literal any name that's 
>> in scope in the macro definition. (For example, the compiler gives the 
>> same error if else is changed to foobar and foobar is defined at the 
>> top level.) Well, you can, but you have to provide that name as well 
>> as the macro. If you can't safely do that, there are uglier ways.
>> Why are literals with syntax properties used for matching?
> Rather, the literals are matched by *binding*, not by their symbolic 
> name. The macro is looking for the 'else' in scope in "cond-lang.ss", 
> which is the 'else' from the 'scheme' language. But the 'else' used in 
> "cond-test.ss" is something else, so the macro interprets it as a 
> 'text-expr^', and it eventually gets flagged as an unbound variable. The 
> solution, as you remark, is to provide 'else'.
> So, why are literals matched by binding, rather than by symbolic name?
> It's a matter of syntax design. Your macro analyzes its clauses and 
> tries to distinguish between an else-clause and an ordinary test-clause. 
> In order for the macro to distinguish the two kinds of clauses, they 
> should not overlap. That is, there shouldn't be any valid test-clause 
> that is also an else-clause. They have the same shape, so the thing that 
> really distinguishes them is the first part: There shouldn't be any 
> valid test expression that is also the else keyword.
> If keywords were recognized by just their spelling, then there would be 
> an overlap between the else keyword and a local variable called 'else' 
> in the "cond-test.ss" module. Instead, the 'else' keyword is defined as 
> a macro that always raises an error when used as an expression. That 
> makes 'else' effectively not a valid expression, so there's no overlap.
> The alternative would be to say that a test-expression is almost like an 
> ordinary expression, except that it can't be a variable named 'else'. 
> This might seem innocuous---who uses 'else' as a variable name? But it's 
> a hidden danger and, at the same time, unnecessary clutter in the 
> meaning of 'new:cond'. Better to *reserve* the word right off the bat 
> and learn of conflicts as early as possible.
> There are other advantages that come from treating keywords as bindings, 
> including the ability to rename them when you import them into a module, 
> the ability to keep some keywords internal (just don't export them), and 
> the ability to get nice documentation links for keywords via Scribble :)

Ah, okay. Dark corner illuminated. Thanks!

Two questions. First, doesn't treating literals as bindings (when they 
exist) mean that macros aren't isolated by default from additions to 
required libraries? A third-party library can break my macro by doing 
nothing more than introducing a new name that happens to match one of my 
macro's literals.

Second, doing a "(define <literal> (void))" and providing it for every 
literal would let me keep proper syntactic abstraction. Should I do 
something like that?


Posted on the users mailing list.