Book

Chapter 1 abstract syntax

Modified just now
  • Programming languages describe computations for humans and machines.

  • Syntax explains how phrases form programs, but "syntax" actually has layers:

    • Concrete (surface) syntax: how code is written/displayed as character strings (ASCII/Unicode).

      -> Ignored.

    • Abstract (structural) syntax: the program's tree structure (ASTs) showing how phrases are built from operators and subphrases.

    • Binding structure: how identifiers are declared and used-binding and scope-captured by enriching ASTs into abstract binding trees (ABTs).

      -> Defines precise operations/relations on ABTs to formalize binding and scope - topics that are tricky, bug-prone in implementations.

Abstract syntax trees (ASTs)

General

  • An AST is an ordered tree:

    • Leaves: Variables/Operators.

    • Interior nodes: Operators.

      Children: Arguments.

  • An AST is classified into sorts corresponding to different forms of syntax.

  • A variable stands for an unspecified, or generic, piece of syntax of a specified sort.

  • Operator:

    • Can be used to combine ASTs.

    • Have an arity specifying the sort of the operator & the number and sorts of its arguments.

      Example: An operator of sort ss and arity s1,,sns_1, \dots, s_n combines n0n \geq 0 AST's of sort s1,,sns_1, \dots , s_n, respectively, into a compound AST of sort ss.

Variables

  • Definition: An unknown object drawn from a domain.

  • The unknown can become known by substitution of a particular object for all occurrences of a variable in a formula.

    -> Specializing a general formula to a particular instance.

Sorts

  • Abstract syntax tree (AST)s are classified by sorts that divide ASTs into Syntactic categorys.

  • Example 1

    Familiar programming languages often have a syntactic distinction between expressions and commands.

    -> 2 sorts of abstract syntax trees.

    -> Variables in abstract syntax trees range over Sorts in the sense that only AST's of the specified sort of the variable can be plugged in for that variable.

    -> It would make no sense to replace an expression variable by a command, nor a command variable by an expression, the two being different sorts of things.

  • Example 2

    A language of arithmetic expressions built from numbers, addition, multiplication.

    The abstract syntax:

    • An operator num[n]\text{num}[n] of sort Exp\text{Exp} for each number nNn \in \mathbb{N}.

    • Two operators, times\text{times} and plus\text{plus}, each of sort Exp\text{Exp}, each with two arguments of sort Exp\text{Exp}.

      -> 2+(3×x)2 + (3 \times x) has the abstract syntax plus(num[2]; times(num[3];x))\text{plus}(\text{num}[2];\ \text{times}(\text{num}[3]; x)).

      -> If xx has sort Exp\text{Exp}, then plus(num[2]; times(num[3];x))\text{plus}(\text{num}[2];\ \text{times}(\text{num}[3]; x)) also has sort Exp\text{Exp}.

  • The tree structure of Abstract syntax tree (AST) allows Structural induction.

    Suppose that we wish to prove that some property P(a)P(a) holds for all ASTs aa of a given sort. To show this, it is enough to consider all the ways in which aa can be generated and show that the property holds in each case under the assumption that it holds for its constituent ASTs (if any).

