On this page:
identifier?
syntax-e
syntax->datum
datum->syntax
bound-identifier=?
8.17.0.6

5 Zuo with Hygienic Macros🔗ℹ

 #lang zuo/hygienic

The zuo/hygienic language provides the same set of bindings as zuo/base, but with hygienic macros. Its macro-expansion protocol uses a different representation of identifiers and binding scope, and different rules for quote-syntax and macros:

  • A zuo/hygienic term’s representation always uses identifier syntax objects in place of symbols. A macro will never receive a plain symbol in its input, and if the macro produces a term with plain symbol, it is automatically coerced to a syntax object using the scope of the module that defines the macro.

  • A syntax object’s context includes a set of scopes, instead of just one scope. Before expanding forms in a new context, a fresh scope representation is added to every identifier appearing within the context. An reference is resolved by finding the binding identifier with the most specific set of scopes that is a subset of the referencing identifier’s scopes.

  • In addition to binding contexts, a specific macro invocation is also represented by a scope: a fresh scope is added to every syntax object introduced by a macro expansion. This fresh scope means that an identifier introduced by the expansion can only bind identifiers that were introduced by the same expansion. Meanwhile, a quote-syntax-imposed scope on an introduced identifier prevents it from being bound by an identifier that’s at the macro-use site and not visible at the macro-definition site.

  • The quote-syntax form produces an identifier syntax object with all of its scope intact. That syntax object acquires additional scope if it is returned from a macro expander into a new context.

These differences particularly affect the functions that operate on syntax objects:

procedure

(identifier? v)  boolean?

  v : any/c

procedure

(syntax-e v)  symbol?

  v : identifier?

procedure

(syntax->datum v)  any/c

  v : any/c

procedure

(datum->syntax ctx v)  any/c

  ctx : identifier?
  v : any/c

procedure

(bound-identifier=? id1 id2)  boolean?

  id1 : identifier?
  id2 : identifier?
Unlike the zuo function, identifier? does not recognize a plain symbol as an identifier. The datum->syntax function converts symbols in v to syntax objects using the context of ctx.