[plt-scheme] Reproviding "else"

From: Ryan Culpepper (ryanc at ccs.neu.edu)
Date: Tue Mar 17 12:10:20 EDT 2009

Robby Findler wrote:
> Ryan, this is a very nice message and, if you have the energy, I bet
> it would fit nicely into the guide somewhere.

Thanks! I'm working in that direction.


> Robby
> On Mon, Mar 16, 2009 at 3:42 PM, Ryan Culpepper <ryanc at ccs.neu.edu> 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 :)
>> Ryan
>>> #lang scheme
>>> (define-syntax new:cond
>>>  (syntax-rules (else)
>>>   [(_)  (void)]
>>>   [(_ [else else-expr])  else-expr]
>>>   [(_ [test-expr^ then-expr^] [test-expr then-expr] ...)
>>>    (if test-expr^
>>>        then-expr^
>>>        (new:cond [test-expr then-expr] ...))]))
>>> (provide
>>> #%module-begin #%datum #%app if define
>>> (rename-out [new:cond cond])
>>> < quote)
>>> #lang s-exp "cond-lang.ss"
>>> (define (classify-age n)
>>>  (cond [(< n 0) 'twinkle-in-daddys-eye]
>>>       [(< n 10) 'precocious]
>>>       [(< n 20) 'cheeky]
>>>       [(< n 30) 'spunky]
>>>       [(< n 50) 'not-dead-yet]
>>>       [(< n 120) 'cobol-programming]
>>>       [else  'holy-fate-worse-than-death-batman!]))
>>> (classify-age 121)
>>> _________________________________________________
>>>  For list-related administrative tasks:
>>>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>> _________________________________________________
>>  For list-related administrative tasks:
>>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme

Posted on the users mailing list.