Scheme includes an easy-to-use and powerful macro mechanism for extending the programming language with new expression and definition forms. Using macros, a Scheme programmer can define a new notation for a specific problem domain and can then state algorithms in this language. Thus, Scheme programmers can formulate layers of abstraction whose expressive power greatly surpasses that of ordinary modules. Unfortunately, Scheme’s macros are also too powerful. The problem is that macro definitions extend the parser, a component of a language’s environment that is always supposed to terminate and produce predictable results, and that they can thus turn the parser into a chaotic and unpredictable tool. In this paper, we report on an experiment to tame the power of macros. Specifically, we introduce a system for specifying and restricting the class of shapes that a macro can transform. We dub the revised macro system well-shaped macros . 1. MACROS ARE USEFUL Over the past 20 years, the Scheme community has developed an expressive and useful standard macro system [8]. The macro system allows programmers to define a large variety of new expression and definition forms in a safe manner. It thus empowers them to follow the old Lisp maxim on problem-solving via language definition, which says that programmers should formulate an embedded programming language for the problem domain and that they should express their solution for the domain in this new language. Standard Scheme macros are easy and relatively safe to use. To introduce a macro, a programmer simply writes down a rewriting rule between two syntactic patterns [10], also called patternand template . Collectively the rules specify how the macro expander, which is a component of the parser, must translate surface syntax into core Scheme, that Permission to make digital or hard copies, to republish, to post on servers or to redistribute to lists all or part of this work is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To otherwise copy or redistribute requires prior specific permission. Fourth Workshop on Scheme and Functional Programming. November 7, 2003, Boston, Massachusetts, USA. Copyright 2003 Ryan Culpepper, Matthias Felleisen. is, Scheme without any extensions. Specifically, the (lefthand side) pattern specifies those S-expressions that the expander should eliminate in favor of the (right-hand side) template. Furthermore, the expander is “hygienic” [9] and “referentially transparent” [3], which means that macro expansion automatically respects the lexical scope of the program. It is a key characteristic of Scheme macros that their uses are indistinguishable from built-in forms. As for built-in and defined functions, a programmer should not, and without context cannot, recognize whether a form is introduced via a macro or exists in core Scheme. Due to this uniformity, (teams of) programmers can build many-tiered towers of abstraction, each using conventional procedural libraries as well as new linguistic mechanisms. Although the Scheme authors have clearly tamed Lisp’s programmed macros and C’s string rewriting macros, they have still left the macro sublanguage with as much power as the untyped lambda calculus. In particular, macro expansion can create ill-formed core syntax, and it can diverge. We illustrate this point with some examples in the next section. The situation suggests that we study ways of taming Scheme macros with a type system. In this paper, we report on the results of one such an experiment. In section 2 we explain how Scheme macros can still perform undesirable computations. In sections 3 and 4, we introduce a modified macro system that allows a Scheme implementation to determine whether macro definitions and programs are syntactically well-formed. In section 5, we compare our work to related work and propose some future research. 2. MACROS ARE TOO POWERFUL Standard Scheme macros suffer from two problems. On one hand, they can turn the macro expander into an infinite loop. Since the expander is a part of the parser, a programmer can turn the most reliable part of an ordinary programming environment into a useless tool. On the other hand, a macro can misapply Scheme’s syntactic constructors, creatWe readily acknowledge that building such towers poses additional, serious problems for language designers [6, 11], but this topic is beyond the scope of our paper. If we were to eliminate ellipses and introduce an induction schema, our result would literally reconstruct for macro systems what the type discipline of Church did for the original lambda calculus.
[1]
Matthew Flatt.
Composable and compilable macros:: you want it when?
,
2002,
ICFP '02.
[2]
Luca Cardelli,et al.
Subtyping recursive types
,
1991,
POPL '91.
[3]
Amr Sabry,et al.
Macros as multi-stage computations: type-safe, generative, binding macros in MacroML
,
2001,
ICFP '01.
[4]
R. Kent Dybvig,et al.
Revised5 Report on the Algorithmic Language Scheme
,
1986,
SIGP.
[5]
Mitchell Wand,et al.
Macro-by-example: Deriving syntactic transformations from their specifications
,
1987,
POPL '87.
[6]
Jonathan Rees,et al.
Macros that work
,
1991,
POPL '91.
[7]
Jonathan Rees,et al.
Revised3 report on the algorithmic language scheme
,
1986,
SIGP.
[8]
Matthias Felleisen,et al.
Hygienic macro expansion
,
1986,
LFP '86.
[9]
R. Kent Dybvig,et al.
The Scheme Programming Language
,
1995
.
[10]
Martín Abadi,et al.
Extensible Syntax with Lexical Scoping
,
1994
.
[11]
Matthias Felleisen,et al.
DrScheme: a programming environment for Scheme
,
2002,
J. Funct. Program..