CADiZ

Reference manual / Extended toolkit / section corelaws


Introduction

This section contains toolkit-independent general-purpose tactics, and toolkit-independent laws, with (some of) their proofs.

section corelaws

Supplied Tactics for the CADi\num Theorem-prover

The following tactics are supplied as part of the CADi\num system. They are intended to serve two purposes: a) to be directly useful in proof work; b) to be used as models when users develop their own tactics.

The current version of this library should be regarded as provisional, since both the rules of inference and the tactic language are still in the course of development.

The proof system manipulates sequents. Each sequent used in a proof becomes a goal of the proof process, so in this document the words "goal" and "sequent" will be used interchangably. Tactics can take several sorts of argument. In this document we proceed "top-down", considering first those tactics which operate on goals, then those which operate on predicates, then those which operate on expressions, and finally those for schema texts and declarations.

Although the tactics are here ordered on the basis of what sort of arguments they have, they also fall fairly neatly into two categories which cut across that basis, namely: a) non-recursive tactics which may fail; b) recursive tactics which are intended never to fail, but which may cause "Nothing changed" to be reported.

The former are: "bindselAbsorb", "unfoldRel", "unfoldFun", "pairInFunction" and "proveWithInduction".

The latter are "flattenGoal", "separateGoals", "flattenPred" and all the simplification tactics whose names begin with "puff".

The first tactics are those whose argument is a single goal.

The tactic "flattenGoal" is used to carry out all those eliminations on a single goal which cause as many as possible of the predicates in the goal to become separate antecedents or consequents, but without producing more than one subgoal.

The tactic takes a single argument, which must be a sequent, and which is bound to the joker "g". The tactic is to be called recursively, and the label "repeat" is declared as the recursion point. Then five alternative possibilities are considered, namely: a) we have finished; b) we can do something with a consequent; c) we can do something with an antecedent; d) we can do something with a declaration; e) the case which is always true.

The first of these cases is where the "axiom" command succeeds. This would otherwise be generated automatically, but in that case the "axiom" node is always displayed in the proof tree, even when "apply tactic" is being used, and there can be cases where the number of such nodes is embarrassingly high. Putting it here means that the "axiom" command is treated like any other command in the tactic.

In the next two of the five possibilities, the appropriate flattening action is carried out and the recursion is taken.

In the fourth case, each declaration is selected for normalization, and if this causes the "axiom" command to be offered, this is accepted and the whole tactic will succeed. This will happen if the result of normalisation is to produce as an antecedent a membership predicate which already occurs as a consequent. The normalization is attempted twice because the two predicates generated as antecedents may be different, one asserting a membership of the stated declarand set, the other asserting membership of the carrier set concerned. If "axiom" is not offered, however, this alternative in which normalization was done will also not succeed, so the result of the whole tactic will be obtained from alternatives without the normalization.

In the final case the tactic stops with a success. Since alternations are tried in the order they are written, the first complete tactic success will be one where either the "axiom" command has been offered, and the goal proved, or all the possible eliminations have been done, until finally a skip has been the only possibility left. The exclamation mark for a "curtail" is put in just to make sure that there is no backtracking, although this will never be attempted if everything goes according to plan. The tactic as a whole always succeeds. If it achieves nothing, "Nothing changed" will be reported.

flattenGoal goal g | rec repeat @

    !("axiom" 0 \lor     (patgoal pred p | \vdash? p @     !("predication" p; repeat \lor     match p ::     | \lnot _pred @     | _pred \lor _pred @     | _pred \implies _pred @     | \forall _stxt @ _pred @ "elimination" p ::     | false @ "thin" p ::     . ; repeat)) \lor     (patgoal pred p | | p \vdash? @     !("predication" p; repeat \lor     match p ::     | \lnot _pred @     | _pred \land _pred @     | \exists _stxt @ _pred @ "elimination" p ::     | true @ "thin" p ::     . ; repeat)) \lor     (patgoal decl var | var \vdash? @     "normalization" var; "normalization" var; "axiom" 0) \lor     skip)

The tactic "separateGoals" takes a single argument, which must be a sequent, and which is bound to the joker "g". The label "repeat" is declared as the recursion point. First the tactic calls "flattenGoal", then it carries out those eliminations which produce more than one subgoal. Where that is successful, the recursive call is made on both of the subgoals. "separateGoals" can thus generate any number of subgoals. The tactic always succeeds. If it achieves nothing, "Nothing changed" will be reported.

