(* August 14, 1997 *)
(* script to be run when omnibus has been run *)
(* this file begins to implement a theory of programming *)
(* this should be considerably improved; it has a type of expressions
with the correct relationship to assignment (the original version of
assignment only allowed assignments of data constants to variables). *)
(* an important point is that function application in the Mark2 logic
is not extensional; forall@[(?f@?1)=?g@?1] does not necessarily imply
?f = ?g. This means that the representation of programs and
expressions as "functions" does not wipe out structural information
about programs and expressions if it is done right. Extensionality
does hold for functions built with brackets ([?P@?1]), so if we want
functions to be nonextensional, we do not define them using bracket
abstraction *)
(* this file begins to implement a theory of programming *)
declareconstant "data"; (* the type of storable data *)
axiom "NATDATA" "Nat:?x" "data:Nat:?x"; (* natural numbers can be data *)
axiom "BOOLDATA" "bool:?x" "data:bool:?x"; (* truth values can be data *)
declareconstant "error"; (* a data value signalling error *)
axiom "ERRORDATA" "error" "data:error";
axiom "ERRORNOTNAT" "error=Nat:error" "false";
axiom "ERRORNOTBOOL" "error=bool:error" "false";
declareconstant "address"; (* the type of addresses *)
declareinfix "++"; (* the operation of shifting addresses up *)
(* this will be used in defining arrays *)
axiom "SHIFTUPTYPE" "?address ++ ?nat" "address:(address:?address)++(Nat:?nat)";
axiom "SHIFTUPASSOC" "(?address ++ ?nat1) ++ ?nat2" "?address ++ ?nat1 + ?nat2";
axiom "SHIFTSHIFTS" "(address:?a) = ?a++?n" "?n=0";
(* it may also be advisable to have "shift down"; more axioms may be needed *)
declareconstant "state"; (* states are functions from addresses to data *)
axiom "STATETYPE" "state:?s" "[data:?s@address:?1]";
(* note that equality between states is extensional *)
declareconstant "command"; (* commands are functions from states to states *)
(* but equality between commands is not necessarily extensional,
which allows commands to be treated as "text" objects where appropriate
(as in the definition of "allguards" below *)
axiom "COMMANDTYPE" "(command:?c)@?s" "state:?c@state:?s";
(* we introduce basic commands *)
(* the "skip" command does nothing *)
declareconstant "skip";
axiom "SKIPTYPE" "skip" "command:skip";
axiom "SKIP" "skip@?s" "state:?s";
(* the "abort" command throws us into total error *)
declareconstant "abort";
axiom "ABORTTYPE" "abort" "command:abort";
axiom "ABORT" "abort@?s" "[error]"; (* [error] is a completely useless state *)
axiom "ERRORINVARIANCE" "(command:?c)@[error]" "[error]";
(* this axiom expresses the uselessness of the state [error] *)
(* composition of programs *)
declareinfix ";";
axiom "PCOMPTYPE" "?c1;?c2" "command:(command:?c1);(command:?c2)";
axiom "PCOMP" "(?c1;?c2)@?s" "(command:?c2)@(command:?c1)@?s";
(* multiple assignment *)
(* implemented very abstractly; values at addresses satisfying a predicate
are copied from a given state; the state [error] cannot be modified *)
(* we develop a "left expression" type of predicates which can be
domains of multiple assignments *)
declareconstant "lexp";
defineinfix "DISJ_SUM" "?R,,?S" "[(~forsome@[bool:(?R@?2)&(?S@?2)])&(?R@?1)|?S@?1]";
(*
DISJ_SUM_1:
?R ,, [?1 = ?u] =
[( ~?R @ ?u) & (?R @ ?1) | ?1 = ?u]
["AND","ASSERT","BOOLDEF","CASEINTRO","CONVIF","DISJ_SUM0","EQBOOL","EQUATION","FNDIST","IF","IFF","IGNOREFIRST","NONTRIV","NOT","ODDCHOICE","OR","REFLEX","TYPES","XOR","forall","forsome"]
*)
s "?R,,[?1=?u]";
ri "DISJ_SUM"; ex();
left();left();
dlls "CSYM";
ri "CSYM"; ex();
ri "LZ"; ex();
up();
rri "ANDBOOL"; ex();
up();up();
ri "FORSOMEDIST2"; ex();
left();
ri "DINSTANTIATEF1@?u"; ex();
ri "LEFT@EVAL**REFLEX"; ex();
ri "DSYM**DZER"; ex();
up();
ri "CSYM**CID"; ex();
up();
ri "NRULE2"; ex();
p "DISJ_SUM_1";
axiom "LEXP1" "[?1=address:?u]" "lexp:[?1=address:?u]";
axiom "LEXP2" "(lexp:?R),,(lexp:?S)" "lexp:(lexp:?R),,(lexp:?S)";
(* develop types "rexp" (right expression) and "rexp_state"
for assignment *)
declareconstant "rexp"; (* right expression: selected functions
from states to data: nonextensional *)
declareconstant "rexp_state"; (* function from addresses to rexps *)
axiom "REXP_STATETYPE" "rexp_state:?x" "[rexp:?x@address:?1]";
(* develop some "right expressions" *)
axiom "REXP0" "(rexp:?x)@?s" "data:?x@state:?s";
defineconstant "con@?x" "[data:?x]";
axiom "REXP1" "con@?x" "rexp:con@?x"; (* data constants *)
defineconstant "var@?u" "[(state:?1)@(address:?u)]";
axiom "REXP2" "var@?u" "rexp:var@?u";
(* contents of variables *)
defineinfix "EXPPLUS" "(?x!+!?y)@?s" "(Nat:(rexp:?x)@?s)+(Nat:(rexp:?y)@?s)";
(* this is developed using definition facility rather than
bracket abstraction to preserve the possibility of
nonextensional operations like text substitution *)
axiom "REXP3" "?x!+!?y" "rexp:(rexp:?x)!+!rexp:?y";
(* sums of expressions *)
defineinfix "ARRAYSUB" "(?v..?i)@?s" "(state:?s)@(address:?v)++(rexp:?i)@(state:?s)";
(* array subscripting -- C style *)
(* this axiom expresses the idea that rexp_states are functions from
addresses to "rexps"; these in turn are functions from states to data *)
declareinfix "=::"; (* := cannot be used because initial colon is meaningful
to Mark2 *)
axiom "MASSIGNTYPE" "?a =:: ?s" "command:(lexp:?a)=::rexp_state:?s";
axiom "MASSIGN" "(?a=::?s)@?t"
"[((~(state:?t)=[error])&(lexp:?a)@address:?1)||(((rexp_state:?s)@(address:?1))@?t),(state:?t)@?1]";
(* single assignment *)
defineinfix "ONE_ASSIGN" "?v =: ?x" "[?1=address:?v]=::[rexp:?x]";
(*
ONE_ASSIGN_1:
((?v =: ?x) @ ?s) @ ?u =
(( ~(state : ?s) = [error]) & (address : ?u)
= address : ?v)
|| ((rexp : ?x) @ ?s) , (state : ?s) @ ?u
["AND","BOOLDEF","CASEINTRO","EQBOOL","EQUATION","FNDIST","LEXP1","MASSIGN","NONTRIV","NOT","ONE_ASSIGN","REFLEX","REXP_STATETYPE","TYPES"]
*)
s "(?v=:?x)@?s";
ri "(LEFT@ONE_ASSIGN)**MASSIGN"; ex();
dlrs "LEXP1";
rri "LEXP1"; ex();
up();
ri "EVAL"; ex();
top();
right();right();left();left();left();
ri "REXP_STATETYPE"; ex();
right();
right();
ri "EVAL"; ex();
up();
ri "TYPES"; ex();
up();up();
ri "EVAL"; ex();
assigninto "?U" "?U@?u"; (* apply both sides of equation to ?u *)
ri "EVAL"; ex();
p "ONE_ASSIGN_1";
(* pair assignment *)
defineinfix "PAIR_ASSIGN" "(?u,?v) =,: ?x,?y" "([?1=address:?u]),,([?1=address:?v])=::[(?1=address:?u)||(data:?x),data:?y]";
(* this is much prettier than the previous version of pair assignment *)
(* the definition of ,, ensures that pair assignment will only have an effect
if the two addresses are distinct *)
(* real list assignment requires development *)
(* the next refinement needed here is the development of an expression type
to serve as the right side type of assignment statements instead of "state" *)
(* alternation *)
declareinfix "|:|"; (* links a guarded subcommand to a command *)
(* alternative commands will have a final "otherwise" clause *)
axiom "IFFITYPE" "(?b,?c)|:|?x"
"command:([bool:?b@state:?1],command:?c)|:|command:?x";
(* the "execution behaviour" axiom given here is deterministic;
a nondeterministic axiom is harder to write, but certainly desirable *)
axiom "IFFI" "((?b,?c)|:|?x)@?s" "(?b@state:?s)||((command:?c)@?s),((command:?x)@?s)";
(* axioms for a function which extracts the "disjunction of the guards"
from a complex alternative statement. Notice that the fact that commands
are _not_ treated as extensional functions from states to states means that we
can allow the extraction of structural information from commands = programs *)
declareconstant "allguards";
axiom "ALLGUARDS0" "allguards@abort" "[false]";
axiom "ALLGUARDS" "allguards@(?b,?c)|:|?x" "[(?b@state:?1)|((allguards@?x)@state:?1)]";
(* the use of allguards allows the definition of a guarded do loop
as an operation on the alternative statement expressing one step *)
declareconstant "loop"; (* transforms alternative statement into loop
statement *)
axiom "LOOPTYPE" "loop@?x" "command:loop@command:?x";
axiom "LOOP" "(loop@?c)@?s" "((allguards@?c)@state:?s)||((loop@?c)@(command:?c)@state:?s),state:?s";
axiom "TERMINATOR" "((allguards@?c)@(loop@?c)@?s)->[error]=(loop@?c)@?s" "true";
(* the axiom TERMINATOR guarantees that a loop either satisfies the
expected exit condition or aborts *)
axiom "INVARIANCE" "((?P @ state : ?s) & forall @ [(?P @ state : ?1) -> ?P @ (command : ?c) @ state : ?1]) -> (?P @ (loop @ ?c) @ ?s) | [error] = (loop @ ?c) @ ?s" "true";
(* the axiom INVARIANCE ensures that loop invariants hold when the
loop stops, unless it aborts *)
(*
ABORTCOMP1:
(?c ; abort) @ ?s =
abort @ ?s
["ABORT","ABORTTYPE","PCOMP"]
*)
s "(?c;abort)@?s";
ri "PCOMP"; ex();
ri "LEFT@ $ABORTTYPE"; ex();
ri "ABORT"; ex();
initializecounter();
rri "ABORT"; ex();
assign "?s_1" "?s";
p "ABORTCOMP1";
(*
(abort ; ?c) @ ?s =
abort @ ?s
["ABORT","ABORTTYPE","ERRORINVARIANCE","PCOMP"]
*)
s "(abort;?c)@?s";
ri "PCOMP"; ex();
ri "RIGHT@LEFT@ $ABORTTYPE"; ex();
ri "RIGHT@ABORT"; ex();
ri "ERRORINVARIANCE"; ex();
initializecounter();
rri "ABORT"; ex();
assign "?s_1" "?s";
p "ABORTCOMP2";
(*
SKIPCOMP1:
(skip ; ?c) @ ?s =
(command : ?c) @ ?s
["COMMANDTYPE","PCOMP","SKIP","SKIPTYPE","TYPES"]
*)
s "(skip;?c)@?s";
ri "PCOMP"; ex();
ri "(RIGHT@LEFT@ $SKIPTYPE)**RIGHT@SKIP"; ex();
ri "COMMANDTYPE"; ex();
ri "RIGHT@RIGHT@ TYPES"; ex();
rri "COMMANDTYPE"; ex();
p "SKIPCOMP1";
(*
SKIPCOMP2:
(?c ; skip) @ ?s =
(command : ?c) @ ?s
["COMMANDTYPE","PCOMP","SKIP","SKIPTYPE","TYPES"]
*)
s "(?c;skip)@?s";
ri "PCOMP"; ex();
ri "(LEFT@ $SKIPTYPE)**SKIP"; ex();
ri "(RIGHT@COMMANDTYPE) ** (EVERYWHERE@TYPES) ** $COMMANDTYPE"; ex();
p "SKIPCOMP2";
(* the preceding theorems are not strict equalities between programs because
programs are not extensional functions *)
(* we give a sample of a different kind of theorem *)
defineconstant "behaviour@?P" "[(command:?P)@?1]";
(* the behaviour operator gives the canonical function corresponding to
a program *)
(*
SKIPCOMP1a:
behaviour @ skip ; ?c =
behaviour @ ?c
["COMMANDTYPE","PCOMP","PCOMPTYPE","SKIP","SKIPTYPE","TYPES","behaviour"]
*)
s "behaviour@skip;?c";
ri "behaviour"; ex();
ri "VALUE@[(EVERYWHERE@PCOMPTYPE) ** (EVERYWHERE@TYPES) ** (EVERYWHERE@ $PCOMPTYPE)]"; ex();
ri "VALUE@[SKIPCOMP1]"; ex();
rri "behaviour"; ex();
p "SKIPCOMP1a";
(*
PCOMPASSOC:
behaviour @ (?P ; ?Q) ; ?R =
behaviour @ ?P ; ?Q ; ?R
["PCOMP","PCOMPTYPE","TYPES","behaviour"]
*)
s "behaviour@(?P;?Q);?R";
ri "behaviour"; ex();
right();left();
ri "(RIGHT@PCOMPTYPE)**TYPES** $PCOMPTYPE"; ex();
up();
ri "PCOMP"; ex();
right();left();
ri "(RIGHT@PCOMPTYPE)**TYPES** $PCOMPTYPE"; ex();
up();
ri "PCOMP"; ex();
top();right();
rri "PCOMP"; ex();
ri "(LEFT@TADDTOP@PCOMPTYPE)** $PCOMP"; ex();
up();
ri "VALUE@[LEFT@TADDTOP@PCOMPTYPE]"; ex();
rri "behaviour"; ex();
p "PCOMPASSOC";