Macros


There are two kinds of macros in ATS. One kind is C-like and the other kind is LISP-like, though they are much simpler as well as weaker than their counterparts in C and LISP, respectively.

C-like Macros

We use some examples to illustrate certain typical uses of C-like macros in ATS.

The following two declarations bind the identifiers N1 and N2 to the abstract syntax trees (not strings) representing 1024 and N1 + N1, respectively:

#define N1 1024
#define N2 N1 + N1
Suppose we have the following value declaration appearing in the scope of the above macro delarations:
val x = N1 * N2
Then N1 * N2 first expands into 1024 * (N1 + N1), which further expands into 1024 * (1024 + 1024). Note that if this example is done in C, then N1 * N2 expands into 1024 * 1024 + 1024, which is different from what we have here. Also note that it makes no difference if we reverse the order of the previous macro definitions:
#define N2 N1 + N1
#define N1 1024
If we declare a marco as follows:
#define LOOP (LOOP + 1)
then an infinite loop is entered (or more precisely, some macro expansion depth is to be reached) when the identifier LOOP is expanded.

LISP-like Macros

There are two forms of LISP-like macros in ATS: short form and long form. These (untyped) macros are highly flexible and expressive, and they can certainly be used in convoluted manners that should probably be avoided in the first place. Some commonly used macro definitions can be found in prelude/macrodef.sats. In order to use LISP-like macros in ATS effectively, the programmer may want to find some examples in LISP involving backquote-comma-notation.

Macros in Long Form   As a macro in short form can simply be considered a special kind of macro in long form, we first give some explanantion on the latter. A macro definition in long form is introduced via the use of the keyword macrodef. For instance, the following syntax introduces a macro name one that refers to some code, that is, abstract syntax tree (AST) representing the integer number 1.

macrodef one = `(1)
The special syntax `(...), where no space is allowed between the backquote "`" and the left parenthsis "(", means to form an abstract syntax tree representing what is written inside the parentheses. This is often referred to as backquote-notation. Intuitively, one may think that a backquote-notation exerts an effect that "freezes" everything inside it. Let us now define another macro as follows:
macrodef one_plus_one = `(1 + 1)
The defined macro name one_plus_one refers to some code (i.e., AST) representing 1 + 1. At this point, it is important to stress that the code representing 1 + 1 is different from the code representing 2. The macro name one_plus_one can also be defined as follows:
macrodef one_plus_one = `(,(one) + ,(one))
The syntax ,(...), where no space is allowed between the comma "," and the left parenthesis "(", indicates the need to expand (or evaluate) whatever is written inside the parentheses. This is often referred to as comma-notation. A comma-notation is only allowed inside a backquote-notation. Intuitively, a comma-notation cancels out the "freezing" effect of the enclosing backquote-notation.

In addition to macro names, we can also define macro functions. For instance, the following syntax introduces a macro function square_mac:

macrodef square_mac (x) = `(,(x) * ,(x)) // [x] should refer to some code
Here are some examples that make use of square_mac:
fun square_fun (i: int): int = ,(square_mac `(i))
fun area_of_circle_fun (r: double): doubld = 3.1416 * ,(square_mac `(r))
Macros in Short Form   The previous macro function square_mac can also be defined as follows:
macdef square_mac (x) = ,(x) * ,(x) // [x] should refer to some code
The keyword macdef introduces a macro definition in short form. The previous examples that make use of square_mac can now be written as follows:
fun square_fun (i: int): int = square_mac (i)
fun area_of_circle_fun (r: double): doubld = 3.1416 * square_mac (r)
In terms of syntax, a macro function in short form is just like an ordinary function. In general, if a unary macro function fmac in short form is defined as as follows:
macdef fmac (x) = $exp_def
then one may essentially think that a macro definition in long form is defined as follows:
macrodef fmac_long (x) = `($exp_def) // please note the backquote
and each occurrence of fmac($exp_arg) is automatically rewritten into ,(fmac_long(`($exp_arg))). Note that macro functions in short form with multiple arguments are handled in precisely the same fashion. The primary purpose for introducing macros in short form is to provide a form of syntax that seems more accessible. While macros in long form can be defined recursively (as is to be explained later), macros in short form cannot.

Recursive Macro Definitions   (to be written later)


The code used for illustration is available here.