Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Notation reference

This book gives a language its meaning with inference rules: compact statements of the form if these facts hold, then this following fact holds. This section explains how to read them and collects the various notations the book uses to formally define semantics. While each notation is introduced and explained when first introduced, this section collects all such notations in one place.

Reading an inference rule

A rule is written with a horizontal line. The statements above the line are its premises, the statement below is its conclusion, and the name on the right identifies the rule:

Read it downward: when every premise holds, the conclusion holds. The premises are the assumptions the conclusion rests on.

A rule with nothing above the line is an axiom. Its conclusion stands on its own, with nothing to assume. A numeric literal evaluates to itself (writing for evaluates to):

When a rule does carry premises, they are the facts that must already hold for it to apply. Addition evaluates each operand, then combines the two results:

Derivations

A premise is itself a conclusion: it holds for some reason, and that reason is another rule. Stacking the rules that justify one another produces a derivation — a tree whose leaves are axioms and whose root is the fact you set out to establish. A derivation is a proof that the judgment at its root holds.

Evaluating builds this tree:

Each leaf is an axiom; each step combines two values already derived; the root is the value of the whole expression. Every step is licensed by a rule, so no line of the tree is taken on faith. When the same shape of derivation recurs, it can be recorded as a single derived rule and used directly wherever that shape appears.

Metavariables

The rules use single letters as metavariables — placeholders that range over a kind of object. A subscript or a prime distinguishes several of the same kind (, , , ).

SymbolRanges over
expressions
integer literals
variable names
values — the result of evaluation
environments (below)
stores (below)
locations — the identity of a store cell

Evaluating expressions

The central judgment of the semantics is

read in environment , expression evaluates to value . The environment records the value of each variable in scope, which is what a variable needs in order to evaluate:

Every rule threads the same through its premises, since a subexpression is evaluated in the same scope as the expression containing it:

An expression with no variables evaluates to the same value under any environment; the arithmetic derivations above drop for that reason and write .

Threading a store

Once a program can create and overwrite a memory cell, the value of an expression depends on what the cells hold, and evaluating an expression can change them. The store — a finite map from locations to values — records those cells, and the judgment carries it, taking one store in and handing one out:

read in environment , evaluating against the store yields the value and leaves the store . The environment goes in but does not come back, since evaluating an expression cannot rebind a name; the store goes in and comes out, since evaluating an expression can change a cell. Threading it left to right through a rule’s premises also fixes the order the subexpressions run in — each premise evaluates against the store the one before it produced:

A form that writes no cell of its own, like , threads the store through unchanged; the forms that create, read, and write a cell are in the mutation chapter. A program that uses no cell leaves the store the same coming out as going in, and the earlier judgment is that case with the store left implicit. The language reference states the judgment in full, threading the relation database and the outcome of a return alongside the store.