Tutorial

This tutorial introduces the features of the macro stepper by way of a few small examples. For more discussion on the macro stepper's features, see the manual.

Follow along by performing the instructions written in emphasized text. Start by opening a new DrScheme window and setting the language level to Textual (MzScheme).

Consider this reimplementation of Scheme's or macro, called myor:

      ;; (myor e1 ... eN) means: evaluate each eI in order until
      ;; one of them returns a true value, then return that value.
      (define-syntax myor
        (syntax-rules ()
          [(myor e)
           e]
          [(myor e1 . es)
           (let ([r e1]) (if r r (myor . es)))]))
      
The myor macro has a base case---one expression---and a recursive case, and it uses syntax-rules to determine which form a particular use of the macro has. In the recursive case, it binds the variable r the the value of the first expression to avoid evaluting it twice.

Copy the definition of myor into DrScheme's definitions window.

The following is a program that uses myor:

      (define (nonzero? r)
        (myor (negative? r)
              (positive? r)))
      
It just tests whether a real number r is nonzero. (A real number is nonzero if it is negative or if it is positive.)

Copy the definition of nonzero? into the definitions window.

Now click the macro stepper button:
[macro stepper button]

When you run the macro stepper on a program, it opens a frame for the program's expansion. The frame has a navigation bar that steps backwards and forwards in the macro expansion of the current term, as well as two buttons that go up and down between the terms of the program. Beneath the navigation bar is the syntax display area: it shows all the terms of the program. Our program, for instance, has two terms: the macro definition and the function definition.

Here is the initial macro stepper frame for our program:
[macro stepper: 1]
The first term is a macro definition. It doesn't contain any macros that we want to see (define-syntax and syntax-rules are part of the mzscheme language), so the macro stepper tells us that expansion is finished for the first term.

Let's move to the second term by clicking the Next term button.

[macro stepper: 2]

The next term has a macro occurrence. The macro stepper highlights the macro use in pink, draws an arrow, and shows the term that it produces, highlighted in light blue. It colors the syntax produced by the macro red to distinguish it from the program's original syntax. The macro stepper uses a new color for each macro expansion step; eventually, when it runs out of colors, it uses numeric suffixes instead.

The colors correspond to marks or timestamps that the macro expander puts on syntax introduced by a macro. Generally, the binding of a colored identifier only affects other identifiers of the same color. So the red r does not bind the black r from the original function definition.

The macro transformation step produces another use of myor, and if we step forward, we see its expansion:
[macro stepper: 3]
If we step forward once more, we find ourselves at the end of this term's expansion:
[macro stepper: 4]
.

That's the end of our program. If we click once more on Next term we can see the macro expansion of the entire program:
[macro stepper: 5]