separateGoals goal g | rec repeat @

    "apply tactic" 0 "flattenGoal";     !((patgoal pred p | | p \vdash? @ "elimination" p; (repeat ||lel repeat)) \lor     (patgoal pred p | \vdash? p @ "elimination" p; (repeat ||lel repeat)) \lor     skip)

Next we come to tactics each of whose argument is a single predicate.

The tactic bindselAbsorb is a dedicated auxiliary tactic used by some of those which follow. It assumes its predicate parameter is a conjunction of any number of equalities, where the left-hand side of each equality is in the form of a selection from a tuple, which may be absorbed. The purpose of the tactic is to carry out all these absorptions.

bindselAbsorb pred p |

    match p     :: expr e1 | e1 = _expr @ "absorption" e1     :: pred p1, p2 | p1 \land p2 @     "apply tactic" p1 "bindselAbsorb" ; "apply tactic" p2 "bindselAbsorb"     :: .

The tactic "unfoldRel" is used to expand a predicate which expresses whether some explicitly stated term or tuple of terms is a member of a named comprehension. The named comprehension is frequently a relational operator.

The name is assumed to have been declared as equal to a comprehension, whose expression part is the tuple of the bound names of the comprehension. The name of the comprehension is expanded to give the comprehension explicitly, and the membership is also expanded. This yields an existential quantification, containing an equality between the actual arguments to the comprehension and their formal names in the comprehension. Expanding this gives us two separate equalities, and the absorption step selects the first and second component, respectively, of the pair formed by the two arguments. This then allows the one-pointing to remove the bound variables of the quantification, and the final absorptions discard the quantification itself and a true condition which gets generated. The alternative skips at the end allow the tactic to succeed in certain cases where the assumptions of use are not fully met.

unfoldRel pred p |

    match p :: expr r | _expr \in r @     "expansion" r :: . ; -- get  the  comprehension     "expansion" p; -- expand  the  membership     match p :: pred equ; expr e1 |     \exists _stxt @ equ as (e1 = ( _exprs ) ) @     match e1 :: | ( _exprs ) @     "expansion" equ; "apply tactic" equ "bindselAbsorb" ::     | e1 @ "expansion" equ :: . :: | p @ skip :: . ;     "one-point" p; -- the  bound  variables     "absorption" p; -- the  exists  quantifier     !("absorption" p \lor skip); -- the  final  true  conjunct  if  any     match p :: pred side | side \land _pred @     "apply tactic" side "puffPred" :: . ;     !("absorption" p \lor skip) -- absorb  the  side-condition

The largest supplied tactics are the general-purpose simplifying procedures whose names begin with "puff". They make frequent recursive calls on themselves and on each other. They are written without any assumption of the presence of toolkit definitions. Within that constraint, their design aim is to apply all simplifications which one would always want, except perhaps in very special circumstances, but to do nothing else.

"puffPred" takes a single predicate argument, which may appear anywhere and be of any form. The main section of the tactic has a matcher which fans out into some eleven different cases, corresponding to the sort of predicate supplied. For each of these any applicable immediate simplifications are sought, usually after a recursive call to simplify the constituent elements. Finally, "resolution" and "linear decision" are tried, using the result of the previous simplifications. "puffPred" always succeeds. If it achieves nothing, the report "Nothing changed" is given.

puffPred pred p | rec repeat @

    match p ::     expr q, r | q = r @     "apply tactic" q "puffExpr"; "apply tactic" r "puffExpr";     !("absorption" p \lor     match p ::     | (_exprs) = (_exprs) @     "expansion" p; repeat ::     | \lblot _decls \rblot = \lblot _decls \rblot @     "expansion" p; repeat ::     | p @ skip :: .) ::     expr q, r | q \in r @     "apply tactic" q "puffExpr" ; "apply tactic" r "puffExpr";     !("absorption" p; repeat \lor "expansion" p; repeat \lor skip) ::     stxt dec; pred prred     | \exists dec @ prred @     | \forall dec @ prred @     "apply tactic" dec "puffStxt";     "apply tactic" prred "puffPred";     !("absorption" p; repeat \lor "one-point" p; repeat \lor skip) ::     stxt dec; pred prred | \exists1 dec @ prred @     "apply tactic" dec "puffStxt";     "apply tactic" prred "puffPred";     !("absorption" p \lor "one-point" p \lor "expansion" p); repeat ::     pred q | \lnot q @     "apply tactic" q "puffPred"; ("absorption" p \lor skip) ::     pred q, r     | q \land r @     | q \lor r @     | q \iff r @     | q \implies r @     "apply tactic" q "puffPred"; "apply tactic" r "puffPred";     !("absorption" p \lor skip) ::     | p @ !("predication" p; repeat \lor "expansion" p; repeat \lor skip) :: . ;     -- this  last  line  does  xor,  true,  false,  and  all  schemas     !("resolution" p; match p :: | true @ skip :: | false @ skip :: . \lor     "linear decision" p \lor skip)

