Variables #
The memory model of programs and procedures:
VariableName— a program variable's name together with its type (see below).VariableAssignment— a value for everyVariableName, withVariableAssignment.initas the initial (unspecified) assignment, andvarLens vonto the slot ofv. TwovarLensare disjoint by instance search when the names are literals that differ.ProgramState— theglobalsand thelocalsof the running procedure, both aVariableAssignment, withglobalL/localLandLens.intoGlobal/Lens.intoLocal.VariableAssignment.setParams— write an argument tuple into the parameter slots.VariableAssignment.embed/rename— view an assignment through an injective name map (types are kept, so no casts), used for flattening.global_var x : T— declares the global variablex, the slot of⟨"N.x", T⟩in the globals (N.xthe full declaration name), disjoint from all other globals by instance search (Lens.IsGlobalVar).
Variable names #
A VariableName is a program variable's name together with its type. Besides the name it
carries a natural-number key, the name's encoding VariableName.encode name, stored as a
literal. The key exists for instance search: two names with different literal keys are
told apart by VariableName.NameNe in a single unification step, whatever their length, which
is what lets disjointness of two variables be found automatically. (Instance search cannot
compare strings in one step: a string literal is opened into a list of characters, and every
character then costs a step and a level of recursion. Nat literals are the one kind of data
the unifier has built-in arithmetic for.)
key and its correctness proof keyCorrect are filled in automatically: key is an implicit
argument of the constructor, and the variable_name_key tactic behind keyCorrect evaluates
encode name when name is a string literal and assigns key the resulting literal. So one
writes ⟨"x", Int⟩ or { name := "x", type := Int } and gets @VariableName.mk "x" Int 121 ⋯.
Argument tuples #
Defined here rather than in Programs.lean, which builds on this file.
Reducible on purpose: at a concrete parameter list the tuple type has to be visible to
unification at reducible transparency, or everything stated about _ × _ gets stuck on it —
typeclass resolution (OfNat (typeListToTuple [Nat]) 5 for a numeral argument of a call,
Lens.Disjoint of two projection lenses) is where it shows.
Equations
- GaudisCrypt.typeListToTuple [] = Unit
- GaudisCrypt.typeListToTuple [x_1] = x_1
- GaudisCrypt.typeListToTuple (x_1 :: xs) = (x_1 × GaudisCrypt.typeListToTuple xs)
Instances For
Variable names #
Bijective base-0x110000 numeration of a character list, least significant digit first:
character c is the digit c.toNat + 1 (in 1 … 0x110000, since a code point is below
0x110000), and the empty list is 0. Reduces by rfl in the kernel on literals (the
corresponding encoding of the UTF-8 bytes does not: String.toUTF8 gets stuck).
Equations
- GaudisCrypt.VariableName.encodeChars [] = 0
- GaudisCrypt.VariableName.encodeChars (c :: cs) = c.toNat + 1 + 1114112 * GaudisCrypt.VariableName.encodeChars cs
Instances For
The key of a variable name: an injective, computable encoding of strings as naturals
(encode_injective). Quadratic in the length of the string — each step multiplies the
accumulated number, about 21 bits per character, by a constant — which is microseconds at any
plausible name length. (An O(n log n) version is possible: with base 2 ^ 21, merge
neighbouring blocks with a ||| (b <<< w) in log n passes, each pass recursing on the list
and the passes on a counter. Both recursions are structural, so it still reduces by rfl,
which variable_name_key relies on. Splitting at the midpoint instead would need well-founded
recursion, which does not reduce.)
Instances For
Close ?key = VariableName.encode name. If name is a string literal, compute the
encoding and assign ?key the resulting Nat literal, so that instance search can compare
keys. Otherwise ?key becomes VariableName.encode name itself: the name is still a valid
variable name, but VariableName.NameNe will not be found for it by instance search.
Equations
- GaudisCrypt.tacticVariable_name_key = Lean.ParserDescr.node `GaudisCrypt.tacticVariable_name_key 1024 (Lean.ParserDescr.nonReservedSymbol "variable_name_key" false)
Instances For
VariableName.encode "x" ↦ the literal variable_name_key assigns for "x". A slot built
from a name that is a variable (as in setParams) carries the key encode n, and once n is
instantiated to "x" it is still encode "x", while the slot localVarLens "x" T written in a
program carries the literal. The two are defeq but not syntactically equal, so without this
simp treats them as different slots (Function.update_self does not fire). The rewrite
is by rfl: encode reduces on literals. A dsimproc, not a simproc: the key is an argument
other arguments depend on (keyCorrect, and the value written in a Function.update), and
simp rewrites such positions only with definitional steps.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A program variable's name and type. key is encode name as a literal and is filled in
automatically, together with its proof (see the module docstring). Two VariableNames are
equal iff their names and types are (nonempty is a proposition, and key/keyCorrect are
determined by the name).
The type has to be nonempty, so that an assignment of values to all variable names exists at
all (VariableAssignment.init). The instance is found by instance search.
Instances For
The variable name n : T as a term, the way localVarLens "n" T elaborates it: the
Nonempty T instance synthesized (unless given), the key the literal variable_name_key
computes. For meta code that makes up variables (hoare_proc_to_stmt, flattening).
Equations
- One or more equations did not get rendered due to their size.
Instances For
a < b, for natural-number literals, found by instance search in one step: unifying
?k + a + 1 =?= b is solved by the unifier's literal-offset rule as ?k := b - a - 1, at any
size of the literals. (The unknown has to be the leftmost summand for that rule to apply.)
Instances
Two variable names whose names differ. Found by instance search from the literal keys,
for names given as constructor applications (as ⟨"x", Int⟩ elaborates); since encode is
injective, it is found exactly when the names differ.
Instances
A variable name is determined by its name and type.
Variable assignments #
A value for every variable name. Inhabited (init) because every VariableName has a
nonempty type. Reducible, so that m v typechecks at every transparency (rewriting needs
this).
Equations
- GaudisCrypt.VariableAssignment = ((v : GaudisCrypt.VariableName) → v.type)
Instances For
The initial assignment: an unspecified value in every slot.
Equations
Instances For
Equations
Reading a slot under a renamed variable name, when the new name is the old one.
The lens onto the slot of variable v. Writing uses Function.update, with classical
decidable equality of variable names (their types are arbitrary, so there is no other).
Equations
- One or more equations did not get rendered due to their size.
Instances For
Slots of different variable names are disjoint.
Slots of differently named variables are disjoint, found by instance search when both names
are literals (VariableName.NameNe). Stated for constructor applications: for a variable v,
the slot type v.type is a projection the instance index cannot match against a concrete type,
while (VariableName.mk n T).type reduces to T.
Writing arguments into parameter slots #
Write an argument tuple typeListToTuple tys into the slots names.zip tys, first
parameter first (so on a duplicate name the later parameter wins). The Nonempty instance each
slot's VariableName needs comes from the argument itself. Lists of different lengths (excluded
by the length hypothesis) leave the assignment unchanged.
Equations
- One or more equations did not get rendered due to their size.
- GaudisCrypt.VariableAssignment.setParams [] [] x_5 x_6 x✝ = x✝
- GaudisCrypt.VariableAssignment.setParams x✝⁴ x✝³ x✝² x✝¹ x✝ = x✝
Instances For
setParams leaves every slot outside the parameter names alone.
Renaming #
View an assignment through an injective name map ι: slot n : T of the view is slot
ι n : T of the assignment. Writing a view back overwrites exactly the slots in the range of
ι. Types are kept, so no casts are needed.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Cleaning lemma: a slot seen through embed ι is the slot of the renamed variable.
Renaming along a permutation of names: an isomorphism of assignments, slot n : T of
rename π m being slot π n : T of m.
Equations
- One or more equations did not get rendered due to their size.
Instances For
embed along a permutation is the isomorphism lens of rename.
Program states #
The state a statement runs in: the program's globals and the running procedure's
locals. Both are variable assignments, the globals named by full declaration names
(see global_var).
- globals : VariableAssignment
- locals : VariableAssignment
Instances For
Lens onto the globals of a ProgramState.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Lens onto the locals of a ProgramState.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A lens into the locals, as a lens into the program state.
Equations
Instances For
A lens into the globals, as a lens into the program state.
Equations
Instances For
The local variable n : T: its slot in the locals, as a lens into the program state. This
is what a parameter or var of a proc stands for. The key of the variable name is filled in
at the use site by variable_name_key, so for a literal n it is a literal, and two local
variables with different literal names are found disjoint by instance search (through
Lens.disjoint_intoLocal and varLens.instDisjoint; an abbrev, so that instance search sees
the slot).
Equations
- GaudisCrypt.localVarLens n T keyCorrect = (GaudisCrypt.varLens { name := n, type := T, nonempty := inst✝, key := key, keyCorrect := keyCorrect }).intoLocal
Instances For
Global variables #
global_var x : T declares the global variable x: the slot of the variable name
⟨"N.x", T⟩ in the globals, where N.x is the full name of the declaration, so two globals
declared in different places never share a slot. It is a plain def (simp does not see through
it), and Lens.IsGlobalVar records which slot it is, which is what instance search uses to find
two globals disjoint (Lens.IsGlobalVar.instDisjoint).
x is the slot of the variable name v (as the instance global_var emits says). v is an
outParam, found from x.
Instances
Two slots of differently named variables are disjoint.
Globals with different (literal) names are disjoint.
global_var x : T declares the global variable x : Lens T VariableAssignment, the slot of
⟨"N.x", T⟩ with N.x the full name of the declaration (T must be nonempty), together with
its Lens.IsGlobalVar instance, so that globals are found disjoint by instance search.
Equations
- One or more equations did not get rendered due to their size.