[plt-scheme] Reproviding "else"
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?
Neil