The tactic "flattenPred" is designed to bring an arbitrary predicate into what is expected to be a more tractable form by systematically absorbing where possiible, distributing quantifiers outwards and distributing negations inwards. It perform approximately the same sorts of simplifications as "flattenGoal". but all within a single predicate, hence its name.

"flattenPred" always succeeds. If it achieves nothing, the report "Nothing changed" is given. flattenPred pred p | rec repeat @

    match p ::     expr e | e @     ("absorption" p; repeat \lor "predication" p; repeat \lor skip) ::     pred prred     | \exists _stxt @ prred @     | \forall _stxt @ prred @     | \exists1 _stxt @ prred @     "apply tactic" prred "flattenPred";     !("absorption" p; repeat \lor     "predication" p ; repeat \lor     "normalization" p; repeat \lor skip) ::     pred q | \lnot q @     "apply tactic" q "flattenPred";     !("absorption" p; repeat \lor "predication" p; repeat \lor     "de Morgan" q; "absorption" p; repeat \lor skip) ::     pred q, r | q \land r @     "apply tactic" q "flattenPred"; "apply tactic" r "flattenPred";     !("absorption" p; repeat \lor "predication" p ; repeat \lor     match q :: | \exists _stxt @ _pred @     "distribution" q; repeat :: . \lor     match r :: | \exists _stxt @ _pred @     "distribution" r; repeat :: . \lor skip) ::     pred q, r | q \lor r @     "apply tactic" q "flattenPred"; "apply tactic" r "flattenPred";     !("absorption" p; repeat \lor "predication" p ; repeat \lor     match q :: | \forall _stxt @ _pred @     "distribution" q; repeat :: . \lor     match r :: | \forall _stxt @ _pred @     "distribution" r; repeat :: . \lor skip) ::     pred q, r | q \iff r @     "apply tactic" q "flattenPred"; "apply tactic" r "flattenPred";     !("absorption" p \lor     match q :: | \lnot _pred @ "distribution" q; repeat :: . \lor     match r :: | \lnot _pred @ "distribution" r; repeat :: . \lor     skip) ::     pred q, r | q \implies r @     "apply tactic" q "flattenPred"; "apply tactic" r "flattenPred";     !("absorption" p; repeat \lor "predication" p ; repeat \lor     match q :: | \exists _stxt @ _pred @     "distribution" q; repeat :: . \lor     match r :: | \forall _stxt @ _pred @     "distribution" r; repeat :: . \lor skip) ::     | p @ !("absorption" p; repeat \lor skip) :: .

Next we have two tactics each of which takes two predicate arguments.

