Blocks, flags, and bit dispatch — proof internals #
The string toolkit the simulation of a machine inside Cobham's algebra is
written in. None of it appears in the statement of CobhamFP_eq_FP; it is the
vocabulary of the proof.
- Dispatch —
Complexity.caseBitselects on a leading bit and returns nothing on the empty string;Complexity.caseBit₀reads "no bit" asfalse. Both are needed: the partial one to read off the end of a string, the total one so that a flag (a one-bit string) is always genuinely one bit. - Flags —
Complexity.andBit,orBit,notBit,bitAt,Complexity.nonemptyFlagandComplexity.matchPrefix, the Boolean layer a machine's finite transition table is written in.matchPrefixunfolds into|c|bit tests for each fixed constantc, so it is a finite composition — the induction is at the meta level, not inside the algebra. - Blocks —
Complexity.padTopads a field to one ruler's width andComplexity.blockAtreads fieldiback, so a packed configuration needs no self-delimiting decoder inside the algebra. The padding algebra (padTo_append_padTo,take_padTo,drop_padTo,padTo_drop) says that re-padding commutes with the edits a simulated step performs.
Bit dispatch: select x or y according to the leading bit of s,
returning the empty string when s is empty.
This is the branching primitive of the algebra. It is definable by a single
limited recursion on notation (Cobham.caseBit) because the step functions of
recNotation are already selected by the bit being peeled — dispatching on a bit
costs nothing beyond the recursion that is there anyway.
Equations
- Complexity.caseBit [] x y = []
- Complexity.caseBit (b :: tail) x y = bif b then x else y
Instances For
Total bit dispatch: like caseBit, but the empty string selects the
false branch instead of returning nothing.
Both variants are needed. caseBit is the partial reader used when running off
the end of a string must produce nothing (Cobham.takePrefix reads bits this
way); caseBit₀ is the total one used for Boolean logic, where "no bit" has to
mean false so that flags are always exactly [true] or [false].
Equations
- Complexity.caseBit₀ [] x y = y
- Complexity.caseBit₀ (b :: tail) x y = bif b then x else y
Instances For
Flags #
A flag is a one-bit string, [true] or [false]. The connectives below are
each one caseBit₀, so they are in the algebra as soon as caseBit₀ is, and
they are how the finite case analysis of a machine's transition function gets
written inside it. Because they are built on the total dispatcher, every flag
these produce is genuinely one bit — never empty — so they compose.
Conjunction of flags.
Equations
Instances For
Disjunction of flags.
Equations
Instances For
Negation of a flag.
Equations
Instances For
Pad (or truncate) x to exactly the width of the ruler r, filling with
zeros.
Fixed-width blocks are how a simulated machine's configuration is packed into the
single string a member of the class returns: every field occupies |r| bits, so
field i is recovered by dropping i rulers and taking one — no self-delimiting
decoder is needed inside the algebra.
Equations
- Complexity.padTo r x = List.take r.length (x ++ List.replicate r.length false)
Instances For
Padding algebra #
A simulated step reads a padded block, edits it, and re-pads. These three lemmas say that the padding is invisible to that: re-padding commutes with the edits, so the encoded step can be reasoned about on raw contents.
Flag: is x nonempty? The partial dispatcher returns [] on the empty
string, and [] reads as false to the flag connectives — so this is the one
place caseBit rather than caseBit₀ is what is wanted.
Without it matchPrefix could not tell "the head bit is 0" from "there is no
head bit", and would report a match of [0] against [].
Equations
Instances For
Flag: does x begin with the fixed constant c? Unfolds into |c| bit
tests joined by andBit, so for each constant it is a finite composition —
no recursion on notation is needed.
Equations
Instances For
A constant is matched by anything it prefixes.
The match test always returns a genuine one-bit flag.