Macros with Ellipses
As previously discussed, a macro is an expression that gets replaced with predetermined code during compile-time. This article examines the broader implications of macros when using the ellipses; denoted as
…. The ellipses is useful whenever a macro wishes to utilize an indefinite amount of parameters in its construction.
Suppose a macro adds two values together.
(define-syntax add (syntax-rules () [(add p q) (+ p q)]))
However, this code is still limited by two arguments. To extend beyond it, the ellipses is used.
(define-syntax add (syntax-rules () [(add p ...) (+ p ...)]))
… symbolizes zero or more arguments, and must always be pair with the named parameter to the left of it. The following uses of
add are now valid:
(add) ; => 0 (add 1) ; => 1 (add 1 2) ; => 3
Infinite Boolean Operators
Previously, macros were used to implement the
or operator. One of the drawbacks of this approach is the parameter limit that
my-or imposes; a limitation of two values.
(define-syntax my-or (syntax-rules () [(my-or p q) (if p #t q)])) ; (my-or #t #t #t) ; => Bad syntax error
As illustrated above, a bad syntax error would occur if
my-or receives more than two values. In order to prevent this, the macro needs to be able to receive an indefinite amount of parameters to perform its computation.
(define-syntax my-or (syntax-rules () [(my-or p q) (if p #t q)] [(my-or p q ...) (my-or p (my-or q ...))])) (my-or #f #f #f #t) ; => #t
By using the ellipses in this example,
my-or is able to take any amount of boolean expressions. The reader might’ve noticed that macro pattern-matching is recursive within its definition. This allows macros to infinitely expand until a base case is reached. The same approach can be used to extend
(define-syntax my-and (syntax-rules () [(my-and p q) (if (not p) #f q)] [(my-and p q ...) (my-and p (my-and q ...))])) (my-and #t #t #t) ; => #t (my-and #f #t #t) ; => #f
… allow macros to have multiple parameters in its expansion.