The tactic "pairInFunction" is designed to show that an inspected predicate, p, of the form (a, f a) \in f is true, using a crossed antecedent, ante, of the form forall b: s @ \exists1 p: f @ p.1 = b and where we assume that the condition a \in s is axiomatic or becomes so by absorption.

    pairInFunction pred ante, p |     match p :: expr a, f, fa | (a, fa) \in f @     "expansion" fa; "mu tac" fa :: . ;     ((     patcons pred ex | 1 @     match ex :: decls x1; expr a1, fa1, f1 |     \exists1 x1 | (a1, fa1) \in f1 @ true @     "quantification tac" "{ 1} " a1 ante;     match ante :: pred ante1, ante2 | ante1 \land ante2 @     "elimination" ante; "one-point" ante2; "absorption" ante2;     match ante2 ::     pred ante21, ante22 | ante21 \implies ante22 @     "apply tactic" ante21 "puffPred" ::     | ante2 @ skip :: . ;     !("absorption" ante2 \lor skip);     "expansion" ante2;     match ante2 ::     decl ppr; pred ant22, ant221; expr pr, val;     pred ant222; stxt ant2221; expr a2, b2, c2, d2 |     \exists ppr @     (ant22 as (ant221 as pr . 1 = val)     \land ant222 as (\forall ant2221 @ a2 = b2 \implies c2 = d2)) @     "elimination" ante2;     "elimination" ant22;     "Leibniz" a1 b2 ant221;     "expansion" ex;     "quantification tac" "{ 1} " (pr ++ ".2") ex;     match ex :: pred ex1, ex2 | ex1 \lor ex2 @     "elimination" ex; "one-point" ex2; "absorption" ex2;     "normalization" ppr;     patante pred ex3 | 1 @     match ex3 :: expr ppr2, fn2 | ppr2 \in fn2 @     "expansion" ppr2;     "normalization" ppr;     patante pred ex4 | 1 @ "expansion" ex4;     match ex2 ::     pred ppr3, ppr4, ppr5, ppr6; decls dc1; expr ex5, fn5 |     ppr3 \land ppr4 as (\forall dc1 | ppr5 as (ex5 \in fn5) @ ppr6) @     "elimination" ex2;     ("apply tactic" 0 "separateGoals" ||lel     "elimination" ppr4;     "absorption" ppr6;     "quantification tac" "{ 1} " ex5 ant222;     match ant222 ::     pred oldant, ant2222 | oldant \land ant2222 @     "elimination" ant222; "one-point" ant2222; "absorption" ant2222;     match ant2222 :: pred imp1, imp2, imp3, imp4 |     imp1 \implies imp2 as (imp3 \implies imp4) @     "expansion" imp4;     "apply tactic" imp2 "puffPred";     "elimination" ant2222;     (!("axiom" 0 \lor skip) ||lel !("axiom" 0 \lor skip)) :: . :: . )     :: . :: . :: . :: . :: . :: . )     ||lel     (     patante pred ex | 1 @ "expansion" ex;     "consequent intro" ex p;     patcons pred e2 | 1 @ "resolution" e2; !("axiom" 0 \lor skip)))

The tactic "proveWithInduction" is designed to do the right call of quantification on a (crossed) induction principle, ind, given an (inspected) target predicate, targ, which takes the form of a universal quantification which the induction principle can prove; then to prove and eliminate the predicate corresponding to the fact that this is what we have done.

    proveWithInduction pred ind, targ |     match targ ::     decls s; pred p1, p2 | \forall s | p1 @ p2 @     "quantification tac" "{ 1} "     ("{ " ++ s ++ "|(" ++ p1 ++ ") implies (" ++ p2 ++ ")} ") ind ;     match ind :: pred i1, i2 | i1 \land i2 @ "elimination" ind;     "one-point" i2; "absorption" i2;     match i2 :: pred j1, j2 | j1 \implies j2 @     "elimination" i2;     (skip ||lel skip)     :: . :: . :: .

Next we come to tactics each of whose argument is a single expression.

The tactic "unfoldFun" takes a single argument, which is an application expression. The tactic is designed to expand the application of the function to its argument or arguments. The function is assumed to have been declared as equal to a suitable set, typically a lambda-expression.

The initial expansion of the function application creates a mu-expression, which the tactic then attempts to simplify. It separates out the bound variables which are equated to the arguments, so that "one-point" can then carry the substitution through.

In the simple cases, the condition part of the mu-expression will be true. If the function is not recognised as being total, however, this will not be so. In that case, the final "absorption" will not succeed, and the skip is taken instead. The user must then reduce that predicate by other means, in order to absorb it away.

unfoldFun expr e |

    "expansion" e; -- generate  the  mu-expression     match e :: pred prred; expr op |     \mu _decl | prred as (_expr \in op) @ _expr @     "expansion" op; -- get  the  function     "expansion" prred; -- expand  the  membership  of  lambda     match prred :: pred equ | \exists _stxt @ equ @     "expansion" equ; -- the  two  pairs     match equ :: pred p; expr a, c |     (p as a = _expr) \land c = _expr @     "absorption" a c; -- tuple  selection,  separating  args  from  results     match p :: expr e1 | (e1 = ( _exprs )) @     match e1 :: | ( _exprs ) @     "expansion" p; "apply tactic" p "bindselAbsorb" ::     | e1 @ "expansion" p :: . :: | p @ skip :: . :: . :: . ;     "one-point" prred; -- within  exists     "absorption" prred :: . ; -- drop  exists  quantifier     "one-point" e; -- the  mu-expression     match e :: pred side | \mu | side @ _expr @     "apply tactic" side "puffPred" :: . ;     !("absorption" e \lor skip) -- the  mu  if  possible