Precise definitions

  • S\mathcal{S}: A finite set of Sorts.

  • An Arity has the form (s1,,sn)s(s_1, \dots , s_n)s, which specifies the sort sSs \in S of an Operator taking n0n \geq 0 arguments, each of sort siSs_i \in S.

  • Let O={ Oα }\mathcal{O} = \{\ \mathcal{O}_\alpha\ \} be an arity-indexed family of disjoint sets of operators Oα\mathcal{O}_\alpha of arity α\alpha.

  • If oo is an Operator of Arity (s1,,sn)s(s_1, \dots , s_n)s, we say that oo has Sort ss and has nn arguments of sorts s1,,sns_1, \dots , s_n.

  • Let X={ Xs }sS\mathcal{X} = \{\ \mathcal{X}_s \ \}_{s \in \mathcal{S}} be a sort-indexed family of disjoint finite sets Xs\mathcal{X}_s of variables xx of sort ss. When X\mathcal{X} is clear from context, we say that:

    • A variable xx is of sort ss if xXsx \in \mathcal{X}_s.
    • A xx is fresh for X\mathcal{X}, or just fresh when X\mathcal{X} is understood, if xXsx \notin \mathcal{X}_s for any sort ss.
  • If xx is fresh for X\mathcal{X} and ss is a sort, then X,x\mathcal{X} , x is the family of sets of variables obtained by adding xx to Xs\mathcal{X}_s.

    The notation is ambiguous in that the sort ss is not explicitly stated but determined from context.

  • The family A[X]={ A[X]s }sS\mathcal{A}[\mathcal{X}] = \{\ \mathcal{A}[\mathcal{X}]_s\ \}_{s \in \mathcal{S}} of abstract syntax trees of sort ss is the smallest family satisfying the following conditions:

    1. A variable of sort ss is an AST of sort ss: if xXsx \in \mathcal{X}_s, then xA[X]sx \in \mathcal{A}[\mathcal{X}]_s.
    2. Operators combine ASTs: if oo is an operator of arity (s1,,sn)s(s_1, \dots , s_n)s, and if a1A[X]s1,,anA[X]sna_1 \in \mathcal{A}[\mathcal{X}]_{s_1}, \dots , a_n \in \mathcal{A}[\mathcal{X}]_{s_n}, then o(a1;;an)A[X]so(a_1 ; \dots ; a_n) \in \mathcal{A}[\mathcal{X}]_s.
  • Variables are given meaning by substitution.

    • If aA[X,x]sa \in \mathcal{A}[\mathcal{X}, x]_{s'} and bA[X]sb \in \mathcal{A}[\mathcal{X}]_s, then [b/x]aA[X]s[b/x]a \in \mathcal{A}[\mathcal{X}]_{s'} is the result of substituting bb for every occurrence of xx in aa.

    • The AST aa is called the target, and xx is called the subject, of the substitution.

    • Substitution is defined by the following equations:

      1. [b/x]x=b[b/x]x = b and [b/x]y=y[b/x]y = y if xyx \not= y.
      2. [b/x]o(a1;;an)=o([b/x]a1;;[b/x]an)[b/x]o(a_1 ; \dots ;a_n) = o([b/x]a_1 ; \dots ;[b/x]a_n).

TIP

Theorem. If aA[X,x]a \in \mathcal{A}[\mathcal{X}, x], then for every bA[X]b \in \mathcal{A}[\mathcal{X}] there exists a unique cA[X]c \in \mathcal{A}[\mathcal{X}] such that [b/x]a=c[b/x]a=c.

Proof

Base step:

  • a=ya = y, with yXy \in \mathcal{X}.

Then, [b/x]a=y[b/x]a = y.

-> Trivially hold.

  • a=xa = x.

Then, [b/x]a=b[b/x]a =b.

-> Trivially hold.

Inductive step: a=o(a1;;an)a = o(a_1; \dots; a_n).

Then, [b/x]a=o([b/x]a1;;[b/x]an)=o(c1;;cn)[b/x]a = o([b/x]a_1; \dots;[b/x]a_n) = o(c_1; \dots; c_n), where c1,,cnc_1, \dots,c_n are unique.

-> Hold.

Abstract binding trees (ABTs)

