Wed Aug 13 10:51:53 CEST 2008
Coma and names: reflection vs. staging
Why does Staapl need two abstraction mechanisms: macros and prefix
The short answer: Coma's code generators are flat anonymous higher
order combinators. All names are just notational shorthands that
identify combinator expressions. Because the naming mechanism is
completely orthogonal to the semantics of the Coma language,
abstractions built on top of the mechanism that associates names to
expressions needs a separate mechanism. See next post.
Let's define a macro as a function that transforms program code into
A Scheme macro transforms a list of Scheme expressions into into a new
Scheme expression. The macros live in the same space as the
expressions that are being transformed.
A Coma macro transforms a stack of instructions into a stack of
instructions. The instructions come from some target concatenative
One essential difference that is immediately observed is that program
transformation with Scheme macros is reflective. Macros operate on
Scheme code and produce Scheme code. The process of expansion is
repeated iteratively until all macros have been invoked and only
primitive forms remain.
In Coma, program transformation is staged. Every transformer function
is a component of a meta language that manipulates a base laguage as
data. These languages are distinct. A Coma program defines a base
Note that the Coma language is a higher order functional language. A
lot of parameterization can be solved using anonymous macros. This
approach gives a really simple structure to Coma that allows to treat
staging in a very straightforward algebraic way without having to
worry about bindings at all. Absence of ``special forms'' allows one
to maintain a very direct relationship between syntax (concatenation)
and semantics (function composition).
When one would like to parameterize over names in a Coma program, a
different abstraction mechanism is necessary. Since Coma is embedded
in Scheme, the straightforward approach is to use Scheme's reflective
macro system to handle this. This mechanism is introduced into
Staapl's Forth preprocessor as ``prefix macros'' or ``parsing words''.
Additionally, since names in Coma are all global, it makes a lot of
sense to build some scoping mechanism on top of this. Coma uses both
PLT Scheme's hierarichal module namespace mechanism and an additional
subdivision into separate namespaces for compilation stages: (macro)
and (target), plus namespaces to embed alternative concatenative
semantics like (scat). On top of this, it is possible to mix Coma and
Scheme code in a way that allows Scheme's lexical bindings to be
spliced into Coma code.