"puffExpr" is the expression counterpart of "puffPred". It takes a single expression argument, which may appear anywhere and be of any form. The main section of the tactic has a matcher which fans out into over twenty different cases, corresponding to the sort of expression supplied. For each of these any applicable immediate simplifications are sought, usually after a recursive call to simplify the constituent elements. "puffExpr" always succeeds. If it achieves nothing, the report "Nothing changed" is given.

puffExpr expr t | rec repeat @ match t ::

    | \theta _expr @ "expansion" t ::     expr p | p . 1 @     | p . 2 @     "apply tactic" p "puffExpr"; !("absorption" t \lor skip) ::     exprs es | ( es ) @ "apply tactic" es "puffExprs" ::     decls ds | \lblot ds \rblot @ "apply tactic" ds "puffConstDecls" ::     expr e | \power e @ "apply tactic" e "puffExpr" ::     expr p, q | p \cross q @     "apply tactic" p "puffExpr"; "apply tactic" q "puffExpr" ::     pred p; expr q, r | if p then q else r @     "apply tactic" p "puffPred";     ("absorption" t; repeat \lor     "apply tactic" q "puffExpr"; "apply tactic" r "puffExpr";     ("absorption" t \lor skip)) ::     stxt s; expr ct | { s @ ct } @     | \lambda s @ ct @     "apply tactic" s "puffStxt";     "apply tactic" ct "puffExpr";     !("absorption" t \lor "one-point" t; repeat \lor skip) ::     stxt s; expr ct | \mu s @ ct @     | let s @ ct @     "apply tactic" s "puffStxt";     "apply tactic" ct "puffExpr";     !("absorption" t; repeat \lor "one-point" t; repeat \lor skip) ::     expr fun, args | fun  args @     !("evaluation" t \lor     "apply tactic" fun "puffExpr";     !(("expansion" t;     match t :: pred prred |     \mu _decl | prred @ _expr @     "expansion" prred; repeat :: .) \lor     "apply tactic" args "puffExpr"));     !("evaluation" t \lor skip) ::     stxt s | [s] @ "apply tactic" s "puffStxt" ::     exprs es | _name[es] @ "apply tactic" es "puffExprs" ::     | t @ !("evaluation" t \lor "absorption" t; repeat \lor skip) :: .

puffExprs exprs ts | match ts :: expr e; exprs es | e, es @

    "apply tactic" e "puffExpr";     "apply tactic" es "puffExprs" :: | ts @ skip :: .

puffStxt stxt s |

    match s     :: decls ds | ds | _pred @     "apply tactic" ds s "puffDecls";     match s :: pred barpart2 | _decls | barpart2 @     "apply tactic" barpart2 "puffPred"     :: .     :: .

puffDecls decls ds; stxt s |

    match ds     :: decl d; decls ds2 | d; ds2 @     match d     :: expr e | _name : e @     "apply tactic" e "puffExpr"     ; match e     :: | { _stxt @ _expr } @ "normalization" d     :: | { _exprs } @ "normalization" d     :: | e @ skip     :: .     :: expr e | _name == e @ "apply tactic" e "puffExpr"     :: expr e | e @     "apply tactic" e "puffExpr";     !("distribution" d \lor skip)     :: . ;     match ds     :: decl dd; decls dds2 | dd; dds2 @     "apply tactic" dds2 s "puffDecls"     :: .     :: | @ skip     :: .

puffConstDecls decls ds |

    match ds     :: expr e; decls ds2 | _name == e; ds2 @     "apply tactic" e "puffExpr" ; "apply tactic" ds2 "puffConstDecls"     :: | @ skip     :: .

Commutation Laws

Description

We begin with equality, then go on with the rules of commutation of predicates which we can represent using empty schemas as predicates.

Laws

com1 ==

[ X ] \vdash? \forall t, u: X @ t = u \iff u = t

Proved by a single call of "puffPred" on the consequent.

com2 ==

\vdash? \forall p, q: \power [ ] @ p \land q \iff q \land p