General (ABTs)

  • Abstract binding tree (ABT) enrichs AST with the means to introduce new variables and symbols (Bindings), with a specified range of significance (Scope).

  • The scope of a binding is an ABT within which the bound identifier can be used, either as a place-holder (in the case of a variable declaration) or as the index of some operator (in the case of a symbol declaration).

    • The set of active identifiers can be larger within a subtree of an ABT than it is within the surrounding tree.

    • Different subtrees may introduce identifiers with disjoint scopes.

      -> The crucial principle is that any use of an identifier should be understood as a reference, or abstract pointer, to its binding.

      -> The choice of identifiers is immaterial, so long as we can always associate a unique binding with each use of an identifier.

  • Renaming of bound variables is constrained to the extent that it must not alter the reference structure of the expression.

    • Example

      The expression let x be 2 in let y be 3 in x+x\text{let}\ x\ \text{be}\ 2\ \text{in}\ \text{let}\ y\ \text{be}\ 3\ \text{in}\ x + x has a different meaning than the expression let y be 2 in let y be 3 in y+y\text{let}\ y\ \text{be}\ 2\ \text{in}\ \text{let}\ y\ \text{be}\ 3\ \text{in}\ y + y, because the yy in the expression y+yy + y in the second case refers to the inner declaration, not the outer one as before.

  • ABT = AST + binding + scope.

    • Allow an operator to bind any finite number (possibly zero) of variables in each argument.

    • An argument to an operator is called an Abstractor and has the form x1,,xk.ax_1, \dots , x_k.a.

      The sequence of variables x1,,xkx_1, \dots , x_k are bound within the ABT aa.

      (When kk is zero, we elide the distinction between .a.a and aa itself)

      Example: The expression let x be a1 in a2\text{let}\ x\ \text{be}\ a_1\ \text{in}\ a_2 has the form let(a1;x.a2)\text{let}(a_1; x.a_2).

      -> Clearly specifies that the variable xx is bound within a2a_2, and not within a1a_1.

  • We often write x\vec{x} to stand for a finite sequence x1,,xnx_1, \dots , x_n of distinct variables and write x.a\vec{x}.a to mean x1,,xn.ax_1, \dots , x_n .a.

  • To account for binding, operators are assigned generalized arities of the form (v1,,vn)s(v_1, \dots , v_n)s, which specifies operators of sort ss with nn arguments of valence v1,,vnv_1, \dots, v_n.

  • A valence vv has the form s1,,sk.ss_1, \dots , s_k .s, which specifies:

    • The sort of an argument.

    • The number and sorts of the variables bound within it.

      -> A sequence x\vec{x} of variables is of sort s\vec{s} = The two sequences have the same length kk and that the variable xix_i is of sort sis_i for each 1ik1 \leq i \leq k.

  • The operator let\text{let} has arity (Exp,Exp.Exp)Exp(\text{Exp}, \text{Exp}.\text{Exp})\text{Exp}.

    -> let\text{let} is of sort Exp\text{Exp} whose:

    • First argument is of sort Exp\text{Exp} and binds no variables.
    • Second argument is also of sort Exp\text{Exp} and within which is bound one variable of sort Exp\text{Exp}.
  • Example: let x be 2+2 in x×x\text{let}\ x\ \text{be}\ 2 + 2\ \text{in}\ x \times x = let(plus(num[2];num[2]);x.times(x;x))\text{let}(\text{plus}(\text{num}[2];\text{num}[2]); x.\text{times}(x;x)).

