commit ed4f7ee1f7ccc73365f072008c0c834b642ed223
parent 7838ef12db91f94552c87484172ffe323028312c
Author: Wolfgang Corcoran-Mathe <wcm@sigwinch.xyz>
Date: Thu, 1 Feb 2024 20:03:36 -0500
Macros: Further Texification.
Oof!
Diffstat:
1 file changed, 183 insertions(+), 96 deletions(-)
diff --git a/doc/r7rs-small/macros.texinfo b/doc/r7rs-small/macros.texinfo
@@ -2,37 +2,53 @@
@section Macros
Scheme programs can define and use new derived expression types, called
-macros.Program-defined expression types have the syntax
+@dfn{macros}. Program-defined expression types have the syntax
-(@svar{keyword} @svar{datum} ...)where @svar{keyword} is an identifier that uniquely determines the
-expression type. This identifier is called the syntactic keyword, or simply keyword, of the
+@display
+@code{(}@svar{keyword} @svar{datum} @dots{}@code{)}
+@end display
+
+where @svar{keyword} is an identifier that uniquely determines the
+expression type. This identifier is called the @dfn{syntactic keyword}, or simply @dfn{keyword}, of the
macro. The number of the @svar{datum}s, and their syntax, depends on the expression type.
-Each instance of a macro is called a useof the macro. The set of rules that specifies how a
-use of a macro is transcribed into a more primitive expression is called the transformerof
+Each instance of a macro is called a @dfn{use} of the macro. The set of rules that specifies how a
+use of a macro is transcribed into a more primitive expression is called the @dfn{transformer} of
the macro.
The macro definition facility consists of two parts:
-* A set of expressions used to establish that certain identifiers are macro keywords,
+@itemize
+
+@item
+A set of expressions used to establish that certain identifiers are macro keywords,
associate them with macro transformers, and control the scope within which a macro
is defined, and
-* a pattern language for specifying macro transformers.
+@item
+a pattern language for specifying macro transformers.
+
+@end itemize
The syntactic keyword of a macro can shadow variable bindings, and local variable
bindings can shadow syntactic bindings. Two mechanisms are provided to prevent
unintended conflicts:
-* If a macro transformer inserts a binding for an identifier (variable or keyword), the
+@itemize
+
+@item
+If a macro transformer inserts a binding for an identifier (variable or keyword), the
identifier will in effect be renamed throughout its scope to avoid conflicts with other
identifiers. Note that a global variable definition may or may not introduce a binding;
- see section 5.3.
+@xref{Variable definitions}.
-* If a macro transformer inserts a free reference to an identifier, the reference refers to
+@item
+If a macro transformer inserts a free reference to an identifier, the reference refers to
the binding that was visible where the transformer was specified, regardless of any
local bindings that surround the use of the macro.
+@end itemize
+
In consequence, all macros defined using the pattern language are ``hygienic'' and
``referentially transparent'' and thus preserve Scheme's lexical scoping. [21, 22, 2, 9, 12]
@@ -47,22 +63,27 @@ Implementations may provide macro facilities of other types.
@node Binding constructs for syntactic keywords
@subsection Binding constructs for syntactic keywords
-The let-syntax and letrec-syntax binding constructs are analogous to let and letrec, but
-they bind syntactic keywords to macro transformers instead of binding variables to
-locations that contain values. Syntactic keywords can also be bound globally or locally
-with define-syntax; see section 5.4.
+The @code{let-syntax} and @code{letrec-syntax} binding constructs are
+analogous to @code{let} and @code{letrec}, but they bind
+syntactic keywords to macro transformers instead of binding variables
+to locations that contain values. Syntactic keywords can also be
+bound globally or locally with @code{define-syntax}; @xref{Syntax definitions}.
-syntax: (let-syntax @svar{bindings} @svar{body})
+@deffn syntax let-syntax @svar{bindings} @svar{body}
Syntax: @svar{Bindings} has the form
-((@svar{keyword} @svar{transformer spec}) @dots{})Each @svar{keyword} is an identifier, each <transformer
-spec> is an instance of syntax-rules, and @svar{body} is a sequence of zero or more
+@display
+@code{((}@svar{keyword} @svar{transformer spec}@code{)} @dots{}@code{)}
+@end display
+
+Each @svar{keyword} is an identifier, each @svar{transformer spec}
+is an instance of @code{syntax-rules}, and @svar{body} is a sequence of zero or more
definitions followed by one or more expressions. It is an error for a @svar{keyword} to
appear more than once in the list of keywords being bound.
Semantics: The @svar{body} is expanded in the syntactic environment obtained by extending
-the syntactic environment of the let-syntax expression with macros whose keywords are
+the syntactic environment of the @code{let-syntax} expression with macros whose keywords are
the @svar{keyword}s, bound to the specified transformers. Each binding of a @svar{keyword} has
@svar{body} as its region.
@@ -74,23 +95,25 @@ the @svar{keyword}s, bound to the specified transformers. Each binding of a @sva
stmt2 ...))))))
(let ((if #t))
(given-that if (set! if 'now))
- if)) @result{} now
+ if)) @result{} now
(let ((x 'outer))
(let-syntax ((m (syntax-rules () ((m) x))))
(let ((x 'inner))
- (m)))) @result{} outer
+ (m)))) @result{} outer
@end example
-syntax: (letrec-syntax @svar{bindings} @svar{body})
+@end deffn
-Syntax: Same as for let-syntax.
+@deffn syntax letrec-syntax @svar{bindings} @svar{body}
+
+Syntax: Same as for @code{let-syntax}.
Semantics: The @svar{body} is expanded in the syntactic environment obtained by extending
-the syntactic environment of the letrec-syntax expression with macros whose keywords
+the syntactic environment of the @code{letrec-syntax} expression with macros whose keywords
are the @svar{keyword}s, bound to the specified transformers. Each binding of a @svar{keyword}
has the @svar{transformer spec}s as well as the @svar{body} within its region, so the transformers
-can transcribe expressions into uses of the macros introduced by the letrec-syntax
+can transcribe expressions into uses of the macros introduced by the @code{letrec-syntax}
expression.
@example
@@ -111,52 +134,72 @@ expression.
(my-or x
(let temp)
(if y)
- y))) @result{} 7
+ y))) @result{} 7
@end example
+@end deffn
+
@node Pattern language
@subsection Pattern language
+@deffn syntax syntax-rules
+@deffnx {auxiliary syntax} _
+@deffnx {auxiliary syntax} @dots{}
+
A @svar{transformer spec} has one of the following forms:
-syntax: (syntax-rules (@svar{pattern literal} @dots{})
- @svar{syntax rule} @dots{})
-syntax: (syntax-rules @svar{ellipsis} (@svar{pattern literal} @dots{})
- @svar{syntax rule} @dots{})
-auxiliary syntax: _
-auxiliary syntax: @dots{}
+@display
+@code{(syntax-rules (}@svar{pattern literal} @dots{}@code{)}
+ @svar{syntax rule} @dots{}@code{)}
+@code{(syntax-rules }@svar{ellipsis} @code{(}@svar{pattern literal} @dots{}@code{)}
+ @svar{syntax rule} @dots{}@code{)}
+@end display
Syntax: It is an error if any of the @svar{pattern literal}s, or the @svar{ellipsis} in the second form, is
not an identifier. It is also an error if @svar{syntax rule} is not of the form
-(@svar{pattern} @svar{template})The @svar{pattern} in a @svar{syntax rule} is a list @svar{pattern} whose first
+@display
+(@svar{pattern} @svar{template})
+@end display
+
+The @svar{pattern} in a @svar{syntax rule} is a list @svar{pattern} whose first
element is an identifier.
A @svar{pattern} is either an identifier, a constant, or one of the following
-(@svar{pattern} @dots{})
-(@svar{pattern} @svar{pattern} @dots{} . @svar{pattern})
-(@svar{pattern} @dots{} @svar{pattern} @svar{ellipsis} @svar{pattern} @dots{})
-(@svar{pattern} @dots{} @svar{pattern} @svar{ellipsis} @svar{pattern} @dots{}
- . @svar{pattern})
-#(@svar{pattern} @dots{})
-#(@svar{pattern} @dots{} @svar{pattern} @svar{ellipsis} @svar{pattern} @dots{})and a @svar{template} is either an identifier, a
-constant, or one of the following (@svar{element} @dots{})
-(@svar{element} @svar{element} @dots{} . @svar{template})
-(@svar{ellipsis} @svar{template})
-#(@svar{element} @dots{})where an @svar{element} is a @svar{template} optionally followed by an @svar{ellipsis}.
-An @svar{ellipsis} is the identifier specified in the second form of syntax-rules, or the default
-identifier ... (three consecutive periods) otherwise.
-
-Semantics: An instance of syntax-rules produces a new macro transformer by specifying a
+@display
+@code{(}@svar{pattern} @dots{}@code{)}
+@code{(}@svar{pattern} @svar{pattern} @dots{} @code{.} @svar{pattern}@code{)}
+@code{(}@svar{pattern} @dots{} @svar{pattern} @svar{ellipsis} @svar{pattern} @dots{}@code{)}
+@code{(}@svar{pattern} @dots{} @svar{pattern} @svar{ellipsis} @svar{pattern} @dots{}
+ @code{.} @svar{pattern}@code{)}
+@code{#(}@svar{pattern} @dots{}@code{)}
+@code{#(}@svar{pattern} @dots{} @svar{pattern} @svar{ellipsis} @svar{pattern} @dots{}@code{)}
+@end display
+
+and a @svar{template} is either an identifier, a
+constant, or one of the following
+
+@display
+@code{(}@svar{element} @dots{}@code{)}
+@code{(}@svar{element} @svar{element} @dots{} @code{.} @svar{template}@code{)}
+@code{(}@svar{ellipsis} @svar{template}@code{)}
+@code{#(}@svar{element} @dots{}@code{)}
+@end display
+
+where an @svar{element} is a @svar{template} optionally followed by an @svar{ellipsis}.
+An @svar{ellipsis} is the identifier specified in the second form of @code{syntax-rules}, or the default
+identifier @code{@dots{}} (three consecutive periods) otherwise.
+
+Semantics: An instance of @code{syntax-rules} produces a new macro transformer by specifying a
sequence of hygienic rewrite rules. A use of a macro whose keyword is associated with a
-transformer specified by syntax-rules is matched against the patterns contained in the
+transformer specified by @code{syntax-rules} is matched against the patterns contained in the
@svar{syntax rule}s, beginning with the leftmost @svar{syntax rule}. When a match is found, the
macro use is transcribed hygienically according to the template.
-An identifier appearing within a @svar{pattern} can be an underscore (_), a literal identifier
+An identifier appearing within a @svar{pattern} can be an underscore (@code{_}), a literal identifier
listed in the list of @svar{pattern literal}s, or the @svar{ellipsis}. All other identifiers appearing
-within a @svar{pattern} are pattern variables.
+within a @svar{pattern} are @dfn{pattern variables}.
The keyword at the beginning of the pattern in a @svar{syntax rule} is not involved in the
matching and is considered neither a pattern variable nor a literal identifier.
@@ -166,11 +209,11 @@ the input in the template. It is an error for the same pattern variable to appea
than once in a @svar{pattern}.
Underscores also match arbitrary input elements but are not pattern variables and so
-cannot be used to refer to those elements. If an underscore appears in the <pattern
-literal>s list, then that takes precedence and underscores in the @svar{pattern} match as
+cannot be used to refer to those elements. If an underscore appears in the
+@svar{pattern literal}s list, then that takes precedence and underscores in the @svar{pattern} match as
literals. Multiple underscores can appear in a @svar{pattern}.
-Identifiers that appear in (@svar{pattern literal} @dots{}) are interpreted as literal identifiers to be
+Identifiers that appear in @code{(}@svar{pattern literal} @dots{}@code{)} are interpreted as literal identifiers to be
matched against corresponding elements of the input. An element in the input matches
a literal identifier if and only if it is an identifier and either both its occurrence in the
macro expression and its occurrence in the macro definition have the same lexical
@@ -179,43 +222,82 @@ binding, or the two identifiers are the same and both have no lexical binding.
A subpattern followed by @svar{ellipsis} can match zero or more elements of the input,
unless @svar{ellipsis} appears in the @svar{pattern literal}s, in which case it is matched as a literal.
-More formally, an input expression E matches a pattern P if and only if:
-
-* P is an underscore (_).
-
-* P is a non-literal identifier; or
-
-* P is a literal identifier and E is an identifier with the same binding; or
-
-* P is a list (P1 @dots{} Pn) and E is a list of n elements that match P1 through Pn, respectively;
- or
-
-* P is an improper list (P1P2 @dots{} Pn . Pn+1) and E is a list or improper list of n or more
- elements that match P1 through Pn, respectively, and whose nth tail matches Pn+1; or
-
-* P is of the form (P1 @dots{} PkPe @svar{ellipsis} Pm+1 @dots{} Pn) where E is a proper list of n elements,
- the first k of which match P1 through Pk, respectively, whose next m−k elements each
- match Pe, whose remaining n−m elements match Pm+1 through Pn; or
-
-* P is of the form (P1 @dots{} PkPe @svar{ellipsis} Pm+1 @dots{} Pn . Px) where E is a list or improper list of n
- elements, the first k of which match P1 through Pk, whose next m−k elements each
- match Pe, whose remaining n−m elements match Pm+1 through Pn, and whose nth and
- final cdr matches Px; or
-
-* P is a vector of the form #(P1 @dots{} Pn) and E is a vector of n elements that match P1
- through Pn; or
-
-* P is of the form #(P1 @dots{} PkPe @svar{ellipsis} Pm+1 @dots{}Pn) where E is a vector of n elements the
- first k of which match P1 through Pk, whose next m−k elements each match Pe, and
- whose remaining n−m elements match Pm+1 through Pn; or
-
-* P is a constant and E is equal to P in the sense of the equal? procedure.
+More formally, an input expression @var{E} matches a pattern @var{P}
+if and only if:
+
+@itemize
+
+@item
+@var{P} is an underscore (@code{_}).
+
+@item
+@var{P} is a non-literal identifier; or
+
+@item
+@var{P} is a literal identifier and @var{E} is an identifier with the
+same binding; or
+
+@item
+@var{P} is a list @code{(}@var{P@sub{1}} @dots{} @var{P@sub{n}}@code{)}
+and @var{E} is a list of @var{n} elements that match @var{P@sub{1}}
+through @var{P@sub{n}}, respectively; or
+
+@item
+@var{P} is an improper list
+@code{(}@var{P@sub{1}} @var{P@sub{2}} @dots{} @var{P@sub{n}} @code{.}
+@var{P@sub{n+1}}@code{)} and @var{E} is a list or
+improper list of @var{n} or more elements that match @var{P@sub{1}}
+through @var{P@sub{n}} respectively, and whose @var{n}th tail matches
+@var{P@sub{n+1}}; or
+
+@item
+
+@var{P} is of the form
+@code{(}@var{P@sub{1}} @dots{} @var{P@sub{k}} @var{P@sub{e}}
+@svar{ellipsis} @var{P@sub{m+1}} @dots{} @var{P@sub{n}}@code{)}
+where @var{E} is a proper list of @var{n} elements, the first @var{k}
+of which match @var{P@sub{1}} through @var{P@sub{k}}, respectively,
+whose next @var{m} @minus{} @var{k} elements each match @var{P@sub{e}},
+whose remaining @var{n} @minus{} @var{m} elements match @var{P@sub{m+1}}
+through @var{P@sub{n}}; or
+
+@item
+@var{P} is of the form
+@code{(}@var{P@sub{1}} @dots{} @var{P@sub{k}} @var{P@sub{e}}
+@svar{ellipsis} @var{P@sub{m+1}} @dots{} @var{P@sub{n}} @code{.}
+@var{P@sub{x}}@code{)} where @var{E} is a list or improper list of
+@var{n} elements, the first @var{k} of which match @var{P@sub{1}} through
+@var{P@sub{k}}, whose next @var{m} @minus{} @var{k} elements each match
+@var{P@sub{e}}, whose remaining @var{n} @minus{} @var{m} elements match
+@var{P@sub{m+1}} through @var{P@sub{n}}, and whose @var{n}th and final cdr
+matches @var{P@sub{x}}; or
+
+@item
+@var{P} is a vector of the form @code{#(}@var{P@sub{1}} @dots{}
+@var{P@sub{n}}@code{)} and @var{E} is a vector of @var{n} elements that
+match @var{P@sub{1}} through @var{P@sub{n}}; or
+
+@item
+@var{P} is of the form
+@code{#(}@var{P@sub{1}} @dots{} @var{P@sub{k}} @var{P@sub{e}}
+@svar{ellipsis} @var{P@sub{m+1}} @dots{} @var{P@sub{n}}@code{)} where @var{E}
+is a vector of @var{n} elements the first @var{k} of which match
+@var{P@sub{1}} through @var{P@sub{k}}, whose next @var{m} @minus{}
+@var{k} elements each match @var{P@sub{e}}, and whose remaining
+@var{n} @minus{} @var{m} elements match @var{P@sub{m+1}} through
+@var{P@sub{n}}; or
+
+@item
+@var{P} is a constant and @var{E} is equal to @var{P} in the sense of
+the @code{equal?} procedure.
+
+@end itemize
It is an error to use a macro keyword, within the scope of its binding, in an expression
that does not match any of the patterns.
-When a macro use is transcribed according to the template of the matching <syntax
-rule>, pattern variables that occur in the template are replaced by the elements they
+When a macro use is transcribed according to the template of the matching
+@svar{syntax rule}, pattern variables that occur in the template are replaced by the elements they
match in the input. Pattern variables that occur in subpatterns followed by one or more
instances of the identifier @svar{ellipsis} are allowed only in subtemplates that are followed
by as many instances of @svar{ellipsis}. They are replaced in the output by all of the elements
@@ -225,13 +307,13 @@ built up as specified.
Identifiers that appear in the template but are not pattern variables or the identifier
@svar{ellipsis} are inserted into the output as literal identifiers. If a literal identifier is inserted
as a free identifier then it refers to the binding of that identifier within whose scope the
-instance of syntax-rules appears. If a literal identifier is inserted as a bound identifier
+instance of @code{syntax-rules} appears. If a literal identifier is inserted as a bound identifier
then it is in effect renamed to prevent inadvertent captures of free identifiers.
-A template of the form (@svar{ellipsis} @svar{template}) is identical to @svar{template}, except that
+A template of the form @code{(}@svar{ellipsis} @svar{template}@code{)} is identical to @svar{template}, except that
ellipses within the template have no special meaning. That is, any ellipses contained
within @svar{template} are treated as ordinary identifiers. In particular, the template
-(@svar{ellipsis} @svar{ellipsis}) produces a single @svar{ellipsis}. This allows syntactic abstractions to
+@code{(}@svar{ellipsis} @svar{ellipsis}@svar{)} produces a single @svar{ellipsis}. This allows syntactic abstractions to
expand into code containing ellipses.
@example
@@ -247,15 +329,16 @@ expand into code containing ellipses.
(sequence 1 2 3 4) @result{} 4
@end example
-As an example, if let and cond are defined as in section 7.3 then
+As an example, if @code{let} and @code{cond} are defined as in
+@ref{Derived expression types formal} then
they are hygienic (as required) and the following is not an error.
@example
(let ((=> #f))
- (cond (#t => 'ok))) @result{} ok
+ (cond (#t => 'ok))) @result{} ok
@end example
-The macro transformer for cond recognizes @code{=>} as a local
+The macro transformer for @code{cond} recognizes @code{=>} as a local
variable, and hence an expression, and not as the base identifier
@code{=>}, which the macro transformer treats as a syntactic
keyword. Thus the example expands into
@@ -275,14 +358,16 @@ instead of
which would result in an invalid procedure call.
+@end deffn
+
@node Signaling errors in macro transformers
@subsection Signaling errors in macro transformers
-syntax: (syntax-error @svar{message} @svar{args} @dots{})
+@deffn syntax syntax-error @svar{message} @svar{args}@dots{}
-syntax-error behaves similarly to error (6.11) except that implementations with an
-expansion pass separate from evaluation should signal an error as soon as syntax-error
-is expanded. This can be used as a syntax-rules @svar{template} for a @svar{pattern} that is an
+syntax-error behaves similarly to error (@ref{Exceptions}) except that implementations with an
+expansion pass separate from evaluation should signal an error as soon as @code{syntax-error}
+is expanded. This can be used as a @code{syntax-rules} @svar{template} for a @svar{pattern} that is an
invalid use of the macro, which can provide more descriptive error messages.
@svar{message} is a string literal, and @svar{args} arbitrary expressions providing additional
information. Applications cannot count on being able to catch syntax errors with
@@ -300,3 +385,5 @@ exception handlers or guards.
((lambda (name ...) body1 body2 ...)
val ...))))
@end example
+
+@end deffn