com3 ==

\vdash? \forall p, q: \power [ ] @ p \lor q \iff q \lor p

com4 ==

\vdash? \forall p, q: \power [ ] @ (p \iff q) \iff (q \iff p)

The above three laws can be proved by a single call of "commutation" on one of the arguments to the "iff", followed by a single call of "puffPred" on the whole consequent.

Absorption Laws

Description

We begin with true and false, then go on with the rules of absorption of predicates which we can represent using empty schemas as predicates.

All the following laws can be proved by a single call of "puffPred" on the consequent.

Laws

abs1 ==

\vdash? \lnot false \iff true

abs2 ==

\vdash? \lnot true \iff false

abs3 ==

\vdash? \forall p: \power [ ] @ \lnot \lnot p \iff p

absAnd1 ==

\vdash? \forall p: \power [ ] @ p \land false \iff false

absAnd2 ==

\vdash? \forall p: \power [ ] @ false \land p \iff false

absAnd3 ==

\vdash? \forall p: \power [ ] @ p \land \lnot p \iff false

absAnd4 ==

\vdash? \forall p: \power [ ] @ \lnot p \land p \iff false

absAnd5 ==

\vdash? \forall p: \power [ ] @ p \land true \iff p

absAnd6 ==

\vdash? \forall p: \power [ ] @ true \land p \iff p

absAnd7 ==

\vdash? \forall p: \power [ ] @ p \land p \iff p

absOr1 ==

\vdash? \forall p: \power [ ] @ p \lor true \iff true

absOr2 ==

\vdash? \forall p: \power [ ] @ true \lor p \iff true

absOr3 ==

\vdash? \forall p: \power [ ] @ p \lor \lnot p \iff true

absOr4 ==

\vdash? \forall p: \power [ ] @ \lnot p \lor p \iff true

absOr5 ==

\vdash? \forall p: \power [ ] @ p \lor false \iff p

absOr6 ==

\vdash? \forall p: \power [ ] @ false \lor p \iff p

absOr7 ==

\vdash? \forall p: \power [ ] @ p \lor p \iff p

absImplies1 ==

\vdash? \forall p: \power [ ] @ false \implies p \iff true

absImplies2 ==

\vdash? \forall p: \power [ ] @ p \implies true \iff true

absImplies3 ==

\vdash? \forall p: \power [ ] @ p \implies p \iff true

absImplies4 ==

\vdash? \forall p: \power [ ] @ true \implies p \iff p

absImplies5 ==

\vdash? \forall p: \power [ ] @ p \implies false \iff \lnot p

absImplies6 ==

\vdash? \forall p: \power [ ] @ p \implies \lnot p \iff \lnot p

absIff1 ==

\vdash? \forall p: \power [ ] @ (p \iff p) \iff true

absIff2 ==

\vdash? \forall p: \power [ ] @ (p \iff \lnot p) \iff false

absIff3 ==

\vdash? \forall p: \power [ ] @ (\lnot p \iff p) \iff false

absIff4 ==

\vdash? \forall p: \power [ ] @ (true \iff p) \iff p

absIff5 ==

\vdash? \forall p: \power [ ] @ (p \iff true) \iff p

absIff6 ==

\vdash? \forall p: \power [ ] @ (false \iff p) \iff \lnot p

absIff7 ==

\vdash? \forall p: \power [ ] @ (p \iff false) \iff \lnot p

Theorems about the Natural Numbers

We could here state and prove various theorems about \nat, both because of their usefulness, and to assist in proving the consistency of the definitions given later in numdefs.

The theorems would mainly be to the effect that \nat is an Abelian monoid under _ + _.

zeroPlusBEqB ==

\vdash? \forall b: \nat @ 0 + b = b

Proved by induction on b

succAPlusB ==

\vdash? \forall a, b: \nat @ (a + 1) + b = (a + b) + 1

Proved similarly using induction on b

PlusCommutes ==

\vdash? \forall a, b: \nat @ a + b = b + a

Proved by induction on a using the previous two results as lemmas

PlusClosed ==

\vdash? \forall a, b: \nat @ a + b \in \nat

PlusAssociates ==

\vdash? \forall a, b, c: \nat @ (a + b) + c = a + (b + c)

PlusConstInjective ==

\vdash? \forall a, b, c: \nat | a + c = b + c @ a = b

IT 22-Jan-2002