Tuesday, September 27, 2011

definitions vs enclosing binding forms

There are two kinds of binding forms in Racket: definitions and enclosing binding forms. The scope of a binding introduced by an enclosing binding form is entirely evident: it’s one (or more) of the form’s sub-terms. For example, in

(lambda (var ...) body)

the scope of the var bindings is body. In contrast, the scope of a definition is determined by its context: the enclosing lambda body, for example, or the enclosing module—except that scope is too simple a term for how bindings work in such contexts. Enclosing binding forms are simpler and cleaner but weaker; definition forms are more powerful, but have a more complicated binding structure. Definitions also have the pleasant property of reducing rightward code drift.

Friday, September 09, 2011

syntax-parse and literals

In my last post, I talked about macros and referential auxiliary identifiers—what we usually call a macro’s “literals.” Scheme macro systems only get it half right, though, because while they compare identifiers using referential equality (i.e., using the free-identifier=? predicate), they allow literals to refer to nonexistent bindings. While the comparison is well-defined via the definition of free-identifier=?, at a higher level the idea is nonsensical.

In contrast, syntax-parse requires that every literal refer to some binding. (I’ll sometimes refer to this requirement as the is-bound property for short.) This requirement is problematic in a different way. Specifically, this property cannot be checked statically (that is, when the syntax-parse expression containing the literal is compiled).

That might strike you as bizarre or unlikely. After all, you can easily imagine checking that a syntax-rules macro, say, satisfies the is-bound property. But in Racket, not every macro uses syntax-rules, and—more importantly—not every bit of syntax-analyzing code is a macro. And both of these facts have to do with phases.

Wednesday, September 07, 2011

macros and literals

Macros often have associated auxiliary identifiers (sometimes called keywords or reserved words, although both terms are problematic in Racket). For example, cond has else; class has public, private, etc; unit has import and export.

The fundamental question is what constitutes a use of an auxiliary identifier, and there are two reasonable answers: symbolic equality and referential equality. By symbolic equality I mean, for example, that any identifier written with exactly the letters else is accepted as an else auxiliary form. By referential equality I mean any identifier that refers to (using the standard notions of binding, environments, etc) the binding identified as the else binding.