Precise definitions (ABTs)

  • Fix a set S\mathcal{S} of sorts and a family O\mathcal{O} of disjoint sets of operators indexed by their generalized arities.

  • For a given family of disjoint sets of variables X\mathcal{X}, B[X]\mathcal{B}[\mathcal{X}] is the family of ABTs.

    This is surprisingly hard to make precise.

    • The first definition attempt

      B[X]\mathcal{B}[\mathcal{X}] is the least family of sets closed under the following conditions:

      1. If xXsx \in \mathcal{X}_s , then xB[X]sx \in \mathcal{B}[\mathcal{X}]_s.

      2. For each operator oo of arity (s1.s1,,sn.sn)s(\vec{s_1}.s_1, \dots , \vec{s_n} .s_n)s, if a1B[X,x1]s1a_1 \in \mathcal{B}[\mathcal{X}, \vec{x_1} ]_{s_1}, ..., and anB[X,xn]sna_n \in \mathcal{B}[\mathcal{X}, \vec{x_n}]_{s_n}, then o(x1.a1;;xn.an)B[X]so(\vec{x_1}.a_1 ; \dots ;\vec{x_n}.a_n) \in \mathcal{B}[\mathcal{X}]_s.

        -> Almost correct, but fails to account for renaming of bound variables: If xXx \in \mathcal{X}, then we cannot introduce another xx.

        -> An ABT of the form let(a1;x.let(a2;x.a3))\text{let}(a_1 ; x.\text{let}(a_2 ; x.a_3 )) is ill-formed according to this definition, because the first binding adds xx to X\mathcal{X}, which implies that the second cannot also add xx to X,x\mathcal{X}, x, because it is not fresh for X,x\mathcal{X} , x.

        -> Goal: Ensure that each of the arguments is well-formed regardless of the choice of bound variable names.

        -> Achieved using fresh renaming - a bijection between sequences of variables.

  • A fresh renaming (relative to X\mathcal{X}) of a finite sequence of variables x\vec{x} is a bijection ρ:xx\rho : \vec{x} \leftrightarrow \vec{x}' between x\vec{x} and x\vec{x}', where x\vec{x}' is fresh for X\mathcal{X}.

    -> ρ^(a)\hat{\rho}(a) is the result of replacing each occurrence of xix_i in aa by ρ(xi)\rho(x_i), its fresh counterpart.

  • B[X]\mathcal{B}[\mathcal{X}] is the least family such that:

    1. If xXsx \in \mathcal{X}_s then xB[X]sx \in \mathcal{B}[\mathcal{X}]_s.

    2. For each operator oo of arity (s1.s1,,sn.sn)s(\vec{s_1}.s_1, \dots, \vec{s_n}.s_n)s, if for each 1in1 \le i \le n and each fresh renaming ρi:xixi\rho_i:\vec{x}_i \leftrightarrow \vec{x}'_i, we have ρ^i(ai)B[X,xi]\hat{\rho}_i(a_i) \in \mathcal{B}[\mathcal{X}, \vec{x}_i'], then o(x1.a1;;xn.an)B[X]so(\vec{x}_1.a_1; \dots; \vec{x}_n.a_n) \in \mathcal{B}[\mathcal{X}]_s.

      -> The renaming ρ^i(ai)\hat{\rho}_i (a_i) of each aia_i ensures that collisions cannot occur and that the ABT is valid for almost all renamings of any bound variables that occur within it.

  • The principle of structural induction extends to ABTs and is called Structural induction modulo fresh renaming.

    It states that to show that P[X](a)\mathcal{P}[\mathcal{X}](a) holds for every aB[X]a \in \mathcal{B}[\mathcal{X}], it is enough to show the following:

    1. If xXsx \in \mathcal{X}_s, then P[X]s(x)\mathcal{P}[\mathcal{X}]_s(x).
    2. For every oo of arity (s1.s1;;sn.sn)s(\vec{s}_1.s_1; \dots ; \vec{s}_n.s_n)s, if for each 1in1 \leq i \leq n, P[X,xi]si(ρ^i(ai))\mathcal{P}[\mathcal{X}, \vec{x}'_i]_{s_i}(\hat{\rho}_i(a_i)) holds for every ρi:xixi\rho_i : \vec{x}_i \leftrightarrow \vec{x}'_i with xiX\vec{x}'_i \notin \mathcal{X}, then P[X]s(o(x1.a1;;xn.an))\mathcal{P}[\mathcal{X}]_s (o(\vec{x}_1.a_1 ; \dots ;\vec{x}_n .a_n)).
    • Subtlety

      • How does this handle free variables in subterms?

        Question:

        Consider λx. λy. y+x\lambda x.\ \lambda y.\ y + x. When applying structural induction at the outer λx\lambda x, we need the induction hypothesis to hold for the subterm λy. y+x\lambda y.\ y + x. But in this subterm, xx is free. How does the principle account for free variables that arise when we descend under binders?

        Answer:

        The property P\mathcal{P} is parameterized by a set of variables X\mathcal{X}, written P[X]\mathcal{P}[\mathcal{X}]. This parameter tracks which free variables are "permitted" in the terms under consideration.

        When you descend under the binder λx\lambda x, the principle applies a fresh renaming ρ:xx\rho : x \leftrightarrow x' where xXx' \notin \mathcal{X}. The induction hypothesis then states that P[X,x]\mathcal{P}[\mathcal{X}, x'] holds for the renamed subterm λy. y+x\lambda y.\ y + x'.

        The key insight: the extended parameter set X{x}\mathcal{X} \cup \{x'\} now includes xx', legitimizing its occurrence as a free variable in the subterm. So the induction hypothesis isn't required to hold for subterms with arbitrary free variables-only for subterms whose free variables are contained in the extended set X{x}\mathcal{X} \cup \{x'\}.

        This is precisely what the notation P[X,xi]si(ρi(ai))\mathcal{P}[\mathcal{X}, \vec{x}'_i]_{s_i}(\rho_i(a_i)) expresses: the property relativized to a variable set that has been extended with the fresh renamings of the bound variables.

  • α-equivalence: The relation a=αba =_\alpha b means that aa and bb are identical up to the choice of bound variable names.

    The α-equivalence relation is the strongest congruence containing the following two conditions:

    • x=αxx =_\alpha x.

    • o(x1.a1;;xn.an)=αo(x1.a1;;xn.an)o(\vec{x}_1.a_1; \ldots; \vec{x}_n.a_n) =_\alpha o(\vec{x}'_1.a'_1; \ldots; \vec{x}'_n.a'_n) if for every 1in1 \leq i \leq n, ρ^i(ai)=αρ^i(ai)\hat{\rho}_i(a_i) =_\alpha \hat{\rho}'_i(a'_i) for all fresh renamings ρi:xizi\rho_i : \vec{x}_i \leftrightarrow \vec{z}_i and ρi:xizi\rho'_i : \vec{x}'_i \leftrightarrow \vec{z}_i.

      The idea is that:

    1. We rename xi\vec{x}_i and xi\vec{x}'_i consistently to common fresh names, avoiding confusion.
    2. We check that aia_i and aia'_i are α-equivalent.
  • If a=αba =_\alpha b, then aa and bb are α-variants of each other.

  • Substitution: The substitution of an ABT bb of sort ss for free occurrences of a variable xx of sort ss in some ABT aa, written [b/x]a[b/x]a, is partially defined by:

    • [b/x]x=b[b/x]x = b, and [b/x]y=y[b/x]y = y if xyx \neq y.

    • [b/x]o(x1.a1;;xn.an)=o(x1.a1;;xn.an)[b/x]o(\vec{x}_1.a_1; \ldots; \vec{x}_n.a_n) = o(\vec{x}_1.a'_1; \ldots; \vec{x}_n.a'_n), where for each 1in1 \leq i \leq n, we require that xib\vec{x}_i \notin b, and we set ai=[b/x]aia'_i = [b/x]a_i if xxix \notin \vec{x}_i, and ai=aia'_i = a_i otherwise.

    • Pitfall 1 - bound variables block substitution

      If xx is bound by an abstractor within aa, then xx does not occur free within the abstractor and hence is unchanged by substitution.

      For example, [b/x]let(a1;x.a2)=let([b/x]a1;x.a2)[b/x]\text{let}(a_1; x.a_2) = \text{let}([b/x]a_1; x.a_2), there being no free occurrences of xx in x.a2x.a_2.

    • Pitfall 2 - variable capture

      If yby \in b and xyx \neq y, then [b/x]let(a1;y.a2)[b/x]\text{let}(a_1; y.a_2) is undefined, rather than being let([b/x]a1;y.[b/x]a2)\text{let}([b/x]a_1; y.[b/x]a_2).

      For example, provided that xyx \neq y, [y/x]let(num[0];y.plus(x;y))[y/x]\text{let}(\text{num}[0]; y.\text{plus}(x; y)) is undefined, not let(num[0];y.plus(y;y))\text{let}(\text{num}[0]; y.\text{plus}(y; y)), which confuses two different variables named yy.

  • Avoiding capture: Capture can always be avoided by first renaming the bound variables in aa to avoid any free variables in bb.

    Example: If we rename the bound variable yy to yy' to obtain a=let(num[0];y.plus(x;y))a' = \text{let}(\text{num}[0]; y'.\text{plus}(x; y')), then [y/x]a[y/x]a' is defined and equals let(num[0];y.plus(y;y))\text{let}(\text{num}[0]; y'.\text{plus}(y; y')).

    The price is that substitution is only determined up to α-equivalence.

  • The identification convention: Abstract binding trees are always identified up to α-equivalence.

    That is, α-equivalent ABTs are regarded as identical.

    Substitution can be extended to α-equivalence classes by choosing representatives such that substitution is defined, then forming the equivalence class of the result.

    Any two valid choices give α-equivalent results, so substitution becomes a well-defined total function.

  • Symbols:

    • Motivation: It will often be necessary to consider languages whose abstract syntax cannot be specified by a fixed set of operators but rather requires that the available operators be sensitive to the context in which they occur.

    • A symbolic parameter, or symbol, indexes families of operators.

    • An indexed operator oo is a family of operators indexed by symbols uu, so that o[u]o[u] is an operator when uu is an available symbol.

    • If UU is a finite set of symbols, then B[U;X]\mathcal{B}[U; \mathcal{X}] is the family of ABTs generated by operators and variables, admitting all indexed operator instances by symbols uUu \in U.

      • A variable is a placeholder that stands for an unknown ABT of its sort.

      • A symbol does not stand for anything and is not itself an ABT.

        The only significance of a symbol is whether it is the same as or differs from another symbol.

    • The set of symbols is extended by introducing a new, fresh symbol within a scope using the abstractor u.au.a, which binds the symbol uu within the ABT aa.

    • The only difference between symbols and variables is that the only operation on symbols is renaming; there is no notion of substitution for a symbol.

  • Notation convention: Arguments to operators can be visually grouped using braces and parentheses (e.g., o{a1;a2}(a3;x.a4)o\{a_1; a_2\}(a_3; x.a_4)), with stages progressing right to left. This is purely a readability aid-it has no semantic significance. The grouped form is identical to the flat form o(a1;a2;a3;x.a4)o(a_1; a_2; a_3; x.a_4).

  • Historical notes:

    • Abstract syntax originates with Church, Turing, and Gödel, who first considered programs acting on representations of programs.
    • Programs were initially encoded as natural numbers via Gödel-numberings based on prime factorization (Kleene, 1952).
    • Lisp introduced a more practical representation as symbolic expressions (McCarthy, 1965; Allen, 1978).
    • ML added a type system capable of expressing abstract syntax trees (Gordon et al., 1979).
    • AUTOMATH introduced using Church's λ notation to handle binding and scope (Church, 1941; Nederpelt et al., 1994), developed further in LF (Harper et al., 1993).
    • Abstract binding trees here were inspired by NuPRL's notation (Constable, 1986) and Martin-Löf's system of arities (Nordström et al., 1990).
    • Symbol binders are influenced by (Pitts and Stark, 1993).

Exercises

Exercise 1.1

Problem statement. Prove by structural induction on abstract syntax trees that if XY\mathcal{X} \subseteq \mathcal{Y}, then A[X]A[Y]\mathcal{A}[\mathcal{X}] \subseteq \mathcal{A}[\mathcal{Y}].

Proof

Consider an AST aXA[X]a_\mathcal{X} \in \mathcal{A}[\mathcal{X}]. We will prove that aXA[Y]a_\mathcal{X} \in \mathcal{A}[\mathcal{Y}].

  • If aXXa_\mathcal{X} \in \mathcal{X} then aXYA[Y]a_\mathcal{X} \in \mathcal{Y} \subseteq \mathcal{A}[\mathcal{Y}].
  • If aX=o(x1;;xn)a_\mathcal{X} = o(x_1; \dots; x_n), then by the induction hypothesis, xiA[Y]x_i \in \mathcal{A}[\mathcal{Y}]. By definition, aX=o(x1;;xn)A[Y]a_\mathcal{X} = o(x_1;\dots; x_n) \in \mathcal{A}[\mathcal{Y}].

Therefore, A[X]A[Y]\mathcal{A}[\mathcal{X}]\subseteq \mathcal{A}[\mathcal{Y}].

Exercise 1.2

Problem statement. Prove by structural induction modulo renaming on abstract binding trees that if XY\mathcal{X} \subseteq \mathcal{Y}, then B[X]B[Y]\mathcal{B}[\mathcal{X}] \subseteq \mathcal{B}[\mathcal{Y}].

Proof

Given two sets of variables X\mathcal{X} and Y\mathcal{Y}, for an ABT bB[X]b \in \mathcal{B}[\mathcal{X}], denote P[X,Y](b)=bB[Y]P[\mathcal{X}, \mathcal{Y}](b) = b \in \mathcal{B}[\mathcal{Y}].

We'll prove that XY\mathcal{X} \subseteq \mathcal{Y} implies bB[X]. P[X,Y](b)\forall b\in \mathcal{B}[\mathcal{X}].\ P[\mathcal{X}, \mathcal{Y}](b).

We perform induction on the structure of bB[X]b \in \mathcal{B}[\mathcal{X}]:

  • If bXb \in \mathcal{X}, it's obvious that P[X,Y](b)P[\mathcal{X}, \mathcal{Y}](b), for all XY\mathcal{X}\subseteq \mathcal{Y}.
  • Suppose b=o(x1.a1;;xn.an)b = o(\vec{x}_1.a_1;\dots;\vec{x}_n.a_n).

Consider a fresh renaming ρi:xixi\rho_i : \vec{x}_i \leftrightarrow \vec{x}'_i relative to both X\mathcal{X} and Y\mathcal{Y}.

It's trivial to see that XxiYxi\mathcal{X} \cup \vec{x}_i' \subseteq \mathcal{Y} \cup \vec{x}_i' and ρ^i(ai)B[X]\hat{\rho}_i(a_i) \in \mathcal{B}[\mathcal{X}].

The induction hypothesis is that P[Xxi,Yxi](ρi^(ai))P[\mathcal{X} \cup \vec{x}'_i, \mathcal{Y} \cup \vec{x}'_i](\hat{\rho_i}(a_i)), or ρ^i(ai)B[Y]\hat{\rho}_i(a_i)\in \mathcal{B}[\mathcal{Y}].

By definition, bB[Y]b \in \mathcal{B}[\mathcal{Y}].

Exercise 1.3

Problem statement. Show that if a=αaa =_\alpha a' and b=αbb =_\alpha b' and both [b/x]a[b/x]a and [b/x]a[b'/x]a' are defined, then [b/x]a=α[b/x]a[b/x]a =_\alpha [b'/x]a'.

Proof

By definition, [b/x]a[b/x]a and [b/x]a[b'/x]a' are defined.

  • If a=xXa = x \in \mathcal{X}, then a=xa' = x.

Therefore, [b/x]a=b=αb=[b/x]a[b/x]a = b =_\alpha b' = [b'/x]a'.

  • If a=yXa = y \in \mathcal{X} and xyx \neq y, then a=ya' = y.

Therefore, [b/x]a=a=[b/x]a[b/x]a = a = [b'/x]a'.

  • If a=o(x1.a1;;xn.an)a = o(\vec{x}_1.a_1;\dots;\vec{x}_n.a_n), then a=o(x1.a1;;xn.an)a' = o(\vec{x}'_1.a_1';\dots;\vec{x}'_n.a_n'), such that for all 1in1 \le i \le n, ρ^i(ai)=αρ^i(ai)\hat{\rho}_i(a_i) =_\alpha \hat{\rho}_i'(a_i') for all fresh renamings ρi:xizi\rho_i : \vec{x}_i \leftrightarrow \vec{z}_i and ρi:xizi\rho'_i : \vec{x}'_i \leftrightarrow \vec{z}_i.

Because [b/x]a[b/x]a is defined, we have xib\vec{x}_i \notin b, and similarly, xib\vec{x}_i' \notin b'.

Therefore, [b/x]a=o(x1.c1;;xn.cn)[b/x]a = o(\vec{x}_1. c_1;\dots;\vec{x}_n.c_n), where ci=[b/x]aic_i = [b/x]a_i if xxix \notin \vec{x}_i, or ci=aic_i = a_i otherwise.

Similarly, [b/x]a=o(x1.c1;;xn.cn)[b'/x]a' = o(\vec{x}'_1. c'_1;\dots;\vec{x}'_n.c'_n), where ci=[b/x]aic'_i = [b'/x]a'_i if xxix \notin \vec{x}'_i, or ci=aic'_i = a'_i otherwise.

By induction, [b/x]a=α[b/x]a[b/x]a =_\alpha [b'/x]a'.

Exercise 1.4

Problem statement. Bound variables can be seen as the formal analogs of pronouns in natural languages. The binding occurrence of a variable at an abstractor fixes a "fresh" pronoun for use within its body that refers unambiguously to that variable (in contrast to English, in which the referent of a pronoun can often be ambiguous). This observation suggests an alternative representation of ABTs, called abstract binding graphs, or ABGs for short, as directed graphs constructed as follows:

(a) Free variables are atomic nodes with no outgoing edges.

(b) Operators with nn arguments are nn-ary nodes, with one outgoing edge directed at each of their children.

(c) Abstractors are nodes with one edge directed to the scope of the abstracted variable.

(d) Bound variables are back edges directed at the abstractor that introduced it.

Notice that ASTs, thought of as ABTs with no abstractors, are acyclic directed graphs (more precisely, variadic trees), whereas general ABTs can be cyclic. Draw a few examples of ABGs corresponding to the example ABTs given in this chapter. Give a precise definition of the sort-indexed family G[X]\mathcal{G}[\mathcal{X}] of abstract binding graphs. What representation would you use for bound variables (back edges)?

Proof