conv
conv
Abbrev.conv = term -> thm
The type of a function which finds an equal term and returns a theorem stating the equality
If the function c is not only of the right type, but is actually what
we call a conversion, then (c : conv) (t : term) returns a theorem of
the form
|- t = t'
If (roughly speaking) t is of the right form to be passed to c, but
c doesn't find a desired equal term t' then c t may raise the
exception UNCHANGED in preference to returning |- t = t, as it can
be dealt with more efficiently.
See also
ARITH_FORM_NORM_CONV
ARITH_FORM_NORM_CONV
Arith.ARITH_FORM_NORM_CONV : conv
Normalises an unquantified formula of linear natural number arithmetic.
ARITH_FORM_NORM_CONV converts a formula of natural number arithmetic
into a disjunction of conjunctions of less-than-or-equal-to
inequalities. The arithmetic expressions are only allowed to contain
natural number constants, numeric variables, addition, the SUC
function, and multiplication by a constant. The formula must not contain
quantifiers, but may have disjunction, conjunction, negation,
implication, equality on Booleans (if-and-only-if), and the natural
number relations: <, <=, =, >=, >. The formula must not
contain products of two expressions which both contain variables.
The inequalities in the result are normalised so that each variable
appears on only one side of the inequality, and each side is a linear
sum in which any constant appears first followed by products of a
constant and a variable. The variables are ordered lexicographically,
and if the coefficient of the variable is 1, the product of 1 and
the variable appears in the term rather than the variable on its own.
Failure
The function fails if the argument term is not a formula in the specified subset.
Example
#ARITH_FORM_NORM_CONV "m < n";;
|- m < n = (1 + (1 * m)) <= (1 * n)
#ARITH_FORM_NORM_CONV
# "(n < 4) ==> ((n = 0) \/ (n = 1) \/ (n = 2) \/ (n = 3))";;
|- n < 4 ==> (n = 0) \/ (n = 1) \/ (n = 2) \/ (n = 3) =
4 <= (1 * n) \/
(1 * n) <= 0 /\ 0 <= (1 * n) \/
(1 * n) <= 1 /\ 1 <= (1 * n) \/
(1 * n) <= 2 /\ 2 <= (1 * n) \/
(1 * n) <= 3 /\ 3 <= (1 * n)
Useful in constructing decision procedures for linear arithmetic.
COND_ELIM_CONV
COND_ELIM_CONV
Arith.COND_ELIM_CONV : conv
Eliminates conditional statements from a formula.
This function moves conditional statements up through a term and if at any point the branches of the conditional become Boolean-valued the conditional is eliminated. If the term is a formula, only an abstraction can prevent a conditional being moved up far enough to be eliminated.
Failure
Never fails.
Example
#COND_ELIM_CONV "!f n. f ((SUC n = 0) => 0 | (SUC n - 1)) < (f n) + 1";;
|- (!f n. (f((SUC n = 0) => 0 | (SUC n) - 1)) < ((f n) + 1)) =
(!f n.
(~(SUC n = 0) \/ (f 0) < ((f n) + 1)) /\
((SUC n = 0) \/ (f((SUC n) - 1)) < ((f n) + 1)))
#COND_ELIM_CONV "!f n. (\m. f ((m = 0) => 0 | (m - 1))) (SUC n) < (f n) + 1";;
|- (!f n. ((\m. f((m = 0) => 0 | m - 1))(SUC n)) < ((f n) + 1)) =
(!f n. ((\m. ((m = 0) => f 0 | f(m - 1)))(SUC n)) < ((f n) + 1))
Useful as a preprocessor to decision procedures which do not allow conditional statements in their argument formula.
See also
DISJ_INEQS_FALSE_CONV
DISJ_INEQS_FALSE_CONV
Arith.DISJ_INEQS_FALSE_CONV : conv
Proves a disjunction of conjunctions of normalised inequalities is false, provided each conjunction is unsatisfiable.
DISJ_INEQS_FALSE_CONV converts an unsatisfiable normalised arithmetic
formula to false. The formula must be a disjunction of conjunctions of
less-than-or-equal-to inequalities. The inequalities must have the
following form: Each variable must appear on only one side of the
inequality and each side must be a linear sum in which any constant
appears first followed by products of a constant and a variable. On each
side the variables must be ordered lexicographically, and if the
coefficient of the variable is 1, the 1 must appear explicitly.
Failure
Fails if the formula is not of the correct form or is satisfiable. The function will also fail on certain unsatisfiable formulae due to incompleteness of the procedure used.
Example
#DISJ_INEQS_FALSE_CONV
# "(1 * n) <= ((1 * m) + (1 * p)) /\
# ((1 * m) + (1 * p)) <= (1 * n) /\
# (5 + (4 * n)) <= ((3 * m) + (1 * p)) \/
# 2 <= 0";;
|- (1 * n) <= ((1 * m) + (1 * p)) /\
((1 * m) + (1 * p)) <= (1 * n) /\
(5 + (4 * n)) <= ((3 * m) + (1 * p)) \/
2 <= 0 =
F
See also
EXISTS_ARITH_CONV
EXISTS_ARITH_CONV
Arith.EXISTS_ARITH_CONV : conv
Partial decision procedure for non-universal Presburger natural arithmetic.
EXISTS_ARITH_CONV is a partial decision procedure for formulae of
Presburger natural arithmetic which are in prenex normal form and have
all variables existentially quantified. Presburger natural arithmetic is
the subset of arithmetic formulae made up from natural number constants,
numeric variables, addition, multiplication by a constant, the relations
<, <=, =, >=, > and the logical connectives ~, /\, \/,
==>, = (if-and-only-if), ! ('forall') and ? ('there exists').
Products of two expressions which both contain variables are not
included in the subset, but the function SUC which is not normally
included in a specification of Presburger arithmetic is allowed in this
HOL implementation.
Given a formula in the specified subset, the function attempts to prove
that it is equal to T (true). The procedure is incomplete; it is not
able to prove all formulae in the subset.
Failure
The function can fail in two ways. It fails if the argument term is not a formula in the specified subset, and it also fails if it is unable to prove the formula. The failure strings are different in each case.
Example
#EXISTS_ARITH_CONV "?m n. m < n";;
|- (?m n. m < n) = T
#EXISTS_ARITH_CONV "?m n. (2 * m) + (3 * n) = 10";;
|- (?m n. (2 * m) + (3 * n) = 10) = T
See also
Arith.NEGATE_CONV,
Arith.FORALL_ARITH_CONV,
numLib.ARITH_CONV
FORALL_ARITH_CONV
FORALL_ARITH_CONV
Arith.FORALL_ARITH_CONV : conv
Partial decision procedure for non-existential Presburger natural arithmetic.
FORALL_ARITH_CONV is a partial decision procedure for formulae of
Presburger natural arithmetic which are in prenex normal form and have
all variables either free or universally quantified. Presburger natural
arithmetic is the subset of arithmetic formulae made up from natural
number constants, numeric variables, addition, multiplication by a
constant, the relations <, <=, =, >=, > and the logical
connectives ~, /\, \/, ==>, = (if-and-only-if), ! ('forall')
and ? ('there exists'). Products of two expressions which both contain
variables are not included in the subset, but the function SUC which
is not normally included in a specification of Presburger arithmetic is
allowed in this HOL implementation.
Given a formula in the specified subset, the function attempts to prove
that it is equal to T (true). The procedure only works if the formula
would also be true of the non-negative rationals; it cannot prove
formulae whose truth depends on the integral properties of the natural
numbers.
Failure
The function can fail in two ways. It fails if the argument term is not a formula in the specified subset, and it also fails if it is unable to prove the formula. The failure strings are different in each case.
Example
#FORALL_ARITH_CONV "m < SUC m";;
|- m < (SUC m) = T
#FORALL_ARITH_CONV "!m n p q. m <= p /\ n <= q ==> (m + n) <= (p + q)";;
|- (!m n p q. m <= p /\ n <= q ==> (m + n) <= (p + q)) = T
#FORALL_ARITH_CONV "!m n. ~(SUC (2 * m) = 2 * n)";;
evaluation failed FORALL_ARITH_CONV -- cannot prove formula
See also
Arith.NEGATE_CONV,
Arith.EXISTS_ARITH_CONV,
numLib.ARITH_CONV,
Arith.ARITH_FORM_NORM_CONV,
Arith.DISJ_INEQS_FALSE_CONV
INSTANCE_T_CONV
INSTANCE_T_CONV
Arith.INSTANCE_T_CONV : ((term -> term list) -> conv -> conv)
Function which allows a proof procedure to work on substitution instances of terms that are in the domain of the procedure.
This function generalises a conversion that is used to prove formulae true. It does this by first replacing any syntactically unacceptable subterms with variables. It then attempts to prove the resulting generalised formula and if successful it re-instantiates the variables.
The first argument should be a function which computes a list of
subterms of a term which are syntactically unacceptable to the proof
procedure. This function should include in its result any variables that
do not appear in other subterms returned. The second argument is the
proof procedure to be generalised; this should be a conversion which
when successful returns an equation between the argument formula and T
(true).
Failure
Fails if either of the applications of the argument functions fail, or if the conversion does not return an equation of the correct form.
Example
#FORALL_ARITH_CONV "!f m (n:num). (m < (f n)) ==> (m <= (f n))";;
evaluation failed FORALL_ARITH_CONV -- formula not in the allowed subset
#INSTANCE_T_CONV non_presburger_subterms FORALL_ARITH_CONV
# "!f m (n:num). (m < (f n)) ==> (m <= (f n))";;
|- (!f m n. m < (f n) ==> m <= (f n)) = T
is_prenex
is_prenex
Arith.is_prenex : (term -> bool)
Determines whether a formula is in prenex normal form.
This function returns true if the term it is given as argument is in prenex normal form. If the term is not a formula the result will be true provided there are no nested Boolean expressions involving quantifiers.
Failure
Never fails.
Example
> Arith.is_prenex ``!x. ?y. x \/ y``;
val it = true: bool
> Arith.is_prenex ``!x. x ==> (?y. x /\ y)``;
val it = false: bool
Useful for determining whether it is necessary to apply a prenex normaliser to a formula before passing it to a function which requires the formula to be in prenex normal form.
See also
is_presburger
is_presburger
Arith.is_presburger : (term -> bool)
Determines whether a formula is in the Presburger subset of arithmetic.
This function returns true if the argument term is a formula in the
Presburger subset of natural number arithmetic. Presburger natural
arithmetic is the subset of arithmetic formulae made up from natural
number constants, numeric variables, addition, multiplication by a
constant, the natural number relations <, <=, =, >=, > and the
logical connectives ~, /\, \/, ==>, = (if-and-only-if), !
('forall') and ? ('there exists').
Products of two expressions which both contain variables are not
included in the subset, but the function SUC which is not normally
included in a specification of Presburger arithmetic is allowed in this
HOL implementation. This function also considers subtraction and the
predecessor function, PRE, to be part of the subset.
Failure
Never fails.
Example
> Arith.is_presburger ``!m n p. m < (2 * n) /\ (n + n) <= p ==> m < SUC p``;
val it = true: bool
> Arith.is_presburger ``!m n p q. m < (n * p) /\ (n * p) < q ==> m < q``;
val it = false: bool
> Arith.is_presburger ``(m <= n) ==> !p. (m < SUC(n + p))``;
val it = true: bool
> Arith.is_presburger ``(m + n) - m = n``;
val it = true: bool
Useful for determining whether a decision procedure for Presburger arithmetic is applicable to a term.
See also
Arith.non_presburger_subterms,
Arith.FORALL_ARITH_CONV,
Arith.EXISTS_ARITH_CONV,
Arith.is_prenex
NEGATE_CONV
NEGATE_CONV
Arith.NEGATE_CONV : (conv -> conv)
Function for negating the operation of a conversion that proves a formula to be either true or false.
This function negates the operation of a conversion that proves a
formula to be either true or false. For example, if conv proves "t"
to be equal to "T" then NEGATE_CONV conv will prove "~t" to be
"F".
Failure
Fails if the application of the conversion to the negation of the
formula does not yield either "T" or "F".
Example
#ARITH_CONV "!n. 0 <= n";;
|- (!n. 0 <= n) = T
#NEGATE_CONV ARITH_CONV "~(!n. 0 <= n)";;
|- ~(!n. 0 <= n) = F
#NEGATE_CONV ARITH_CONV "?n. ~(0 <= n)";;
|- (?n. ~0 <= n) = F
non_presburger_subterms
non_presburger_subterms
Arith.non_presburger_subterms : (term -> term list)
Computes the subterms of a term that are not in the Presburger subset of arithmetic.
This function computes a list of subterms of a term that are not in the
Presburger subset of natural number arithmetic. All numeric variables in
the term are included in the result. Presburger natural arithmetic is
the subset of arithmetic formulae made up from natural number constants,
numeric variables, addition, multiplication by a constant, the natural
number relations <, <=, =, >=, > and the logical connectives
~, /\, \/, ==>, = (if-and-only-if), ! ('forall') and ?
('there exists').
Products of two expressions which both contain variables are not
included in the subset, so such products will appear in the result list.
However, the function SUC which is not normally included in a
specification of Presburger arithmetic is allowed in this HOL
implementation. This function also considers subtraction and the
predecessor function, PRE, to be part of the subset.
Failure
Never fails.
Example
#non_presburger_subterms "!m n p. m < (2 * n) /\ (n + n) <= p ==> m < SUC p";;
["m"; "n"; "p"] : term list
#non_presburger_subterms "!m n p q. m < (n * p) /\ (n * p) < q ==> m < q";;
["m"; "n * p"; "q"] : term list
#non_presburger_subterms "(m + n) - m = f n";;
["m"; "n"; "f n"] : term list
See also
Arith.INSTANCE_T_CONV,
Arith.is_presburger
PRENEX_CONV
PRENEX_CONV
Arith.PRENEX_CONV : conv
Puts a formula into prenex normal form.
This function puts a formula into prenex normal form, and in the process splits any Boolean equalities (if-and-only-if) into two implications. If there is a Boolean-valued subterm present as the condition of a conditional, the subterm will be put in prenex normal form, but quantifiers will not be moved out of the condition. Some renaming of variables may take place.
Failure
Never fails.
Example
> Arith.PRENEX_CONV ``!m n. (m <= n) ==> !p. (m < SUC(n + p))``;
val it =
⊢ (∀m n. m ≤ n ⇒ ∀p. m < SUC (n + p)) ⇔ ∀m n p. m ≤ n ⇒ m < SUC (n + p):
thm
> Arith.PRENEX_CONV ``!p. (!m. m >= p) = (p = 0)``;
val it =
⊢ (∀p. (∀m. m ≥ p) ⇔ p = 0) ⇔
∀p m. ∃m'. (m' ≥ p ⇒ p = 0) ∧ (p = 0 ⇒ m ≥ p): thm
Useful as a preprocessor to decision procedures which require their argument formula to be in prenex normal form.
See also
SUB_AND_COND_ELIM_CONV
SUB_AND_COND_ELIM_CONV
Arith.SUB_AND_COND_ELIM_CONV : conv
Eliminates natural number subtraction, PRE, and conditional statements from a formula.
This function eliminates natural number subtraction and the predecessor
function, PRE, from a formula, but in doing so may generate
conditional statements, so these are eliminated too. The conditional
statements are moved up through the term and if at any point the
branches of the conditional become Boolean-valued the conditional is
eliminated. Subtraction operators are moved up until a relation (such as
less-than) is reached. The subtraction can then be transformed into an
addition. Provided the argument term is a formula, only an abstraction
can prevent a conditional being moved up far enough to be eliminated. If
the term is not a formula it may not be possible to eliminate the
subtraction. The function is also incapable of eliminating subtractions
that appear in arguments to functions other than the standard operators
of arithmetic.
The function is not as delicate as it could be; it tries to eliminate all conditionals in a formula when it need only eliminate those that have to be removed in order to eliminate subtraction.
Failure
Never fails.
Example
#SUB_AND_COND_ELIM_CONV
# "((p + 3) <= n) ==> (!m. ((m = 0) => (n - 1) | (n - 2)) > p)";;
|- (p + 3) <= n ==> (!m. ((m = 0) => n - 1 | n - 2) > p) =
(p + 3) <= n ==>
(!m. (~(m = 0) \/ n > (1 + p)) /\ ((m = 0) \/ n > (2 + p)))
#SUB_AND_COND_ELIM_CONV
# "!f n. f ((SUC n = 0) => 0 | (SUC n - 1)) < (f n) + 1";;
|- (!f n. (f((SUC n = 0) => 0 | (SUC n) - 1)) < ((f n) + 1)) =
(!f n.
(~(SUC n = 0) \/ (f 0) < ((f n) + 1)) /\
((SUC n = 0) \/ (f((SUC n) - 1)) < ((f n) + 1)))
#SUB_AND_COND_ELIM_CONV
# "!f n. (\m. f ((m = 0) => 0 | (m - 1))) (SUC n) < (f n) + 1";;
|- (!f n. ((\m. f((m = 0) => 0 | m - 1))(SUC n)) < ((f n) + 1)) =
(!f n. ((\m. ((m = 0) => f 0 | f(m - 1)))(SUC n)) < ((f n) + 1))
Useful as a preprocessor to decision procedures which do not allow natural number subtraction in their argument formula.
See also
&&
&&
op BasicProvers.&& : simpset * thm list -> simpset
Re-exported from bossLib.&&. See that
entry for full documentation.
Abbr
Abbr
BasicProvers.Abbr : term quotation -> thm
Signals to simplification tactics that an abbreviation should be used.
The Abbr function is used to signal to various simplification tactics
that an abbreviation in the current goal should be eliminated before
simplification proceeds. Each theorem created by Abbr is removed from
the tactic's theorem-list argument, and causes a call to
Q.UNABBREV_TAC with that Abbr theorem's argument. Finally, the
simplification tactic continues, with the rest of the theorem-list as
its argument. Thus,
tac [..., Abbr`v`, ..., Abbr`u`, ...]
has the same effect as
Q.UNABBREV_TAC `v` THEN Q.UNABBREV_TAC `u` THEN
tac [..., ..., ...]
Every theorem created by Abbr in the argument list is treated in this
way. The tactics that understand Abbr arguments are SIMP_TAC,
ASM_SIMP_TAC, FULL_SIMP_TAC, RW_TAC and SRW_TAC.
Failure
Abbr itself never fails, but the tactic it is used in may do,
particularly if the induced calls to UNABBREV_TAC fail.
Comments
This function is a notational convenience that allows the effect of multiple tactics to be packaged into just one.
See also
Q.ABBREV_TAC,
simpLib.SIMP_TAC,
Q.UNABBREV_TAC
augment_srw_ss
augment_srw_ss
BasicProvers.augment_srw_ss : ssfrag list -> unit
Re-exported from bossLib.augment_srw_ss. See that
entry for full documentation.
bool_ss
bool_ss
BasicProvers.bool_ss : simpset
Re-exported from bossLib.bool_ss. See that
entry for full documentation.
CASE_TAC
CASE_TAC
BasicProvers.CASE_TAC : tactic
Case splits on a term t that features in the goal as case t of ...,
and then performs some simplification.
BasicProvers.CASE_TAC first calls BasicProvers.PURE_CASE_TAC, which
searches the goal for an instance of case t of ... and performs a
BasicProvers.Cases_on `t`. If this succeeds, it then simplifies
the goal using definitions of case constants, plus distinctness and
injectivity theorems for datatypes.
Comments
When there are multiple case constants in the goal, it can be very
convenient to execute the tactic REPEAT CASE_TAC. bossLib.CASE_TAC
is the same as BasicProvers.CASE_TAC.
Failure
BasicProvers.CASE_TAC fails precisely when
BasicProvers.PURE_CASE_TAC fails.
See also
Cases
Cases
BasicProvers.Cases : tactic
Re-exported from bossLib.Cases. See that
entry for full documentation.
Cases_on
Cases_on
BasicProvers.Cases_on : term quotation -> tactic
Re-exported from bossLib.Cases_on. See that
entry for full documentation.
diminish_srw_ss
diminish_srw_ss
BasicProvers.diminish_srw_ss : string list -> ssfrag list
Removes named simpset fragments from the stateful simpset.
A call to diminish_srw_ss fragnames removes the simpset fragments with
names given in fragnames from the stateful simpset which is returned
by srw_ss(), and which is used by SRW_TAC. This removal is done as a
side effect.
The function also returns the simpset fragments that have been removed.
This allows them to be put back into the simpset with a call to
augment_srw_ss.
The effect of this call is not exported to descendent theories.
Failure
Fails with the Conv.UNCHANGED exception if the call would make no
change to the underlying simpset (i.e., if no name in fragnames
corresponds to a fragment in the stateful simpset. Apart from this, a
name can be provided for a fragment that does not appear in the stateful
simpset. In this case, the name is just ignored, and there will be no
corresponding fragment in the list that the function returns.
Example
> SIMP_CONV (srw_ss()) [] ``MAP ($+ 1) [3;4;5]``;
val it = ⊢ MAP ($+ 1) [3; 4; 5] = [4; 5; 6]: thm
> val frags = diminish_srw_ss ["REDUCE"]
val frags = (): unit
> SIMP_CONV (srw_ss()) [] ``MAP ($+ 1) [3;4;5]``;
val it = ⊢ MAP ($+ 1) [3; 4; 5] = [1 + 3; 1 + 4; 1 + 5]: thm
> augment_srw_ss frags;
Exception- Type error in function application.
Function: augment_srw_ss : ssfrag list -> unit
Argument: frags : unit
Reason: Can't unify ssfrag list to {} (Incompatible types)
Fail "Static Errors" raised
> SIMP_CONV (srw_ss()) [] ``MAP ($+ 1) [3;4;5]``;
val it = ⊢ MAP ($+ 1) [3; 4; 5] = [1 + 3; 1 + 4; 1 + 5]: thm
See also
BasicProvers.augment_srw_ss,
simpLib.remove_ssfrags
export_rewrites
export_rewrites
BasicProvers.export_rewrites : string list -> unit
Exports theorems so that they merge with the "stateful" rewriter's
simpset.
A call to export_rewrites strlist causes the theorems named by the
strings in strlist to be merged into the simpset value maintained
behind the function srw_ss(), both in the current session and also
when the theory generated by the script file is loaded.
Theorems are named by giving the name of the segment, a full-stop (or
period) character, and the name of theorem. If the theorem is in the
current segment, the segment can be omitted. Thus, if working in the
development of the theory of lists, the following are valid names
list.MAP_GENLIST, MAP_GENLIST and arithmetic.LESS_TRANS.
The collection of all the theorems specified in calls to
export_rewrites can be obtained as a value of type simpLib.ssfrag
using the thy_ssfrag function.
Multiple calls to export_rewrites cumulatively add to the list of
theorems being exported.
Failure
Fails if any of the strings in the list does not name a theorem in the current context.
Comments
This function is useful for ensuring that the stateful rewriter is
augmented as theories are loaded. This in turn means that users of these
theories don't need to learn the names of their "obvious" theorems.
Because theorems can not be removed from the stateful rewriter's
underlying simpset, choice of "obvious" theorems needs to be done with
care.
See also
bossLib.augment_srw_ss,
bossLib.srw_ss,
bossLib.SRW_TAC,
BasicProvers.thy_ssfrag
Induct
Induct
BasicProvers.Induct : tactic
Re-exported from bossLib.Induct. See that
entry for full documentation.
Induct_on
Induct_on
BasicProvers.Induct_on : term quotation -> tactic
Re-exported from bossLib.Induct_on. See that
entry for full documentation.
namedCases
namedCases
BasicProvers.namedCases : string list -> tactic
Re-exported from bossLib.namedCases. See that
entry for full documentation.
namedCases_on
namedCases_on
BasicProvers.namedCases_on : term quotation -> string list -> tactic
Re-exported from bossLib.namedCases_on. See that
entry for full documentation.
PROVE
PROVE
BasicProvers.PROVE : thm list -> term -> thm
Re-exported from bossLib.PROVE. See that
entry for full documentation.
PROVE_TAC
PROVE_TAC
BasicProvers.PROVE_TAC : thm list -> tactic
Re-exported from bossLib.PROVE_TAC. See that
entry for full documentation.
PURE_CASE_TAC
PURE_CASE_TAC
BasicProvers.PURE_CASE_TAC : tactic
Case splits on a term t that features in the goal as case t of ....
BasicProvers.PURE_CASE_TAC searches the goal for an instance of
case t of ..., and performs a BasicProvers.Cases_on `t`.
Failure
BasicProvers.PURE_CASE_TAC fails if there is no instance of
case t of ... in the goal, where the case term is a case constant in
the typebase and all the free variables of t are free in the goal.
See also
RW_TAC
RW_TAC
BasicProvers.RW_TAC : simpset -> thm list -> tactic
Re-exported from bossLib.RW_TAC. See that
entry for full documentation.
srw_ss
srw_ss
BasicProvers.srw_ss : unit -> simpset
Re-exported from bossLib.srw_ss. See that
entry for full documentation.
SRW_TAC
SRW_TAC
BasicProvers.SRW_TAC : ssfrag list -> thm list -> tactic
Re-exported from bossLib.SRW_TAC. See that
entry for full documentation.
thy_ssfrag
thy_ssfrag
BasicProvers.thy_ssfrag : string -> simpLib.ssfrag
Returns simplifier fragment for a theory
Returns the simpset fragment recorded for the given theory. This
consists of the rewrites passed to export_rewrites.
Failure
Fails if the theory was not found, or did not export any theorems.
See also
VAR_EQ_TAC
VAR_EQ_TAC
BasicProvers.VAR_EQ_TAC : tactic
Simplifies a goal using any assumption of the form v = t or t = v,
where v is a variable
VAR_EQ_TAC simplifies the goal, including its assumptions, using one
assumption of the form v = t or t = v, where v is a variable which
is not contained in t.
In both cases, v is replaced throughout by t, and the relevant
assumption is deleted.
Failure
VAR_EQ_TAC fails if there are no such assumptions
See also
bossLib.FULL_SIMP_TAC,
bossLib.ASM_SIMP_TAC,
Rewrite.ASM_REWRITE_TAC
BBLAST_CONV
BBLAST_CONV
blastLib.BBLAST_CONV : conv
Bit-blasting conversion for words.
This conversion expands bit-vector terms into Boolean propositions. It
goes beyond the functionality of wordsLib.WORD_BIT_EQ_CONV by handling
addition, subtraction and orderings. Consequently, this conversion can
automatically handle small, but tricky, bit-vector goals that
wordsLib.WORD_DECIDE cannot handle. Obviously bit-blasting is a brute
force approach, so this conversion should be used with care. It will
only work well for smallish word sizes and when there is only and
handful of additions around. It is also "eager" -- additions are
expanded out even when not strictly necessary. For example, in
(a + b) <+ c /\ c <+ d ==> (a + b) <+ d:word32
the sum a + b is expanded. Users may be able to achieve speed-ups by
first introducing abbreviations and then proving general forms, e.g.
x <+ c /\ c <+ d ==> x <+ d:word32
The conversion handles most operators, however, the following are not covered / interpreted:
-
Type variables for word lengths, i.e. terms of type
:'a word. -
General multiplication, i.e.
w1 * w2. Multiplication by a literal is okay, although this may introduce many additions. -
Bit-field selections with non-literal bounds, e.g.
(expr1 -- expr2) w. -
Shifting by non-literal amounts, e.g.
w << expr. -
n2w exprandw2n w. Alsow2s,s2w,w2landl2w. -
word_div,word_sdiv,word_modandword_log2.
Example
Word orderings are handled:
> blastLib.BBLAST_CONV
“!a b. ~word_msb a /\ ~word_msb b ==> (a <+ b <=> a < b:word32)”;
val it = ⊢ (∀a b. ¬word_msb a ∧ ¬word_msb b ⇒ (a <₊ b ⇔ a < b)) ⇔ T: thm
In some cases the result will be a proposition over bit values:
> blastLib.BBLAST_CONV “!a. (a + 1w:word8) ' 1”;
val it = ⊢ (∀a. (a + 1w) ' 1) ⇔ ∀a. a ' 1 ⇔ ¬a ' 0: thm
This conversion is especially useful where "logical" and "arithmetic" bit-vector operations are combined:
> blastLib.BBLAST_CONV
“!a. ((((((a:word8) * 16w) + 0x10w)) && 0xF0w) >>> 4) = (3 -- 0) (a + 1w)”;
val it = ⊢ (∀a. (a * 16w + 16w && 240w) ⋙ 4 = (3 -- 0) (a + 1w)) ⇔ T: thm
See also
wordsLib.WORD_ss,
wordsLib.WORD_ARITH_CONV,
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_EVAL_CONV,
wordsLib.WORD_CONV
first_fv_term
first_fv_term
boolLib.first_fv_term : (term -> tactic) -> tactic
Applies a term-tactic to goal's first free variable that makes it succeed
A call to first_fv_term tmtac applies the function tmtac to all of a
goal's free variables. This generates a list of tactics, which is then
applied to the goal tactic-by-tactic (this is the action of the tactical
MAP_FIRST). The first application that succeeds (doesn't raise a
HOL_ERR) is taken as the result. Later applications are not attempted.
Failure
Fails if there is no free variable v in the goal A ?- g that makes
the application tmtac v (A?-g) succeed.
See also
fv_term
fv_term
boolLib.fv_term : (term -> tactic) -> tactic
Applies a term-tactic to a goal's "first" free variable
Applying fv_term tmtac to a goal A ?- g, finds the first free
variable in the goal, and passes that variable to the function tmtac,
generating a tactic, which is then applied to the goal. The first free
variable is the first returned by successive calls to free_vars
applied to first g and then each assumption in A in turn.
Failure
Fails if a goal does not have any free variables, or if tmtac v fails
when applied to the goal, with v the "first" free variable as defined
above.
Example
?- 0 < f (n:num)
================================== fv_term (C tmCases_on ["", "j"])
?- 0 < f 0 ?- 0 < f (SUC j)
See also
tyvar_sequence
tyvar_sequence
boolLib.tyvar_sequence : int -> hol_type list
Generates a canonical list of distinct type variables.
A call to tyvar_sequence n generates a list consisting of n distinct
type variables, with early members of the sequence being :'a
("alpha"), :'b ("beta") etc. After the first 26 members of the list,
the remainder are of the form :'a1, :'a2 etc.
Failure
Never fails. If n is negative the generated list is empty.
Example
> tyvar_sequence 3;
val it = [“:α”, “:β”, “:γ”]: hol_type list
See also
bool_ss
bool_ss
boolSimps.bool_ss : simpset
Re-exported from bossLib.bool_ss. See that
entry for full documentation.
DNF_ss
DNF_ss
boolSimps.DNF_ss : ssfrag
A simpset fragment that does aggressive propositional and quantifier normalisation.
Adding the DNF_ss simpset fragment to a simpset augments it with
rewrites that make the simplifier normalise "towards" disjunctive normal
form. This normalisation at the propositional level does leave
implications alone (rather than convert them to disjunctions). DNF_ss
also includes normalisations pertaining to quantifiers. The complete
list of rewrites is
|- !P Q. (!x. P x /\ Q x) <=> (!x. P x) /\ !x. Q x
|- !P Q. (?x. P x \/ Q x) <=> (?x. P x) \/ ?x. Q x
|- !P Q R. P \/ Q ==> R <=> (P ==> R) /\ (Q ==> R)
|- !P Q R. P ==> Q /\ R <=> (P ==> Q) /\ (P ==> R)
|- !A B C. (B \/ C) /\ A <=> B /\ A \/ C /\ A
|- !A B C. A /\ (B \/ C) <=> A /\ B \/ A /\ C
|- !P Q. (?x. P x) ==> Q <=> !x. P x ==> Q
|- !P Q. P ==> (!x. Q x) <=> !x. P ==> Q x
|- !P Q. (?x. P x) /\ Q <=> ?x. P x /\ Q
|- !P Q. P /\ (?x. Q x) <=> ?x. P /\ Q x
Failure
As a value rather than a function, DNF_ss can't fail.
Example
> SIMP_CONV (bool_ss ++ DNF_ss) []
``!x. (?y. P x y) /\ Q z ==> R1 x z /\ R2 z x``;
val it =
⊢ (∀x. (∃y. P x y) ∧ Q z ⇒ R1 x z ∧ R2 z x) ⇔
(∀x y. P x y ∧ Q z ⇒ R1 x z) ∧ ∀x y. P x y ∧ Q z ⇒ R2 z x: thm
Comments
The DNF_ss fragment interacts well with the one-point elimination
rules for equalities under quantifiers (provided in bool_ss and its
descendants).
See also
boolSimps.bool_ss,
simpLib.SIMP_CONV
NORMEQ_ss
NORMEQ_ss
boolSimps.NORMEQ_ss : ssfrag
A simpset fragment that reorients equalities.
The NORMEQ_ss simpset fragment embodies a conversion that flips terms
of the form l = r when l contains no free variables, and r
contains at least one variable. To flip an equality is to rewrite it so
that l = r becomes r = l.
Failure
As a static value, this cannot fail.
Example
In this example, the simplifier flips the 3 = x term, making it useful
as a rewrite when attacking the consequent of the implication.
SIMP_CONV (bool_ss ++ boolSimps.NORMEQ_ss) [] ``(3 = x) ==> x + 1 < y``;
> val it =
|- (3 = x) ==> x + 1 < y <=> (x = 3) ==> 3 + 1 < y : thm
See also
arb
arb
boolSyntax.arb : term
Constant denoting arbitrary items.
The ML variable boolSyntax.arb is bound to the term bool$ARB.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.bool_case
bool_case
bool_case
boolSyntax.bool_case : term
Constant denoting case expressions for bool.
The ML variable boolSyntax.bool_case is bound to the term
bool$bool_case.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.let_tm,
boolSyntax.arb
conditional
conditional
boolSyntax.conditional : term
Constant denoting conditional expressions.
The ML variable boolSyntax.conditional is bound to the term
bool$COND.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
conjunction
conjunction
boolSyntax.conjunction : term
Constant denoting logical conjunction.
The ML variable boolSyntax.conjunction is bound to the term bool$/\.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
dest_arb
dest_arb
boolSyntax.dest_arb : term -> hol_type
Extract the type of an instance of the ARB constant.
If M is an instance of the constant ARB with type ty, then
dest_arb M equals ty.
Failure
Fails if M is not an instance of ARB.
Comments
When it succeeds, an invocation of dest_arb is equivalent to
type_of.
See also
boolSyntax.mk_arb,
boolSyntax.is_arb
dest_bool_case
dest_bool_case
boolSyntax.dest_bool_case : term -> term * term * term
Destructs a case expression over bool.
If M has the form bool_case M1 M2 b, then dest_bool_case M returns
M1,M2,b.
Failure
Fails if M is not a full application of the bool_case constant.
See also
boolSyntax.mk_bool_case,
boolSyntax.is_bool_case
dest_cond
dest_cond
boolSyntax.dest_cond : term -> term * term * term
Breaks apart a conditional into the three terms involved.
If M has the form if t then t1 else t2 then dest_cond M returns
(t,t1,t2).
Failure
Fails if M is not a conditional.
See also
boolSyntax.mk_cond,
boolSyntax.is_cond
dest_conj
dest_conj
boolSyntax.dest_conj : term -> term * term
Term destructor for conjunctions.
If M is a term t1 /\ t2, then dest_conj M returns (t1,t2).
Failure
Fails if M is not a conjunction.
See also
boolSyntax.mk_conj,
boolSyntax.is_conj,
boolSyntax.list_mk_conj,
boolSyntax.strip_conj
dest_disj
dest_disj
boolSyntax.dest_disj : term -> term * term
Term destructor for disjunctions.
If M is a term having the form t1 \/ t2, then dest_disj M returns
(t1,t2).
Failure
Fails if M is not a disjunction.
See also
boolSyntax.mk_disj,
boolSyntax.is_disj,
boolSyntax.strip_disj,
boolSyntax.list_mk_disj
dest_eq
dest_eq
boolSyntax.dest_eq : term -> term * term
Term destructor for equality.
If M is the term t1 = t2, then dest_eq M returns (t1, t2).
Failure
Fails if M is not an equality.
See also
boolSyntax.mk_eq,
boolSyntax.is_eq,
boolSyntax.lhs, boolSyntax.rhs
dest_eq_ty
dest_eq_ty
boolSyntax.dest_eq_ty : term -> term * term * hol_type
Term destructor for equality.
If M is the term t1 = t2, then dest_eq_ty M returns
(t1, t2, ty), where ty is the type of t1 (and thus also of t2).
Failure
Fails if M is not an equality.
Gives an efficient way to break apart an equality and get the type of the equality. Useful for obtaining that last fraction of speed when optimizing the bejeesus out of an inference rule.
See also
boolSyntax.mk_eq,
boolSyntax.is_eq,
boolSyntax.lhs, boolSyntax.rhs
dest_exists
dest_exists
boolSyntax.dest_exists : term -> term * term
Breaks apart an existentially quantified term into quantified variable and body.
If M has the form ?x. t, then dest_exists M returns (x,t).
Failure
Fails if M is not an existential quantification.
See also
boolSyntax.mk_exists,
boolSyntax.is_exists,
boolSyntax.strip_exists
dest_exists1
dest_exists1
boolSyntax.dest_exists1 : term -> term * term
Breaks apart a unique existence term into quantified variable and body.
If M has the form ?!x. t, then dest_exists1 M returns (x,t).
Failure
Fails if M is not a unique existence term.
See also
boolSyntax.mk_exists1,
boolSyntax.is_exists1
dest_forall
dest_forall
boolSyntax.dest_forall : term -> term * term
Breaks apart a universally quantified term into quantified variable and body.
If M has the form !x. t, then dest_forall M returns (x,t).
Failure
Fails if M is not a universal quantification.
See also
boolSyntax.mk_forall,
boolSyntax.is_forall,
boolSyntax.strip_forall,
boolSyntax.list_mk_forall
dest_imp
dest_imp
boolSyntax.dest_imp : term -> term * term
Breaks an implication or negation into antecedent and consequent.
dest_imp is a term destructor for implications. It treats negations as
implications with consequent F. Thus, if M is a term with the form
t1 ==> t2, then dest_imp M returns (t1,t2), and if M has the
form ~t, then dest_imp M returns (t,F).
Failure
Fails if M is neither an implication nor a negation.
Comments
Destructs negations for increased functionality of HOL-style resolution.
If the ability to destruct negations is not desired, as is only right,
then use dest_imp_only.
See also
boolSyntax.mk_imp,
boolSyntax.dest_imp_only,
boolSyntax.is_imp,
boolSyntax.is_imp_only,
boolSyntax.strip_imp,
boolSyntax.list_mk_imp
dest_imp_only
dest_imp_only
boolSyntax.dest_imp_only : term -> term * term
Breaks an implication into antecedent and consequent.
If M is a term with the form t1 ==> t2, then dest_imp_only M
returns (t1,t2).
Failure
Fails if M is not an implication.
See also
boolSyntax.mk_imp,
boolSyntax.dest_imp,
boolSyntax.is_imp,
boolSyntax.is_imp_only,
boolSyntax.strip_imp,
boolSyntax.list_mk_imp
dest_let
dest_let
boolSyntax.dest_let : term -> term * term
Breaks apart a let-expression.
If M is a term of the form LET M N, then dest_let M returns
(M,N).
Example
> dest_let (Term `let x = P /\ Q in x \/ x`);
Exception- HOL_ERR
(at boolpp.Term: on line 1, characters 20-29: let with non-equality) raised
Failure
Fails if M is not of the form LET M N.
See also
boolSyntax.mk_let,
boolSyntax.is_let
dest_neg
dest_neg
boolSyntax.dest_neg : term -> term
Breaks apart a negation, returning its body.
dest_neg is a term destructor for negations: if M has the form ~t,
then dest_neg M returns t.
Failure
Fails with dest_neg if term is not a negation.
See also
boolSyntax.mk_neg,
boolSyntax.is_neg
dest_select
dest_select
boolSyntax.dest_select : term -> term * term
Breaks apart a choice term into selected variable and body.
If M has the form @v. t then dest_select M returns (v,t).
Failure
Fails if M is not an epsilon-term.
See also
boolSyntax.mk_select,
boolSyntax.is_select
dest_strip_comb
dest_strip_comb
boolSyntax.dest_strip_comb : term -> string * term list
Strips a function application, and breaks head constant.
If t is a term of the form c t1 t2 .. tn, with c a constant, then
a call to dest_strip_comb t returns a pair (s,[t1,...,tn]), where
s is a string of the form thy$name. The thy prefix identifies the
theory where the constant was defined, and the name suffix is the
constant's name.
Failure
Fails if the term is not a constant applied to zero or more arguments.
Example
> dest_strip_comb ``SUC 2``;
val it = ("num$SUC", [“2”]): string * term list
Comments
Useful for pattern-matching at the ML level, where doing a case on
Lib.total dest_strip_comb t allows patterns of interest to be
idiomatically identified. In the absence of view-patterns in SML, one
has to use custom destructors.
See also
disjunction
disjunction
boolSyntax.disjunction : term
Constant denoting logical disjunction.
The ML variable boolSyntax.disjunction is bound to the term bool$\/.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
equality
equality
boolSyntax.equality : term
Constant denoting logical equality.
The ML variable boolSyntax.equality is bound to the term min$=.
See also
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
existential
existential
boolSyntax.existential : term
Constant denoting existential quantification.
The ML variable boolSyntax.existential is bound to the term bool$?.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
exists1
exists1
boolSyntax.exists1 : term
Constant denoting the unique existence quantifier.
The ML variable boolSyntax.exists1 is bound to the term bool$?!.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
F
F
boolSyntax.F : term
Constant denoting falsity.
The ML variable boolSyntax.F is bound to the term bool$F.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
gen_tyvar_sigma
gen_tyvar_sigma
boolSyntax.gen_tyvar_sigma : hol_type list -> (hol_type,hol_type) Lib.subst
Generates an instantiation mapping each type to a fresh type variable
A call to gen_tyvar_sigma tys generates an instantiation (a list of
{redex,residue} pairs) mapping the types in tys to fresh type
variables (generated in turn with gen_tyvar). Standard practice would
be to have tys be a list of distinct type variables, but this is not
checked.
Failure
Never fails.
Example
> gen_tyvar_sigma [“:'c”, “:'a”, “:'bob”];
val it =
[{redex = “:γ”, residue = “:%%gen_tyvar%%32”},
{redex = “:α”, residue = “:%%gen_tyvar%%33”},
{redex = “:'bob”, residue = “:%%gen_tyvar%%34”}]:
(hol_type, hol_type) Lib.subst
See also
Type.gen_tyvar,
Drule.GEN_TYVARIFY
gen_tyvarify
gen_tyvarify
boolSyntax.gen_tyvarify : term -> term
Instantiates a term with fresh type variables
A call to gen_tyvarify tm renames all of the type variables in term
tm to fresh replacements (generated with gen_tyvar).
Failure
Never fails.
Example
> show_types := true;
gen_tyvarify “h::t”;
val it = (): unit
val it = “(h :%%gen_tyvar%%35)::(t :%%gen_tyvar%%35 list)”: term
See also
implication
implication
boolSyntax.implication : term
Constant denoting logical implication.
The ML variable boolSyntax.implication is bound to the term min$==>.
See also
boolSyntax.equality,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
is_arb
is_arb
boolSyntax.is_arb : term -> bool
Tests a term to see if it's an instance of ARB.
Returns true if and only if M has the form ARB.
None known.
See also
boolSyntax.mk_arb,
boolSyntax.dest_arb
is_bool_case
is_bool_case
boolSyntax.is_bool_case : term -> bool
Tests a case expression over bool.
If M has the form bool_case M1 M2 b, then is_bool_case M returns
true. Otherwise, it returns false.
Failure
Never fails.
See also
boolSyntax.mk_bool_case,
boolSyntax.dest_bool_case
is_cond
is_cond
boolSyntax.is_cond : term -> bool
Tests a term to see if it is a conditional.
If M has the form if t then t1 else t2 then is_cond M returns
true If the term is not a conditional the result is false.
Failure
Never fails.
See also
boolSyntax.mk_cond,
boolSyntax.dest_cond
is_conj
is_conj
boolSyntax.is_conj : term -> bool
Tests a term to see if it is a conjunction.
If M has the form t1 /\ t2, then is_conj M returns true. If M
is not a conjunction the result is false.
Failure
Never fails.
See also
boolSyntax.mk_conj,
boolSyntax.dest_conj
is_disj
is_disj
boolSyntax.is_disj : term -> bool
Tests a term to see if it is a disjunction.
If M has the form t1 \/ t2, then is_disj M returns true. If M
is not a disjunction the result is false.
Failure
Never fails.
See also
boolSyntax.mk_disj,
boolSyntax.dest_disj
is_eq
is_eq
boolSyntax.is_eq : term -> bool
Tests a term to see if it is an equation.
If M has the form t1 = t2 then is_eq M returns true. If M is
not an equation the result is false.
Failure
Never fails.
See also
boolSyntax.mk_eq,
boolSyntax.dest_eq
is_exists
is_exists
boolSyntax.is_exists : term -> bool
Tests a term to see if it is an existential quantification.
If M has the form ?v. t then is_exists M returns true. If the
term is not an existential quantification the result is false.
Failure
Never fails.
See also
boolSyntax.mk_exists,
boolSyntax.dest_exists
is_exists1
is_exists1
boolSyntax.is_exists1 : term -> bool
Tests a term to see if it is a unique existence term.
If M has the form ?!v. t then is_exists1 M returns true. If the
term is not a unique existence quantification the result is false.
Failure
Never fails.
See also
boolSyntax.mk_exists1,
boolSyntax.dest_exists
is_forall
is_forall
boolSyntax.is_forall : term -> bool
Tests a term to see if it is a universal quantification.
If M is a term with the form !x. t, then is_forall M returns
true. If M is not a universal quantification the result is false.
Failure
Never fails.
See also
boolSyntax.mk_forall,
boolSyntax.dest_forall
is_imp
is_imp
boolSyntax.is_imp : term -> bool
Tests a term to see if it is an implication or a negation.
If M has the form t1 ==> t2, or the form ~t, then is_imp M
returns true. If the term is neither an implication nor a negation the
result is false.
Failure
Never fails.
Comments
Yields true of negations because dest_imp destructs negations (for
backwards compatibility with PPLAMBDA). Use is_imp_only if you don't
want this behaviour.
See also
boolSyntax.mk_imp,
boolSyntax.dest_imp,
boolSyntax.is_imp_only,
boolSyntax.dest_imp_only
is_imp_only
is_imp_only
boolSyntax.is_imp_only : term -> bool
Tests a term to see if it is an implication.
If M has the form t1 ==> t2 then is_imp_only M returns true. If
the term is not an implication, the result is false.
Failure
Never fails.
See also
boolSyntax.is_imp,
boolSyntax.mk_imp,
boolSyntax.dest_imp,
boolSyntax.dest_imp_only,
boolSyntax.list_mk_imp,
boolSyntax.strip_imp
is_let
is_let
boolSyntax.is_let : term -> bool
Tests a term to see if it is a let-expression.
If tm is a term of the form LET M N, then dest_let tm returns
true. Otherwise, it returns false.
Failure
Never fails.
Example
> Term `LET f x`;
val it = “LET f x”: term
> is_let it;
val it = true: bool
> is_let (Term `let x = P /\ Q in x \/ x`);
Exception- HOL_ERR
(at boolpp.Term: on line 1, characters 18-27: let with non-equality) raised
See also
boolSyntax.mk_let,
boolSyntax.dest_let
is_neg
is_neg
boolSyntax.is_neg : term -> bool
Tests a term to see if it is a negation.
If M has the form ~t, then is_neg M returns true. If the term is
not a negation the result is false.
Failure
Never fails.
See also
boolSyntax.mk_neg,
boolSyntax.dest_neg
is_select
is_select
boolSyntax.is_select : (term -> bool)
Tests a term to see if it is a choice binding.
is_select "@var. t" returns true. If the term is not an epsilon-term
the result is false.
Failure
Never fails.
See also
boolSyntax.mk_select,
boolSyntax.dest_select
let_tm
let_tm
boolSyntax.let_tm : term
Constant denoting let expressions.
The ML variable boolSyntax.let_tm is bound to the term bool$LET.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.bool_case,
boolSyntax.arb
lhand
lhand
boolSyntax.lhand : term -> term
Returns the left-hand argument of a binary application.
A call to lhand t returns x in those situations where t is of the
form ``f x y``.
Failure
Fails if the argument is not of the required form.
Example
> lhand ``3 + 2``;
val it = “3”: term
Comments
The name lhand is an abbreviation of "left-hand", but rand is
so-named as an abbreviation of "operand". Nonetheless, rand does
return the right-hand argument of a binary application.
See also
lhs
lhs
boolSyntax.lhs : term -> term
Returns the left-hand side of an equation.
If M has the form t1 = t2 then lhs M returns t1.
Failure
Fails if the term is not an equation.
See also
boolSyntax.rhs,
boolSyntax.dest_eq,
boolSyntax.mk_eq
list_mk_abs
list_mk_abs
boolSyntax.list_mk_abs : term list * term -> term
Re-exported from Term.list_mk_abs. See that
entry for full documentation.
list_mk_conj
list_mk_conj
boolSyntax.list_mk_conj : term list -> term
Constructs the conjunction of a list of terms.
list_mk_conj([t1,...,tn]) returns t1 /\ ... /\ tn.
Failure
Fails if the list is empty or if the list has more than one element, one
or more of which are not of type bool.
Example
> list_mk_conj [T,F,T];
val it = “T ∧ F ∧ T”: term
> try list_mk_conj [T,mk_var("x",alpha),F];
Exception- HOL_ERR (at boolSyntax.mk_conj: Non-boolean argument) raised
> list_mk_conj [mk_var("x",alpha)];
val it = “x”: term
See also
boolSyntax.strip_conj,
boolSyntax.mk_conj
list_mk_disj
list_mk_disj
boolSyntax.list_mk_disj : term list -> term
Constructs the disjunction of a list of terms.
list_mk_disj([t1,...,tn]) returns t1 \/ ... \/ tn.
Failure
Fails if the list is empty or if the list has more than one element, one
or more of which are not of type bool.
Example
> list_mk_disj [T,F,T];
val it = “T ∨ F ∨ T”: term
> try list_mk_disj [T,mk_var("x",alpha),F];
Exception- HOL_ERR (at boolSyntax.mk_disj: Non-boolean argument) raised
> list_mk_disj [mk_var("x",alpha)];
val it = “x”: term
See also
boolSyntax.strip_disj,
boolSyntax.mk_disj
list_mk_exists
list_mk_exists
boolSyntax.list_mk_exists : term list * term -> term
Iteratively constructs an existential quantification.
list_mk_exists([x1,...,xn],t) returns ?x1 ... xn. t.
Failure
Fails if the terms in the list are not variables or if t is not of
type bool and the list of terms is non-empty. If the list of terms is
empty the type of t can be anything.
See also
boolSyntax.strip_exists,
boolSyntax.mk_exists
list_mk_forall
list_mk_forall
boolSyntax.list_mk_forall : term list * term -> term
Iteratively constructs a universal quantification.
list_mk_forall([x1,...,xn],t) returns !x1 ... xn. t.
Failure
Fails if the terms in the list are not variables or if t is not of
type bool and the list of terms is non-empty. If the list of terms is
empty the type of t can be anything.
See also
boolSyntax.strip_forall,
boolSyntax.mk_forall
list_mk_fun
list_mk_fun
boolSyntax.list_mk_fun : hol_type list * hol_type -> hol_type
Iteratively constructs function types.
list_mk_fun([ty1,...,tyn],ty) returns ty1 -> ( ... (tyn -> t)...).
Failure
Never fails.
Example
> list_mk_fun ([alpha,bool],beta);
val it = “:α -> bool -> β”: hol_type
See also
boolSyntax.strip_fun,
Type.mk_type, Type.-->
list_mk_icomb
list_mk_icomb
boolSyntax.list_mk_icomb : term * term list -> term
Folds mk_icomb over a series of arguments.
A call to list_mk_icomb(f,args) combines f with each of the elements
of the list args in turn, moving from left to right. If args is
empty, then the result is simply f. When args is non-empty, the
growing application-term is created with successive calls to mk_icomb,
possibly causing type variables in any of the terms to become
instantiated.
Failure
Fails if any of the underlying calls to mk_icomb fails, which will
occur if the type of the accumulating term (starting with f) is not of
a function type, or if it has a domain type that can not be instantiated
to equal the type of the next argument term.
Comments
list_mk_icomb is to mk_icomb what list_mk_comb is to
mk_comb. However, it is important to be aware that list_mk_icomb
instantiates types sequentially, and not, as one might expect, in
parallel. For example the pairing function (,) is usually written
infix and has type :'a -> 'b -> 'a # 'b. A pair where the first
component has type :'b and the second has type :num can be
built with
> pairSyntax.mk_pair(``x:'b``, ``y:num``);
val it = “(x,y)”: term
> type_of it;
val it = “:β # num”: hol_type
but an attempt to do the same via list_mk_icomb
> list_mk_icomb
(``(,):'a -> 'b -> 'a # 'b``, [``x:'b``, ``y:num``]);
val it = “(x,y)”: term
> type_of it;
val it = “:num # num”: hol_type
confounds expectations since the call first instantiates :'a in the
type of (,) by :'b, then instantiates :'b in the result by
:num.
See also
Term.list_mk_comb,
Term.mk_comb,
boolSyntax.mk_icomb
list_mk_imp
list_mk_imp
boolSyntax.list_mk_imp : term list * term -> term
Iteratively constructs implications.
list_mk_imp([t1,...,tn],t) returns t1 ==> ( ... (tn ==> t)...).
Failure
Fails if any of t1,...,tn are not of type bool. Also fails if the
list of terms is non-empty and t is not of type bool. If the list of
terms is empty the type of t can be anything.
Example
> list_mk_imp ([T,F],T);
val it = “T ⇒ F ⇒ T”: term
> try list_mk_imp ([T,F],mk_var("x",alpha));
Exception- HOL_ERR (at boolSyntax.mk_imp: Non-boolean argument) raised
> list_mk_imp ([],mk_var("x",alpha));
val it = “x”: term
See also
boolSyntax.strip_imp,
boolSyntax.mk_imp
list_mk_ucomb
list_mk_ucomb
boolSyntax.list_mk_ucomb : term * term list -> term
Folds mk_ucomb over a series of arguments.
A call to list_mk_ucomb(f, args) combines f with each of the
elements of the list args in turn, moving from left to right. If
args is empty, then the result is simply f. When args is
non-empty, the growing application-term is created with successive calls
to mk_ucomb, possibly causing type variables in any of the terms to
become instantiated.
Failure
Fails if any of the underlying calls to mk_ucomb fails, which will
occur if the type of the accumulating term (starting with f) is not of
a function type, or if it has a domain type that can not be instantiated
to equal the type of some instantiation of the next argument term.
Comments
list_mk_ucomb is to mk_ucomb what list_mk_comb is to mk_comb.
See also
Term.list_mk_comb,
Term.mk_comb,
boolSyntax.mk_ucomb
mk_arb
mk_arb
boolSyntax.mk_arb : hol_type -> term
Creates a type instance of the ARB constant.
For any HOL type ty, mk_arb ty creates a type instance of the ARB
constant.
Failure
Never fails.
Comments
ARB is a constant of type 'a. It is sometimes used for creating
pseudo-partial functions.
See also
boolSyntax.dest_arb,
boolSyntax.is_arb,
boolSyntax.arb
mk_bool_case
mk_bool_case
boolSyntax.mk_bool_case : term * term * term -> term
Constructs a case expression over bool.
mk_bool_case M1 M2 b returns bool_case M1 M2 b. The prettyprinter
displays this as case b of T -> M1 || F -> M2. The bool_case
constant may be thought of as a pattern-matching version of the
conditional.
Failure
Fails if b is not of type bool. Also fails if M1 and M2 do not
have the same type.
Example
> mk_bool_case (Term`f x`,Term`b:'b`,Term`x:bool`);
val it = “if x then f x else b”: term
See also
boolSyntax.dest_bool_case,
boolSyntax.is_bool_case
mk_cond
mk_cond
boolSyntax.mk_cond : term * term * term -> term
Constructs a conditional term.
mk_cond(t,t1,t2) constructs an application COND t t1 t2. This is
rendered by the prettyprinter as if t then t1 else t2.
Failure
Fails if t is not of type bool or if t2 and t2 are of different
types.
Comments
The prettyprinter can be trained to print if t then t1 else t2 as
t => t1 | t2.
See also
boolSyntax.dest_cond,
boolSyntax.is_cond
mk_conj
mk_conj
boolSyntax.mk_conj : term * term -> term
Constructs a conjunction.
mk_conj(t1, t2) returns the term t1 /\ t2.
Failure
Fails if t1 and t2 do not both have type bool.
See also
boolSyntax.dest_conj,
boolSyntax.is_conj,
boolSyntax.list_mk_conj,
boolSyntax.strip_conj
mk_disj
mk_disj
boolSyntax.mk_disj : term * term -> term
Constructs a disjunction.
If t1 and t2 are terms, both of type bool, then mk_disj(t1,t2)
returns the term t1 \/ t2.
Failure
Fails if t1 or t2 does not have type bool.
See also
boolSyntax.dest_disj,
boolSyntax.is_disj,
boolSyntax.list_mk_disj,
boolSyntax.strip_disj
mk_eq
mk_eq
boolSyntax.mk_eq : term * term -> term
Constructs an equation.
mk_eq(t1, t2) returns the term t1 = t2.
Failure
Fails if the type of t1 is not equal to that of t2.
See also
boolSyntax.dest_eq,
boolSyntax.is_eq
mk_exists
mk_exists
boolSyntax.mk_exists : term * term -> term
Term constructor for existential quantification.
If v is a variable and t is a term of type bool, then
mk_exists (v,t) returns the term ?v. t.
Failure
Fails if v is not a variable or if t is not of type bool.
See also
boolSyntax.dest_exists,
boolSyntax.is_exists,
boolSyntax.list_mk_exists,
boolSyntax.strip_exists
mk_exists1
mk_exists1
boolSyntax.mk_exists1 : term * term -> term
Term constructor for unique existence.
If v is a variable and t is a term of type bool, then
mk_exists1 (v,t) returns the term ?!v. t.
Failure
Fails if v is not a variable or if t is not of type bool.
See also
boolSyntax.dest_exists1,
boolSyntax.is_exists1
mk_forall
mk_forall
boolSyntax.mk_forall : term * term -> term
Term constructor for universal quantification.
If v is a variable and t is a term of type bool, then
mk_forall (v,t) returns the term !v. t.
Failure
Fails if v is not a variable or if t is not of type bool.
See also
boolSyntax.dest_forall,
boolSyntax.is_forall,
boolSyntax.list_mk_forall,
boolSyntax.strip_forall
mk_icomb
mk_icomb
boolSyntax.mk_icomb : term * term -> term
Forms an application term, possibly instantiating the function.
A call to mk_icomb(f,x) checks to see if the term f, which must have
function type, can have any of its type variables instantiated so as to
make the domain of the function match the type of x. If so, then the
call returns the application of the instantiated f to x.
Failure
Fails if there is no way to instantiate the function term to make its domain match the argument's type.
Example
Note how both the S combinator and the argument have type variables invented for them when the two quotations are parsed.
- val t = mk_icomb(``S``, ``\n:num b. (n,b)``);
<<HOL message: inventing new type variable names: 'a, 'b, 'c>>
<<HOL message: inventing new type variable names: 'a>>
> val t = ``S (\n b. (n,b))`` : term
The resulting term t has only the type variable :'a left after
instantiation.
- type_of t;
> val it = ``:(num -> 'a) -> num -> num # 'a`` : hol_type
This term can now be combined with an argument and the final type variable instantiated:
- mk_icomb(t, ``ODD``);
> val it = ``S (\n b. (n,b)) ODD`` : term
- type_of it;
> val it = ``:num -> num # bool``;
Attempting to use mk_comb above results in immediate error because it
requires domain and arguments types to be identical:
- mk_comb(``S``, ``\n:num b. (n,b)``) handle e => Raise e;
<<HOL message: inventing new type variable names: 'a, 'b, 'c>>
<<HOL message: inventing new type variable names: 'a>>
Exception raised at Term.mk_comb:
incompatible types
! Uncaught exception:
! HOL_ERR
See also
boolSyntax.list_mk_icomb,
Term.mk_comb
mk_imp
mk_imp
boolSyntax.mk_imp : term * term -> term
Constructs an implication.
If t1 and t2 are terms of type bool, then mk_imp(t1,t2)
constructs the term t1 ==> t2.
Failure
Fails if t1 and t2 are not both of type bool.
See also
boolSyntax.dest_imp,
boolSyntax.dest_imp_only,
boolSyntax.is_imp,
boolSyntax.is_imp_only,
boolSyntax.list_mk_imp
mk_let
mk_let
boolSyntax.mk_let : term * term -> term
Constructs a let term.
The invocation mk_let (M,N) returns the term `LET M N`. If M
is of the form \x.t then the result will be pretty-printed as
let x = N in t. Since LET M N is defined to be M N, one can think
of a let-expression as a suspended beta-redex (if that helps).
Failure
Fails if the types of M and N are such that LET M N is not
well-typed, i.e., the type of M must be a function type, and the type
of N must equal the domain of the type of M.
Example
> mk_let(Term`\x. x \/ x`, Term`Q /\ R`);
val it = “let x = (Q ∧ R) in x ∨ x”: term
Comments
let expressions may be nested.
Pairing can also be used in the let syntax, provided pairTheory has
been loaded. The library pairLib provides support for manipulating
'paired' lets.
See also
boolSyntax.dest_let,
boolSyntax.is_let,
pairSyntax.mk_anylet
mk_neg
mk_neg
boolSyntax.mk_neg : (term -> term)
Constructs a negation.
mk_neg "t" returns "~t".
Failure
Fails with mk_neg unless t is of type bool.
See also
boolSyntax.dest_neg,
boolSyntax.is_neg
mk_select
mk_select
boolSyntax.mk_select : term * term -> term
Constructs a choice-term.
If v is a variable and t is a term of type bool, then
mk_select (v,t) returns @var. t.
Failure
Fails if v is not a variable or if t is not of type bool.
See also
boolSyntax.dest_select,
boolSyntax.is_select
mk_ucomb
mk_ucomb
boolSyntax.mk_ucomb : term * term -> term
Forms an application term, possibly instantiating both the function and the argument types.
A call to mk_ucomb(f,x) checks to see if the term f (which must have
a function type) can have its type variables instantiated to make the
domain of the function match some instantiation of the type of x. If
so, then the call returns the application of the instantiated f to the
instantiated x.
Failure
Fails if there is no way to instantiate the types to make the function domain match the argument type.
Example
Note how both the FOLDR combinator and the argument (the K combinator) have type variables invented for them when the two quotations are parsed.
- val t = mk_ucomb(``FOLDR``, ``K``);
<<HOL message: inventing new type variable names: 'a, 'b>>
<<HOL message: inventing new type variable names: 'a, 'b>>
> val t = ``FOLDR K`` : term
The resulting term t has only the type variable :'a left after
instantiation.
- type_of t;
> val it = ``:'a -> 'a list -> 'a`` : hol_type
This term can now be combined with an argument and the final type variable instantiated:
- mk_ucomb(t, ``T``);
> val it = ``FOLDR K T`` : term
- type_of it;
> val it = ``:bool list -> bool``;
Attempting to use mk_icomb in the first example above results in
immediate error because it can only instantiate the function type:
- mk_icomb(``FOLDR``, ``K``) handle e => Raise e;
<<HOL message: inventing new type variable names: 'a, 'b>>
<<HOL message: inventing new type variable names: 'a, 'b>>
Exception raised at HolKernel.list_mk_icomb:
double bind on type variable 'b
Exception-
HOL_ERR
{message = "double bind on type variable 'b", origin_function =
"list_mk_icomb", origin_structure = "HolKernel"} raised
However it can be used in the second example, as only the function type requires instantiation:
- mk_icomb(t, ``T``);
> val it = ``FOLDR K T`` : term
Comments
mk_ucomb makes use of sep_type_unify.
See also
boolSyntax.list_mk_ucomb,
boolSyntax.sep_type_unify,
Term.mk_icomb, Term.mk_comb
negation
negation
boolSyntax.negation : term
Constant denoting logical negation.
The ML variable boolSyntax.negation is bound to the term bool$~.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
new_binder
new_binder
boolSyntax.new_binder : string * hol_type -> unit
Sets up a new binder in the current theory.
A call new_binder(bnd,ty) declares a new binder bnd in the current
theory. The type must be of the form ('a -> 'b) -> 'c, because being a
binder, bnd will apply to an abstraction; for example
!x:bool. (x=T) \/ (x=F)
is actually a prettyprinting of
$! (\x. (x=T) \/ (x=F))
Failure
Fails if the type does not correspond to the above pattern.
Example
- new_theory "anorak";
> val it = () : unit
- new_binder ("!!", (bool-->bool)-->bool);
> val it = () : unit
- Term `!!x. T`;
> val it = `!! x. T` : term
See also
Theory.constants,
Theory.new_constant,
boolSyntax.new_infix,
Definition.new_definition,
boolSyntax.new_infixl_definition,
boolSyntax.new_infixr_definition,
boolSyntax.new_binder_definition
new_binder_definition
new_binder_definition
boolSyntax.new_binder_definition : string * term -> thm
Defines a new constant, giving it the syntactic status of a binder.
The function new_binder_definition provides a facility for making
definitional extensions to the current theory by introducing a constant
definition. It takes a pair of arguments, consisting of the name under
which the resulting theorem will be saved in the current theory segment
and a term giving the desired definition. The value returned by
new_binder_definition is a theorem which states the definition
requested by the user.
Let v1, ..., vn be syntactically distinct tuples constructed from
the variables x1,...,xm. A binder is defined by evaluating
new_binder_definition (name, `b v1 ... vn = t`)
where b does not occur in t, all the free variables that occur in
t are a subset of x1,...,xn, and the type of b has the form
(ty1->ty2)->ty3. This declares b to be a new constant with the
syntactic status of a binder in the current theory, and with the
definitional theorem
|- !x1...xn. b v1 ... vn = t
as its specification. This constant specification for b is saved in
the current theory under the name name and is returned as a theorem.
The equation supplied to new_binder_definition may optionally have any
of its free variables universally quantified at the outermost level. The
constant b has binder status only after the definition has been made.
Failure
new_binder_definition fails if t contains free variables that are
not in any one of the variable structures v1, ..., vn or if any
variable occurs more than once in v1, ..., v2. Failure also occurs if
the type of b is not of the form appropriate for a binder, namely a
type of the form (ty1->ty2)->ty3. Finally, failure occurs if there is
a type variable in v1, ..., vn or t that does not occur in the
type of b.
Example
The unique-existence quantifier ?! is defined as follows.
> new_binder_definition
(`EXISTS_UNIQUE_DEF`,
Term`$?! = \P:(*->bool). ($? P) /\ (!x y. ((P x) /\ (P y)) ==> (x=y))`);
Exception- Type error in function application.
Function: new_binder_definition : string * term -> thm
Argument:
(
[QUOTE " (*#loc 2 4*)EXISTS_UNIQUE_DEF"],
Term
[
QUOTE
" (*#loc 3 8*)$?! = \\P:(*->bool). ($? P) /\\ (!x y. ((P x) /\\ (P y)) ==> (x=y))"
]
) : 'a frag list * term
Reason:
Can't unify string (*In Basis*) with 'a frag list (*In Basis*)
(Different type constructors)
Fail "Static Errors" raised
Comments
It is a common practice among HOL users to write a $ before the
constant being defined as a binder to indicate that it will have a
special syntactic status after the definition is made:
new_binder_definition(name, Term `$b = ... `);
This use of $ is not necessary; but after the definition has been made
$ must, of course, be used if the syntactic status of b needs to be
suppressed.
See also
Definition.new_definition,
boolSyntax.new_infixl_definition,
boolSyntax.new_infixr_definition,
Prim_rec.new_recursive_definition,
TotalDefn.Define
new_infix
new_infix
boolSyntax.new_infix : string * hol_type * int -> unit
Declares a new infix constant in the current theory.
A call new_infix ("i", ty, n) makes i a right associative infix
constant in the current theory. It has binding strength of n, the
larger this number, the more tightly the infix will attempt to "grab"
arguments to its left and right. Note that the call to new_infix does
not specify the value of the constant. The constant may have a
polymorphic type, which may be arbitrarily instantiated. Like any other
infix or binder, its special parse status may be suppressed by preceding
it with a dollar sign.
Comments
Infixes defined with new_infix associate to the right, i.e.,
A <op> B <op> C is equivalent to A op (B <op> C). Some standard
infixes, with their precedences and associativities in the system are:
$, ---> 50 RIGHT
$= ---> 100 NONASSOC
$==> ---> 200 RIGHT
$\/ ---> 300 RIGHT
$/\ ---> 400 RIGHT
$>, $< ---> 450 RIGHT
$>=, $<= ---> 450 RIGHT
$+, $- ---> 500 LEFT
$*, $DIV ---> 600 LEFT
$MOD ---> 650 LEFT
$EXP ---> 700 RIGHT
$o ---> 800 RIGHT
Note that the arithmetic operators +, -, *, DIV and MOD are
left associative in hol98 releases from Taupo onwards. Non-associative
infixes (= above, for example) will cause parse errors if an attempt
is made to group them (e.g., x = y = z).
Failure
Fails if the name is not a valid constant name.
Example
The following shows the use of the infix and the prefix form of an infix constant. It also shows binding resolution between infixes of different precedence.
- new_infix("orelse", Type`:bool->bool->bool`, 50);
val it = () : unit
- Term`T \/ T orelse F`;
val it = `T \/ T orelse F` : term
- “$orelse T F”;
val it = `T orelse F` : term
- dest_comb “T \/ T orelse F”;
> val it = (`$orelse (T \/ T)`, `F`) : term * term
See also
Parse.add_infix,
Theory.constants,
Theory.new_constant,
boolSyntax.new_binder,
Definition.new_definition,
boolSyntax.new_binder_definition
new_infixl_definition
new_infixl_definition
boolSyntax.new_infixl_definition : string * term * int -> thm
Declares a new left associative infix constant and installs a definition in the current theory.
The function new_infix_definition provides a facility for definitional
extensions to the current theory. It takes a triple consisting of the
name under which the resulting definition will be saved in the current
theory segment, a term giving the desired definition and an integer
giving the precedence of the infix. The value returned by
new_infix_definition is a theorem which states the definition
requested by the user.
Let v_1 and v_2 be tuples of distinct variables, containing the
variables x_1,...,x_m. Evaluating
new_infix_definition (name, ix v_1 v_2 = t) declares the sequent
({},\v_1 v_2. t) to be a definition in the current theory, and
declares ix to be a new constant in the current theory with this
definition as its specification. This constant specification is returned
as a theorem with the form
|- !x_1 ... x_m. v_1 ix v_2 = t
and is saved in the current theory under (the name) name. Optionally,
the definitional term argument may have any of its variables universally
quantified. The constant ix has infix status only after the infix
declaration has been processed. It is therefore necessary to use the
constant in normal prefix position when making the definition.
Failure
new_infixl_definition fails if t contains free variables that are
not in either of the variable structures v_1 and v_2 (this is
equivalent to requiring \v_1 v_2. t to be a closed term); or if any
variable occurs more than once in v_1, v_2. It also fails if the
precedence level chosen for the infix is already home to parsing rules
of a different form of fixity (infixes associating in a different way,
or suffixes, prefixes etc). Finally, failure occurs if there is a type
variable in v_1, ..., v_n or t that does not occur in the type of
ix.
Example
The nand function can be defined as follows.
- new_infix_definition
("nand", “$nand in_1 in_2 = ~(in_1 /\ in_2)”, 500);;
> val it = |- !in_1 in_2. in_1 nand in_2 = ~(in_1 /\ in_2) : thm
Comments
It is a common practice among HOL users to write a $ before the
constant being defined as an infix to indicate that after the definition
is made, it will have a special syntactic status; ie. to write:
new_infixl_definition("ix_DEF", Term `$ix m n = ... `)
This use of $ is not necessary; but after the definition has been made
$ must, of course, be used if the syntactic status needs to be
suppressed.
In releases of hol98 past Taupo 1, new_infixl_definition and its
sister new_infixr_definition replace the old new_infix_definition,
which has been superseded. Its behaviour was to define a right
associative infix, so can be freely replaced by new_infixr_definition.
See also
boolSyntax.new_binder_definition,
Definition.new_definition,
Definition.new_specification,
boolSyntax.new_infixr_definition,
Prim_rec.new_recursive_definition,
TotalDefn.Define
new_infixr_definition
new_infixr_definition
boolSyntax.new_infixr_definition : string * term * int -> thm
Declares a new right associative infix constant and installs a definition in the current theory.
The function new_infixr_definition has exactly the same effect as
new_infixl_definition except that the infix constant defined will
associate to the right.
See also
Definition.new_definition,
Definition.new_specification,
boolSyntax.new_infix,
boolSyntax.new_infixl_definition
rhs
rhs
boolSyntax.rhs : term -> term
Returns the right-hand side of an equation.
If M has the form t1 = t2 then rhs M returns t2.
Failure
Fails if term is not an equality.
See also
boolSyntax.lhs,
boolSyntax.dest_eq
select
select
boolSyntax.select : term
Constant denoting Hilbert's choice operator.
The ML variable boolSyntax.select is bound to the term min$@.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
sep_type_unify
sep_type_unify
boolSyntax.sep_type_unify : hol_type -> hol_type ->
(hol_type,hol_type) subst * (hol_type,hol_type) subst
Calculates a pair of substitutions (theta1, theta2) such that
instantiating the first argument with theta1 equals the second
argument instatiated with theta2.
If sep_type_unify ty1 ty2 succeeds, then
type_subst (sep_type_unify ty1 ty2 |> fst) ty1 =
type_subst (sep_type_unify ty1 ty2 |> snd) ty2
Failure
If no such substitution can be found.
Example
> let val alpha_list = Type `:'a list`
in
sep_type_unify alpha alpha_list
end;
val it = ([{redex = “:α”, residue = “:α list”}], []):
(hol_type, hol_type) Lib.subst * (hol_type, hol_type) Lib.subst
> let val ty1 = Type `:'a -> 'b -> 'b`
val ty2 = Type `:'a list -> 'b list -> 'a list`
in
sep_type_unify ty1 ty2
end;
val it =
([{redex = “:β”, residue = “:α list”},
{redex = “:α”, residue = “:α list”}], [{redex = “:β”, residue = “:α”}]):
(hol_type, hol_type) Lib.subst * (hol_type, hol_type) Lib.subst
Note that in these examples, type_unify would fail due to an occurs
check:
> let val ty1 = Type `:'a -> 'b -> 'b`
val ty2 = Type `:'a list -> 'b list -> 'a list`
in
type_unify ty1 ty2
end;
Exception- HOL_ERR (at boolSyntax.type_unify: occurs check) raised
Comments
sep_type_unify is similar to type_unify, but does not run into
problems with occurs checks. It first renames all type variables, then
attempt to unify the argument types, returning two separate
substitutions as a result.
See also
boolSyntax.type_unify,
Type.type_subst, Term.inst
strip_abs
strip_abs
boolSyntax.strip_abs : term -> term list * term
Re-exported from Term.strip_abs. See that
entry for full documentation.
strip_comb
strip_comb
boolSyntax.strip_comb : term -> term * term list
Iteratively breaks apart combinations (function applications).
If M has the form t t1 ... tn then strip_comb M returns
(t,[t1,...,tn]). Note that
strip_comb(list_mk_comb(t,[t1,...,tn]))
will not be (t,[t1,...,tn]) if t is a combination.
Failure
Never fails.
Example
> strip_comb (Term `x /\ y`);
val it = (“$/\”, [“x”, “y”]): term * term list
> strip_comb T;
val it = (“T”, []): term * term list
See also
Term.list_mk_comb,
Term.dest_comb
strip_conj
strip_conj
boolSyntax.strip_conj : term -> term list
Recursively breaks apart conjunctions.
If M is of the form t1 /\ ... /\ tn, where no ti is a conjunction,
then strip_conj M returns [t1,...,tn]. Any ti that is a
conjunction is broken down by strip_conj, hence
strip_conj(list_mk_conj [t1,...,tn])
will not return [t1,...,tn] if any ti is a conjunction.
Failure
Never fails.
Example
> strip_conj (Term `(a /\ b) /\ c /\ d`);
val it = [“a”, “b”, “c”, “d”]: term list
See also
boolSyntax.dest_conj,
boolSyntax.mk_conj,
boolSyntax.list_mk_conj
strip_disj
strip_disj
boolSyntax.strip_disj : term -> term list
Recursively breaks apart disjunctions.
If M is of the form t1 \/ ... \/ tn, where no ti is a disjunction,
then strip_disj M returns [t1,...,tn]. Any ti that is a
disjunction is broken down by strip_disj, hence
strip_disj(list_mk_disj [t1,...,tn])
will not return [t1,...,tn] if any ti is a disjunction.
Failure
Never fails.
Example
> strip_disj (Term `(a \/ b) \/ c \/ d`);
val it = [“a”, “b”, “c”, “d”]: term list
See also
boolSyntax.dest_disj,
boolSyntax.mk_disj,
boolSyntax.list_mk_disj
strip_exists
strip_exists
boolSyntax.strip_exists : term -> term list * term
Iteratively breaks apart existential quantifications.
If M has the structure ?x1 ... xn. t then strip_exists M returns
([x1,...,xn],t). Note that
strip_exists(list_mk_exists(["x1";...;"xn"],"t"))
will not return ([x1,...,xn],t) if t is an existential
quantification.
Failure
Never fails.
See also
boolSyntax.list_mk_exists,
boolSyntax.dest_exists
strip_forall
strip_forall
boolSyntax.strip_forall : term -> term list * term
Iteratively breaks apart universal quantifications.
If M has the form !x1 ... xn. t then strip_forall M returns
([x1,...,xn],t). Note that
strip_forall(list_mk_forall([x1,...,xn],t,))
will not return ([x1,...,xn],t) if t is a universal quantification.
Failure
Never fails.
See also
boolSyntax.list_mk_forall,
boolSyntax.dest_forall
strip_fun
strip_fun
boolSyntax.strip_fun : hol_type -> hol_type list * hol_type
Iteratively breaks apart function types.
If fty is of the form ty1 -> (... (tyn -> ty) ...), then
strip_fun fty returns ([ty1,...,tyn],ty). Note that
strip_fun(list_mk_fun([ty1,...,tyn],ty))
will not return ([ty1,...,tyn],ty) if ty is a function type.
Failure
Never fails.
Example
> strip_fun (Type `:(a -> 'bool) -> ('b -> 'c)`);
Exception- HOL_ERR
(at Parse.type parser: at line 1, character 19:
a not a known type operator) raised
See also
boolSyntax.list_mk_fun,
Type.dom_rng, Type.dest_type
strip_imp
strip_imp
boolSyntax.strip_imp : term -> term list * term
Iteratively breaks apart implications.
If M is of the form t1 ==> (... (tn ==> t) ...), then strip_imp M
returns ([t1,...,tn],t). Note that
strip_imp(list_mk_imp([t1,...,tn],t))
will not return ([t1,...,tn],t) if t is an implication.
Failure
Never fails.
Example
> strip_imp "(T ==> F) ==> (T ==> F)";;
Exception- Type error in function application.
Function: strip_imp : term -> term list * term
Argument: "(T ==> F) ==> (T ==> F)" : string
Reason:
Can't unify term (*Created from opaque signature*) with
string (*In Basis*) (Different type constructors)
Fail "Static Errors" raised
> strip_imp (Term `t1 ==> t2 ==> t3 ==> ~t`);
val it = ([“t1”, “t2”, “t3”, “t”], “F”): term list * term
See also
boolSyntax.list_mk_imp,
boolSyntax.dest_imp
strip_imp_only
strip_imp_only
boolSyntax.strip_imp_only : term -> term list * term
Iteratively breaks apart implications.
If M is of the form t1 ==> (... (tn ==> t) ...), then
strip_imp_only M returns ([t1,...,tn],t). Note that
strip_imp_only(list_mk_imp([t1,...,tn],t))
will not return ([t1,...,tn],t) if t is an implication.
Failure
Never fails.
Example
> strip_imp_only (Term `(T ==> F) ==> (T ==> F)`);
val it = ([“T ⇒ F”, “T”], “F”): term list * term
> strip_imp_only (Term `t1 ==> t2 ==> t3 ==> ~t`);
val it = ([“t1”, “t2”, “t3”], “¬t”): term list * term
See also
boolSyntax.list_mk_imp,
boolSyntax.dest_imp
strip_neg
strip_neg
boolSyntax.strip_neg : term -> term * int
Breaks iterated negations down to an unnegated core.
If M is of the form ~...~t, then strip_neg M returns (t,n),
where n is the number of consecutive negations being applied to t.
Failure
Never fails.
Example
> strip_neg (Term `~~~~t`);
val it = (“t”, 4): term * int
> strip_neg (Term `x`);
val it = (“x”, 0): term * int
Comments
There is no corresponding entrypoint for building iterated negations. If
such functionality is desired, funpow may be used:
- funpow 3 mk_neg T;
> val it = `~~~T` : term
See also
boolSyntax.dest_neg,
boolSyntax.mk_neg, Lib.funpow
T
T
boolSyntax.T : term
Constant denoting truth.
The ML variable boolSyntax.T is bound to the term bool$T.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
type_unify
type_unify
boolSyntax.type_unify : hol_type -> hol_type -> (hol_type,hol_type) subst
Performs classical type unification.
Calculates a substitution theta such that instantiating each of the
arguments with theta gives the same result type.
If type_unify ty1 ty2 succeeds, then
type_subst (type_unify ty1 ty2) ty1 = type_subst (type_unify ty1 ty2) ty2
Failure
If no such substitution can be found. This could be due to incompatible type constructors, or the failing of an occurs check.
Example
> let val ty1 = Type `:'a -> 'b -> 'a`
val ty2 = Type `:'a -> 'b -> 'b`
in
type_subst (type_unify ty1 ty2) ty1 = type_subst (type_unify ty1 ty2) ty2
end;
val it = true: bool
> let val alpha_list = Type `:'a list`
in
type_unify alpha alpha_list handle e => Raise e
end;
Exception- HOL_ERR (at boolSyntax.type_unify: occurs check) raised
Note that attempting to use Type.match_type in the first example
results in immediate error, as it can only attempt to substitute the
first argument to match the second:
> let val ty1 = Type `:'a -> 'b -> 'a`
val ty2 = Type `:'a -> 'b -> 'b`
in
match_type ty1 ty2 handle e => Raise e
end;
Exception- HOL_ERR (at Type.raw_match_type: double bind on type variable 'a) raised
See also
boolSyntax.sep_type_unify,
Type.match_type,
Type.type_subst, Term.inst
universal
universal
boolSyntax.universal : term
Constant denoting universal quantification.
The ML variable boolSyntax.universal is bound to the term bool$!.
See also
boolSyntax.equality,
boolSyntax.implication,
boolSyntax.select,
boolSyntax.T, boolSyntax.F,
boolSyntax.universal,
boolSyntax.existential,
boolSyntax.exists1,
boolSyntax.conjunction,
boolSyntax.disjunction,
boolSyntax.negation,
boolSyntax.conditional,
boolSyntax.bool_case,
boolSyntax.let_tm,
boolSyntax.arb
&&
&&
op bossLib.&& : simpset * thm list -> simpset
Also exported as BasicProvers.&&.
Infix operator for adding theorems into a simpset.
It is occasionally necessary to extend an existing simpset ss with a
collection rwlist of new rewrite rules. To achieve this, one applies
the && function via ss && rwlist.
Failure
Never fails.
Example
> val ss = boolSimps.bool_ss && pairLib.pair_rws;
val ss =
Included fragments (with 1 anonymous fragment [remove using name ""]):
BOOL, CONG, NOT, PURE, UNWIND
Rewrites (with 9 anonymous rewrites)
Other net names/keys:
.rewrite:COND_BOOL_CLAUSES.1, .rewrite:COND_BOOL_CLAUSES.2,
.rewrite:COND_BOOL_CLAUSES.3, .rewrite:COND_BOOL_CLAUSES.4,
.rewrite:EXCLUDED_MIDDLE'.1, .rewrite:EXISTS_REFL'.1,
.rewrite:EXISTS_UNIQUE_REFL'.1, .rewrite:NOT_AND'.1,
.rewrite:lift_disj_eq.1, .rewrite:lift_disj_eq.2,
[...Output elided...]
Comments
Of limited applicability since most of the tactics for rewriting already
include this functionality. However, applications of ZAP_TAC can
benefit.
See also
simpLib.++,
simpLib.SIMP_CONV,
bossLib.RW_TAC
arith_ss
arith_ss
bossLib.arith_ss : simpset
Simplification set for arithmetic.
The simplification set arith_ss is a version of std_ss enhanced for
arithmetic. It includes many arithmetic rewrites, an evaluation
mechanism for ground arithmetic terms, and a decision procedure for
linear arithmetic. It also incorporates a cache of successfully solved
conditions proved when conditional rewrite rules are successfully
applied.
The following rewrites are currently used to augment those already
present from std_ss:
|- !m n. (m * n = 0) = (m = 0) \/ (n = 0)
|- !m n. (0 = m * n) = (m = 0) \/ (n = 0)
|- !m n. (m + n = 0) = (m = 0) /\ (n = 0)
|- !m n. (0 = m + n) = (m = 0) /\ (n = 0)
|- !x y. (x * y = 1) = (x = 1) /\ (y = 1)
|- !x y. (1 = x * y) = (x = 1) /\ (y = 1)
|- !m. m * 0 = 0
|- !m. 0 * m = 0
|- !x y. (x * y = SUC 0) = (x = SUC 0) /\ (y = SUC 0)
|- !x y. (SUC 0 = x * y) = (x = SUC 0) /\ (y = SUC 0)
|- !m. m * 1 = m
|- !m. 1 * m = m
|- !x.((SUC x = 1) = (x = 0)) /\ ((1 = SUC x) = (x = 0))
|- !x.((SUC x = 2) = (x = 1)) /\ ((2 = SUC x) = (x = 1))
|- !m n. (m + n = m) = (n = 0)
|- !m n. (n + m = m) = (n = 0)
|- !c. c - c = 0
|- !m. SUC m - 1 = m
|- !m. (0 - m = 0) /\ (m - 0 = m)
|- !a c. a + c - c = a
|- !m n. (m - n = 0) = m <= n
|- !m n. (0 = m - n) = m <= n
|- !n m. n - m <= n
|- !n m. SUC n - SUC m = n - m
|- !m n p. m - n > p = m > n + p
|- !m n p. m - n < p = m < n + p /\ 0 < p
|- !m n p. m - n >= p = m >= n + p \/ 0 >= p
|- !m n p. m - n <= p = m <= n + p
|- !n. n <= 0 = (n = 0)
|- !m n p. m + p < n + p = m < n
|- !m n p. p + m < p + n = m < n
|- !m n p. m + n <= m + p = n <= p
|- !m n p. n + m <= p + m = n <= p
|- !m n p. (m + p = n + p) = (m = n)
|- !m n p. (p + m = p + n) = (m = n)
|- !x y w. x + y < w + x = y < w
|- !x y w. y + x < x + w = y < w
|- !m n. (SUC m = SUC n) = (m = n)
|- !m n. SUC m < SUC n = m < n
|- !n m. SUC n <= SUC m = n <= m
|- !m i n. SUC n * m < SUC n * i = m < i
|- !p m n. (n * SUC p = m * SUC p) = (n = m)
|- !m i n. (SUC n * m = SUC n * i) = (m = i)
|- !n m. ~(SUC n <= m) = m <= n
|- !p q n m. (n * SUC q ** p = m * SUC q ** p) = (n = m)
|- !m n. ~(SUC n ** m = 0)
|- !n m. ~(SUC (n + n) = m + m)
|- !m n. ~(SUC (m + n) <= m)
|- !n. ~(SUC n <= 0)
|- !n. ~(n < 0)
|- !n. (MIN n 0 = 0) /\ (MIN 0 n = 0)
|- !n. (MAX n 0 = n) /\ (MAX 0 n = n)
|- !n. MIN n n = n
|- !n. MAX n n = n
|- !n m. MIN m n <= m /\ MIN m n <= n
|- !n m. m <= MAX m n /\ n <= MAX m n
|- !n m. (MIN m n < m = ~(m = n) /\ (MIN m n = n)) /\
(MIN m n < n = ~(m = n) /\ (MIN m n = m)) /\
(m < MIN m n = F) /\ (n < MIN m n = F)
|- !n m. (m < MAX m n = ~(m = n) /\ (MAX m n = n)) /\
(n < MAX m n = ~(m = n) /\ (MAX m n = m)) /\
(MAX m n < m = F) /\ (MAX m n < n = F)
|- !m n. (MIN m n = MAX m n) = (m = n)
|- !m n. MIN m n < MAX m n = ~(m = n)
The decision procedure proves valid purely univeral formulas constructed
using variables and the operators SUC,PRE,+,-,<,>,<=,>=.
Multiplication by constants is accomodated by translation to repeated
addition. An attempt is made to generalize sub-formulas of type num
not fitting into this syntax.
Comments
The philosophy behind this simpset is fairly conservative. For example, some potential rewrite rules, e.g., the recursive clauses for addition and multiplication, are not included, since it was felt that their incorporation too often resulted in formulas becoming more complex rather than simpler. Also, transitivity theorems are avoided because they tend to make simplification diverge.
See also
BasicProvers.RW_TAC,
BasicProvers.SRW_TAC,
simpLib.SIMP_TAC,
simpLib.SIMP_CONV,
simpLib.SIMP_RULE,
BasicProvers.bool_ss,
bossLib.std_ss,
bossLib.list_ss
asm
asm
bossLib.asm : string -> thm_tactic -> tactic
Passes the named assumption to the continuation.
Given a name n, applies the continuation to the assumption n :- t.
Failure
Fails if there is no assumption with name n, i.e., no assumption
n :- t, or if the continuation fails for the given assumption.
See also
ASM_QI_TAC
ASM_QI_TAC
bossLib.ASM_QI_TAC : tactic
Try to instantiate quantifiers with some default heuristics using also the assumptions..
ASM_QI_TAC is short for ASM_QUANT_INSTANTIATE_TAC [std_qp].
See also
bossLib.QI_TAC,
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC,
quantHeuristicsLib.QUANT_INSTANTIATE_TAC
ASM_SET_TAC
ASM_SET_TAC
bossLib.ASM_SET_TAC : thm list -> tactic
Tactic to automate some routine set theory by reduction to FOL, using the assumptions and the theorems given.
ASM_SET_TAC is identical in behaviour to SET_TAC except that it uses
the assumptions of a goal as well as the provided theorems.
Failure
Fails if the underlying resolution machinery (METIS_TAC) cannot prove
the goal, or the supplied theorems (and the assumptions) are not enough
for the FOL reduction.
See also
bossLib.SET_TAC,
bossLib.SET_RULE
ASM_SIMP_TAC
ASM_SIMP_TAC
bossLib.ASM_SIMP_TAC : simpset -> thm list -> tactic
Also exported as simpLib.ASM_SIMP_TAC.
Simplifies a goal using the simpset, the provided theorems, and the goal's assumptions.
ASM_SIMP_TAC does a simplification of the goal, adding both the
assumptions and the provided theorem to the given simpset as rewrites.
This simpset is then applied to the goal in the manner explained in the
entry for SIMP_CONV.
ASM_SIMP_TAC is to SIMP_TAC, as ASM_REWRITE_TAC is to
REWRITE_TAC.
Failure
ASM_SIMP_TAC never fails, though it may diverge.
Example
The simple goal x < y ?- x + y < y + y can be proved by using
bossLib.arith_ss and the assumption by
ASM_SIMP_TAC bossLib.arith_ss []
See also
bossLib.++, bossLib.bool_ss,
bossLib.FULL_SIMP_TAC,
simpLib.mk_simpset,
bossLib.SIMP_CONV,
bossLib.SIMP_TAC,
Rewrite.ASM_REWRITE_TAC,
BasicProvers.VAR_EQ_TAC
asm_x
asm_x
bossLib.asm_x : string -> thm_tactic -> tactic
Passes the named assumption to the continuation.
Given a name n, applies the continuation to the assumption n :- t and
removes n :- t from the assumption list.
Failure
Fails if there is no assumption with name n, i.e., no assumption
n :- t, or if the continuation fails for the given assumption.
See also
augment_srw_ss
augment_srw_ss
bossLib.augment_srw_ss : simpLib.ssfrag list -> unit
Also exported as BasicProvers.augment_srw_ss.
Augments the "stateful rewriter" with a list of simpset fragments.
A call to augment_srw_ss sslist causes each element of sslist to be
merged into the simpset value that the system maintains "behind"
srw_ss().
Failure
Never fails.
Comments
The change to the srw_ss() simpset brought about with
augment_srw_ss is not exported with a theory, so it is not
"permanent". But see export_rewrites for a simple way to achieve a
sort of permanence.
See also
BasicProvers.export_rewrites,
bossLib.srw_ss,
bossLib.SRW_TAC
bool_ss
bool_ss
bossLib.bool_ss : simpset
Also exported as BasicProvers.bool_ss, boolSimps.bool_ss.
Basic simpset containing standard propositional and first order logic simplifications, plus beta conversion.
The bool_ss simpset is almost at the base of the system-provided
simpset hierarchy. Though not very powerful, it does include the
following ad hoc collection of rewrite rules for propositions and first
order terms:
|- !A B. ~(A ==> B) = A /\ ~B
|- !A B. (~(A /\ B) = ~A \/ ~B) /\
(~(A \/ B) = ~A /\ ~B)
|- !P. ~(!x. P x) = ?x. ~P x
|- !P. ~(?x. P x) = !x. ~P x
|- (~p = ~q) = (p = q)
|- !x. (x = x) = T
|- !t. ((T = t) = t) /\
((t = T) = t) /\
((F = t) = ~t) /\
((t = F) = ~t)
|- (!t. ~~t = t) /\ (~T = F) /\ (~F = T)
|- !t. (T /\ t = t) /\
(t /\ T = t) /\
(F /\ t = F) /\
(t /\ F = F) /\
(t /\ t = t)
|- !t. (T \/ t = T) /\
(t \/ T = T) /\
(F \/ t = t) /\
(t \/ F = t) /\
(t \/ t = t)
|- !t. (T ==> t = t) /\
(t ==> T = T) /\
(F ==> t = T) /\
(t ==> t = T) /\
(t ==> F = ~t)
|- !t1 t2. ((if T then t1 else t2) = t1) /\
((if F then t1 else t2) = t2)
|- !t. (!x. t) = t
|- !t. (?x. t) = t
|- !b t. (if b then t else t) = t
|- !a. ?x. x = a
|- !a. ?x. a = x
|- !a. ?!x. x = a,
|- !a. ?!x. a = x,
|- (!b e. (if b then T else e) = b \/ e) /\
(!b t. (if b then t else T) = b ==> t) /\
(!b e. (if b then F else e) = ~b /\ e) /\
(!b t. (if b then t else F) = b /\ t)
|- !t. t \/ ~t
|- !t. ~t \/ t
|- !t. ~(t /\ ~t)
|- !x. (@y. y = x) = x
|- !x. (@y. x = y) = x
|- !f v. (!x. (x = v) ==> f x) = f v
|- !f v. (!x. (v = x) ==> f x) = f v
|- !P a. (?x. (x = a) /\ P x) = P a
|- !P a. (?x. (a = x) /\ P x) = P a
Also included in bool_ss is a conversion to perform beta reduction, as
well as the following congruence rules, which allow the simplifier to
glean additional contextual information as it descends through
implications and conditionals.
|- !x x' y y'.
(x = x') ==>
(x' ==> (y = y')) ==> (x ==> y = x' ==> y')
|- !P Q x x' y y'.
(P = Q) ==>
(Q ==> (x = x')) ==>
(~Q ==> (y = y')) ==> ((if P then x else y) = (if Q then x' else y'))
Failure
Can't fail, as it is not a functional value.
The bool_ss simpset is an appropriate simpset from which to build new
user-defined simpsets. It is also useful in its own right, for example
when a delicate simplification is desired, where other more powerful
simpsets might cause undue disruption to a goal. If even less system
rewriting is desired, the pure_ss value can be used.
See also
pureSimps.pure_ss,
bossLib.std_ss,
bossLib.arith_ss,
bossLib.list_ss,
bossLib.SIMP_CONV,
bossLib.SIMP_TAC,
bossLib.RW_TAC
by
by
op bossLib.by : term quotation * tactic -> tactic
Prove and place a theorem on the assumptions of the goal.
An invocation tm by tac, when applied to goal A ?- g, applies tac
to goal A ?- tm. If tm is thereby proved, it is added to A,
yielding the new goal A,tm ?- g. If tm is not proved by tac, then
the application fails.
When tm is added to the existing assumptions A, it is "stripped",
i.e., broken apart by eliminating existentials, conjunctions, and
disjunctions. This can lead to case splitting.
Failure
Fails if tac fails when applied to A ?- tm, or if tac fails to
prove that goal.
Example
Given the goal {x <= y, w < x} ?- P, suppose that the fact
?n. y = n + w would help in eventually proving P. Invoking
`?n. y = n + w` by (EXISTS_TAC ``y-w`` THEN DECIDE_TAC)
yields the goal {y = n + w, x <= y, w < x} ?- P in which the proved
fact has been added to the assumptions after its existential quantifier
is eliminated. Note the parentheses around the tactic: this is needed
for the example because by binds more tightly than THEN.
Comments
Use of by can be more convenient than IMP_RES_TAC and RES_TAC when
they would generate many useless assumptions.
See also
bossLib.subgoal,
bossLib.suffices_by,
Tactical.SUBGOAL_THEN,
Tactic.IMP_RES_TAC,
Tactic.RES_TAC,
Tactic.STRIP_ASSUME_TAC
Cases
Cases
bossLib.Cases : tactic
Also exported as BasicProvers.Cases.
Performs case analysis on the variable of the leading universally quantified variable of the goal.
When applied to a universally quantified goal ?- !u. G, Cases
performs a case-split, based on the cases theorem for the type of u
stored in the global TypeBase database.
The cases theorem for a type ty will be of the form:
|- !v:ty. (?x11...x1n1. v = C1 x11 ... x1n1) \/ .... \/
(?xm1...xmnm. v = Cm xm1 ... xmnm)
where there is no requirement for there to be more than one disjunct,
nor for there to be any particular number of existentially quantified
variables in any disjunct. For example, the cases theorem for natural
numbers initially in the TypeBase is:
|- !n. (n = 0) \/ (?m. n = SUC m)
Case-splitting consists of specialising the cases theorem with the
variable from the goal and then generating as many sub-goals as there
are disjuncts in the cases theorem, where in each sub-goal (including
the assumptions) the variable has been replaced by an expression
involving the given 'constructor' (the Ci's above) applied to as many
fresh variables as appropriate.
Failure
Fails if the goal is not universally quantified, or if the type of the
universally quantified variable does not have a case theorem in the
TypeBase, as will happen, for example, with variable types.
Example
If we have defined the following type:
- Hol_datatype `foo = Bar of num | Baz of bool`;
> val it = () : unit
and the following function:
- val foofn_def = Define `(foofn (Bar n) = n + 10) /\
(foofn (Baz x) = 10)`;
> val foofn_def =
|- (!n. foofn (Bar n) = n + 10) /\
!x. foofn (Baz x) = 10 : thm
then it is possible to make progress with the goal !x. foofn x >= 10
by applying the tactic Cases, thus:
?- !x. foofn x >= 10
====================================================== Cases
?- foofn (Bar n) >= 10 ?- foofn (Baz b) >= 10
producing two new goals, one for each constructor of the type.
See also
bossLib.Cases_on,
bossLib.Induct,
Tactic.STRUCT_CASES_TAC
Cases_on
Cases_on
bossLib.Cases_on : term quotation -> tactic
Also exported as BasicProvers.Cases_on.
Performs case analysis on the type of a given term.
An application Cases_on M performs a case-split based on the type ty
of M, using the cases theorem for ty from the global TypeBase
database.
Cases_on can be used to specify variables that are buried in the
quantifier prefix. Cases_on can also be used to perform case splits on
non-variable terms. If M is a non-variable term that does not occur
bound in the goal, then the cases theorem is instantiated with M and
used to generate as many sub-goals as there are disjuncts in the cases
theorem.
Failure
Fails if ty does not have a case theorem in the TypeBase.
Example
None yet.
See also
bossLib.Cases, bossLib.Induct,
bossLib.Induct_on,
Tactic.STRUCT_CASES_TAC
cheat
cheat
bossLib.cheat : tactic
Discharge a goal without proving it.
The cheat tactic solves the current goal immediately without proving
it, using mk_oracle_thm and adding the "cheat" tag to any theorem
thereby obtained.
Failure
Never fails.
Comments
The intended use of cheat is to temporarily plug gaps in large theory
developments in order to sketch the bigger picture before filling in the
details. It can be useful as a kind of high-level SUFF_TAC: cheat on a
difficult lemma, see whether it works as intended for the main theorem,
then go back and prove the lemma properly.
The usual caveats associated with mk_oracle_thm apply: cheating
exposes you to the possibility of false theorems and contradictions. To
be sure a theorem was proved without cheating, check its tags.
See also
Thm.mk_oracle_thm, Thm.tag,
Globals.show_tags,
Tactic.SUFF_TAC
completeInduct_on
completeInduct_on
bossLib.completeInduct_on : term quotation -> tactic
Perform complete induction.
If q parses into a well-typed term M, an invocation
completeInduct_on q begins a proof by complete (also known as
'course-of-values') induction on M. The term M should occur free in
the current goal.
Failure
If M does not parse into a term or does not occur free in the current
goal.
Example
Suppose we wish to prove that every number not equal to one has a prime factor:
!n. ~(n = 1) ==> ?p. prime p /\ p divides n
A natural way to prove this is by complete induction. Invoking
completeInduct_on `n` yields the goal
{ !m. m < n ==> ~(m = 1) ==> ?p. prime p /\ p divides m }
?-
~(n = 1) ==> ?p. prime p /\ p divides n
See also
bossLib.measureInduct_on,
bossLib.Induct,
bossLib.Induct_on
CONG_TAC
CONG_TAC
bossLib.CONG_TAC : int option -> tactic
Applies congruence rules backwards repeatedly to attack an equality
Applying CONG_TAC dopt to a goal ?- x = y attempts to apply
congruence rules backwards repeatedly, generating a number of further
equality subgoals. The dopt parameter limits the number of times this
will be done: when dopt is NONE, there is no limit: the base
transformation will be tried on the initial and all subsequent goals. If
dopt is SOME i, then i is the total number of transformations that
will be made. (If dopt is SOME 0 then CONG_TAC dopt is equivalent
to ALL_TAC.)
If at least one of the equality's arguments is an abstraction (possibly paired), then the transformation rewrites with function extensionality, strips the universally quantified variables, and beta-reduces where necessary.
If at least one of the equality's arguments is a set comprehension, then the transformation rewrites with set-extensionality and applies the conversion that calculates what it is for a term to be a member of a comprehension to one or both sides of the equality. Unless both sides are set comprehensions, this is likely to be the last transformation possible.
If the goal matches the conclusion of any of the theorems stored as
congruences for the definition package (with attribute name defncong
or cong), then this theorem is applied backwards to generate new
sub-goals. If the new sub-goals include preconditions and universally
quantified variables, these are stripped into the assumptions.
Finally, the "base transformation" depends on the shape of the
equality's arguments. If both sides are combinations (M e1 and N e2,
say), then the base transformation will be similar to an application of
MK_COMB_TAC, generating at least the goals ?- M = N and
?- e1 = e2. When the head terms of both applications are equal, then
one step of the base transformation is taken to be the iteration of
MK_COMB_TAC that strips all arguments, so that
?- f e1 .. en = f e1' .. en' will turn into n subgoals, each of the
form ?- ei = ei'. (The ?- f = f subgoal will be eliminated
immediately, as below.)
In all cases, new subgoals that are instances of reflexivity, or which occur in the goal's assumptions (with either orientation) are immediately eliminated.
Failure
Fails if the provided depth is either NONE or SOME i with i
greater than zero, and the goal is not an equality at all, or cannot be
changed by any of the transformations described above. For example, with
f : 'a -> num and g : num -> num, the goal ?- f a = g n cannot be
reduced.
Example
The following involves a handling of abstractions:
> CONG_TAC NONE ([], “(∀x. f (z:'a) < x) ⇔ (∀y. c < y)”);
val it = ([([], “f z = c”)], fn): goal list * validation
Slightly altering the goal, and keeping the depth as NONE turns
something true into something unprovable:
> CONG_TAC NONE ([], “(∀x. f (z:'a) < x) ⇔ (∀y. y < 6)”);
val it = ([([], “f z = x”), ([], “x = 6”)], fn): goal list * validation
where the x in each sub-goal is completely fresh.
Finally, user-congruences can give richer contexts when proving functions equal:
> CONG_TAC NONE
([], “MAP (λa. f a + 1) (l1:'a list) = MAP g (l2:'a list)”);
val it = ([([“MEM x l2”], “f x + 1 = g x”), ([], “l1 = l2”)], fn):
goal list * validation
Comments
This is a powerful tool for taking apart two terms that share a skeleton and need only have their leaves shown to be equal. Equally, it is quite possible for this tactic to turn a solvable goal into an unsolvable one.
An application of CONG_TAC will never break apart the function
applications that lie within the representation of natural number
numerals.
The name cong_tac can be used as an alias for CONG_TAC.
See also
Tactic.AP_TERM_TAC,
Tactic.AP_THM_TAC,
Tactic.MK_COMB_TAC
Datatype
Datatype
bossLib.Datatype : hol_type quotation -> unit
Define a concrete datatype.
Many formalizations require the definition of new types. For example,
ML-style datatypes are commonly used to model the abstract syntax of
programming languages and the state-space of elaborate transition
systems. In HOL, such datatypes (at least, those that are inductive, or,
alternatively, have a model in an initial algebra) may be specified
using the invocation Datatype `<spec>`, where <spec> should
conform to the following grammar:
spec ::= [ <binding> ; ]* <binding>
binding ::= <ident> = [ <clause> | ]* <clause>
| <ident> = <| [ <ident> : <type> ; ]* <ident> : <type> |>
clause ::= <ident> <tyspec>*
tyspec ::= ( <type> )
| <atomic-type>
where <atomic-type> is a single token denoting a type. For example,
num, bool and 'a.
When a datatype is successfully defined, a number of standard theorems
are automatically proved about the new type: the constructors of the
type are proved to be injective and disjoint, induction and case
analysis theorems are proved, and each type also has a 'size' function
defined for it. All these theorems are stored in the current theory and
added to a database accessed via the functions in TypeBase.
The notation used to declare datatypes is, unfortunately, not the same as that of ML. If anything, the syntax is rather more like Haskell's. For example, an ML declaration
datatype ('a,'b) btree = Leaf of 'a
| Node of ('a,'b) btree * 'b * ('a,'b) btree
would most likely be declared in HOL as
Datatype `btree = Leaf 'a
| Node btree 'b btree`
Note that any type parameters for the new type are not allowed; they are inferred from the right hand side of the binding. The type variables in the specification become arguments to the new type operator in alphabetic order.
When a record type is defined, the parser is adjusted to allow new
syntax (appropriate for records), and a number of useful simplification
theorems are also proved. The most useful of the latter are
automatically stored in the TypeBase and can be inspected using the
simpls_of function. For further details on record types, see the
DESCRIPTION.
Example
In the following, we shall give an overview of the kinds of types that
may be defined by Datatype.
To start, enumerated types can be defined as in the following example:
Datatype `enum = A1 | A2 | A3 | A4 | A5
| A6 | A7 | A8 | A9 | A10
| A11 | A12 | A13 | A14 | A15
| A16 | A17 | A18 | A19 | A20
| A21 | A22 | A23 | A24 | A25
| A26 | A27 | A28 | A29 | A30`
Other non-recursive types may be defined as well:
Datatype `foo = N num
| B bool
| Fn ('a -> 'b)
| Pr ('a # 'b`)
Turning to recursive types, we can define a type of binary trees where the leaves are numbers.
Datatype `tree = Leaf num | Node tree tree`
We have already seen a type of binary trees having polymorphic values at internal nodes. This time, we will declare it in "paired" format.
Datatype `tree = Leaf 'a
| Node (tree # 'b # tree)`
This specification seems closer to the declaration that one might make in ML, but is more difficult to deal with in proof than the curried format used above.
The basic syntax of the named lambda calculus is easy to describe:
- load "stringTheory";
> val it = () : unit
- Datatype `lambda = Var string
| Const 'a
| Comb lambda lambda
| Abs lambda lambda`
The syntax for 'de Bruijn' terms is roughly similar:
Datatype `dB = Var string
| Const 'a
| Bound num
| Comb dB dB
| Abs dB`
Arbitrarily branching trees may be defined by allowing a node to hold the list of its subtrees. In such a case, leaf nodes do not need to be explicitly declared.
Datatype `ntree = Node of 'a (ntree list)`
A (tupled) type of 'first order terms' can be declared as follows:
Datatype `term = Var string
| Fnapp (string # term list)`
Mutally recursive types may also be defined. The following, extracted by Elsa Gunter from the Definition of Standard ML, captures a subset of Core ML.
Datatype
`atexp = var_exp string
| let_exp dec exp ;
exp = aexp atexp
| app_exp exp atexp
| fn_exp match ;
match = match rule
| matchl rule match ;
rule = rule pat exp ;
dec = val_dec valbind
| local_dec dec dec
| seq_dec dec dec ;
valbind = bind pat exp
| bindl pat exp valbind
| rec_bind valbind ;
pat = wild_pat
| var_pat string`
Simple record types may be introduced using the <| ... |> notation.
Datatype `state = <| Reg1 : num; Reg2 : num; Waiting : bool |>`
The use of record types may be recursive. For example, the following declaration could be used to formalize a simple file system.
Datatype
`file = Text string
| Dir directory
;
directory = <| owner : string ;
files : (string # file) list |>`
Failure
Now we address some types that cannot be declared with Datatype. In
some cases they cannot exist in HOL at all; in others, the type can be
built in the HOL logic, but Datatype is not able to make the
definition.
First, an empty type is not allowed in HOL, so the following attempt is doomed to fail.
Datatype `foo = A foo`
So called 'nested types', which are occasionally quite useful, cannot at
present be built with Datatype:
Datatype `btree = Leaf 'a
| Node (('a # 'a) btree)`
Co-algebraic types may not currently be built with Datatype, not even
by attempting to encode the remainder of the list as a function:
Datatype `lazylist = Nil
| Cons ('a # (one -> lazylist))`
Indeed, this specification corresponds to an algebraic type isomorphic
to "standard" lists, but Datatype rejects it because it cannot handle
recursion to the right of a function arrow. The type of co-algebraic
lists can be built in HOL: see llistTheory.
Finally, for cardinality reasons, HOL does not allow the following
attempt to model the untyped lambda calculus as a set (note the -> in
the clause for the Abs constructor):
Datatype `lambda = Var string
| Const 'a
| Comb lambda lambda
| Abs (lambda -> lambda)`
Instead, one would have to build a theory of complete partial orders (or something similar) with which to model the untyped lambda calculus.
Comments
The consequences of an invocation of Datatype are stored in the
current theory segment and in TypeBase. The principal consequences of
a datatype definition are the primitive recursion and induction
theorems. These provide the ability to define simple functions over the
type, and an induction principle for the type. For a type named ty,
the primitive recursion theorem is stored under ty_Axiom and the
induction theorem is put under ty_induction. Other consequences
include the distinctness of constructors (ty_distinct), and the
injectivity of constructors (ty_11). A 'degenerate' version of
ty_induction is also stored under ty_nchotomy: it provides for
reasoning by cases on the construction of elements of ty. Finally,
some special-purpose theorems are stored: ty_case_cong gives a
congruence theorem for "case" statements on elements of ty. These case
statements are introduced by ty_case_def. Also, a definition of the
"size" of the type is added to the current theory, under the name
ty_size_def.
For example, invoking
Datatype `tree = Leaf num | Node tree tree`;
results in the definitions
tree_case_def =
|- (!a f f1. tree_CASE (Leaf a) f f1 = f a) /\
!a0 a1 f f1. tree_CASE (Node a0 a1) f f1 = f1 a0 a1
tree_size_def
|- (!a. tree_size (Leaf a) = 1 + a) /\
!a0 a1. tree_size (Node a0 a1) = 1 + (tree_size a0 + tree_size a1)
being added to the current theory. The following theorems about the datatype are also stored in the current theory.
tree_Axiom
|- !f0 f1.
?fn. (!a. fn (Leaf a) = f0 a) /\
!a0 a1. fn (Node a0 a1) = f1 a0 a1 (fn a0) (fn a1)
tree_induction
|- !P. (!n. P (Leaf n)) /\
(!t t0. P t /\ P t0 ==> P (Node t t0))
==>
!t. P t
tree_nchotomy |- !t. (?n. t = Leaf n) \/ ?t' t0. t = Node t' t0
tree_11
|- (!a a'. (Leaf a = Leaf a') = (a = a')) /\
!a0 a1 a0' a1'. (Node a0 a1 = Node a0' a1') = (a0=a0') /\ (a1=a1')
tree_distinct |- !a1 a0 a. Leaf a <> Node a0 a1
tree_case_cong
|- !M M' f f1.
(M = M') /\
(!a. (M' = Leaf a) ==> (f a = f' a)) /\
(!a0 a1. (M' = Node a0 a1) ==> (f1 a0 a1 = f1' a0 a1))
==>
(tree_CASE M f f1 = tree_CASE M' f' f1')
When a type involving records is defined, many more definitions are made and added to the current theory.
A definition of mutually recursives types results in the above theorems and definitions being added for each of the defined types.
See also
Definition.new_type_definition,
TotalDefn.Define,
IndDefLib.Hol_reln, TypeBase
DECIDE
DECIDE
bossLib.DECIDE : term -> thm
Invoke decision procedure(s).
An application DECIDE M, where M is a boolean term, attempts to
prove M using a propositional tautology checker and a linear
arithmetic decision procedure.
Failure
The invocation fails if M is not of boolean type. It also fails if M
is not a tautology or an instance of a theorem of linear arithmetic.
Example
> DECIDE (Term `p /\ p /\ r ==> r`);
val it = ⊢ p ∧ p ∧ r ⇒ r: thm
> DECIDE (Term `x < 17 /\ y < 26 ==> x + y < 17 + 26`);
val it = ⊢ x < 17 ∧ y < 26 ⇒ x + y < 17 + 26: thm
Comments
DECIDE is currently somewhat underpowered. Formerly it was implemented
by a cooperating decision procedure mechanism. However, most proofs
seemed to go somewhat smoother with simplification using the arith_ss
simpset, so we have adopted a simpler implementation. That should not be
taken as final, since cooperating decision procedures are an important
component in highly automated proof systems.
See also
bossLib.RW_TAC,
bossLib.arith_ss
DECIDE_TAC
DECIDE_TAC
bossLib.DECIDE_TAC : tactic
Invoke decision procedure(s).
DECIDE_TAC is the tactical version of DECIDE.
Failure
As for DECIDE
See also
Define
Define
bossLib.Define : term quotation -> thm
Also exported as TotalDefn.Define.
General-purpose function definition facility.
Define takes a high-level specification of a HOL function, and
attempts to define the function in the logic. If this attempt is
successful, the specification is derived from the definition. The
derived specification is returned to the user, and also stored in the
current theory. Define may be used to define abbreviations, recursive
functions, and mutually recursive functions. An induction theorem may be
stored in the current theory as a by-product of Define's activity.
This induction theorem follows the recursion structure of the function,
and may be useful when proving properties of the function.
Define takes as input a quotation representing a conjunction of
equations. The specified function(s) may be phrased using ML-style
pattern-matching. A call Define `<spec>` should conform with the
following grammar:
spec ::= <eqn>
| (<eqn>) /\ <spec>
eqn ::= <alphanumeric> <pat> ... <pat> = <term>
pat ::= <variable>
| <wildcard>
| <cname> (* 0-ary constructor *)
| (<cname>_n <pat>_1 ... <pat>_n) (* constructor appl. *)
cname ::= <alphanumeric> | <symbolic>
wildcard ::= _
| _<wildcard>
When processing the specification of a recursive function, Define must
perform a termination proof. It automatically constructs termination
conditions for the function, and invokes a termination prover in an
attempt to prove the termination conditions.
If the function is primitive recursive, in the sense that it exactly
follows the recursion pattern of a previously declared HOL datatype,
then this proof always succeeds, and Define stores the derived
equations in the current theory segment. Otherwise, the function is not
an instance of primitive recursion, and the termination prover may
succeed or fail.
If it succeeds, then Define stores the specified equations in the
current theory segment. An induction theorem customized for the defined
function is also stored in the current segment. Note, however, that an
induction theorem is not stored for primitive recursive functions, since
that theorem would be identical to the induction theorem resulting from
the declaration of the datatype.
If the termination proof fails, then Define fails.
In general, Define attempts to derive exactly the specified
conjunction of equations. However, the rich syntax of patterns allows
some ambiguity. For example, the input
Define `(f 0 _ = 1)
/\ (f _ 0 = 2)`
is ambiguous at f 0 0: should the result be 1 or 2? The system
attempts to resolve this ambiguity in the same way as compilers and
interpreters for functional languages. Namely, a conjunction of
equations is treated as being processed left-conjunct first, followed by
processing the right conjunct. Therefore, in the example above, the
right-hand side of the first clause is taken as the value of f 0 0. In
the implementation, ambiguities arising from such overlapping patterns
are systematically translated away in a pre-processing step.
Another case of vagueness in patterns is shown above: the specification
is 'incomplete' since it does not tell us how f should behave when
applied to two non-zero arguments: e.g., f (SUC m) (SUC n). In the
implementation, such missing clauses are filled in, and have the value
ARB. This 'pattern-completion' step is a way of turning descriptions
of partial functions into total functions suitable for HOL. However,
since the user has not completely specified the function, the system
takes that as a hint that the user is not interested in using the
function at the missing-but-filled-in clauses, and so such clauses are
dropped from the final theorem.
In summary, Define will derive the unambiguous and complete equations
|- (f 0 (SUC v4) = 1) /\
(f 0 0 = 1) /\
(f (SUC v2) 0 = 2)
(f (SUC v2) (SUC v4) = ARB)
from the above ambiguous and incomplete equations. The odd-looking
variable names are due to the pre-processing steps described above. The
above result is only an intermediate value: in the final result returned
by Define, the last equation is droppped:
|- (f 0 (SUC v4) = 1) /\
(f 0 0 = 1) /\
(f (SUC v2) 0 = 2)
Define automatically generates names with which to store the
definition and, (if it exists) the associated induction theorem, in the
current theory. The name for storing the definition is built by
concatenating the name of the function with the value of the reference
variable Defn.def_suffix. The name for storing the induction theorem
is built by concatenating the name of the function with the value of the
reference variable Defn.ind_suffix. For mutually recursive functions,
where there is a choice of names, the name of the function in the first
clause is taken.
Since the names used to store elements in the current theory segment are
transformed into ML bindings after the theory is exported, it is
required that every invocation of Define generates names that will be
valid ML identifiers. For this reason, Define requires alphanumeric
function names. If one wishes to define symbolic identifiers, the ML
function xDefine should be used.
Failure
Define fails if its input fails to parse and typecheck.
Define fails if the name of the function being defined is not
alphanumeric.
Define fails if there are more free variables on the right hand sides
of the recursion equations than the left.
Define fails if it cannot prove the termination of the specified
recursive function. In that case, one has to embark on the following
multi-step process in order to get the same effect as if Define had
succeeded: (1) construct the function and synthesize its termination
conditions with Hol_defn; (2) set up a goal to prove the termination
conditions with tgoal; (3) interactively prove the termination
conditions, starting with an invocation of WF_REL_TAC; and (4) package
everything up with an invocation of tDefine.
Example
We will give a number of examples that display the range of functions
that may be defined with Define. First, we have a recursive function
that uses "destructors" in the recursive call. Since fact is not
primitive recursive, an induction theorem for fact is generated and
stored in the current theory.
Define `fact x = if x = 0 then 1 else x * fact(x-1)`;
Equations stored under "fact_def".
Induction stored under "fact_ind".
> val it = |- fact x = (if x = 0 then 1 else x * fact (x - 1)) : thm
- DB.fetch "-" "fact_ind";
> val it =
|- !P. (!x. (~(x = 0) ==> P (x - 1)) ==> P x) ==> !v. P v : thm
Next we have a recursive function with relatively complex pattern-matching. We omit to examine the generated induction theorem.
Define `(flatten [] = [])
/\ (flatten ([]::rst) = flatten rst)
/\ (flatten ((h::t)::rst) = h::flatten(t::rst))`
<<HOL message: inventing new type variable names: 'a>>
Equations stored under "flatten_def".
Induction stored under "flatten_ind".
> val it =
|- (flatten [] = []) /\
(flatten ([]::rst) = flatten rst) /\
(flatten ((h::t)::rst) = h::flatten (t::rst)) : thm
Next we define a curried recursive function, which uses wildcard expansion and pattern-matching pre-processing.
Define `(min (SUC x) (SUC y) = min x y + 1)
/\ (min ____ ____ = 0)`;
Equations stored under "min_def".
Induction stored under "min_ind".
> val it =
|- (min (SUC x) (SUC y) = min x y + 1) /\
(min (SUC v2) 0 = 0) /\
(min 0 v1 = 0) : thm
Next we make a primitive recursive definition. Note that no induction theorem is generated in this case.
Define `(filter P [] = [])
/\ (filter P (h::t) = if P h then h::filter P t else filter P t)`;
<<HOL message: inventing new type variable names: 'a>>
Definition has been stored under "filter_def".
> val it =
|- (!P. filter P [] = []) /\
!P h t. filter P (h::t) =
(if P h then h::filter P t else filter P t) : thm
Define may also be used to define mutually recursive functions. For
example, we can define a datatype of propositions and a function for
putting a proposition into negation normal form as follows. First we
define a datatype for boolean formulae (prop):
- Hol_datatype
`prop = VAR of 'a
| NOT of prop
| AND of prop => prop
| OR of prop => prop`;
> val it = () : unit
Then two mutually recursive functions nnfpos and nnfneg are defined:
- Define
`(nnfpos (VAR x) = VAR x)
/\ (nnfpos (NOT p) = nnfneg p)
/\ (nnfpos (AND p q) = AND (nnfpos p) (nnfpos q))
/\ (nnfpos (OR p q) = OR (nnfpos p) (nnfpos q))
/\ (nnfneg (VAR x) = NOT (VAR x))
/\ (nnfneg (NOT p) = nnfpos p)
/\ (nnfneg (AND p q) = OR (nnfneg p) (nnfneg q))
/\ (nnfneg (OR p q) = AND (nnfneg p) (nnfneg q))`;
The system returns:
<<HOL message: inventing new type variable names: 'a>>
Equations stored under "nnfpos_def".
Induction stored under "nnfpos_ind".
> val it =
|- (nnfpos (VAR x) = VAR x) /\
(nnfpos (NOT p) = nnfneg p) /\
(nnfpos (AND p q) = AND (nnfpos p) (nnfpos q)) /\
(nnfpos (OR p q) = OR (nnfpos p) (nnfpos q)) /\
(nnfneg (VAR x) = NOT (VAR x)) /\
(nnfneg (NOT p) = nnfpos p) /\
(nnfneg (AND p q) = OR (nnfneg p) (nnfneg q)) /\
(nnfneg (OR p q) = AND (nnfneg p) (nnfneg q)) : thm
Define may also be used to define non-recursive functions.
Define `f x (y,z) = (x + 1 = y DIV z)`;
Definition has been stored under "f_def".
> val it = |- !x y z. f x (y,z) = (x + 1 = y DIV z) : thm
Define may also be used to define non-recursive functions with complex
pattern-matching. The pattern-matching pre-processing of Define can be
convenient for this purpose, but can also generate a large number of
equations. For example:
Define `(g (0,_,_,_,_) = 1) /\
(g (_,0,_,_,_) = 2) /\
(g (_,_,0,_,_) = 3) /\
(g (_,_,_,0,_) = 4) /\
(g (_,_,_,_,0) = 5)`
yields a definition with thirty-one clauses.
Comments
In an eqn, no variable can occur more than once on the left hand side
of the equation.
In HOL, constructors are curried functions, unlike in ML. When used in a pattern, a constructor must be fully applied to its arguments.
Also unlike ML, a pattern variable in a clause of a definition is not distinct from occurrences of that variable in other clauses.
Define translates a wildcard into a new variable, which is named to be
different from any other variable in the function definition. As in ML,
wildcards are not allowed to occur on the right hand side of any clause
in the definition.
An induction theorem generated in the course of processing an invocation
of Define can be applied by recInduct.
Invoking Define on a conjunction of non-recursive clauses having
complex pattern-matching will result in an induction theorem being
stored. This theorem may be useful for case analysis, and can be applied
by recInduct.
Define takes a 'quotation' as an argument. Some might think that the
input to Define should instead be a term. However, some important
pre-processing happens in Define that would not be possible if the
input was a term.
Define is a mechanization of a well-founded recursion theorem
(relationTheory.WFREC_COROLLARY).
Define currently has a rather weak termination prover. For example, it
always fails to prove the termination of nested recursive functions.
bossLib.Define is most commonly used. TotalDefn.Define is identical
to bossLib.Define, except that the TotalDefn structure comes with
less baggage---it depends only on numLib and pairLib.
Define automatically adds the definition it makes into the hidden
'compset' accessed by EVAL and EVAL_TAC.
See also
bossLib.tDefine,
bossLib.xDefine,
TotalDefn.DefineSchema,
bossLib.Hol_defn, Defn.tgoal,
Defn.tprove,
bossLib.WF_REL_TAC,
bossLib.recInduct,
bossLib.EVAL, bossLib.EVAL_TAC
EVAL
EVAL
bossLib.EVAL : conv
Evaluate a term by deduction.
An invocation EVAL M symbolically evaluates M by applying the
defining equations of constants occurring in M. These equations are
held in a mutable datastructure that is automatically added to by
Hol_datatype, Define, and tprove. The underlying algorithm is
call-by-value with a few differences, see the entry for CBV_CONV for
details.
Failure
Never fails, but may diverge.
Example
> EVAL (Term `REVERSE (MAP (\x. x + a) [x;y;z])`);
val it = ⊢ REVERSE (MAP (λx. x + a) [x; y; z]) = [z + a; y + a; x + a]: thm
Comments
In order for recursive functions over numbers to be applied by EVAL,
pattern matching over SUC and 0 needs to be replaced by destructors.
For example, the equations for FACT would have to be rephrased as
FACT n = if n = 0 then 1 else n * FACT (n-1).
See also
computeLib.CBV_CONV,
computeLib.RESTR_EVAL_CONV,
bossLib.EVAL_TAC,
computeLib.monitoring,
bossLib.Define
EVAL_RULE
EVAL_RULE
bossLib.EVAL_RULE : thm -> thm
Evaluate conclusion of a theorem.
An invocation EVAL_RULE th symbolically evaluates the conclusion of
th by applying the defining equations of constants which occur in the
conclusion of th. These equations are held in a mutable datastructure
that is automatically added to by Hol_datatype, Define, and
tprove. The underlying algorithm is call-by-value with a few
differences, see the entry for CBV_CONV for details.
Failure
Never fails, but may diverge.
Example
> val th = ASSUME(Term `x = MAP FACT (REVERSE [1;2;3;4;5;6;7;8;9;10])`);
val th = [.] ⊢ x = MAP FACT (REVERSE [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]): thm
> EVAL_RULE th;
val it = [.] ⊢ x = [3628800; 362880; 40320; 5040; 720; 120; 24; 6; 2; 1]:
thm
> hyp it;
val it = [“x = MAP FACT (REVERSE [1; 2; 3; 4; 5; 6; 7; 8; 9; 10])”]:
term list
Comments
In order for recursive functions over numbers to be applied by
EVAL_RULE, pattern matching over SUC and 0 needs to be replaced by
destructors. For example, the equations for FACT would have to be
rephrased as FACT n = if n = 0 then 1 else n * FACT (n-1).
See also
bossLib.EVAL,
bossLib.EVAL_TAC,
computeLib.CBV_CONV
EVAL_TAC
EVAL_TAC
bossLib.EVAL_TAC : tactic
Evaluate a goal deductively.
Applying EVAL_TAC to a goal A ?- g results in EVAL being applied
to g to obtain |- g = g'. This theorem is used to transform the goal
to A ?- g'.
The notion of evaluation is based around rules for replacing constants
by their (equational) definitions. Thus EVAL_TAC is currently suited
to evaluation of expressions that look like functional programs.
Evaluation of inductive relations is not currently supported.
Failure
Shouldn't fail, but may diverge.
Example
EVAL_TAC reduces the goal
?- P (REVERSE (FLAT [[x; y]; [a; b; c; d]])) to the goal
?- P [d; c; b; a; y; x]
Comments
The main problem with EVAL_TAC is knowing when it will terminate. One
typical cause of non-termination is that a constant in the goal has not
been added to the_compset. Another is that a test in a conditional in
the expression may involve a variable.
Symbolic evaluation.
See also
EVALn
EVALn
bossLib.EVALn : int -> conv
Evaluate a term by deduction, limiting number of steps taken.
An invocation EVALn n M symbolically evaluates M by applying the
defining equations of constants occurring in M, stopping when M
reduces to a normal form, or after n reduction steps have occurred. If
n is large enough and there is a normal form, the behaviour will be
the same as EVAL M, which see.
Failure
Never fails.
Example
In the example below, a custom pretty-printer hides a potentially large term involving the terms that are used to represent intermediates stages of numeral computation.
- EVALn 50 “MAP (\x. x * x) [1;2;3;4;5]”;
val it =
⊢ MAP (λx. x²) [1; 2; 3; 4; 5] =
1::4:: <..num comp'n..> ::MAP (λx. x²) [4; 5]: thm
See also
computeLib.CBV_CONV,
computeLib.RESTR_EVAL_CONV,
bossLib.EVAL_TAC,
computeLib.monitoring,
bossLib.Define
FULL_SIMP_TAC
FULL_SIMP_TAC
bossLib.FULL_SIMP_TAC : simpset -> thm list -> tactic
Also exported as simpLib.FULL_SIMP_TAC.
Simplifies the goal (assumptions as well as conclusion) with the given simpset.
FULL_SIMP_TAC is a powerful simplification tactic that simplifies all
of a goal. It proceeds by applying simplification to each assumption of
the goal in turn, accumulating simplified assumptions as it goes. These
simplified assumptions are used to simplify further assumptions, and all
of the simplified assumptions are used as additional rewrites when the
conclusion of the goal is simplified.
In addition, simplified assumptions are added back onto the goal using
the equivalent of STRIP_ASSUME_TAC and this causes automatic
skolemization of existential assumptions, case splits on disjunctions,
and the separate assumption of conjunctions. If an assumption is
simplified to TRUTH, then this is left on the assumption list. If an
assumption is simplified to falsity, this proves the goal.
Failure
FULL_SIMP_TAC never fails, but it may diverge.
Example
Here FULL_SIMP_TAC is used to prove a goal:
> FULL_SIMP_TAC arith_ss [] (map Term [`x = 3`, `x < 2`],
Term `?y. x * y = 51`)
- val it = ([], fn) : tactic_result
Using LESS_OR_EQ |- !m n. m <= n = m < n \/ (m = n), a useful case
split can be induced in the next goal:
> FULL_SIMP_TAC bool_ss [LESS_OR_EQ] (map Term [`x <= y`, `x < z`],
Term `x + y < z`);
- val it =
([([`x < y`, `x < z`], `x + y < z`),
([`x = y`, `x < z`], `y + y < z`)], fn)
: tactic_result
Note that the equality x = y is not used to simplify the subsequent
assumptions, but is used to simplify the conclusion of the goal.
Comments
The application of STRIP_ASSUME_TAC to simplified assumptions means
that FULL_SIMP_TAC can cause unwanted case-splits and other
undesirable transformations to occur in one's assumption list. If one
wants to apply the simplifier to assumptions without this occurring, the
best approach seems to be the use of RULE_ASSUM_TAC and SIMP_RULE.
Each assumption is used to rewrite lower-numbered assumptions. To get
the opposite effect, where each assumption is used to rewrite
higher-numbered assumptions, use REV_FULL_SIMP_TAC.
See also
bossLib.REV_FULL_SIMP_TAC,
bossLib.ASM_SIMP_TAC,
bossLib.SIMP_CONV,
bossLib.SIMP_RULE,
bossLib.SIMP_TAC,
BasicProvers.VAR_EQ_TAC
GEN_EXISTS_TAC
GEN_EXISTS_TAC
bossLib.GEN_EXISTS_TAC : string -> Parse.term Lib.frag list -> tactic
Instantiate a quantifier at subposition.
GEN_EXISTS_TAC v_name i tries to instantiate a quantifier for a
variable with name v_name with i. It is short for
quantHeuristicsLib.QUANT_TAC [(v, i, [])]. It can be seen as a
generalisation of Q.EXISTS_TAC.
See also
Tactic.EXISTS_TAC,
quantHeuristicsLib.QUANT_TAC
gs
gs
bossLib.gs : thm list -> tactic
Simplifies assumptions and goal conclusion until a normal form is reached.
A call to gs ths produces a simplification tactic that repeatedly
simplifies with the theorems ths, the stateful simpset, the natural
number arithmetic decision procedure and normalizer, and let-elimination
(as done by simp) over both a goal's assumptions and the goal's
conclusion.
Assumptions are simplified first, with assumption terms simplified in
turn in a context that includes all of the other assumptions. After
simplification, if an assumption has been reduced to T (truth), it is
dropped. Otherwise, it is added back to the assumption list using
STRIP_ASSUME_TAC. After this process of assumption simplification
produces no further change (assessed using CHANGED_TAC), the goal's
conclusion is also simplified, in a context that assumes all of the (now
simplified) asssumptions.
Theorems with restrictions (Once, Ntimes) passed to the gs tactic
will not have those restrictions refreshed as invocations of the base
simplification procedure are repeated. This means that the restricted
theorems will likely only be applied to the first assumption where the
left-hand-sides match.
Failure
Never fails, but may loop.
Example
The theorem SUB_CANCEL has two preconditions:
> arithmeticTheory.SUB_CANCEL;
val it = ⊢ ∀p n m. n ≤ p ∧ m ≤ p ⇒ (p − n = p − m ⇔ n = m): thm
If those preconditions are distributed awkwardly in a goal, neither fs
nor rfs (which make passes over the assumptions in a particular order)
may be able to apply the rewrite. However, gs will make progress:
x ≤ b, b - x = b - y, y ≤ b ?- x * y < 10
============================================== gs[SUB_CANCEL]
y ≤ b, x = y ?- y ** 2 < 10
Comments
The accompanying functions gvs, gnvs and gns are similar, but
tweak the behaviours slightly. The functions with v in their name
eliminate equalities (the x = y in the example above, say), and the
functions with n in the name do not use STRIP_ASSUME_TAC when adding
assumptions back to the goal. The latter can prevent case-splits.
The rgs variant attacks the assumptions in the reverse order to gs.
The latter simplifies older assumptions using newer assumptions, but
rgs uses the opposite order. If, for example, the assumption list
includes both 0 < n and n ≠ 0, then gs will preserve one of these
and rgs will preserve the other.
See also
Tactical.CHANGED_TAC,
bossLib.simp
Hol_datatype
Hol_datatype
bossLib.Hol_datatype : hol_type quotation -> unit
Define a concrete datatype (deprecated syntax).
The Hol_datatype function provides exactly the same definitional power
as the Datatype function (which see), with a slightly different input
syntax, given below:
spec ::= [ <binding> ; ]* <binding>
binding ::= <ident> = [ <clause> | ]* <clause>
| <ident> = <| [ <ident> : <type> ; ]* <ident> : <type> |>
clause ::= <ident>
| <ident> of [<type> => ]* <type>
Example
For example, what with Datatype would be
Datatype`btree = Leaf 'a | Node btree 'b btree
is
Hol_datatype `btree = Leaf of 'a
| Node of btree => 'b => btree`
when using Hol_datatype.
The => notation in the description highlights the fact that, in HOL,
constructors are by default curried.
Comments
The Datatype function's syntax is easier to write and easier to
understand.
See also
Hol_defn
Hol_defn
bossLib.Hol_defn : string -> term quotation -> defn
Also exported as Defn.Hol_defn.
General-purpose function definition facility.
Hol_defn allows one to define functions, recursive functions in
particular, while deferring termination issues. Hol_defn should be
used when Define or xDefine fails, or when the context required by
Define or xDefine is too much.
Hol_defn takes the same arguments as xDefine.
Hol_defn s q automatically constructs termination constraints for the
function specified by q, defines the function, derives the specified
equations, and proves an induction theorem. All these results are
packaged up in the returned defn value. The defn type is best
thought of as an intermediate step in the process of deriving the
unconstrained equations and induction theorem for the function.
The termination conditions constructed by Hol_defn are for a function
that takes a single tuple as an argument. This is an artifact of the way
that recursive functions are modelled.
A prettyprinter, which prints out a summary of the known information on
the results of Hol_defn, has been installed in the interactive system.
Hol_defn may be found in bossLib and also in Defn.
Failure
Hol_defn s q fails if s is not an alphanumeric identifier.
Hol_defn s q fails if q fails to parse or typecheck.
Hol_defn may extract unsatisfiable termination conditions when asked
to define a higher-order recursion involving a higher-order function
that the termination condition extraction mechanism of Hol_defn is
unaware of.
Example
Here we attempt to define a quick-sort function qsort:
- Hol_defn "qsort"
`(qsort ___ [] = []) /\
(qsort ord (x::rst) =
APPEND (qsort ord (FILTER ($~ o ord x) rst))
(x :: qsort ord (FILTER (ord x) rst)))`;
<<HOL message: inventing new type variable names: 'a>>
> val it =
HOL function definition (recursive)
Equation(s) :
[...]
|- (qsort v0 [] = []) /\
(qsort ord (x::rst) =
APPEND (qsort ord (FILTER ($~ o ord x) rst))
(x::qsort ord (FILTER (ord x) rst)))
Induction :
[...]
|- !P.
(!v0. P v0 []) /\
(!ord x rst.
P ord (FILTER ($~ o ord x) rst) /\
P ord (FILTER (ord x) rst) ==> P ord (x::rst))
==> !v v1. P v v1
Termination conditions :
0. WF R
1. !rst x ord. R (ord,FILTER ($~ o ord x) rst) (ord,x::rst)
2. !rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)
In the following we give an example of how to use Hol_defn to define a
nested recursion. In processing this definition, an auxiliary function
N_aux is defined. The termination conditions of N are phrased in
terms of N_aux for technical reasons.
- Hol_defn "ninety1"
`N x = if x>100 then x-10
else N(N(x+11))`;
> val it =
HOL function definition (nested recursion)
Equation(s) :
[...] |- N x = (if x > 100 then x - 10 else N (N (x + 11)))
Induction :
[...]
|- !P.
(!x. (~(x > 100) ==> P (x + 11)) /\
(~(x > 100) ==> P (N (x + 11))) ==> P x)
==>
!v. P v
Termination conditions :
0. WF R
1. !x. ~(x > 100) ==> R (x + 11) x
2. !x. ~(x > 100) ==> R (N_aux R (x + 11)) x
Comments
An invocation of Hol_defn is usually the first step in a multi-step
process that ends with unconstrained recursion equations for a function,
along with an induction theorem. Hol_defn is used to construct the
function and synthesize its termination conditions; next, one invokes
tgoal to set up a goal to prove termination of the function. The
termination proof usually starts with an invocation of WF_REL_TAC.
After the proof is over, the desired recursion equations and induction
theorem are available for further use.
It is occasionally important to understand, at least in part, how
Hol_defn constructs termination constraints. In some cases, it is
necessary for users to influence this process in order to have correct
termination constraints extracted. The process is driven by so-called
congruence theorems for particular HOL constants. For example, suppose
we were interested in defining a 'destructor-style' version of the
factorial function over natural numbers:
fact n = if n=0 then 1 else n * fact (n-1).
In the absence of a congruence theorem for the 'if-then-else' construct,
Hol_defn would extract the termination constraints
0. WF R
1. !n. R (n - 1) n
which are unprovable, because the context of the recursive call has not
been taken account of. This example is in fact not a problem for HOL,
since the following congruence theorem is known to Hol_defn:
|- !b b' x x' y y'.
(b = b') /\
(b' ==> (x = x')) /\
(~b' ==> (y = y')) ==>
((if b then x else y) = (if b' then x' else y'))
This theorem is interpreted by Hol_defn as an ordered sequence of
instructions to follow when the termination condition extractor hits an
'if-then-else'. The theorem is read as follows:
When an instance `if B then X else Y` is encountered while the
extractor traverses the function definition, do the following:
1. Go into B and extract termination conditions TCs(B) from
any recursive calls in it. This returns a theorem
TCs(B) |- B = B'.
2. Assume B' and extract termination conditions from any
recursive calls in X. This returns a theorem
TCs(X) |- X = X'. Each element of TCs(X) will have
the form "B' ==> M".
3. Assume ~B' and extract termination conditions from any
recursive calls in Y. This returns a theorem
TCs(Y) |- Y = Y'. Each element of TCs(Y) will have
the form "~B' ==> M".
4. By equality reasoning with (1), (2), and (3), derive
TCs(B) u TCs(X) u TCs(Y)
|-
(if B then X else Y) = (if B' then X' else Y')
5. Replace "if B then X else Y" by "if B' then X' else Y'".
The accumulated termination conditions are propagated until the
extraction process finishes, and appear as hypotheses in the final
result. In our example, context is properly accounted for in recursive
calls under either branch of an 'if-then-else'. Thus the extracted
termination conditions for fact are
0. WF R
1. !n. ~(n = 0) ==> R (n - 1) n
and are easy to prove.
Now we discuss congruence theorems for higher-order functions. A
'higher-order' recursion is one in which a higher-order function is used
to apply the recursive function to arguments. In order for the correct
termination conditions to be proved for such a recursion, congruence
rules for the higher order function must be known to the termination
condition extraction mechanism. Congruence rules for common higher-order
functions, e.g., MAP, EVERY, and EXISTS for lists, are already
known to the mechanism. However, at times, one must manually prove and
install a congruence theorem for a higher-order function.
For example, suppose we define a higher-order function SIGMA for
summing the results of a function in a list. We then use SIGMA in the
definition of a function for summing the results of a function in an
arbitrarily (finitely) branching tree.
- Define `(SIGMA f [] = 0) /\
(SIGMA f (h::t) = f h + SIGMA f t)`;
- Hol_datatype `ltree = Node of 'a => ltree list`;
> val it = () : unit
- Defn.Hol_defn
"ltree_sigma" (* higher order recursion *)
`ltree_sigma f (Node v tl) = f v + SIGMA (ltree_sigma f) tl`;
> val it =
HOL function definition (recursive)
Equation(s) :
[..] |- ltree_sigma f (Node v tl)
= f v + SIGMA (\a. ltree_sigma f a) tl
Induction :
[..] |- !P. (!f v tl. (!a. P f a) ==> P f (Node v tl))
==> !v v1. P v v1
Termination conditions :
0. WF R
1. !tl v f a. R (f,a) (f,Node v tl) : defn
The termination conditions for ltree_sigma seem to require finding a
well-founded relation R such that the pair (f,a) is R-less than
(f, Node v tl). However, this is a hopeless task, since there is no
relation between a and Node v tl, besides the fact that they are
both ltrees. The termination condition extractor has not performed
properly, because it didn't know a congruence rule for SIGMA. Such a
congruence theorem is the following:
SIGMA_CONG =
|- !l1 l2 f g.
(l1=l2) /\ (!x. MEM x l2 ==> (f x = g x)) ==>
(SIGMA f l1 = SIGMA g l2)
Once Hol_defn has been told about this theorem, via write_congs, the
termination conditions extracted for the definition are provable, since
a is a proper subterm of Node v tl.
- local open DefnBase
in
val _ = write_congs (SIGMA_CONG::read_congs())
end;
- Defn.Hol_defn
"ltree_sigma"
`ltree_sigma f (Node v tl) = f v + SIGMA (ltree_sigma f) tl`;
> val it =
HOL function definition (recursive)
Equation(s) : ... (* as before *)
Induction : ... (* as before *)
Termination conditions :
0. WF R
1. !v f tl a. MEM a tl ==> R (f,a) (f,Node v tl)
One final point : for every HOL datatype defined by application of
Hol_datatype, a congruence theorem is automatically proved for the
'case' constant for that type, and stored in the TypeBase. For
example, the following congruence theorem for num_case is stored in
the TypeBase:
|- !f' f b' b M' M.
(M = M') /\
((M' = 0) ==> (b = b')) /\
(!n. (M' = SUC n) ==> (f n = f' n))
==>
(num_case b f M = num_case b' f' M')
This allows the contexts of recursive calls in branches of 'case' expressions to be tracked.
See also
Defn.tgoal, Defn.tprove,
bossLib.WF_REL_TAC,
bossLib.Define,
bossLib.xDefine,
bossLib.Hol_datatype
Hol_reln
Hol_reln
bossLib.Hol_reln : term quotation -> (thm * thm * thm)
Also exported as IndDefLib.Hol_reln.
Defines inductive relations.
The Hol_reln function is used to define inductively characterised
relations. It takes a term quotation as input and attempts to define the
relations there specified. The input term quotation must parse to a term
that conforms to the following grammar:
<input-format> ::= <clause> /\ <input-format> | <clause>
<clause> ::= (!x1 .. xn. <hypothesis> ==> <conclusion>)
| (!x1 .. xn. <conclusion>)
<conclusion> ::= <con> sv1 sv2 ....
<hypothesis> ::= any term
<con> ::= a new relation constant
The sv1 terms that appear after a constant name are so-called
"schematic variables". The same variables must always follow the same
constant name throughout the definition. These variables and the names
of the constants-to-be must not be quantified over in each <clause>.
Otherwise, a <clause> must not include any free variables. (The
universal quantifiers at the head of the clause can be used to bind free
variables, but it is also permissible to use existential quantification
in the hypotheses. If a clause has no free variables, it is permissible
to have no universal quantification.)
The Hol_reln function may be used to define multiple relations. These
may or may not be mutually recursive. The clauses for each relation need
not be contiguous.
The function returns three theorems. Each is also saved in the current
theory segment. The first is a conjunction of implications that will be
the same as the input term quotation. This theorem is saved under the
name <stem>_rules, where <stem> is the name of the first relation
defined by the function. The second is the induction principle for the
relations, saved under the name <stem>_ind. The third is the cases
theorem for the relations, saved under the name <stem>_cases. The
cases theorem is of the form
(!a0 .. an. R1 a0 .. an = <R1's first rule possibility> \/
<R1's second rule possibility> \/ ...)
/\
(!a0 .. am. R2 a0 .. am = <R2's first rule possibility> \/
<R2's second rule possibility> \/ ...)
/\
...
Failure
The Hol_reln function will fail if the provided quotation does not
parse to a term of the specified form. It will also fail if a clause's
only free variables do not follow a relation name, or if a relation name
is followed by differing schematic variables. If the definition
principle can not prove that the characterisation is inductive (as would
happen if a hypothesis included a negated occurence of one of the
relation names), then the same theorems are returned, but with extra
assumptions stating the required inductive property.
If the name of the new constants are such that they will produce invalid
SML identifiers when bound in a theory file, using export_theory will
fail, and suggest the use of set_MLname to fix the problem.
Example
Defining ODD and EVEN:
- Hol_reln`EVEN 0 /\
(!n. ODD n ==> EVEN (n + 1)) /\
(!n. EVEN n ==> ODD (n + 1))`;
> val it =
(|- EVEN 0 /\ (!n. ODD n ==> EVEN (n + 1)) /\
!n. EVEN n ==> ODD (n + 1),
|- !EVEN' ODD'.
EVEN' 0 /\ (!n. ODD' n ==> EVEN' (n + 1)) /\
(!n. EVEN' n ==> ODD' (n + 1)) ==>
(!a0. EVEN a0 ==> EVEN' a0) /\ !a1. ODD a1 ==> ODD' a1,
|- (!a0. EVEN a0 = (a0 = 0) \/
?n. (a0 = n + 1) /\ ODD n) /\
!a1. ODD a1 = ?n. (a1 = n + 1) /\ EVEN n)
: thm * thm * thm
Defining reflexive and transitive closure, using a schematic variable.
This is appropriate because it is RTC R that has the inductive
characterisation, not RTC itself.
- Hol_reln `(!x. RTC R x x) /\
(!x z. (?y. R x y /\ RTC R y z) ==> RTC R x z)`;
<<HOL message: inventing new type variable names: 'a>>
> val it =
(|- !R. (!x. RTC R x x) /\
!x z. (?y. R x y /\ RTC R y z) ==> RTC R x z,
|- !R RTC'.
(!x. RTC' x x) /\
(!x z. (?y. R x y /\ RTC' y z) ==> RTC' x z) ==>
!a0 a1. RTC R a0 a1 ==> RTC' a0 a1,
|- !R a0 a1. RTC R a0 a1 =
(a1 = a0) \/ ?y. R a0 y /\ RTC R y a1)
: thm * thm * thm
Comments
Being a definition principle, the Hol_reln function takes a quotation
rather than a term. The structure IndDefRules provides functions for
applying the results of an invocation of Hol_reln.
See also
bossLib.Define,
bossLib.Hol_datatype,
IndDefRules
IgnAsm
IgnAsm
bossLib.IgnAsm : 'a quotation -> thm
Creates marker theorems causing matching assumptions to be ignored
A call to IgnAsm q creates a theorem that can be passed to various
simplification tactics (those based on simpLib.ASM_SIMP_TAC) which
will in turn those tactics to not use assumptions matching the provided
pattern q. If the quotation includes the string '(* sa *)' as a
suffix, the matching will be considered successful (leading to an
assumption being ignored) if the pattern matches any sub-term of the
assumption.
All assumptions matching the pattern will be ignored (see last example below). The matching process treats variables from the goal as constants.
Failure
Fails if the provided quotation includes any anti-quotations.
Example
In the first example below, the pattern mentions x, which occurs in
the goal, so that this pattern does not match the assumption about
variable y:
> simp[IgnAsm‘x = _’] ([“x = F”, “y = T”], “p ∧ x ∧ y”);
val it = ([([“x ⇔ F”, “y ⇔ T”], “p ∧ x”)], fn): goal list * validation
> simp[IgnAsm‘F’] ([“x = F”, “y = T”], “p ∧ x ∧ y”);
val it = ([([“x ⇔ F”, “y ⇔ T”], “F”)], fn): goal list * validation
> simp[IgnAsm‘F (* sa *)’] ([“x = F”, “y = T”], “p ∧ x ∧ y”);
val it = ([([“x ⇔ F”, “y ⇔ T”], “p ∧ x”)], fn): goal list * validation
> simp[IgnAsm‘_ = _’] ([“x = F”, “y = T”, “p:bool”], “p ∧ x ∧ y”);
val it = ([([“x ⇔ F”, “y ⇔ T”, “p”], “x ∧ y”)], fn): goal list * validation
See also
Induct
Induct
bossLib.Induct : tactic
Also exported as BasicProvers.Induct.
Performs structural induction over the type of the goal's outermost universally quantified variable.
Given a universally quantified goal, Induct attempts to perform an
induction based on the type of the leading universally quantified
variable. The induction theorem to be used is looked up in the
TypeBase database, which holds useful facts about the system's defined
types. Induct may also be used to reason about mutually recursive
types.
Failure
Induct fails if the goal is not universally quantified, or if the type
of the variable universally quantified does not have an induction
theorem in the TypeBase database.
Example
If attempting to prove
!list. LENGTH (REVERSE list) = LENGTH list
one can apply Induct to begin a proof by induction on list.
- e Induct;
This results in the base and step cases of the induction as new goals.
?- LENGTH (REVERSE []) = LENGTH []
LENGTH (REVERSE list) = LENGTH list
?- !h. LENGTH (REVERSE (h::list)) = LENGTH (h::list)
The same tactic can be used for induction over numbers. For example expanding the goal
?- !n. n > 2 ==> !x y z. ~(x EXP n + y EXP n = z EXP n)
with Induct yields the two goals
?- 0 > 2 ==> !x y z. ~(x EXP 0 + y EXP 0 = z EXP 0)
n > 2 ==> !x y z. ~(x EXP n + y EXP n = z EXP n)
?- SUC n > 2 ==> !x y z. ~(x EXP SUC n + y EXP SUC n = z EXP SUC n)
Induct can also be used to perform induction on mutually recursive
types. For example, given the datatype
Hol_datatype
`exp = VAR of string (* variables *)
| IF of bexp => exp => exp (* conditional *)
| APP of string => exp list (* function application *)
;
bexp = EQ of exp => exp (* boolean expressions *)
| LEQ of exp => exp
| AND of bexp => bexp
| OR of bexp => bexp
| NOT of bexp`
one can use Induct to prove that all objects of type exp and bexp
are of a non-zero size. (Recall that size definitions are automatically
defined for datatypes.) Typically, mutually recursive types lead to
mutually recursive induction schemes having multiple predicates. The
scheme for the above definition has 3 predicates: P0, P1, and P2,
which respectively range over expressions, boolean expressions, and
lists of expressions.
|- !P0 P1 P2.
(!a. P0 (VAR a)) /\
(!b e e0. P1 b /\ P0 e /\ P0 e0 ==> P0 (IF b e e0)) /\
(!l. P2 l ==> !b. P0 (APP b l)) /\
(!e e0. P0 e /\ P0 e0 ==> P1 (EQ e e0)) /\
(!e e0. P0 e /\ P0 e0 ==> P1 (LEQ e e0)) /\
(!b b0. P1 b /\ P1 b0 ==> P1 (AND b b0)) /\
(!b b0. P1 b /\ P1 b0 ==> P1 (OR b b0)) /\
(!b. P1 b ==> P1 (NOT b)) /\
P2 [] /\
(!e l. P0 e /\ P2 l ==> P2 (e::l))
==>
(!e. P0 e) /\ (!b. P1 b) /\ !l. P2 l
Invoking Induct on a goal such as
!e. 0 < exp_size e
yields the three subgoals
?- !s. 0 < exp_size (APP s l)
[ 0 < exp_size e, 0 < exp_size e' ] ?- 0 < exp_size (IF b e e')
?- !s. 0 < exp_size (VAR s)
In this case, P1 and P2 have been vacuously instantiated in the
application of Induct, since it detects that only P0 is needed.
However, it is also possible to use Induct to start the proofs of
(!e. 0 < exp_size e) /\ (!b. 0 < bexp_size b)
and
(!e. 0 < exp_size e) /\
(!b. 0 < bexp_size b) /\
(!list. 0 < exp1_size list)
See also
bossLib.Induct_on,
bossLib.completeInduct_on,
bossLib.measureInduct_on,
Prim_rec.INDUCT_THEN,
bossLib.Cases,
bossLib.Hol_datatype,
proofManagerLib.g,
proofManagerLib.e
Induct_on
Induct_on
bossLib.Induct_on : term quotation -> tactic
Also exported as BasicProvers.Induct_on.
Performs structural induction, using the type of the given term.
Given a term M, Induct_on attempts to perform an induction based on
the type of M. The induction theorem to be used is extracted from the
TypeBase database, which holds useful facts about the system's defined
types.
Induct_on can be used to specify variables that are buried in the
quantifier prefix, i.e., not the leading quantified variable.
Induct_on can also perform induction on non-variable terms. If M is
a non-variable term that does not occur bound in the goal, then
Induct_on equates M to a new variable v (one not occurring in the
goal), moves all hypotheses in which free variables of M occur to the
conclusion of the goal, adds the antecedent v = M, and quantifies all
free variables of M before universally quantifying v and then
finally inducting on v.
Induct_on may also be used to apply an induction theorem coming from
declaration of a mutually recursive datatype.
Failure
Induct_on fails if an induction theorem corresponding to the type of
M is not found in the TypeBase database.
Example
If attempting to prove
!x. LENGTH (REVERSE x) = LENGTH x
one can apply Induct_on `x` to begin a proof by induction on the
list structure of x. In this case, Induct_on serves as an explicit
version of Induct.
See also
bossLib.Induct,
bossLib.completeInduct_on,
bossLib.measureInduct_on,
Prim_rec.INDUCT_THEN,
bossLib.Cases,
bossLib.Hol_datatype,
proofManagerLib.g,
proofManagerLib.e
lambdify
lambdify
bossLib.lambdify : thm -> thm
Convert a theorem representing a single-line definition into a fully lambda-abstracted version.
Given a theorem which describes an equation for a constant applied to a series of distinct variables, derive a reformulation which equates the constant with a lambda-abstraction over those variables.
To advance a proof by unfolding a partially-applied function. Most
effectively used on theorems produced by oneline.
Example
Consider the result of applying oneline to listTheory.MAP:
> oneline listTheory.MAP;
val it = ⊢ MAP f v = case v of [] => [] | h::t => f h::MAP f t: thm
> lambdify it;
val it = ⊢ MAP = (λf v. case v of [] => [] | h::t => f h::MAP f t): thm
Failure
Fails on theorems of the wrong form, i.e. theorems which are not a single equation with a left-hand side consisting of an application to a series of distinct variables.
Comments
Shorthand for DefnBase.LIST_HALF_MK_ABS.
See also
bossLib.oneline,
jrhUtils.HALF_MK_ABS
list_ss
list_ss
bossLib.list_ss : simpset
Simplification set for lists.
The simplification set list_ss is a version of arith_ss enhanced for
the theory of lists. The following rewrites are currently used to
augment those already present from arith_ss:
|- (!l. APPEND [] l = l) /\
!l1 l2 h. APPEND (h::l1) l2 = h::APPEND l1 l2
|- (!l1 l2 l3. (APPEND l1 l2 = APPEND l1 l3) = (l2 = l3)) /\
!l1 l2 l3. (APPEND l2 l1 = APPEND l3 l1) = (l2 = l3)
|- (!l. EL 0 l = HD l) /\ !l n. EL (SUC n) l = EL n (TL l)
|- (!P. EVERY P [] = T) /\ !P h t. EVERY P (h::t) = P h /\ EVERY P t
|- (FLAT [] = []) /\ !h t. FLAT (h::t) = APPEND h (FLAT t)
|- (LENGTH [] = 0) /\ !h t. LENGTH (h::t) = SUC (LENGTH t)
|- (!f. MAP f [] = []) /\ !f h t. MAP f (h::t) = f h::MAP f t
|- (!f. MAP2 f [] [] = []) /\
!f h1 t1 h2 t2.
MAP2 f (h1::t1) (h2::t2) = f h1 h2::MAP2 f t1 t2
|- (!x. MEM x [] = F) /\ !x h t. MEM x (h::t) = (x = h) \/ MEM x t
|- (NULL [] = T) /\ !h t. NULL (h::t) = F
|- (REVERSE [] = []) /\ !h t. REVERSE (h::t) = APPEND (REVERSE t) [h]
|- (SUM [] = 0) /\ !h t. SUM (h::t) = h + SUM t
|- !h t. HD (h::t) = h
|- !h t. TL (h::t) = t
|- !l1 l2 l3. APPEND l1 (APPEND l2 l3) = APPEND (APPEND l1 l2) l3
|- !l. ~NULL l ==> (HD l::TL l = l)
|- !a0 a1 a0' a1'. (a0::a1 = a0'::a1') = (a0 = a0') /\ (a1 = a1')
|- !l1 l2. LENGTH (APPEND l1 l2) = LENGTH l1 + LENGTH l2
|- !l f. LENGTH (MAP f l) = LENGTH l
|- !f l1 l2. MAP f (APPEND l1 l2) = APPEND (MAP f l1) (MAP f l2)
|- !a1 a0. ~(a0::a1 = [])
|- !a1 a0. ~([] = a0::a1)
|- !l f. ((MAP f l = []) = (l = [])) /\
(([] = MAP f l) = (l = []))
|- !l. APPEND l [] = l
|- !l x. ~(l = x::l) /\ ~(x::l = l)
|- (!v f. case v f [] = v) /\
!v f a0 a1. case v f (a0::a1) = f a0 a1
|- (!l1 l2. ([] = APPEND l1 l2) = (l1 = []) /\ (l2 = [])) /\
!l1 l2. (APPEND l1 l2 = []) = (l1 = []) /\ (l2 = [])
|- (ZIP ([][]) = []) /\
!x1 l1 x2 l2. ZIP (x1::l1,x2::l2) = (x1,x2)::ZIP (l1,l2)
|- (UNZIP [] = ([],[])) /\
!x l. UNZIP (x::l) = (FST x::FST (UNZIP l),SND x::SND (UNZIP l))
|- !P l1 l2. EVERY P (APPEND l1 l2) = EVERY P l1 /\ EVERY P l2
|- !P l1 l2. EXISTS P (APPEND l1 l2) = EXISTS P l1 \/ EXISTS P l2
|- !e l1 l2. MEM e (APPEND l1 l2) = MEM e l1 \/ MEM e l2
|- (!x. LAST [x] = x) /\ !x y z. LAST (x::y::z) = LAST (y::z)
|- (!x. FRONT [x] = []) /\ !x y z. FRONT (x::y::z) = x::FRONT (y::z)
|- (!f e. FOLDL f e [] = e) /\
!f e x l. FOLDL f e (x::l) = FOLDL f (f e x) l
|- (!f e. FOLDR f e [] = e) /\
!f e x l. FOLDR f e (x::l) = f x (FOLDR f e l)
See also
BasicProvers.RW_TAC,
BasicProvers.SRW_TAC,
simpLib.SIMP_TAC,
simpLib.SIMP_CONV,
simpLib.SIMP_RULE,
BasicProvers.bool_ss,
bossLib.std_ss,
bossLib.arith_ss
measureInduct_on
measureInduct_on
bossLib.measureInduct_on : term quotation -> tactic
Perform complete induction with a supplied measure function.
If q parses into a well-typed term M N, an invocation
measureInduct_on q begins a proof by induction, using M to map N
into a number. The term N should occur free in the current goal.
Failure
If M N does not parse into a term or if N does not occur free in the
current goal.
Example
Suppose we wish to prove P (APPEND l1 l2) by induction on the length
of l1. Then measureInduct_on `LENGTH ll` yields the goal
{ !y. LENGTH y < LENGTH l1 ==> P (APPEND y l2) } ?- P (APPEND l1 l2)
See also
bossLib.completeInduct_on,
bossLib.Induct,
bossLib.Induct_on
METIS_TAC
METIS_TAC
bossLib.METIS_TAC : thm list -> tactic
Performs first-order resolution to try to prove goal
When METIS_TAC ths is applied to a goal (asl,w), it attempts to find
a resolution proof that the provided theorems in ths and the
assumptions in asl together imply the goal in w. METIS_TAC
implements ordered resolution and as such its ability to reason about
equality is generally better than MESON_TAC's.
Failure
Fails if the underlying resolution machinery cannot prove the goal.
METIS_TAC may also consume more and more time, and more and more
memory as a search for a proof proceeds without ever explicitly failing.
Comments
The alternative lower-case spelling metis_tac is also available for
this tactic from the bossLib structure. There is no "metis" entrypoint
that allows one to ignore the assumptions (with "meson", there is both
MESON_TAC and ASM_MESON_TAC).
See also
mk_asm
mk_asm
bossLib.mk_asm : string -> thm -> tactic
Creates a new named assumption with the given name and the given fact.
Failure
Never fails.
See also
namedCases
namedCases
bossLib.namedCases : string list -> tactic
Also exported as BasicProvers.namedCases.
Case split on type of leading universally quantified variable in the goal, using given names for introduced constructor arguments.
An application of namedCases [s1, ..., sn] to a goal of the form
!x:ty. P will perform a case split on the type ty, using the given
names for the arguments of the introduced constructor terms. The type
ty should be that of a dataype that has a so-called "nchotomy" theorem
installed in the system database of declared datatypes, accessible via
TypeBase.nchotomy_of.
For a datatype with n constructors, n strings are expected to be
supplied. If no strings are supplied, the system will use a default
naming scheme. If the ith constructor has no arguments, then si
should be the empty string. If the ith constructor has k arguments,
then si should consist of k space-separated names. In case a name
does not need to be specified, an underscore _ or dash - can be
supplied, in which case a default name will be conjured up.
In case ty is a product type ty1 # ... # tyi, namedCases [s] will
iteratively case split on all product types in ty, thus replacing
x:ty by a tuple with i variables, the names of which are taken from
s.
Failure
Fails if there is not an nchotomy theorem installed for the topmost type
constructor of ty. If slist is not the empty list,
namedCases slist will fail if the length of slist is not equal to
the number of constructors in the nchotomy theorem. Fails if the given
names for arguments of an introduced constructor are not equinumerous
with the arguments.
Example
Consider the goal
A ?- !x:num#num#bool. P x
Invoking namedCases ["a b c"] yields the goal
A ?- P (a,b,c)
while namedCases ["a _ _"] yields the goal
A ?- P (a,_gv0,_gv1)
Example
Consider a datatype of arithmetic expressions declared as
Datatype:
arith
= Var 'a
| Const num
| Add arith arith
| Sub arith arith
| Mult arith arith
End
and the goal
A ?- !x:'a arith. P x
Invoking namedCases ["v","c","a1 a2", "s1 s2", "m1 m2"] yields the
following 5 goals
P (Mult m1 m2)
P (Sub s1 s2)
P (Add a1 a2)
P (Const c)
P (Var v)
See also
bossLib.namedCases_on,
bossLib.Cases_on,
bossLib.Cases,
TypeBase.nchotomy_of
namedCases_on
namedCases_on
bossLib.namedCases_on : term quotation -> string list -> tactic
Also exported as BasicProvers.namedCases_on.
Case split on type of given term, using given names for introduced constructor arguments.
An application of namedCases_on q [s1, ..., sn] to a goal A ?- P
first parses q in the context of the goal to yield a term tm:ty,
then uses ty to look up a a so-called "nchotomy" theorem installed in
the system database of declared datatypes, then performs a case split on
how tm can be constructed. The strings s1, ..., sn designate the
names to be used as arguments of the constructor in each case. This
yields the goals
(A, tm = <constr>1 <names>1 ?- P)
,...,
(A, tm = <constr>n <names>n ?- P)
For a datatype with n constructors, n strings are expected to be
supplied. If no strings are supplied, the system will use a default
naming scheme. If the ith constructor has no arguments, then si
should be the empty string. If the ith constructor has k arguments,
then si should consist of k space-separated names. In case a name
does not need to be specified, an underscore _ or dash - can be
supplied, in which case a default name will be conjured up.
In case ty is a product type ty1 # ... # tyi, namedCases_on q [s]
will iteratively case split on all product types in ty, thus replacing
x:ty by a tuple with i variables, the names of which are taken from
s.
Failure
Fails if there is not an nchotomy theorem installed for the topmost type
constructor of ty. If slist is not the empty list,
namedCases_on q slist will fail if the length of slist is not equal
to the number of constructors in the nchotomy theorem. Fails if the
given names for arguments of an introduced constructor are not
equinumerous with the arguments.
Comments
This is a version of namedCases where the (free) term being split on
is specified.
See also
bossLib.namedCases,
bossLib.Cases_on,
bossLib.Cases,
TypeBase.nchotomy_of
NoAsms
NoAsms
bossLib.NoAsms : thm
A special marker theorem that makes the simplifier ignore a goal's assumptions
The NoAsms theorem is a special value that causes a variety of
simplification tactics (those ultimately based on
simpLib.ASM_SIMP_TAC) to ignore a goal's assumptions, even if those
tactics might otherwise attempt to use those assumptions when modifying
the goal.
Failure
Never fails.
Example
> simp[] ([“x = T”], “p ∧ x”);
val it = ([([“x ⇔ T”], “p”)], fn): goal list * validation
> simp[NoAsms] ([“x = T”], “p ∧ x”);
val it = ([([“x ⇔ T”], “p ∧ x”)], fn): goal list * validation
See also
oneline
oneline
bossLib.oneline : thm -> thm
Collapse a theorem representing a single definition into a single line.
Given a theorem which consists of equations defining constants, derive a
reformulation where any pattern matching clauses have been combined and
replaced by a single case expression. This produces left-hand sides
consisting of the constant applied only to variables. When supplied
equations for several constants (e.g., for mutually recursive
functions), oneline returns a theorem with one equation per constant.
To advance a proof by unfolding a function defined by pattern-matching, but where the pattern is not yet constrained enough.
Example
> listTheory.MAP;
val it = ⊢ (∀f. MAP f [] = []) ∧ ∀f h t. MAP f (h::t) = f h::MAP f t: thm
> oneline it;
val it = ⊢ MAP f v = case v of [] => [] | h::t => f h::MAP f t: thm
Failure
Fails on theorems of the wrong form, including definition of multiple constants.
Comments
Shorthand for DefnBase.one_line_ify NONE.
See also
bossLib.lambdify,
bossLib.AllCaseEqs
pairarg_tac
pairarg_tac
bossLib.pairarg_tac : tactic
Adds a "splitting" equation for a pair term to goal assumptions.
A call to pairarg_tac will search the goal (starting with the
conclusion and moving onto each assumption in turn), for a sub-term of
the form (\(x,y,...). body) arg, where the variables appearing in
arg are free in the goal. The tactic will then introduce a new
assumption in the goal of the form
arg = (x,y,...)
where the variables x, y etc., are chosen to be as close as possible
to the names in the paired abstraction. In other words, they will vary
only if those names are already free in the goal.
Failure
Fails if there is no such sub-term.
Example
> pairarg_tac ([], ``(\(x,y). x + y) p = 10``);
val it = ([([“p = (x,y)”], “(λ(x,y). x + y) p = 10”)], fn):
goal list * validation
See also
pairLib.PairCases_on,
bossLib.split_pair_case_tac
plus2
++
op bossLib.++ : simpset * ssfrag -> simpset
Infix operator for augmenting simpsets with ssfrag values.
The ++ function combines its two arguments and creates a new simpset.
This is a way of creating simpsets that are tailored to the particular
simplification task at hand.
Failure
Never fails.
Example
Here we add the UNWIND_ss ssfrag value to the pure_ss simpset to
exploit the former's point-wise elimination conversions.
> SIMP_CONV (pureSimps.pure_ss ++ boolSimps.UNWIND_ss) []
(Term`!x. x ==> (?y. P(x,y) /\ (y = 5))`);
val it = ⊢ (∀x. x ⇒ ∃y. P (x,y) ∧ y = 5) ⇔ P (T,5): thm
See also
simpLib.mk_simpset,
simpLib.rewrites,
simpLib.SIMP_CONV,
pureSimps.pure_ss
PROVE
PROVE
bossLib.PROVE : thm list -> term -> thm
Also exported as BasicProvers.PROVE.
Prove a theorem with use of supplied lemmas.
An invocation PROVE thl M attempts to prove M using an automated
reasoner supplied with the lemmas in thl. The automated reasoner
performs a first order proof search. It currently provides some support
for polymorphism and higher-order values (lambda terms).
Failure
If the proof search fails, or if M does not have type bool.
Example
> PROVE [] (concl SKOLEM_THM);
Meson search level: ........
val it = ⊢ ∀P. (∀x. ∃y. P x y) ⇔ ∃f. ∀x. P x (f x): thm
> let open arithmeticTheory
in
PROVE [ADD_ASSOC, ADD_SYM, ADD_CLAUSES]
(Term `x + 0 + y + z = y + (z + x)`)
end;
Meson search level: ............
val it = ⊢ x + 0 + y + z = y + (z + x): thm
Comments
Some output (a row of dots) is currently generated as PROVE works. If
the frequency of dot emission becomes slow, that is a sign that the term
is not likely to be proved with the current lemmas.
Unlike MESON_TAC, PROVE can handle terms with conditionals.
See also
bossLib.PROVE_TAC,
mesonLib.MESON_TAC,
mesonLib.ASM_MESON_TAC
PROVE_TAC
PROVE_TAC
bossLib.PROVE_TAC : thm list -> tactic
Also exported as BasicProvers.PROVE_TAC.
Solve a goal with use of hypotheses and supplied lemmas.
An invocation PROVE_TAC thl attempts to solve the goal it is applied
to by executing a proof procedure that is semi-complete for pure first
order logic. The assumptions of the goal and the theorems in thl are
used. The procedure makes special provision for handling polymorphic and
higher-order values (lambda terms). It also handles conditional
expressions.
Failure
PROVE_TAC fails if it searches to a depth equal to the contents of the
reference variable mesonLib.max_depth (set to 30 by default, but
changeable by the user) without finding a proof.
Comments
PROVE_TAC can only progress the goal to a successful proof of the goal
or not at all. In this respect it differs from tactics such as
simplification and rewriting. Its ability to solve existential goals and
to make effective use of transitivity theorems make it a particularly
powerful tactic.
See also
bossLib.PROVE,
mesonLib.MESON_TAC,
mesonLib.ASM_MESON_TAC,
mesonLib.GEN_MESON_TAC
QI_ss
QI_ss
bossLib.QI_ss : ssfrag
Simpset-fragment for instantiating quantifiers with some default heuristics.
QI_ss is short for QUANT_INST_ss [std_qp].
See also
bossLib.QI_TAC,
quantHeuristicsLib.QUANT_INST_ss
QI_TAC
QI_TAC
bossLib.QI_TAC : tactic
Try to instantiate quantifiers with some default heuristics.
QI_TAC is short for QUANT_INSTANTIATE_TAC [std_qp].
See also
bossLib.ASM_QI_TAC,
quantHeuristicsLib.QUANT_INSTANTIATE_TAC,
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC
recInduct
recInduct
bossLib.recInduct : thm -> tactic
Performs recursion induction.
An invocation recInduct thm on a goal g, where thm is typically an
induction scheme returned from an invocation of Define or Hol_defn,
attempts to match the consequent of thm to g and, if successful,
then replaces g by the instantiated antecedents of thm. The order of
quantification of the goal should correspond with the order of
quantification in the conclusion of thm.
Failure
recInduct fails if the goal is not universally quantified in a way
corresponding with the quantification of the conclusion of thm.
Example
Suppose we had introduced a function for incrementing a number until it no longer can be found in a given list:
variant x L = if MEM x L then variant (x + 1) L else x
Typically Hol_defn would be used to make such a definition, and some
subsequent proof would be required to establish termination. Once that
work was done, the specified recursion equations would be available as a
theorem and, as well, a corresponding induction theorem would also be
generated. In the case of variant, the induction theorem variant_ind
is
|- !P. (!x L. (MEM x L ==> P (x + 1) L) ==> P x L) ==> !v v1. P v v1
Suppose now that we wish to prove that the variant with respect to a list is not in the list:
?- !x L. ~MEM (variant x L) L`,
One could try mathematical induction, but that won't work well, since
x gets incremented in recursive calls. Instead, induction with
'variant-induction' works much better. recInduct can be used to
apply such theorems in tactic proof. For our example,
recInduct variant_ind yields the goal
?- !x L. (MEM x L ==> ~MEM (variant (x + 1) L) L) ==> ~MEM (variant x L) L
A few simple tactic applications then prove this goal.
See also
bossLib.Induct,
bossLib.Induct_on,
bossLib.completeInduct_on,
bossLib.measureInduct_on,
Prim_rec.INDUCT_THEN,
bossLib.Cases,
bossLib.Hol_datatype,
proofManagerLib.g,
proofManagerLib.e
REV_FULL_SIMP_TAC
REV_FULL_SIMP_TAC
bossLib.REV_FULL_SIMP_TAC : simpset -> thm list -> tactic
Simplifies the goal (assumptions as well as conclusion) with the given simpset.
REV_FULL_SIMP_TAC is the same as FULL_SIMP_TAC except that it
simplifies the assumptions in the opposite order.
That is, in REV_FULL_SIMP_TAC, each assumption is used to rewrite
higher-numbered assumptions, whereas in FULL_SIMP_TAC, each assumption
is used to rewrite lower-numbered assumptions.
See also
bossLib.FULL_SIMP_TAC,
bossLib.ASM_SIMP_TAC,
bossLib.SIMP_TAC
rewrites
rewrites
bossLib.rewrites : thm list -> ssfrag
Also exported as simpLib.rewrites.
Creates an ssfrag value consisting of the given theorems as rewrites.
Failure
Never fails.
Example
Instead of writing the simpler SIMP_CONV std_ss thmlist, one could
write
SIMP_CONV (std_ss ++ rewrites thmlist) []
More plausibly, rewrites can be used to create commonly used ssfrag
values containing a great number of rewrites. This is how the basic
system's various ssfrag values are constructed where those values
consist only of rewrite theorems.
See also
bossLib.++,
simpLib.mk_simpset,
simpLib.SSFRAG,
bossLib.SIMP_CONV
RW_TAC
RW_TAC
bossLib.RW_TAC : simpset -> thm list -> tactic
Also exported as BasicProvers.RW_TAC.
Simplification with case-splitting and built-in knowledge of declared datatypes.
RW_TAC is a simplification tactic that provides conditional and
contextual rewriting, and automatic invocation of conversions and
decision procedures in the course of simplification. An application
RW_TAC ss thl adds the theorems in thl to the simpset ss and
proceeds to simplify the goal.
The process is based upon the simplification procedures in simpLib,
but is more persistent in attempting to apply rewrite rules. It
automatically incorporates relevant results from datatype declarations
(the most important of these are injectivity and distinctness of
constructors). It uses the current hypotheses when rewriting the goal.
It automatically performs case-splitting on conditional expressions in
the goal. It simplifies any equation between constructors occurring in
the goal or the hypotheses. It automatically substitutes through the
goal any assumption that is an equality v = M or M = v, if v is a
variable not occurring in M. It eliminates any boolean variable or
negated boolean variable occurring as a hypothesis. It breaks down any
conjunctions, disjunctions, double negations, or existentials occurring
as hypotheses. It keeps the goal in "stripped" format so that the
resulting goal will not be an implication or universally quantified.
Failure
Never fails, but may diverge.
Comments
The case splits arising from conditionals and disjunctions can result in
many unforeseen subgoals. In that case, SIMP_TAC or even REWRITE_TAC
should be used.
The automatic incorporation of datatype facts can be slow when operating
in a context with many datatypes (or a few large datatypes). In such
cases, SRW_TAC is preferable to RW_TAC.
See also
bossLib.SRW_TAC,
bossLib.SIMP_TAC,
Rewrite.REWRITE_TAC,
bossLib.Hol_datatype
SET_RULE
SET_RULE
bossLib.SET_RULE : term -> thm
Automatically prove a set-theoretic theorem by reduction to FOL.
An application DECIDE M, where M is a set-theoretic term, attempts
to automatically prove M by reducing basic set-theoretic operators
(IN, SUBSET, PSUBSET, INTER, UNION, INSERT, DELETE,
REST, DISJOINT, BIGINTER, BIGUNION, IMAGE, SING and GSPEC)
in M to their definitions in first-order logic. With SET_RULE, many
simple set-theoretic results can be directly proved without finding
needed lemmas in pred_setTheory.
Example
> SET_RULE ``!s t c. DISJOINT s t ==> DISJOINT (s INTER c) (t INTER c)``;
metis: r[+0+5]+0+0+0+0+1#
val it = ⊢ ∀s t c. DISJOINT s t ⇒ DISJOINT (s ∩ c) (t ∩ c): thm
Failure
Fails if the underlying resolution machinery used by METIS_TAC cannot
prove the goal, e.g. when there are other set operators in the term.
Comments
SET_RULE calls SET_TAC without extra lemmas.
See also
bossLib.SET_TAC,
bossLib.ASM_SET_TAC,
bossLib.METIS_TAC
SET_TAC
SET_TAC
bossLib.SET_TAC : thm list -> tactic
Tactic to automate some routine pred_set theory by reduction to FOL, using the given theorems as additional assumptions in the search.
SET_TAC reduces basic set-theoretic operators (IN, SUBSET,
PSUBSET, INTER, UNION, INSERT, DELETE, REST, DISJOINT,
BIGINTER, BIGUNION, IMAGE, SING and GSPEC) in the goal to
their definitions in first-order logic (FOL) and then call METIS_TAC
to solve it. With SET_TAC, many simple set-theoretic results can be
directly proved without finding needed lemmas in pred_setTheory.
Failure
Fails if the underlying resolution machinery (METIS_TAC) cannot prove
the goal, or the supplied theorems are not enough for the FOL reduction,
e.g., when there are other set-theoretic operators in the goal.
Example
A simple theorem about disjoint sets:
Theorem DISJOINT_RESTRICT_L :
!s t c. DISJOINT s t ==> DISJOINT (s INTER c) (t INTER c)
Proof SET_TAC []
QED
SET_TAC can only progress the goal to a successful proof of the
(whole) goal or not at all. SET_RULE can be used to prove an
intermediate set-theoretic lemma (there is no way to provide extra
lemmas, however).
Comments
The assumptions of a goal are ignored when SET_TAC is applied. To
include assumptions use ASM_SET_TAC.
See also
bossLib.ASM_SET_TAC,
bossLib.SET_RULE,
bossLib.METIS_TAC
SF
SF
bossLib.SF : ssfrag -> thm
Presents a simpset fragment as a theorem for inclusion in simplification
A call to SF sfrag creates a theorem that encodes (by way of an
indirection through a global register of fragments) the simpset fragment
sfrag. If this theorem is then passed to a simplification tactic (or
conversion), the simplification tactic will add the given fragment to
the simpset underpinning the simplification.
Failure
Fails if the given fragment doesn't have a name.
Comments
If the given fragment has a name, but has not been previously registered, it is registered at the time the simplification tactic or conversion is called. Given that this registration probably happens as part of a script's execution, this registration is unlikely to persist.
Example
> SIMP_CONV bool_ss [SF ETA_ss] “P (λx. f x) ∧ Q”;
val it = ⊢ P (λx. f x) ∧ Q ⇔ P f ∧ Q: thm
> simp[SF ETA_ss] ([], “P (λx. f x) ∧ Q”);
val it = ([([], “P f ∧ Q”)], fn): goal list * validation
See also
simpLib.AC, simpLib.Cong,
simpLib.register_frag
SIMP_CONV
SIMP_CONV
bossLib.SIMP_CONV : simpset -> thm list -> conv
Also exported as simpLib.SIMP_CONV.
Applies a simpset and a list of rewrite rules to simplify a term.
SIMP_CONV is the fundamental engine of the HOL simplification library.
It repeatedly applies the transformations included in the provided
simpset (which is augmented with the given rewrite rules) to a term,
ultimately yielding a theorem equating the original term to another.
Values of the simpset type embody a suite of different transformations
that might be applicable to given terms. These "transformational
components" are rewrites, conversions, AC-rules, congruences, decision
procedures and a filter, which is used to modify the way in which
rewrite rules are added to the simpset. The exact types for these
components, known as simpset fragments, and the way they can be combined
to create simpsets is given in the reference entry for SSFRAG.
Rewrite rules are used similarly to the way in they are used in the
rewriting system (REWRITE_TAC et al.). These are equational theorems
oriented to rewrite from left-hand-side to right-hand-side. Further,
SIMP_CONV handles obvious problems. If a rewrite rule is of the
general form [...] |- x = f x, then it will be discarded, and a
message is printed to this effect. On the other hand, if the
right-hand-side is a permutation of the pattern on the left, as in
|- x + y = y + x and
|- x INSERT (y INSERT s) = y INSERT (x INSERT s), then such rules will
only be applied if the term to which they are being applied is strictly
reduced according to some term ordering.
Rewriting is done using a form of higher-order matching, and also uses
conditional rewriting. This latter means that theorems of the form
|- P ==> (x = y) can be used as rewrites. If a term matching x is
found, the simplifier will attempt to satisfy the side-condition P. If
it is able to do so, then the rewriting will be performed. In the
process of attempting to rewrite P to true, further side conditions
may be generated. The simplifier limits the size of the stack of side
conditions to be solved (the reference variable Cond_rewr.stack_limit
holds this limit), so this will not introduce an infinite loop.
Rewrite rules can always be added "on the fly" as all of the
simplification functions take a thm list argument where these rules
can be specified. If a set of rewrite rules is frequently used, then
these should probably be made into a ssfrag value with the rewrites
function and then added to an existing simpset with ++.
The conversions which are part of simpsets are useful for situations
where simple rewriting is not enough to transform certain terms. For
example, the BETA_CONV conversion is not expressible as a standard
first order rewrite, but is part of the bool_ss simpset and the
application of this simpset will thus simplify all occurrences of
(\x. e1) e2.
In fact, conversions in simpsets are not typically applied
indiscriminately to all sub-terms. (If a conversion is applied to an
inappropriate sub-term and fails, this failure is caught by the
simplifier and ignored.) Instead, conversions in simpsets are
accompanied by a term-pattern which specifies the sort of situations in
which they should be applied. This facility is used in the definition of
bool_ss to include ETA_CONV, but stop it from transforming !x. P x
into $! P.
AC-rules allow simpsets to be constructed that automatically normalise terms involving associative and commutative operators, again according to some arbitrary term ordering metric.
Congruence rules allow SIMP_CONV to assume additional context as a
term is rewritten. In a term such as P ==> Q /\ f x the truth of term
P may be assumed as an additional piece of context in the rewriting of
Q /\ f x. The congruence theorem that states this is valid is
(IMP_CONG):
|- (P = P') ==> (P' ==> (Q = Q')) ==> ((P ==> Q) = (P' ==> Q'))
Other congruence theorems can be part of simpsets. The system provides
IMP_CONG above and COND_CONG as part of the CONG_ss ssfrag
value. (These simpset fragments can be incorporated into simpsets with
the ++ function.) Other congruence theorems are already proved for
operators such as conjunction and disjunction, but use of these in
standard simpsets is not recommended as the computation of all the
additional contexts for a simple chain of conjuncts or disjuncts can be
very computationally intensive.
Decision procedures in simpsets are similar to conversions. They are
arbitrary pieces of code that are applied to sub-terms at low priority.
They are given access to the wider context through a list of relevant
theorems. The arith_ss simpset includes an arithmetic decision
procedure implemented in this way.
Failure
SIMP_CONV never fails, but may diverge.
Example
> SIMP_CONV arith_ss [] ``(\x. x + 3) 4``;
val it = ⊢ (λx. x + 3) 4 = 7: thm
SIMP_CONV is a powerful way of manipulating terms. Other functions in
the simplification library provide the same facilities when in the
contexts of goals and tactics (SIMP_TAC, ASM_SIMP_TAC etc.), and
theorems (SIMP_RULE), but SIMP_CONV provides the underlying
functionality, and is useful in its own right, just as conversions are
generally.
See also
bossLib.++,
bossLib.ASM_SIMP_TAC,
bossLib.FULL_SIMP_TAC,
simpLib.mk_simpset,
bossLib.rewrites,
bossLib.SIMP_RULE,
bossLib.SIMP_TAC,
simpLib.SSFRAG, bossLib.EVAL
SIMP_RULE
SIMP_RULE
bossLib.SIMP_RULE : simpset -> thm list -> thm -> thm
Also exported as simpLib.SIMP_RULE.
Simplifies the conclusion of a theorem according to the given simpset and theorem rewrites.
SIMP_RULE simplifies the conclusion of a theorem, adding the given
theorems to the simpset parameter as rewrites. The way in which terms
are transformed as a part of simplification is described in the entry
for SIMP_CONV.
Failure
Never fails, but may diverge.
Example
The following also demonstrates the higher order rewriting possible with
simplification (FORALL_AND_THM states
|- (!x. P x /\ Q x) = (!x. P x) /\ (!x. Q x)):
> SIMP_RULE bool_ss [boolTheory.FORALL_AND_THM]
(ASSUME (Term`!x. P (x + 1) /\ R x /\ x < y`));
val it = [.] ⊢ (∀x. P (x + 1)) ∧ (∀x. R x) ∧ ∀x. x < y: thm
Comments
SIMP_RULE ss thmlist is equivalent to
CONV_RULE (SIMP_CONV ss thmlist).
See also
simpLib.ASM_SIMP_RULE,
bossLib.SIMP_CONV,
bossLib.SIMP_TAC,
bossLib.bool_ss
SIMP_TAC
SIMP_TAC
bossLib.SIMP_TAC : simpset -> thm list -> tactic
Also exported as simpLib.SIMP_TAC.
Simplifies the goal, using the given simpset and the additional theorems listed.
SIMP_TAC adds the theorems of the second argument to the simpset
argument as rewrites and then applies the resulting simpset to the
conclusion of the goal. The exact behaviour of a simpset when applied to
a term is described further in the entry for SIMP_CONV.
With simple simpsets, SIMP_TAC is similar in effect to REWRITE_TAC;
it transforms the conclusion of a goal by using the (equational)
theorems given and those already in the simpset as rewrite rules over
the structure of the conclusion of the goal.
Just as ASM_REWRITE_TAC includes the assumptions of a goal in the
rewrite rules that REWRITE_TAC uses, ASM_SIMP_TAC adds the
assumptions of a goal to the rewrites and then performs simplification.
Failure
SIMP_TAC never fails, though it may diverge.
Example
SIMP_TAC and the arith_ss simpset combine to prove quite difficult
seeming goals:
- val (_, p) = SIMP_TAC arith_ss []
([], Term`P x /\ (x = y + 3) ==> P x /\ y < x`);
> val p = fn : thm list -> thm
- p [];
> val it = |- P x /\ (x = y + 3) ==> P x /\ y < x : thm
SIMP_TAC is similar to REWRITE_TAC if used with just the bool_ss
simpset. Here it is used in conjunction with the arithmetic theorem
GREATER_DEF, |- !m n. m > n = n < m, to advance a goal:
- SIMP_TAC bool_ss [GREATER_DEF] ([], Term`T /\ 5 > 4 \/ F`);
> val it = ([([], `4 < 5`)], fn) : subgoals
Comments
The simplification library is described further in other documentation, but its full capabilities are still rather opaque.
Simplification is one of the most powerful tactics available to the HOL user. It can be used both to solve goals entirely or to make progress with them. However, poor simpsets or a poor choice of rewrites can still result in divergence, or poor performance.
See also
bossLib.++,
bossLib.ASM_SIMP_TAC,
bossLib.std_ss,
bossLib.bool_ss,
bossLib.arith_ss,
bossLib.list_ss,
bossLib.FULL_SIMP_TAC,
simpLib.mk_simpset,
Rewrite.REWRITE_TAC,
bossLib.SIMP_CONV,
simpLib.SIMP_PROVE,
bossLib.SIMP_RULE
split_pair_case_tac
split_pair_case_tac
bossLib.split_pair_case_tac : tactic
Splits pairs that are arguments to a pair-case expression.
A call to split_pair_case_tac will search the goal (starting with the
conclusion and moving onto each assumption in turn), for a sub-term of
the form case p of (x,y,...) => e, where the variables appearing in
p are free in the goal. The tactic will then introduce a new
assumption in the goal of the form
p = (x,y,...)
where the variables x, y etc., are chosen to be as close as possible
to the names in the case expression. In other words, they will vary only
if those names are already free in the goal.
Failure
Fails if there is no such sub-term.
Example
> split_pair_case_tac ([], ``(case p of (x,y,z) => x + y * z) > 10``);
val it = ([([“p = (x,y,z)”], “(case p of (x,y,z) => x + y * z) > 10”)], fn):
goal list * validation
See also
bossLib.pairarg_tac,
pairLib.Pair_Cases_on
SPOSE_NOT_THEN
SPOSE_NOT_THEN
bossLib.SPOSE_NOT_THEN : (thm -> tactic) -> tactic
Initiate proof by contradiction.
SPOSE_NOT_THEN provides a flexible way to start a proof by
contradiction. Simple tactics for contradiction proofs often simply
negate the goal and place it on the assumption list. However, if the
goal is quantified, as is often the case, then more processing is
required in order to get it into a suitable form for subsequent work.
SPOSE_NOT_THEN ttac negates the current goal, pushes the negation
inwards, and applies ttac to it.
Failure
Never fails, unless ttac fails.
Example
Suppose we want to prove Euclid's theorem.
!m. ?n. prime n /\ m < n
The classic proof is by contradiction. However, if we start such a proof
with CCONTR_TAC, we get the goal
{ ~!m. ?n. prime n /\ m < n } ?- F
and one would immediately want to simplify the assumption, which is a
bit awkward. Instead, an invocation SPOSE_NOT_THEN ASSUME_TAC yields
{ ?m. !n. ~prime n \/ ~(m < n) } ?- F
and SPOSE_NOT_THEN STRIP_ASSUME_TAC results in
{ !n. ~prime n \/ ~(m < n) } ?- F
See also
Tactic.CCONTR_TAC,
Tactic.CONTR_TAC,
Tactic.ASSUME_TAC,
Tactic.STRIP_ASSUME_TAC
SQI_ss
SQI_ss
bossLib.SQI_ss : simpLib.ssfrag
A synonym for quantHeuristicsLib.SIMPLE_QUANT_INST_ss.
See also
quantHeuristicsLib.SIMPLE_QUANT_INST_ss
SRULE
SRULE
bossLib.SRULE : thm list -> thm -> thm
Simplification with standard simpset as a derived rule
A call to SRULE ths th simplifies the theorem th using the standard
simpset (accessible through a call to srw_ss()) and the theorems
ths, returning the simplified theorem.
The implementation of SRULE is
fun SRULE ths th = SIMP_RULE (srw_ss()) ths th
The fact that this definition is not eta-reduced means that partial
applications of SRULE will continue to pick up the current value of
srw_ss() when they are eventually fully applied, rather than bake in
the value from the time of the partial application.
Failure
Should never fail.
See also
Conv.CONV_RULE,
simpLib.SIMP_RULE,
BasicProvers.srw_ss
srw_ss
srw_ss
bossLib.srw_ss : unit -> simpset
Also exported as BasicProvers.srw_ss.
Returns the "stateful rewriting" system's underlying simpset.
A call to srw_ss() returns a simpset value that is internally
maintained and updated by the system. Its value changes as new types
enter the TypeBase, and as theories are loaded. For this reason, it
can't be accessed as a simple value, but is instead hidden behind a
function.
The value behind srw_ss() can change in three ways. Firstly, whenever
a type enters the TypeBase, the type's associated simplification
theorems (accessible directly using the function TypeBase.simpls_of)
are all added to the simpset. This ensures that the "obvious" rewrite
theorems for a type (such as the disjointness of constructors) need
never be explicitly specified.
Secondly, users can interactively add simpset fragments to the
srw_ss() value by using the function augment_srw_ss. This function
might be used after a definition is made to ensure that a particular
constant always has its definition expanded. (Whether or not a constant
warrants this is something that needs to be determined on a case-by-case
basis.)
Thirdly, theories can augment the srw_ss() value as they load. This is
set up in a theory's script file with the function export_rewrites.
This causes a list of appropriate theorems to be added when the theory
loads. It is up to the author of the theory to ensure that the theorems
added to the simpset are sensible.
Failure
Never fails.
See also
bossLib.augment_srw_ss,
BasicProvers.export_rewrites,
bossLib.SRW_TAC
SRW_TAC
SRW_TAC
bossLib.SRW_TAC : ssfrag list -> thm list -> tactic
Also exported as BasicProvers.SRW_TAC.
A version of RW_TAC with an implicit simpset.
A call to SRW_TAC [d1,...,dn] thlist produces the same result as
RW_TAC (srw_ss() ++ d1 ++ ... ++ dn) thlist
Failure
When applied to a goal, the tactic resulting from an application of
SRW_TAC may diverge.
Comments
There are two reasons why one might prefer SRW_TAC to RW_TAC.
Firstly, when a large number of datatypes are present in the TypeBase,
the implementation of RW_TAC has to merge the attendant
simplifications for each type onto its simpset argument each time it
is called. This can be rather time-consuming. Secondly, the simpset
returned by srw_ss() can be augmented with fragments from other
sources than the TypeBase, using the functions augment_srw_ss and
export_rewrites. This can make for a tool that is simple to use, and
powerful because of all its accumulated simpset fragments.
Naturally, the latter advantage can also be a disadvantage: if SRW_TAC
does too much because there is too much in the simpset underneath
srw_ss(), then there is no way to get around this using SRW_TAC.
Typical invocations of SRW_TAC will be of the form
SRW_TAC [][th1, th2,.. ]
The first argument, for lists of simpset fragments is for the
inclusion of fragments that are not always appropriate. An example of
such a fragment is numSimps.ARITH_ss, which embodies an arithmetic
decision procedure for the natural numbers.
See also
bossLib.srw_ss,
bossLib.augment_srw_ss,
BasicProvers.export_rewrites,
simpLib.SSFRAG
std_ss
std_ss
bossLib.std_ss : simpset
Basic simplification set.
The simplification set std_ss extends bool_ss with a useful set of
rewrite rules for terms involving options, pairs, and sums. It also
performs beta and eta reduction. It applies some standard rewrites to
evaluate expressions involving only numerals.
The following rewrites from pairTheory are included in std_ss:
|- !x. (FST x,SND x) = x
|- !x y. FST (x,y) = x
|- !x y. SND (x,y) = y
|- !x y a b. ((x,y) = (a,b)) = (x = a) /\ (y = b)
|- !f. CURRY (UNCURRY f) = f
|- !f. UNCURRY (CURRY f) = f
|- (CURRY f = CURRY g) = (f = g)
|- (UNCURRY f = UNCURRY g) = (f = g)
|- !f x y. CURRY f x y = f (x,y)
|- !f x y. UNCURRY f (x,y) = f x y
|- !f g x y. (f ## g) (x,y) = (f x,g y)
The following rewrites from sumTheory are included in std_ss:
|- !x. ISL x ==> (INL (OUTL x) = x)
|- !x. ISR x ==> (INR (OUTR x) = x)
|- (!x. ISL (INL x)) /\ !y. ~ISL (INR y)
|- (!x. ISR (INR x)) /\ !y. ~ISR (INL y)
|- !x. OUTL (INL x) = x
|- !x. OUTR (INR x) = x
|- !x y. ~(INL x = INR y)
|- !x y. ~(INR y = INL x)
|- (!y x. (INL x = INL y) = (x = y)) /\
(!y x. (INR x = INR y) = (x = y))
|- (!f g x. case f g (INL x) = f x) /\
(!f g y. case f g (INR y) = g y)
The following rewrites from optionTheory are included in std_ss:
|- (!x y. (SOME x = SOME y) = (x = y))
|- (!x. ~(NONE = SOME x))
|- (!x. ~(SOME x = NONE))
|- (!x. THE (SOME x) = x)
|- (!x. IS_SOME (SOME x) = T)
|- (IS_SOME NONE = F)
|- (!x. IS_NONE x = (x = NONE))
|- (!x. ~IS_SOME x = (x = NONE))
|- (!x. IS_SOME x ==> (SOME (THE x) = x))
|- (!x. case NONE SOME x = x)
|- (!x. case x SOME x = x)
|- (!x. IS_NONE x ==> (case e f x = e))
|- (!x. IS_SOME x ==> (case e f x = f (THE x)))
|- (!x. IS_SOME x ==> (case e SOME x = x))
|- (!u f. case u f NONE = u)
|- (!u f x. case u f (SOME x) = f x)
|- (!f x. OPTION_MAP f (SOME x) = SOME (f x))
|- (!f. OPTION_MAP f NONE = NONE)
|- (OPTION_JOIN NONE = NONE)
|- (!x. OPTION_JOIN (SOME x) = x)
|- !f x y. (OPTION_MAP f x = SOME y) = ?z. (x = SOME z) /\ (y = f z)
|- !f x. (OPTION_MAP f x = NONE) = (x = NONE)
For performing obvious simplification steps on terms, formulas, and
goals. Also, sometimes simplification with more powerful simpsets, like
arith_ss, becomes too slow, in which case one can use std_ss
supplemented with whatever theorems are needed.
Comments
The simplification sets provided in BasicProvers and bossLib
(currently bool_ss, std_ss, arith_ss, and list_ss) do not
include useful rewrites stemming from HOL datatype declarations, such as
injectivity and distinctness of constructors. However, the
simplification routines RW_TAC and SRW_TAC automatically load these
rewrites.
See also
BasicProvers.RW_TAC,
BasicProvers.SRW_TAC,
simpLib.SIMP_TAC,
simpLib.SIMP_CONV,
simpLib.SIMP_RULE,
BasicProvers.bool_ss,
bossLib.arith_ss,
bossLib.list_ss
subgoal
subgoal
bossLib.subgoal : term quotation -> tactic
Produces a subgoal.
A call to subgoal q is equivalent (by definition) to a call to
Q.SUBGOAL_THEN q STRIP_ASSUME_TAC.
Failure
Fails if the provided quotation does not parse to a term of boolean type in the context of the current goal.
Comments
The subgoal tactic is also available via the name sg.
See also
suffices_by
suffices_by
op bossLib.suffices_by : term quotation * tactic -> tactic
Replace the goal's conclusion with a sufficient alternative.
A call to the tactic q suffices_by tac will first attempt to parse the
quotation q in the context of the current goal. Assuming this
generates a term qt of boolean type, it will then generate two
sub-goals. Assuming the current goal is asl ?- g, the first new
sub-goal will be that qt implies g, thus asl ?- qt ==> g. The
second goal will be asl ?- qt.
The system next applies tac to the first sub-goal (the implication).
If tac solves the goal (the common or at least, desired, case), the
user will then be presented with one goal, where the original g has
been replaced with qt. In this way, the user has adjusted the goal,
replacing the old g with a qt that is sufficient to prove it.
Failure
A call to q suffices_by tac will fail if the quotation q does not
parse to a term of boolean type. This parsing is done in the context of
the whole goal (asl,g), using the parse_in_context function. The
call will also fail if tac does not solve the newly generated subgoal.
Example
If the current goal is
f n m = f m n
------------------------------------
0. m <= n
1. n <= m
then the tactic `m = n` suffices_by SIMP_TAC bool_ss [] will
result in the goal
m = n
------------------------------------
0. m <= n
1. n <= m
where the call to SIMP_TAC has successfully proved the theorem
|- (m = n) ==> (f m n = f n m)
eliminating the first of the two sub-goals that was generated.
Comments
The tactic suffices_by is designed to support a backwards style of
reasoning. Superficially, it appears to be dual to the tactic by,
which provides a forward-reasoning facility. In fact, both are
implementing a backwards application of the sequent calculus's "cut"
rule; the difference is which of the two premises to the rule is worked
on by the provided tactics.
See also
bossLib.by,
Parse.parse_in_context,
Tactic.SUFF_TAC
suspend
suspend
bossLib.suspend : string -> tactic
Suspends a goal (proving it), so that it can be resumed later.
Given any goal g, a call to suspend nm proves that goal by assuming an encoding of the goal as a hypothesis.
This encoding includes the name nm, so that the resulting theorem is effectively
[e(nm,g)] |- g
Of course, if the goal is a subgoal in a larger proof, this new hypothesis will propagate out to the final theorem proved, recording the point at which the wider goal was suspended.
If suspend is called multiple times within the wider goal, multiple such hypotheses will be created.
Failure
Never fails.
Comment
The VALID tactical considers suspend-encoded assumptions legitimate, not flagging them as invalid and causing a tactic that uses them to fail.
See also
bossLib.cheat,
Tactical.VALID.
tDefine
tDefine
bossLib.tDefine : string -> term quotation -> tactic -> thm
General-purpose function definition facility.
tDefine is a definition package similar to Define except that it has
a tactic parameter which is used to perform the termination proof for
the specified function. tDefine accepts the same syntax used by
Define for specifying functions.
If the specification is a simple abbreviation, or is primitive recursive
(i.e., it exactly follows the recursion pattern of a previously declared
HOL datatype) then the invocation of tDefine succeeds and stores the
derived equations in the current theory segment. Otherwise, the function
is not an instance of primitive recursion, and the termination prover
may succeed or fail.
When processing the specification of a recursive function, tDefine
must perform a termination proof. It automatically constructs
termination conditions for the function, and invokes the supplied tactic
in an attempt to prove the termination conditions. If that attempt
fails, then tDefine fails.
If it succeeds, then tDefine stores the specified equations in the
current theory segment, using the string argument as a stem for the
name. An induction theorem customized for the defined function is also
stored in the current segment. Note, however, that an induction theorem
is not stored for primitive recursive functions, since that theorem
would be identical to the induction theorem resulting from the
declaration of the datatype.
If the tactic application fails, then tDefine fails.
Failure
tDefine fails if its input fails to parse and typecheck.
tDefine fails if it cannot prove the termination of the specified
recursive function. In that case, one has to embark on the following
multi-step process: (1) construct the function and synthesize its
termination conditions with Hol_defn; (2) set up a goal to prove the
termination conditions with tgoal; (3) interactively prove the
termination conditions, usually by starting with an invocation of
WF_REL_TAC; and (4) package everything up with an invocation of
tDefine.
Example
The following attempt to invoke Define fails because the current
default termination prover for Define is too weak:
Hol_datatype`foo = c1 | c2 | c3`;
Define `(f c1 x = x) /\
(f c2 x = x + 3) /\
(f c3 x = f c2 (x + 6))`;
The following invocation of tDefine uses the supplied tactic to prove
termination.
tDefine "f"
`(f c1 x = x) /\
(f c2 x = x + 3) /\
(f c3 x = f c2 (x + 6))`
(WF_REL_TAC `measure (\p. case FST p of c3 -> 1 || _ -> 0)`);
Equations stored under "f_def".
Induction stored under "f_ind".
> val it = |- (f c1 x = x) /\ (f c2 x = x + 3) /\ (f c3 x = f c2 (x + 6)) : thm
Comments
tDefine automatically adds the definition it makes into the hidden
'compset' accessed by EVAL and EVAL_TAC.
See also
bossLib.Define,
bossLib.xDefine,
TotalDefn.DefineSchema,
bossLib.Hol_defn, Defn.tgoal,
Defn.tprove,
bossLib.WF_REL_TAC,
bossLib.recInduct,
bossLib.EVAL, bossLib.EVAL_TAC
tmCases_on
tmCases_on
bossLib.tmCases_on : term -> string list -> tactic
Begins a "cases" proof on the provided term
A call to tmCases_on t names will do the equivalent of a
FULL_STRUCT_CASES_TAC on the term t, using the cases (or "nchotomy")
theorem stored in the TypeBase for t's type. If the names list is
not empty, the names encoded there will be used to give names to any
existentially quantified names in the cases theorem. Each element of the
names list corresponds to the cases of the theorem, and, as
constructors may take multiple arguments, each corresponding to an
existentially quantified variable, the element is itself a list of
names, separated by spaces. For example, the cases theorem for lists
could be passed a string list of the form ["", "head tail"]. If the
names is empty, then the system will choose names for the
existentially quantified variables.
As a convenience, if the term argument is a variable, and there are variables of that name free in the goal, or bound by top-level universal quantifiers in the goal's conclusion, then the type of the variable is ignored and its name is used to generate the argument to the tactic. If a goal has multiple variables of the same name (always a bad idea!) the choice of variable is unspecified.
Failure
Fails if the term is not of a type occurring in the TypeBase.
Example
Note how in this example, the parser will give the argument l bare
type “:α”, but it still picks the appropriately instantiated list
cases theorem for the l that appears in the goal, which may have type
“:num list”, for example.
?- MAP f l = []
========================================= tmCases_on “l” ["", "e es"]
?- MAP f [] = [] ?- MAP f (e::es) = []
See also
bossLib.Cases_on,
Tactic.FULL_STRUCT_CASES_TAC
type_rws
type_rws
bossLib.type_rws : hol_type -> thm list
List rewrites for a concrete type.
An application type_rws ty, where ty is a declared datatype, returns
a list of rewrite rules corresponding to the type. The list typically
contains theorems about the distinctness and injectivity of
constructors, the definition of the case constant introduced at the time
the type was defined, and any extra rewrites coming from the use of
records.
Failure
If ty is not a declared datatype.
Example
> type_rws ``:'a list``;
val it =
[⊢ (∀v f. list_CASE [] v f = v) ∧
∀a0 a1 v f. list_CASE (a0::a1) v f = f a0 a1, ⊢ ∀a1 a0. [] ≠ a0::a1,
⊢ ∀a1 a0. a0::a1 ≠ [],
⊢ ∀a0 a1 a0' a1'. a0::a1 = a0'::a1' ⇔ a0 = a0' ∧ a1 = a1',
⊢ (∀f. list_size f [] = 0) ∧
∀f a0 a1. list_size f (a0::a1) = 1 + (f a0 + list_size f a1)]: thm list
> Hol_datatype `point = <| x:num ; y:num |>`;
val it = (): unit
> type_rws ``:point``;
val it =
[⊢ ∀p g f.
p with <|y updated_by f; x updated_by g|> =
p with <|x updated_by g; y updated_by f|>,
⊢ (∀g f. y_fupd f ∘ x_fupd g = x_fupd g ∘ y_fupd f) ∧
∀h g f. y_fupd f ∘ x_fupd g ∘ h = x_fupd g ∘ y_fupd f ∘ h,
⊢ (∀n n0. (point n n0).x = n) ∧ ∀n n0. (point n n0).y = n0,
⊢ (∀p f. (p with y updated_by f).x = p.x) ∧
(∀p f. (p with x updated_by f).y = p.y) ∧
(∀p f. (p with x updated_by f).x = f p.x) ∧
∀p f. (p with y updated_by f).y = f p.y,
⊢ ∀p n0 n. p with <|x := n0; y := n|> = <|x := n0; y := n|>,
⊢ ∀n01 n1 n02 n2.
<|x := n01; y := n1|> = <|x := n02; y := n2|> ⇔ n01 = n02 ∧ n1 = n2,
⊢ (∀p g f.
p with <|x updated_by f; x updated_by g|> =
p with x updated_by f ∘ g) ∧
∀p g f.
p with <|y updated_by f; y updated_by g|> = p with y updated_by f ∘ g,
⊢ ((∀g f. x_fupd f ∘ x_fupd g = x_fupd (f ∘ g)) ∧
∀h g f. x_fupd f ∘ x_fupd g ∘ h = x_fupd (f ∘ g) ∘ h) ∧
(∀g f. y_fupd f ∘ y_fupd g = y_fupd (f ∘ g)) ∧
∀h g f. y_fupd f ∘ y_fupd g ∘ h = y_fupd (f ∘ g) ∘ h,
⊢ ∀a0 a1 f. point_CASE (point a0 a1) f = f a0 a1,
⊢ ∀a0 a1 a0' a1'. point a0 a1 = point a0' a1' ⇔ a0 = a0' ∧ a1 = a1',
⊢ ∀a0 a1. point_size (point a0 a1) = 1 + (a0 + a1)]: thm list
Comments
RW_TAC and SRW_TAC automatically include these rewrites.
See also
bossLib.rewrites,
bossLib.RW_TAC
using
using
bossLib.using : tactic * thm -> tactic
Specifies alternative theorem to use for given tactic
The standard HOL environment has using an infix, so one writes
tac using thm. Such a call stashes an encoding of thm's name onto
the goal's assumption list and then calls tac. If tac is aware of
the possibility, it can use this theorem instead of the theorem it would
usually consult. After tac completes, the implementation of using
removes the reference.
This is typically used with the tactics Induct, Induct_on, Cases,
or Cases_on which consult the TypeBase to find the theorems their
underlying code requires.
Failure
Fails if the specified theorem has no hypotheses, is polymorphic, and
cannot be found by reverse lookup in the theorem database (using
DB.revlookup). Also fails if the underlying tactic fails.
Example
Induct_on ‘l’ using SNOC_INDUCT
sets up an induction on the term “l” using the SNOC_INDUCT principle
("structural induction from the back of the list").
Comments
Tactics unaware of the possibility of the presence of augmented assumption lists can behave strangely.
See also
bossLib.Induct_on,
markerSyntax.MK_USING
WF_REL_TAC
WF_REL_TAC
bossLib.WF_REL_TAC : term quotation -> tactic
Also exported as TotalDefn.WF_REL_TAC.
Start termination proof.
WF_REL_TAC builds a tactic that starts a termination proof. An
invocation WF_REL_TAC q, where q should parse into a term that
denotes a well-founded relation, builds a tactic tac that is intended
to be applied to a goal arising from an application of tgoal or
tprove. Such a goal has the form
?R. WF R /\ ...
The tactic tac will instantiate R with the relation denoted by q
and will attempt various simplifications of the goal. For example, it
will try to automatically prove the well-foundedness of the relation
denoted by q, and will also attempt to simplify the goal using some
basic facts about well-founded relations. Often this can result in a
much simpler goal.
Failure
WF_REL_TAC q fails if q does not parse into a term whose type is an
instance of 'a -> 'a -> bool.
Example
Suppose that a version of Quicksort had been defined as follows:
val qsort_defn =
Hol_defn "qsort"
`(qsort ___ [] = []) /\
(qsort ord (x::rst) =
APPEND (qsort ord (FILTER ($~ o ord x) rst))
(x :: qsort ord (FILTER (ord x) rst)))`;
Then one can start a termination proof as follows: set up a goalstack
with tgoal and then apply WF_REL_TAC with a quotation denoting a
suitable well-founded relation.
- tgoal qsort_defn;
> val it =
Proof manager status: 1 proof.
1. Incomplete:
Initial goal:
?R. WF R /\
(!rst x ord. R (ord,FILTER ($~ o ord x) rst) (ord,x::rst)) /\
!rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)
- e (WF_REL_TAC `measure (LENGTH o SND)`);
OK..
2 subgoals:
> val it =
!rst x ord. LENGTH (FILTER (ord x) rst) < LENGTH (x::rst)
!rst x ord. LENGTH (FILTER (\x'. ~ord x x') rst) < LENGTH (x::rst)
Execution of WF_REL_TAC has automatically proved the well-foundedness
of
measure (LENGTH o SND)
and the remainder of the goal has been simplified into a pair of easy goals.
Comments
There are two problems to deal with when trying to prove termination. First, one has to understand, intuitively and then mathematically, why the function under consideration terminates. Second, one must be able to phrase this in HOL. In the following, we shall give a few examples of how this is done.
There are a number of basic and advanced means of specifying well-founded relations. The most common starting point for dealing with termination problems for recursive functions is to find some function, known as a 'measure' under which the arguments of a function call are larger than the arguments to any recursive calls that result.
For a very simple starter example, consider the following definition of a function that computes the greatest common divisor of two numbers:
- val gcd_defn = Hol_defn "gcd"
`(gcd (0,n) = n) /\
(gcd (m,n) = gcd (n MOD m, m))`;
- Defn.tgoal gcd_defn;
> val it =
Proof manager status: 1 proof.
1. Incomplete:
Initial goal:
?R. WF R /\ !v2 n. R (n MOD SUC v2,SUC v2) (SUC v2,n)
The recursion happens in the first argument, and the recursive call in
that position is a smaller number. The way to phrase the termination of
gcd in HOL is to use a 'measure' function to map from the domain of
gcd---a pair of numbers---to a number. The definition of measure is
equivalent to
measure f x y = (f x < f y).
(The actual definition of measure in prim_recTheory is more
primitive.) Now we must pick out the argument position to measure and
invoke WF_REL_TAC:
- e (WF_REL_TAC `measure FST`);
OK..
1 subgoal:
> val it =
!v2 n. n MOD SUC v2 < SUC v2
This goal is easy to prove with a few simple arithmetic facts:
- e (PROVE_TAC [arithmeticTheory.DIVISION, prim_recTheory.LESS_0]);
OK..
Goal proved. ...
Sometimes one needs a measure function that is itself recursive. For
example, consider a type of binary trees and a function that
'unbalances' trees. The algorithm works by rotating the tree until it
gets a Leaf in the left branch, then it recurses into the right
branch. At the end of execution the tree has been linearized.
- Hol_datatype
`btree = Leaf
| Brh of btree => btree`;
- val Unbal_defn =
Hol_defn "Unbal"
`(Unbal Leaf = Leaf)
/\ (Unbal (Brh Leaf bt) = Brh Leaf (Unbal bt))
/\ (Unbal (Brh (Brh bt1 bt2) bt) = Unbal (Brh bt1 (Brh bt2 bt)))`;
- Defn.tgoal Unbal_defn;
> val it =
Proof manager status: 1 proof.
1. Incomplete:
Initial goal:
?R. WF R /\
(!bt. R bt (Brh Leaf bt)) /\
!bt bt2 bt1. R (Brh bt1 (Brh bt2 bt)) (Brh (Brh bt1 bt2) bt)
Since the size of the tree is unchanged in the last clause in the
definition of Unbal, a simple size measure will not work. Instead, we
can assign weights to nodes in the tree such that the recursive calls of
Unbal decrease the total weight in every case. One such assignment is
Weight (Leaf) = 0
Weight (Brh x y) = (2 * Weight x) + (Weight y) + 1
It is easiest to use Define to define Weight, but if one is worried
about "polluting" the signature, one can also use prove_rec_fn_exists
from the Prim_rec structure:
val Weight =
Prim_rec.prove_rec_fn_exists (TypeBase.axiom_of ("", "btree"))
(Term`(Weight (Leaf) = 0) /\
(Weight (Brh x y) = (2 * Weight x) + (Weight y) + 1)`);
> val Weight =
|- ?Weight.
(Weight Leaf = 0) /\
!x y. Weight (Brh x y) = 2 * Weight x + Weight y + 1 : thm
- e (STRIP_ASSUME_TAC Weight);
OK..
1 subgoal:
> val it =
?R.
WF R /\ (!bt. R bt (Brh Leaf bt)) /\
!bt bt2 bt1. R (Brh bt1 (Brh bt2 bt)) (Brh (Brh bt1 bt2) bt)
------------------------------------
0. Weight Leaf = 0
1. !x y. Weight (Brh x y) = 2 * Weight x + Weight y + 1
Now we can invoke WF_REL_TAC:
e (WF_REL_TAC `measure Weight`);
OK..
2 subgoals:
> val it =
!bt bt2 bt1.
Weight (Brh bt1 (Brh bt2 bt)) < Weight (Brh (Brh bt1 bt2) bt)
------------------------------------
0. Weight Leaf = 0
1. !x y. Weight (Brh x y) = 2 * Weight x + Weight y + 1
!bt. Weight bt < Weight (Brh Leaf bt)
------------------------------------
0. Weight Leaf = 0
1. !x y. Weight (Brh x y) = 2 * Weight x + Weight y + 1
Both of these subgoals are quite easy to prove.
The technique of 'weighting' nodes in a tree in order to prove termination also goes by the name of 'polynomial interpretation'. It must be admitted that finding the correct weighting for a termination proof is more an art than a science. Typically, one makes a guess and then tries the termination proof to see if it works.
Occasionally, there's a combination of factors that complicate the
termination argument. For example, the following specification describes
a naive pattern matching algorithm on strings (represented as lists
here). The function takes four arguments: the first is the remainder of
the pattern being matched. The second is the remainder of the string
being searched. The third argument holds the original pattern to be
matched. The fourth argument is the string being searched. If the
pattern (first argument) becomes exhausted, then a match has been found
and the function returns T. Otherwise, if the string being searched
becomes exhausted, the function returns F.
val match0_defn =
Hol_defn "match0"
`(match0 [] __ __ __ = T)
/\ (match0 __ [] __ __ = F)
/\ (match0 (p::pp) (s::ss) p0 rs =
if p=s then match0 pp ss p0 rs else
if NULL rs then F
else match0 p0 (TL rs) p0 (TL rs))`;
- val match = Define `match pat str = match0 pat str pat str`;
The remaining case is when there's more searching to do; the function
checks if the head of the pattern is the same as the head of the string
being searched. If yes, then we recursively search, using the tail of
the pattern and the tail of the string being searched. If no, that means
that we have failed to match the pattern, so we should move one
character ahead in the string being searched and try again. If the
string being searched is empty, however, then we return F. The second
and third arguments both represent the string being searched. The second
argument is a kind of 'local' version of the string being searched; we
recurse into it as long as there are matches with the pattern. However,
if the search eventually fails, then the fourth argument, which
'remembers' where the search started from, is used to restart the
search.
So much for the behaviour of the function. Why does it terminate? There are two recursive calls. The first call reduces the size of the first and second arguments, and leaves the other arguments unchanged. The second call can increase the size of the first and second arguments, but reduces the size of the fourth.
This is a classic situation in which to use a lexicographic ordering:
some arguments to the function are reduced in some recursive calls, and
some others are reduced in other recursive calls. Recall that LEX is
an infix operator, defined in pairTheory as follows:
LEX R1 R2 = \(x,y) (p,q). R1 x p \/ ((x=p) /\ R2 y q)
In the second recursive call, the length of rs is reduced, and in the
first it stays the same. This motivates having the length of the fourth
argument be the first component of the lexicographic combination, and
the length of the second argument as the second component.
What we need now is to formalize this. We want to map from the
four-tuple of arguments into a lexicographic combination of relations.
This is enabled by inv_image from relationTheory:
inv_image R f = \x y. R (f x) (f y)
The actual relation maps from the four-tuple of arguments into a pair of
numbers (m,n), where m is the length of the fourth argument, and n
is the length of the second argument. These lengths are then compared
lexicographically with respect to less-than (<).
- Defn.tgoal match0_defn;
- e (WF_REL_TAC `inv_image ($< LEX $<)
(\(w,x,y,z). (LENGTH z, LENGTH x))`);
OK..
2 subgoals:
> val it =
!rs ss s p.
(p=s) ==> LENGTH rs < LENGTH rs \/ LENGTH ss < LENGTH (s::ss)
!ss rs s p.
~(p = s) /\ ~NULL rs ==>
LENGTH (TL rs) < LENGTH rs \/
(LENGTH (TL rs) = LENGTH rs) /\ LENGTH (TL rs) < LENGTH (s::ss)
The first subgoal needs a case-split on rs before it is proved by
rewriting, and the seconds is also easy to prove by rewriting.
As a final example, one occasionally needs to recurse over non-concrete data, such as finite sets or multisets. We can define a 'fold' function (of questionable utility) for finite sets as follows:
load "pred_setTheory"; open pred_setTheory;
val FOLD_SET_defn =
Defn.Hol_defn "FOLD_SET"
`FOLD_SET (s:'a->bool) (b:'b) =
if FINITE s then
if s={} then b
else FOLD_SET (REST s) (f (CHOICE s) b)
else ARB`;
Typically, such functions terminate because the cardinality of the set
(or multiset) is reduced in the recursive call, and this is another
application of measure:
val (FOLD_SET_0, FOLD_SET_IND) =
Defn.tprove (FOLD_SET_defn,
WF_REL_TAC `measure (CARD o FST)`
THEN PROVE_TAC [CARD_PSUBSET, REST_PSUBSET]);
The desired recursion equation
|- FINITE s ==> (FOLD_SET f s b =
if s = {} then b
else FOLD_SET f (REST s) (f (CHOICE s) b))
is easy to obtain from FOLD_SET_0.
See also
Defn.tgoal, Defn.tprove,
bossLib.Hol_defn
wlog_tac
wlog_tac
bossLib.wlog_tac : term quotation -> term quotation list -> tactic
Also exported as wlogLib.wlog_tac.
Enrich the hypotheses with a proposition that can be assumed without loss of generality.
The user provides term quotations that parse to a proposition P and a
list of variables. Typically there are 2 subgoals. The first subgoal is
to prove that the general case of the original goal follows from the
specific case where P holds; the second subgoal is the original goal
with P added to the assumptions. The first subgoal is always present,
and the subgoals (if any) produced by strip_assume_tac P |- P follows.
If the goal is hyp ?- t then the first subgoal is
hyp, !vars. ant ==> t, ~P ?- t where ant is the conjunction of P
and those hypotheses of the original subgoal where any variable in the
user-provided list occurs free. The universal quantification is over the
variables in the user-provided list plus any variable that appears free
in P or t and is not a local constant. For convenience ~P is
always added to the assumptions in the first subgoal because the case
for P follows immediately from the hypothesis. Passing a non-empty
list of variables allows to quantify over local constants in the
hypothesis !vars. ant ==> t.
Detailed description: Given wlog_tac q vars_q let asm ?- c be the
the goal. q is parsed in the goal context to a proposition P.
vars_q are parsed to variables in the goal context. Let efv
(effectively free variables) be the free variables of P and c that
are not free in the assumptions and are not in vars from left to right
and first P, then c. Let gen_vars be vars @ efv. Let asm' be
the elements of asm in which any of vars is a free variable. Let
ant be the result of splicing p :: asm'. The first subgoal is
asm, (!(gen_vars). ant ==> c), ~P ?- c. The proposition P is added
to the assumptions with strip_assume_tac. If this generates subgoals
(as is usually the case), then those subgoals follow.
A typical use case is to continue the proof assuming one case where all
cases are symmetric. The first subgoal is a good candidate to be solved
by a first order prover like PROVE_TAC or METIS_TAC providing to it
the appropriate symmetry theorems.
Example
In the following examples assume arithmeticTheory is open.
> g(`ABS_DIFF x y + ABS_DIFF y z <= ABS_DIFF x z`);
val it =
Proof manager status: 3 proofs.
3. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
Current goal:
0. p ⇒ q
------------------------------------
p
2. Incomplete goalstack:
Initial goal:
p ∧ q ⇒ r ∧ s
Current goal:
0. p
1. q
------------------------------------
p'
1. Incomplete goalstack:
Initial goal:
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
> e(wlog_tac `x <= z` []);
OK..
2 subgoals:
val it =
0. x ≤ z
------------------------------------
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
0. ∀x z y. x ≤ z ⇒ ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
1. ¬(x ≤ z)
------------------------------------
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
The first subgoal can be solved by
prove_tac [ABS_DIFF_SYM, LESS_EQ_CASES, ADD_COMM].
> g`MAX x y <= z <=> x <= z /\ y <= z`
val it =
Proof manager status: 4 proofs.
4. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
Current goal:
0. p ⇒ q
------------------------------------
p
3. Incomplete goalstack:
Initial goal:
p ∧ q ⇒ r ∧ s
Current goal:
0. p
1. q
------------------------------------
p'
2. Incomplete goalstack:
Initial goal:
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
Current goal:
0. ∀x z y. x ≤ z ⇒ ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
1. ¬(x ≤ z)
------------------------------------
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
1. Incomplete goalstack:
Initial goal:
MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z
> e(wlog_tac `x <= y` []);
OK..
2 subgoals:
val it =
0. x ≤ y
------------------------------------
MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z
0. ∀x y z. x ≤ y ⇒ (MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z)
1. ¬(x ≤ y)
------------------------------------
MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z
The first subgoal can be solved by
prove_tac [LESS_EQ_CASES, MAX_COMM];
Failure
Never fails.
See also
wlog_then
wlog_then
bossLib.wlog_then : term quotation -> term quotation list -> thm_tactic -> tactic
Also exported as wlogLib.wlog_then.
Apply a theorem-tactic using a proposition that can be assumed without loss of generality.
Like wlog_tac, but the theorem P |- P is passed to the user-provided
theorem-tactic instead of strip_assume_tac.
Failure
Never fails when applied to a theorem-tactical. The resulting tactic fails if and only if the user-provided theorem-tactical fails when used as a tactic (i.e.: when applied to a theorem and a goal).
See also
xDefine
xDefine
bossLib.xDefine : string -> term quotation -> thm
Also exported as TotalDefn.xDefine.
General-purpose function definition facility.
xDefine behaves exactly like Define, except that it takes an
alphanumeric string which is used as a stem for building names with
which to store the definition, associated induction theorem (if there is
one), and any auxiliary definitions used to construct the specified
function (if there are any) in the current theory segment.
Failure
xDefine allows the definition of symbolic identifiers, but Define
doesn't. In all other respects, xDefine and Define succeed and fail
in the same way.
Example
The following example shows how Define fails when asked to define a
symbolic identifier.
- set_fixity ("/", Infixl 600); (* tell the parser about "/" *)
> val it = () : unit
- Define
`x/y = if y=0 then NONE else
if x<y then SOME 0
else OPTION_MAP SUC ((x-y)/y)`;
Definition failed! Can't make name for storing definition
because there is no alphanumeric identifier in:
"/".
Try "xDefine <alphanumeric-stem> <eqns-quotation>" instead.
Next the same definition is attempted with xDefine, supplying the name
for binding the definition and the induction theorem with in the current
theory.
- xDefine "div"
`x/y = if y=0 then NONE else
if x<y then SOME 0
else OPTION_MAP SUC ((x-y)/y)`;
Equations stored under "div_def".
Induction stored under "div_ind".
> val it =
|- x / y =
(if y = 0 then NONE
else
(if x < y then SOME 0
else OPTION_MAP SUC ((x - y) / y))) : thm
Comments
Define can be thought of as an application of xDefine, in which the
stem is taken to be the name of the function being defined.
bossLib.xDefine is most commonly used. TotalDefn.xDefine is
identical to bossLib.xDefine, except that the TotalDefn structure
comes with less baggage---it depends only on numLib and pairLib.
See also
zDefine
zDefine
bossLib.zDefine : term quotation -> thm
General-purpose function definition facility.
zDefine behaves exactly like Define, except that it does not add the
definition to computeLib.the_compset. Consequently the definition is
not used by bossLib.EVAL when evaluating expressions.
Failure
zDefine and Define succeed and fail in the same way.
Example
> zDefine `foo = 10 ** 10 ** 10`
val it = ⊢ foo = 10 ** 10 ** 10: thm
> EVAL ``foo``;
val it = ⊢ foo = foo: thm
Comments
zDefine is helpful when users wish to derive and use their own
efficient evaluation theorems, which can be added using
computeLib.add_funs or computeLib.add_persistent_funs.
See also
Ntimes
Ntimes
BoundedRewrites.Ntimes : thm -> int -> thm
Rewriting control.
When used as an argument to the rewriter or simplifier, Ntimes th n is
a directive saying that th should be used at most n times in the
rewriting process. This is useful for controlling looping rewrites.
Failure
Never fails.
Example
Suppose factorial was defined as follows:
- val fact_def = Define `fact n = if n=0 then 1 else n * fact (n-1)`;
Equations stored under "fact_def".
Induction stored under "fact_ind".
> val fact_def = |- fact n = (if n = 0 then 1 else n * fact (n - 1)) : thm
The theorem fact_def is a looping rewrite since the recursive call
fac (n-1) matches the left-hand side of fact_def. Thus, a naive
application of the simplifier will loop:
- SIMP_CONV arith_ss [fact_def] ``fact 6``;
(* looping *)
> Interrupted.
In order to expand the definition of fact_def three times, the
following invocation can be made
- SIMP_CONV arith_ss [Ntimes Fact_def 3] ``fact 6``;
> val it = |- fact 6 = 6 * (5 * (4 * fact 3)) : thm
Comments
Use of Ntimes does not compose well. For example,
tac1 THENL [SIMP_TAC std_ss [Ntimes th 1],
SIMP_TAC std_ss [Ntimes th 1]]
is not equivalent in behaviour to
tac1 THEN SIMP_TAC std_ss [Ntimes th 1].
In the first call two rewrites using th can occur; in the second, only
one can occur.
See also
BoundedRewrites.Once,
Tactical.THEN,
simpLib.SIMP_TAC,
bossLib.RW_TAC,
Rewrite.REWRITE_TAC
Once
Once
BoundedRewrites.Once : thm -> thm
Rewriting control.
When used as an argument to the rewriter or simplifier, Once th is a
directive saying that th should be used at most once in the rewriting
process. This is useful for controlling looping rewrites.
Failure
Never fails.
Example
Suppose factorial was defined as follows:
- val fact_def = Define `fact n = if n=0 then 1 else n * fact (n-1)`;
Equations stored under "fact_def".
Induction stored under "fact_ind".
> val fact_def = |- fact n = (if n = 0 then 1 else n * fact (n - 1)) : thm
The theorem fact_def is a looping rewrite since the recursive call
fac (n-1) matches the left-hand side of fact_def. Thus, a naive
application of the simplifier will loop:
- SIMP_CONV arith_ss [fact_def] ``fact 6``;
(* looping *)
> Interrupted.
In order to expand the definition of fact_def, the following
invocation can be made
- SIMP_CONV arith_ss [Once fact_def] ``fact 6``;
> val it = |- fact 6 = 6 * fact 5 : thm
Comments
Use of Once does not compose well. For example,
tac1 THENL [SIMP_TAC std_ss [Once th],
SIMP_TAC std_ss [Once th]]
is not equivalent in behaviour to
tac1 THEN SIMP_TAC std_ss [Once th].
In the first call two rewrites using th can occur; in the second, only
one can occur.
See also
BoundedRewrites.Ntimes,
Tactical.THEN,
simpLib.SIMP_TAC,
bossLib.RW_TAC,
Rewrite.ONCE_REWRITE_TAC
bool_compset
bool_compset
computeLib.bool_compset : compset
A simplification set for use with CBV_CONV for basic computations.
This compset is a simplification set for use with the compute library performing computations about operations on primitive booleans and other basic constants, such as LET, conditional, implication, conjunction, disjunction, and negation.
Example
> computeLib.CBV_CONV computeLib.bool_compset (Term `F ==> (T \/ F)`);
val it = ⊢ F ⇒ T ∨ F ⇔ T: thm
See also
CBV_CONV
CBV_CONV
computeLib.CBV_CONV : compset -> conv
Call by value rewriting.
The conversion CBV_CONV expects a simplification set and a term. Its
term argument is rewritten using the equations added in the
simplification set. The strategy used is somewhat similar to ML's, that
is call-by-value (arguments of constants are completely reduced before
the rewrites associated to the constant are applied) with weak reduction
(no reduction of the function body before the function is applied). The
main differences are that beta-redexes are reduced with a call-by-name
strategy (the argument is not reduced), and reduction under binders is
done when it occurs in a position where it cannot be substituted.
The simplification sets are mutable objects, this means they are
extended by side-effect. The function new_compset will create a new
set containing reflexivity (REFL_CLAUSE), plus the supplied rewrites.
Theorems can be added to an existing compset with the function
add_thms.
This function (add_thms) scans the supplied theorems using
BODY_CONJUNCTS. Let thm be one such element. If thm is of the form
P1 ⇒ P2 ⇒ ... ⇒ t for possibly-zero implications, then proccess t.
If t is an equation, add it as a reduction rule. If t is of the form
¬t', then add the rule t ⇔ F, otherwise add the rule t ⇔ T. If
there is at least one implication then also add P1 ⇒ P2 ⇒ ... ⇒ t ⇔ T.
It is also possible to add conversions to a simplification set with
add_conv. The only restriction is that a constant (c) and an arity
(n) must be provided. The conversion will be called only on terms in
which c is applied to n arguments.
Two theorem "preprocessors" are provided to control the strictness of
the arguments of a constant. lazyfy_thm has pattern variables on the
left hand side turned into abstractions on the right hand side. This
transformation is applied on every conjunct, and removes prenex
universal quantifications. A typical example is COND_CLAUSES:
(COND T a b = a) /\ (COND F a b = b)
Using these equations is very inefficient because both a and b are
evaluated, regardless of the value of the boolean expression. It is
better to use COND_CLAUSES with the form above
(COND T = \a b. a) /\ (COND F = \a b. b)
The call-by-name evaluation of beta redexes avoids computing the unused branch of the conditional.
Conversely, strictify_thm does the reverse transformation. This is
particularly relevant for LET_DEF:
LET = \f x. f x --> LET f x = f x
This forces the evaluation of the argument before reducing the
beta-redex. Hence the usual behaviour of LET.
It is necessary to provide rules for all the constants appearing in the
expression to reduce (all also for those that appear in the right hand
side of a rule), unless the given constant is considered as a
constructor of the representation chosen. As an example,
reduceLib.num_compset creates a new simplification set with all the
rules needed for basic boolean and arithmetical calculations built in.
Example
- val rws = computeLib.new_compset [computeLib.lazyfy_thm COND_CLAUSES];
> val rws = <compset> : compset
- computeLib.CBV_CONV rws ``(\x.x) ((\x.x) if T then 0+0 else 10)``;
> val it = |- (\x. x) ((\x. x) (if T then 0 + 0 else 10)) = 0 + 0 : thm
- computeLib.CBV_CONV reduceLib.num_compset
``if 100 - 5 * 5 < 80 then 2 EXP 16 else 3``;
> val it = |- (if 100 - 5 * 5 < 80 then 2 ** 16 else 3) = 65536 : thm
Failing to give enough rules may make CBV_CONV build a huge result, or
even loop. The same may occur if the initial term to reduce contains
free variables.
val eqn = bossLib.Define `exp n p = if p=0 then 1 else n * (exp n (p-1))`;
val _ = computeLib.add_thms [eqn] rws;
- computeLib.CBV_CONV rws ``exp 2 n``;
> Interrupted.
- computeLib.set_skip rws ``COND`` (SOME 1);
> val it = () : unit
- computeLib.CBV_CONV rws ``exp 2 n``;
> val it = |- exp 2 n = if n = 0 then 1 else 2 * exp 2 (n - 1) : thm
The first invocation of CBV_CONV loops since the exponent never
reduces to 0. Below the first steps are computed:
exp 2 n
if n = 0 then 1 else 2 * exp 2 (n-1)
if n = 0 then 1 else 2 * if (n-1) = 0 then 1 else 2 * exp 2 (n-1-1)
...
The call to set_skip means that if the constants COND appears
applied to one argument and does not create a redex (in the example, if
the condition does not reduce to T or F), then the forthcoming
arguments (the two branches of the conditional) are not reduced at all.
Failure
Should never fail. Nonetheless, using rewrites with assumptions may cause problems when rewriting under abstractions. The following example illustrates that issue.
- val th = ASSUME “0 = x”;
- val tm = Term`\(x:num). x = 0`;
- val rws = from_list [th];
- CBV_CONV rws tm;
This fails because the 0 is replaced by x, making the assumption
0 = x. Then, the abstraction cannot be rebuilt since x appears free
in the assumptions.
See also
numLib.REDUCE_CONV,
computeLib.bool_compset,
bossLib.EVAL
listItems
listItems
computeLib.listItems : compset -> ((string * string) * transform list) list
List elements in compset
The function listItems expects a simplification set and returns a
listing of its elements, in the form of an association list mapping
constant names to the transformations that can be performed on
applications of that constant. For a given constant, more than one
transformation can be attached.
Example
> val compset = computeLib.bool_compset
val compset = <compset> : computeLib.compset
> computeLib.listItems compset;
val it =
[(("/\\", "bool"),
[RRules
[|- $/\ F = (\t. F),
|- $/\ T = (\t. t)],
RRules
[|- !t. t /\ t <=> t,
|- !t. t /\ F <=> F,
|- !t. t /\ T <=> t]]),
(("=", "min"),
[RRules
[|- $<=> F = (\t. ~t),
|- $<=> T = (\t. t)],
RRules
[|- !x. (x = x) <=> T],
RRules
[|- !t. (t <=> F) <=> ~t,
|- !t. (t <=> T) <=> t]]),
(("==>", "min"),
[RRules
[|- $==> F = (\t. T),
|- $==> T = (\t. t)],
RRules
[|- !t. t ==> F <=> ~t,
|- !t. t ==> t <=> T,
|- !t. t ==> T <=> T]]),
(("COND", "bool"),
[RRules
[|- COND F = (\t1 t2. t2),
|- COND T = (\t1 t2. t1)],
RRules
[|- !t b. (if b then t else t) = t]]),
(("F", "bool"), []),
(("LET", "bool"),
[RRules
[|- !x f. LET f x = f x]]),
(("T", "bool"), []),
(("\\/", "bool"),
[RRules
[|- $\/ F = (\t. t),
|- $\/ T = (\t. T)],
RRules
[|- !t. t \/ t <=> t,
|- !t. t \/ F <=> t,
|- !t. t \/ T <=> T]]),
(("literal_case", "bool"),
[RRules
[|- !x f. literal_case f x = f x]]),
(("~", "bool"),
[RRules
[|- ~F <=> T,
|- ~T <=> F,
|- !t. ~~t <=> t]])]
: ((string * string) * transform list) list
Failure
Should never fail.
See also
computeLib.bool_compset,
bossLib.EVAL,
computeLib.transform
monitoring
monitoring
computeLib.monitoring : (term -> bool) option ref
Monitoring support for evaluation.
The reference variable monitoring provides a simple way to view the
operation of EVAL, EVAL_RULE, and EVAL_TAC. The initial value of
monitoring is NONE. If one wants to monitor the expansion of a
function, defined with constant c, then setting monitoring to
SOME (same_const c) will tell the system to print out the expansion of
c by the evaluation entrypoints. To monitor the expansions of a
collection of functions, defined with c1,...,cn, then monitoring
can be set to
SOME (fn x => same_const c1 x orelse ... orelse same_const cn x)
Failure
Never fails.
Example
> val [FACT] = decls "FACT";
val FACT = “FACT”: term
> computeLib.monitoring := SOME (same_const FACT);
val it = (): unit
> EVAL (Term `FACT 4`);
FACT 4 = 4 * FACT 3
FACT 3 = 3 * FACT (PRE 3)
FACT 2 = 2 * FACT 1
FACT 1 = 1 * FACT (PRE 1)
FACT 0 = 1
val it = ⊢ FACT 4 = 24: thm
See also
computeLib.RESTR_EVAL_CONV,
Term.decls
RESTR_EVAL_CONV
RESTR_EVAL_CONV
computeLib.RESTR_EVAL_CONV : term list -> conv
Symbolically evaluate a term, except for specified constants.
An application RESTR_EVAL_CONV [c1, ..., cn] M evaluates the term M
in the call-by-value style of EVAL. When a type instance c of any
element in c1,...,cn is encountered, c is not expanded by
RESTR_EVAL_CONV. The effect is that evaluation stops at c (even
though any arguments to c may be evaluated). This facility can be used
to control EVAL_CONV to some extent.
Failure
Never fails, but may diverge.
Example
In the following, we first attempt to map the factorial function FACT
over a list of variables. This attempt goes into a loop, because the
conditional statement in the evaluation rule for FACT is never
determine when the argument is equal to zero. However, if we suppress
the evaluation of FACT, then we can return a useful answer.
- EVAL (Term `MAP FACT [x; y; z]`); (* loops! *)
> Interrupted.
- val [FACT] = decls "FACT"; (* find FACT constant *)
> val FACT = `FACT` : term
- RESTR_EVAL_CONV [FACT] (Term `MAP FACT [x; y; z]`);
> val it = |- MAP FACT [x; y; z] = [FACT x; FACT y; FACT z] : thm
Controlling symbolic evaluation when it loops or becomes exponential.
See also
bossLib.EVAL,
computeLib.RESTR_EVAL_TAC,
computeLib.RESTR_EVAL_RULE,
Term.decls
RESTR_EVAL_RULE
RESTR_EVAL_RULE
computeLib.RESTR_EVAL_RULE : term list -> thm -> thm
Symbolically evaluate a theorem, except for specified constants.
This is a version of RESTR_EVAL_CONV that works on theorems.
Failure
As for RESTR_EVAL_CONV.
Controlling symbolic evaluation when it loops or becomes exponential.
See also
bossLib.EVAL,
bossLib.EVAL_RULE,
computeLib.RESTR_EVAL_CONV,
computeLib.RESTR_EVAL_TAC
RESTR_EVAL_TAC
RESTR_EVAL_TAC
computeLib.RESTR_EVAL_TAC : term list -> tactic
Symbolically evaluate a theorem, except for specified constants.
This is a tactic version of RESTR_EVAL_CONV.
Failure
As for RESTR_EVAL_CONV.
Controlling symbolic evaluation when it loops or becomes exponential.
See also
bossLib.EVAL,
bossLib.EVAL_RULE,
bossLib.EVAL_TAC,
computeLib.RESTR_EVAL_CONV,
computeLib.RESTR_EVAL_RULE
transform
transform
computeLib.type transform
Type of elements in compset
An element of a compset can map to a collection of rewrite rules or a
conversion (or both, in some cases). The type transform is declared as
follows:
datatype transform
= Conversion of (term -> thm * db fterm)
| RRules of thm list
Failure
Can not fail.
See also
unmapped
unmapped
computeLib.unmapped : compset -> (string * string) list
List unmapped elements in compset
The function unmapped takes a compset value and returns a listing of
the elements of the compset that have no transformation attached to
them.
Example
The listing omits constructors, but can include constants that effectively act as constructors for rewrites in the compset.
> val compset = reduceLib.num_compset;
val compset = <compset>: computeLib.compset
> computeLib.unmapped compset;
val it =
[("BIT1", "arithmetic"),
("BIT2", "arithmetic"),
("ZERO", "arithmetic")]
: (string * string) list
Example
In the following example, a function is added to a compset without also adding functions that get "called" by it:
> load "sortingTheory";
val it = (): unit
> sortingTheory.QSORT_DEF;
val it =
|- (!ord. QSORT ord [] = []) /\
!t ord h.
QSORT ord (h::t) =
(let (l1,l2) = PARTITION (\y. ord y h) t
in
QSORT ord l1 ++ [h] ++ QSORT ord l2) : thm
> val compset = computeLib.add_thms [sortingTheory.QSORT_DEF] compset;
> computeLib.unmapped compset;
val it =
[("APPEND", "list"),
("BIT1", "arithmetic"),
("BIT2", "arithmetic"),
("PARTITION", "sorting"),
("UNCURRY", "pair"),
("ZERO", "arithmetic")]
:(string * string) list
Comments
Intended to support the construction of large compsets, where it is
often unclear what functions and conversions still need to be added in
order to make applications of EVAL_CONV terminate.
Failure
Never fails.
See also
bossLib.EVAL,
computeLib.listItems
COND_REWR_CANON
COND_REWR_CANON
Cond_rewrite.COND_REWR_CANON : thm -> thm
Transform a theorem into a form accepted by COND_REWR_TAC.
COND_REWR_CANON transforms a theorem into a form accepted by
COND_REWR_TAC. The input theorem should be an implication of the
following form
!x1 ... xn. P1[xi] ==> ... ==> !y1 ... ym. Pr[xi,yi] ==>
(!z1 ... zk. u[xi,yi,zi] = v[xi,yi,zi])
where each antecedent Pi itself may be a conjunction or disjunction.
The output theorem will have all universal quantifications moved to the
outer most level with possible renaming to prevent variable capture, and
have all antecedents which are a conjunction transformed to
implications. The output theorem will be in the following form
!x1 ... xn y1 ... ym z1 ... zk.
P11[xi] ==> ... ==> P1p[xi] ==> ... ==>
Pr1[xi,yi] ==> ... ==> Prq[x1,yi] ==> (u[xi,yi,zi] = v[xi,yi,zi])
Failure
This function fails if the input theorem is not in the correct form.
Example
COND_REWR_CANON transforms the built-in theorem CANCL_SUB into the
form for conditional rewriting:
#COND_REWR_CANON CANCEL_SUB;;
Theorem CANCEL_SUB autoloading from theory `arithmetic` ...
CANCEL_SUB = |- !p n m. p <= n /\ p <= m ==> ((n - p = m - p) = (n = m))
|- !p n m. p <= n ==> p <= m ==> ((n - p = m - p) = (n = m))
See also
Cond_rewrite.COND_REWRITE1_TAC,
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CONV,
Cond_rewrite.search_top_down
COND_REWR_CONV
COND_REWR_CONV
Cond_rewrite.COND_REWR_CONV : ((term -> term ->
((term # term) list # (type # type) list) list) -> thm -> conv)
A lower level conversion implementing simple conditional rewriting.
COND_REWR_CONV is one of the basic building blocks for the
implementation of the simple conditional rewriting conversions in the
HOL system. In particular, the conditional term replacement or rewriting
done by all the conditional rewriting conversions in this library is
ultimately done by applications of COND_REWR_CONV. The description
given here for COND_REWR_CONV may therefore be taken as a
specification of the atomic action of replacing equals by equals in a
term under certain conditions that are used in all these higher level
conditional rewriting conversions.
The first argument to COND_REWR_CONV is expected to be a function
which returns a list of matches. Each of these matches is in the form of
the value returned by the built-in function match. It is used to
search the input term for instances which may be rewritten.
The second argument to COND_REWR_CONV is expected to be an implicative
theorem in the following form:
A |- !x1 ... xn. P1 ==> ... Pm ==> (Q[x1,...,xn] = R[x1,...,xn])
where x1, ..., xn are all the variables that occur free in the left
hand side of the conclusion of the theorem but do not occur free in the
assumptions.
The last argument to COND_REWR_CONV is the term to be rewritten.
If fn is a function and th is an implicative theorem of the kind
shown above, then COND_REWR_CONV fn th will be a conversion. When
applying to a term tm, it will return a theorem
P1', ..., Pm' |- tm = tm[R'/Q']
if evaluating fn Q[x1,...,xn] tm returns a non-empty list of matches.
The assumptions of the resulting theorem are instances of the
antecedents of the input theorem th. The right hand side of the
equation is obtained by rewriting the input term tm with instances of
the conclusion of the input theorem.
Failure
COND_REWR_CONV fn th fails if th is not an implication of the form
described above. If th is such an equation, but the function fn
returns a null list of matches, or the function fn returns a non-empty
list of matches, but the term or type instantiation fails.
Example
The following example illustrates a straightforward use of
COND_REWR_CONV. We use the built-in theorem LESS_MOD as the input
theorem, and the function search_top_down as the search function.
#LESS_MOD;;
Theorem LESS_MOD autoloading from theory `arithmetic` ...
LESS_MOD = |- !n k. k < n ==> (k MOD n = k)
|- !n k. k < n ==> (k MOD n = k)
#search_top_down;;
- : (term -> term -> ((term # term) list # (type # type) list) list)
#COND_REWR_CONV search_top_down LESS_MOD "2 MOD 3";;
2 < 3 |- 2 MOD 3 = 2
See also
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWRITE1_TAC,
Cond_rewrite.COND_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.search_top_down
COND_REWR_TAC
COND_REWR_TAC
Cond_rewrite.COND_REWR_TAC :
(term -> term -> ((term * term) list * (type * type) list) list) ->
thm_tactic
A lower level tactic used to implement simple conditional rewriting tactic.
COND_REWR_TAC is one of the basic building blocks for the
implementation of conditional rewriting in the HOL system. In
particular, the conditional term replacement or rewriting done by all
the built-in conditional rewriting tactics is ultimately done by
applications of COND_REWR_TAC. The description given here for
COND_REWR_TAC may therefore be taken as a specification of the atomic
action of replacing equals by equals in the goal under certain
conditions that aare used in all these higher level conditional
rewriting tactics.
The first argument to COND_REWR_TAC is expected to be a function which
returns a list of matches. Each of these matches is in the form of the
value returned by the built-in function match. It is used to search
the goal for instances which may be rewritten.
The second argument to COND_REWR_TAC is expected to be an implicative
theorem in the following form:
A |- !x1 ... xn. P1 ==> ... Pm ==> (Q[x1,...,xn] = R[x1,...,xn])
where x1, ..., xn are all the variables that occur free in the
left-hand side of the conclusion of the theorem but do not occur free in
the assumptions.
If fn is a function and th is an implicative theorem of the kind
shown above, then COND_REWR_TAC fn th will be a tactic which returns a
list of subgoals if evaluating
fn Q[x1,...,xn] gl
returns a non-empty list of matches when applied to a goal (asm,gl).
Let ml be the match list returned by evaluating fn Q[x1,...,xn] gl.
Each element in this list is in the form of
([(e1,x1);...;(ep,xp)], [(ty1,vty1);...;(tyq,vtyq)])
which specifies the term and type instantiations of the input theorem
th. Either the term pair list or the type pair list may be empty. In
the case that both lists are empty, an exact match is found, i.e., no
instantiation is required. If ml is an empty list, no match has been
found and the tactic will fail.
For each match in ml, COND_REWR_TAC will perform the following: 1)
instantiate the input theorem th to get
th' = A |- P1' ==> ... ==> Pm' ==> (Q' = R')
where the primed subterms are instances of the corresponding unprimed
subterms obtained by applying INST_TYPE with
[(ty1,vty1);...;(tyq,vtyq)] and then INST with
[(e1,x1);...;(ep,xp)]; 2) search the assumption list asm for
occurrences of any antecedents P1', ..., Pm'; 3) if all antecedents
appear in asm, the goal gl is reduced to gl' by substituting R'
for each free occurrence of Q', otherwise, in addition to the
substitution, all antecedents which do not appear in asm are added to
it and new subgoals corresponding to these antecedents are created. For
example, if Pk', ..., Pm' do not appear in asm, the following
subgoals are returned:
asm ?- Pk' ... asm ?- Pm' {{asm,Pk',...,Pm'}} ?- gl'
If COND_REWR_TAC is given a theorem th:
A |- !x1 ... xn y1 ... yk. P1 ==> ... ==> Pm ==> (Q = R)
where the variables y1, ..., ym do not occur free in the left-hand
side of the conclusion Q but they do occur free in the antecedents,
then, when carrying out Step 2 described above, COND_REWR_TAC will
attempt to find instantiations for these variables from the assumption
asm. For example, if x1 and y1 occur free in P1, and a match is
found in which e1 is an instantiation of x1, then P1' will become
P1[e1/x1, y1]. If a term P1'' = P1[e1,e1'/x1,y1] appears in asm,
th' is instantiated with (e1', y1) to get
th'' = A |- P1'' ==> ... ==> Pm'' ==> (Q' = R'')
then R'' is substituted into gl for all free occurrences of Q'. If
no consistent instantiation is found, then P1' which contains the
uninstantiated variable y1 will become one of the new subgoals. In
such a case, the user has no control over the choice of the variable
yi.
Failure
COND_REWR_TAC fn th fails if th is not an implication of the form
described above. If th is such an equation, but the function fn
returns a null list of matches, or the function fn returns a non-empty
list of matches, but the term or type instantiation fails.
Example
The following example illustrates a straightforward use of
COND_REWR_TAC. We use the built-in theorem LESS_MOD as the input
theorem, and the function search_top_down as the search function.
#LESS_MOD;;
Theorem LESS_MOD autoloading from theory `arithmetic` ...
LESS_MOD = |- !n k. k < n ==> (k MOD n = k)
|- !n k. k < n ==> (k MOD n = k)
#search_top_down;;
- : (term -> term -> ((term # term) list # (type # type) list) list)
We set up a goal
#g"2 MOD 3 = 2";;
"2 MOD 3 = 2"
() : void
and then apply the tactic
#e(COND_REWR_TAC search_top_down LESS_MOD);;
OK..
2 subgoals
"2 = 2"
[ "2 < 3" ]
"2 < 3"
() : void
See also
Cond_rewrite.COND_REWRITE1_TAC,
Cond_rewrite.COND_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.search_top_down
COND_REWRITE1_CONV
COND_REWRITE1_CONV
Cond_rewrite.COND_REWRITE1_CONV : thm list -> thm -> conv
A simple conditional rewriting conversion.
COND_REWRITE1_CONV is a front end of the conditional rewriting
conversion COND_REWR_CONV. The input theorem should be in the
following form
A |- !x11 ... . P1 ==> ... !xm1 ... . Pm ==> (!x ... . Q = R)
where each antecedent Pi itself may be a conjunction or disjunction.
This theorem is transformed to a standard form expected by
COND_REWR_CONV which carries out the actual rewriting. The
transformation is performed by COND_REWR_CANON. The search function
passed to COND_REWR_CONV is search_top_down. The effect of applying
the conversion COND_REWRITE1_CONV ths th to a term tm is to derive a
theorem
A' |- tm = tm[R'/Q']
where the right hand side of the equation is obtained by rewriting the
input term tm with an instance of the conclusion of the input theorem.
The theorems in the list ths are used to discharge the assumptions
generated from the antecedents of the input theorem.
Failure
COND_REWRITE1_CONV ths th fails if th cannot be transformed into the
required form by COND_REWR_CANON. Otherwise, it fails if no match is
found or the theorem cannot be instantiated.
Example
The following example illustrates a straightforward use of
COND_REWRITE1_CONV. We use the built-in theorem LESS_MOD as the
input theorem.
#LESS_MOD;;
Theorem LESS_MOD autoloading from theory `arithmetic` ...
LESS_MOD = |- !n k. k < n ==> (k MOD n = k)
|- !n k. k < n ==> (k MOD n = k)
#COND_REWRITE1_CONV [] LESS_MOD "2 MOD 3";;
2 < 3 |- 2 MOD 3 = 2
#let less_2_3 = REWRITE_RULE[LESS_MONO_EQ;LESS_0]
#(REDEPTH_CONV num_CONV "2 < 3");;
less_2_3 = |- 2 < 3
#COND_REWRITE1_CONV [less_2_3] LESS_MOD "2 MOD 3";;
|- 2 MOD 3 = 2
In the first example, an empty theorem list is supplied to
COND_REWRITE1_CONV so the resulting theorem has an assumption 2 < 3.
In the second example, a list containing a theorem |- 2 < 3 is
supplied, the resulting theorem has no assumptions.
See also
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWRITE1_TAC,
Cond_rewrite.COND_REWR_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.search_top_down
COND_REWRITE1_TAC
COND_REWRITE1_TAC
Cond_rewrite.COND_REWRITE1_TAC : thm_tactic
A simple conditional rewriting tactic.
COND_REWRITE1_TAC is a front end of the conditional rewriting tactic
COND_REWR_TAC. The input theorem should be in the following form
A |- !x11 ... . P1 ==> ... !xm1 ... . Pm ==> (!x ... . Q = R)
where each antecedent Pi itself may be a conjunction or disjunction.
This theorem is transformed to a standard form expected by
COND_REWR_TAC which carries out the actual rewriting. The
transformation is performed by COND_REWR_CANON. The search function
passed to COND_REWR_TAC is search_top_down. The effect of applying
this tactic is to substitute into the goal instances of the right hand
side of the conclusion of the input theorem Ri' for the corresponding
instances of the left hand side. The search is top-down left-to-right.
All matches found by the search function are substituted. New subgoals
corresponding to the instances of the antecedents which do not appear in
the assumption of the original goal are created. See manual page of
COND_REWR_TAC for details of how the instantiation and substitution
are done.
Failure
COND_REWRITE1_TAC th fails if th cannot be transformed into the
required form by the function COND_REWR_CANON. Otherwise, it fails if
no match is found or the theorem cannot be instantiated.
Example
The following example illustrates a straightforward use of
COND_REWRITE1_TAC. We use the built-in theorem LESS_MOD as the input
theorem.
#LESS_MOD;;
Theorem LESS_MOD autoloading from theory `arithmetic` ...
LESS_MOD = |- !n k. k < n ==> (k MOD n = k)
|- !n k. k < n ==> (k MOD n = k)
We set up a goal
#g"2 MOD 3 = 2";;
"2 MOD 3 = 2"
() : void
and then apply the tactic
#e(COND_REWRITE1_TAC LESS_MOD);;
OK..
2 subgoals
"2 = 2"
[ "2 < 3" ]
"2 < 3"
() : void
See also
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.search_top_down
search_top_down
search_top_down
Cond_rewrite.search_top_down
: (term -> term -> ((term # term) list # (type # type) list) list)
Search a term in a top-down fashion to find matches to another term.
search_top_down tm1 tm2 returns a list of instantiations which make
the whole or part of tm2 match tm1. The first term should not have a
quantifier at the outer most level. search_top_down first attempts to
match the whole second term to tm1. If this fails, it recursively
descend into the subterms of tm2 to find all matches.
The length of the returned list indicates the number of matches found.
An empty list means no match can be found between tm1 and tm2 or any
subterms of tm2. The instantiations returned in the list are in the
same format as for the function match. Each instantiation is a pair of
lists: the first is a list of term pairs and the second is a list of
type pairs. Either of these lists may be empty. The situation in which
both lists are empty indicates that there is an exact match between the
two terms, i.e., no instantiation is required to make the entire tm2
or a part of tm2 the same as tm1.
Failure
Never fails.
Example
#search_top_down "x = y:*" "3 = 5";;
[([("5", "y"); ("3", "x")], [(":num", ":*")])]
: ((term # term) list # (type # type) list) list
#search_top_down "x = y:*" "x =y:*";;
[([], [])] : ((term # term) list # (type # type) list) list
#search_top_down "x = y:*" "0 < p ==> (x <= p = y <= p)";;
[([("y <= p", "y"); ("x <= p", "x")], [(":bool", ":*")])]
: ((term # term) list # (type # type) list) list
The first example above shows the entire tm2 matching tm1. The
second example shows the two terms match exactly. No instantiation is
required. The last example shows that a subterm of tm2 can be
instantiated to match tm1.
See also
CHANGED_CONSEQ_CONV
CHANGED_CONSEQ_CONV
ConseqConv.CHANGED_CONSEQ_CONV : (conseq_conv -> conseq_conv)
Makes a consequence conversion fail if applying it leaves a term unchanged.
If c is a consequence conversion that maps a term ``t`` to a
theorem |- t = t', |- t' ==> t or |- t ==> t', where t' is
alpha-equivalent to t, or if c raises the UNCHANGED exception when
applied to ``t``, then CHANGED_CONSEQ_CONV c fails when
applied to the term ``t``. Otherwise, CHANGED_CONSEQ_CONV c
behaves like c.
See also
Conv.CHANGED_CONV,
ConseqConv.QCHANGED_CONSEQ_CONV
conseq_conv
conseq_conv
ConseqConv.type conseq_conv
A type for functions that given a term produce a theorem with an implication at the top level.
Classical conversions (see Conv) convert a given term t to a term
eqt that is equal to t. For a boolean term t, it is however
sometimes useful not to preserve equivalence, but to either strengthen
t to st or to weaken it to wt. The type conseq_conv is used for
ML functions that perform these operations. These ML Functions are
called consequence conversions in the following.
Given a consequence conversion CONSEQ_CONV and a term t, then
CONSEQ_CONV can either fail with an HOL_ERR-exception, raise an
UNCHANGED-exception or produce a theorem of one of the following
forms:
1. st ==> t
2. t ==> wt
3. t = eqt
Example
Examples of simple consequence conversion are TRUE_CONSEQ_CONV and
FALSE_CONSEQ_CONV.
See also
ConseqConv.directed_conseq_conv,
ConseqConv.TRUE_FALSE_REFL_CONSEQ_CONV
CONSEQ_CONV_direction
CONSEQ_CONV_direction
ConseqConv.type CONSEQ_CONV_direction
A type used to tell directed consequence conversions what the desired result should look like.
This type is used to instruct a directed consequence conversion how to
behave. Given a direction dir and a boolean term t the result of a
directed consequence conversion DCONSEQ_CONV should be of the form
st ==> t for dir = CONSEQ_CONV_STRENGTHEN_direction
t ==> wt for dir = CONSEQ_CONV_WEAKEN_direction
st ==> t, t ==> wt or t = eqt for dir = CONSEQ_CONV_UNKNOWN_direction
See also
ConseqConv.directed_conseq_conv,
ConseqConv.TRUE_FALSE_REFL_CONSEQ_CONV
CONSEQ_CONV_TAC
CONSEQ_CONV_TAC
ConseqConv.CONSEQ_CONV_TAC : directed_conseq_conv -> tactic
Reduces the goal using a consequence conversion.
CONSEQ_CONV_TAC c tries to strengthen a goal P using c to a new
goal P'. It then remains to show that P' holds.
See also
CONSEQ_REWRITE_CONV
CONSEQ_REWRITE_CONV
ConseqConv.CONSEQ_REWRITE_CONV : (thm list * thm list * thm list) -> directed_conseq_conv
Applies CONSEQ_TOP_REWRITE_CONV repeatedly at subterms.
This directed consequence conversion is a combination of
CONSEQ_TOP_REWRITE_CONV and DEPTH_CONSEQ_CONV. Given lists of
theorems, these theorems are preprocessed to extract implications. Then
these implications are used to either weaken or strengthen an input
term.
Example
Reconsider the example for DEPTH_CONSEQ_CONV. Let rewrite_every_thm
be the following theorem:
val rewrite_every_thm =
|- FEVERY P FEMPTY /\
(FEVERY P f /\ P (x,y) ==> FEVERY P (f |+ (x,y)));
Then the following call of CONSEQ_REWRITE_CONV
CONSEQ_REWRITE_CONV ([], [rewrite_every_thm], []) CONSEQ_CONV_STRENGTHEN_direction
``!y2. FEVERY P (f |+ (x1, y1) |+ (x2,y2)) /\ Q z``
results in
|- (!y2. ((FEVERY P f /\ P (x1, y1)) /\ P (x2,y2)) /\ Q z) ==>
(!y2. FEVERY P (f |+ (x1, y1) |+ (x2,y2)) /\ Q z)
More examples can be found at the end of ConseqConv.sml.
See also
Drule.MATCH_MP,
ConseqConv.CONSEQ_TOP_REWRITE_CONV,
ConseqConv.DEPTH_CONSEQ_CONV,
ConseqConv.EXT_CONSEQ_REWRITE_CONV
CONSEQ_TOP_REWRITE_CONV
CONSEQ_TOP_REWRITE_CONV
ConseqConv.CONSEQ_TOP_REWRITE_CONV : (thm list * thm list * thm list) -> directed_conseq_conv
An extended version of MATCH_MP.
This consequence conversion gets 3 lists of theorems as parameters:
both_thmL, strengthen_thmL and weaken_thmL. The theorems in these
lists are used to strengthen or weaken a given boolean term at toplevel.
If using them for strengthening this consequence conversion behaves
similar to MATCH_MP. As the names suggest, the theorems in
strengthen_thmL are used for strengthening, the ones in weaken_thmL
for weakening and the ones in both_thmL for both.
Before trying to apply the conversion, the theorem lists are
preprocessed. The theorems are split along conjunctions and
allquantification is removed. Then theorems with toplevel negation
|- ~P are rewritten to |- P = F. Afterwards every theorem |- P
that is not an implication or an boolean equation is replaced by
|- P = T. Finally, boolean equations |- P = Q are splitted into two
theorems |- P ==> Q and |- Q ==> P. One ends up with a list of
implications.
Given a term t the conversion tries to find a theorem |- P ==> Q
and - depending on to the direction - strengthen t by matching it with
Q or weaken it by matching it with P.
Example
This directed consequence conversion is intended to be used together
with DEPTH_CONSEQ_CONV. The combination of both is called
CONSEQ_REWRITE_CONV. Please have a look there for an example.
See also
Drule.MATCH_MP,
ConseqConv.CONSEQ_REWRITE_CONV,
ConseqConv.DEPTH_CONSEQ_CONV
DEPTH_CONSEQ_CONV
DEPTH_CONSEQ_CONV
ConseqConv.DEPTH_CONSEQ_CONV : directed_conseq_conv -> directed_conseq_conv
Applies a consequence conversion repeatedly to all the sub-terms of a term, in top-down order.
DEPTH_CONSEQ_CONV c tm tries to apply the given conversion at
toplevel. If this fails, it breaks the term tm down into boolean
subterms. It can break up the following operators: /\, \/, ~,
==> and quantification. Then it applies the directed consequence
conversion c to terms and iterates. Finally, it puts everything
together again.
Notice that some operators switch the direction that is passed to c,
e.g. to strengthen a term ~t, DEPTH_CONSEQ_CONV tries to weaken t.
Example
Consider the expression FEVERY P (f |+ (x1, y1) |+ (x2,y2)). It states
that all elements of the finite map f |+ (x1, y1) |+ (x2, y2) satisfy
the predicate P. However, the definition of x1 and x2 possible
hide definitions of these keys inside f or in case x1 = x2 the
middle update is void. You easily get into a lot of aliasing problems
while proving thus a statement. However, the following theorem holds:
|- !f x y. FEVERY P (f |+ (x,y)) /\ P (x,y) ==> FEVERY P (f |+ (x,y))
Given a directed consequence conversion c that instantiates this
theorem, DEPTH_CONSEQ_CONV can be used to apply it repeatedly and at
substructures as well:
DEPTH_CONSEQ_CONV c CONSEQ_CONV_STRENGTHEN_direction
``!y2. FEVERY P (f |+ (x1, y1) |+ (x2,y2)) /\ Q z`` =
|- (!y2. FEVERY P f /\ P (x1, y1) /\ P (x2,y2) /\ Q z) ==>
(!y2. FEVERY P (f |+ (x1, y1) |+ (x2,y2)) /\ Q z)
See also
Conv.DEPTH_CONV,
ConseqConv.ONCE_DEPTH_CONSEQ_CONV,
ConseqConv.NUM_DEPTH_CONSEQ_CONV,
ConseqConv.DEPTH_STRENGTHEN_CONSEQ_CONV,
ConseqConv.REDEPTH_CONSEQ_CONV
DEPTH_STRENGTHEN_CONSEQ_CONV
DEPTH_STRENGTHEN_CONSEQ_CONV
ConseqConv.DEPTH_STRENGTHEN_CONSEQ_CONV : conseq_conv -> conseq_conv
Applies a consequence conversion repeatedly to all the sub-terms of a term, in bottom-up order.
DEPTH_STRENGTHEN_CONSEQ_CONV c is defined as
DEPTH_CONSEQ_CONV (K c) CONSEQ_CONV_STRENGTHEN_direction. So, its just
a slightly simplified interface to DEPTH_CONSEQ_CONV, that tries to
strengthen all the time and that does not require the conversion to know
about directions.
See also
Conv.DEPTH_CONV,
ConseqConv.ONCE_DEPTH_CONSEQ_CONV,
ConseqConv.NUM_DEPTH_CONSEQ_CONV,
ConseqConv.DEPTH_CONSEQ_CONV
directed_conseq_conv
directed_conseq_conv
ConseqConv.type directed_conseq_conv
A type for consequence conversions that can be instructed on whether to strengthen or weaken a given term.
Given a CONSEQ_CONV_direction, a directed consequence conversion tries
to strengthen, weaken or whatever it can depending on the given
direction.
See also
ConseqConv.conseq_conv,
ConseqConv.CONSEQ_CONV_direction
EVERY_CONSEQ_CONV
EVERY_CONSEQ_CONV
ConseqConv.EVERY_CONSEQ_CONV : (conseq_conv list -> conseq_conv)
Applies in sequence all the consequence conversions in a given list of conversions.
See also
ConseqConv.THEN_CONSEQ_CONV,
Conv.EVERY_CONV
EXISTS_CONSEQ_CONV
EXISTS_CONSEQ_CONV
ConseqConv.EXISTS_CONSEQ_CONV : (conseq_conv -> conseq_conv)
Applies a consequence conversion to the body of an existentially quantified term.
If c is a consequence conversion that maps a term ``t x`` to a
theorem |- t x = t' x, |- t' x ==> t x or |- t x ==> t' x, then
EXISTS_CONSEQ_CONV c maps ``?x. t x`` to
|- ?x. t x = ?x. t' x, |- ?x. t' x ==> ?x. t x or
|- ?x. t x ==> ?x. t' x, respectively.
Failure
EXISTS_CONSEQ_CONV c t fails, if t is not an existentially
quantified term or if c fails on the body of t.
See also
Conv.QUANT_CONV,
ConseqConv.FORALL_CONSEQ_CONV,
ConseqConv.QUANT_CONSEQ_CONV
EXISTS_EQ___CONSEQ_CONV
EXISTS_EQ___CONSEQ_CONV
ConseqConv.EXISTS_EQ___CONSEQ_CONV : conseq_conv
Given a term of the form (?x. P x) = (?x. Q x) this consequence
conversion returns the theorem
|- (!x. (P x = Q x)) ==> ((?x. P x) = (?x. Q x)).
See also
EXISTS_INTRO_IMP
EXISTS_INTRO_IMP
ConseqConv.EXISTS_INTRO_IMP : term -> thm -> thm
Existentially quantifies both sides of an implication in the conclusion of a theorem.
When applied to a term x and a theorem A |- t1 ==> t2, the inference
rule EXISTS_INTRO_IMP returns the theorem
A |- (?x. t1) ==> (?x. t2), provided x is a variable not free in any
of the assumptions. There is no compulsion that x should be free in
t1 or t2.
A |- (t1 ==> t2)
---------------------------- EXISTS_INTRO_IMP x [where x is not free in A]
A |- (?x. t1) ==> (?x. t2)
Failure
Fails if x is not a variable, the conclusion of the theorem is not an
implication, or if x is free in any of the assumptions.
Example
- val thm0 = mk_thm ([], Term `P (x:'a) ==> Q x`);
> val thm0 = |- P (x :'a) ==> Q x : thm
- val thm1 = EXISTS_INTRO_IMP (Term `x:'a`) thm0;
> val thm1 = |- (?x. P x) ==> (?x. Q x)
See also
EXT_CONSEQ_REWRITE_CONV
EXT_CONSEQ_REWRITE_CONV
ConseqConv.EXT_CONSEQ_REWRITE_CONV : (thm list -> conv) list -> thm list ->
(thm list * thm list * thm list) ->
directed_conseq_conv
Applies CONSEQ_REWRITE_CONV interleaved with conversions and rewrites.
CONSEQ_REWRITE_CONV often results in theorems of the following form
|- (!x. T) /\ (T /\ (T /\ T)) /\ (\x. P) y /\ T ==>
something
The problem is that CONSEQ_REWRITE_CONV applies consequence
conversions, but no normal convs or simplifications. This is changed by
EXT_CONSEQ_REWRITE_CONV. EXT_CONSEQ_REWRITE_CONV gets a list of
conversions and a list of rewrite theorems. Moreover there are the
parameters of CONSEQ_REWRITE_CONV. It then applies these conversions
(e.g. DEPTH_CONV BETA_CONV) and a REWRITE_CONV with the given
theorem list interleaved with CONSEQ_REWRITE_CONV. As a result the
theorem above might look now like
|- P y ==> something
See also
ConseqConv.CONSEQ_REWRITE_CONV
EXT_DEPTH_CONSEQ_CONV
EXT_DEPTH_CONSEQ_CONV
ConseqConv.EXT_DEPTH_CONSEQ_CONV : conseq_conv_congruence list ->
depth_conseq_conv_cache_opt -> int option ->
bool ->
(bool * int option * (thm list -> directed_conseq_conv)) list ->
thm list ->
directed_conseq_conv
The general depth consequence conversion of which DEPTH_CONSEQ_CONV,
REDEPTH_CONSEQ_CONV, ONCE_DEPTH_CONSEQ_CONV etc are just
instantiations.
DEPTH_CONSEQ_CONV and similar conversions are able to apply a
consequence conversion by breaking down the structure of a term using
lemmata about /\, \/, ~, ==>, if-then-else and quantification.
While doing so, these conversions collect various amounts of context
information. EXT_DEPTH_CONSEQ_CONV congruence_list cache_opt
step_opt redepth convL context is the function used by these
other depth conversions. For this purpose, the
cache_opt determines which cache to use: NONE means no caching; a
standard cache that stores everything is configured by
CONSEQ_CONV_default_cache_opt.
The number of steps taken is determined by step_opt. NONE means
arbitrarily many; SOME n means at most n. ONCE_DEPTH_CONSEQ_CONV for
example uses SOME 1. The parameter redepth determines whether
modified terms should be revisited and convL is a basically a list of
directed consequence conversions of the conversions that should be
applied at subpositions. Its entries consist of a flag, whether to apply
the conversion before or after descending into subterms; the weight
(i.e. the number of counted steps) for the conversion, and a function
from the context (a list of theorems) to the conversion. context
provides additional context that might be used.
The first parameter congruence_list is a list of congruence functions
that determine how to break down terms. Each element of this list has to
be a function congruence context sys dir t which returns a pair of the
number of performed steps and a resulting theorem. sys is a callback
that allows to apply the depth conversion recursively to subterms.
context represents the context that can be used. If you ignore the
slightly different return type, the congruence is otherwise a directed
consequence conversion. If the congruence can't be applied, it should
either fail or raise an UNCHANGED exception. The callback sys gets
the number of already performed steps, a direction and a term. It then
returns a accumulated number of steps and a thm option. It never fails.
The number of steps is used to abort if the maximum number of globally
allowed steps has been reached. The first call of sys should get 0,
then the accumulated number has to be passed. The congruence should
return the finally accumulated number of steps.
See also
ConseqConv.DEPTH_CONSEQ_CONV,
ConseqConv.REDEPTH_CONSEQ_CONV,
ConseqConv.ONCE_DEPTH_CONSEQ_CONV,
ConseqConv.NUM_DEPTH_CONSEQ_CONV
FALSE_CONSEQ_CONV
FALSE_CONSEQ_CONV
ConseqConv.FALSE_CONSEQ_CONV : conseq_conv
Given a term t of type bool this consequence conversion returns the
theorem |- F ==> t.
See also
ConseqConv.TRUE_CONSEQ_CONV,
ConseqConv.REFL_CONSEQ_CONV,
ConseqConv.TRUE_FALSE_REFL_CONSEQ_CONV
FIRST_CONSEQ_CONV
FIRST_CONSEQ_CONV
ConseqConv.FIRST_CONSEQ_CONV : (conseq_conv list -> conseq_conv)
Apply the first of the conversions in a given list that succeeds.
See also
ConseqConv.ORELSE_CONSEQ_CONV,
Conv.FIRST_CONV
FORALL_CONSEQ_CONV
FORALL_CONSEQ_CONV
ConseqConv.FORALL_CONSEQ_CONV : (conseq_conv -> conseq_conv)
Applies a consequence conversion to the body of a universally-quantified term.
If c is a consequence conversion that maps a term ``t x`` to a
theorem |- t x = t' x, |- t' x ==> t x or |- t x ==> t' x, then
FORALL_CONSEQ_CONV c maps ``!x. t x`` to
|- !x. t x = !x. t' x, |- !x. t' x ==> !x. t x or
|- !x. t x ==> !x. t' x, respectively.
Failure
FORALL_CONSEQ_CONV c t fails, if t is not an all-quantified term or
if c fails on the body of t.
See also
Conv.QUANT_CONV,
ConseqConv.EXISTS_CONSEQ_CONV,
ConseqConv.QUANT_CONSEQ_CONV
FORALL_EQ___CONSEQ_CONV
FORALL_EQ___CONSEQ_CONV
ConseqConv.FORALL_EQ___CONSEQ_CONV : conseq_conv
Given a term of the form (!x. P x) = (!x. Q x) this consequence
conversion returns the theorem
|- (!x. (P x = Q x)) ==> ((!x. P x) = (!x. Q x)).
See also
GEN_ASSUM
GEN_ASSUM
ConseqConv.GEN_ASSUM : term -> thm -> thm
Generalizes the conclusion of a theorem and the hypotheses containing the same variable.
When applied to a term x and a theorem [A1, A2] |- t, where x
occurs in A1 but not in A2, the inference rule GEN_ASSUM returns
the theorem [!x. A1 x, A2 |- !x. t. There is no compulsion that x
should be free in t.
GEN_ASSUM is a generalisation of GEN. While GEN fails, if x is
free in an assumption, GEN_ASSUM succeeds.
A1, A2 |- t
--------------------- GEN_ASSUM x [where x is free in A1, but not in A2]
(!x. A1), A2 |- !x. t
Failure
Fails if x is not a variable.
See also
GEN_IMP
GEN_IMP
ConseqConv.GEN_IMP : term -> thm -> thm
Generalizes both sides of an implication in the conclusion of a theorem.
When applied to a term x and a theorem A |- t1 ==> t2, the inference
rule GEN_IMP returns the theorem A |- (!x. t1) ==> (!x. t2),
provided x is a variable not free in any of the assumptions. There is
no compulsion that x should be free in t1 or t2.
A |- (t1 ==> t2)
---------------------------- GEN_IMP x [where x is not free in A]
A |- (!x. t1) ==> (!x. t2)
Failure
Fails if x is not a variable, the conclusion of the theorem is not an
implication, or if x is free in any of the assumptions.
Example
- val thm0 = mk_thm ([], Term `P (x:'a) ==> Q x`);
> val thm0 = |- P (x :'a) ==> Q x : thm
- val thm1 = GEN_IMP (Term `x:'a`) thm0;
> val thm1 = |- (!x. P x) ==> (!x. Q x)
See also
NUM_DEPTH_CONSEQ_CONV
NUM_DEPTH_CONSEQ_CONV
ConseqConv.NUM_DEPTH_CONSEQ_CONV : directed_conseq_conv -> int -> directed_conseq_conv
Applies a consequence conversion at most a given number of times to the sub-terms of a term, in bottom-up order.
While DEPTH_CONSEQ_CONV c tm applies c repeatedly,
NUM_DEPTH_CONSEQ_CONV c n tm applies it at most n-times.
See also
Conv.DEPTH_CONV,
ConseqConv.ONCE_DEPTH_CONSEQ_CONV,
ConseqConv.DEPTH_CONSEQ_CONV,
ConseqConv.DEPTH_STRENGTHEN_CONSEQ_CONV
ONCE_DEPTH_CONSEQ_CONV
ONCE_DEPTH_CONSEQ_CONV
ConseqConv.ONCE_DEPTH_CONSEQ_CONV : directed_conseq_conv -> directed_conseq_conv
Applies a consequence conversion at most once to a sub-terms of a term.
While DEPTH_CONSEQ_CONV c tm applies c repeatedly,
ONCE_DEPTH_CONSEQ_CONV c tm applies c at most once.
See also
Conv.DEPTH_CONV,
ConseqConv.NUM_DEPTH_CONSEQ_CONV,
ConseqConv.DEPTH_CONSEQ_CONV,
ConseqConv.DEPTH_STRENGTHEN_CONSEQ_CONV
ORELSE_CONSEQ_CONV
ORELSE_CONSEQ_CONV
ConseqConv.ORELSE_CONSEQ_CONV : (conseq_conv -> conseq_conv -> conseq_conv)
Applies the first of two consequence conversions that succeeds.
See also
Conv.ORELSEC,
ConseqConv.FIRST_CONSEQ_CONV
QCHANGED_CONSEQ_CONV
QCHANGED_CONSEQ_CONV
ConseqConv.QCHANGED_CONSEQ_CONV : conseq_conv -> conseq_conv
Makes a consequence conversion fail if applying it raises the
UNCHANGED exception.
See also
Conv.QCHANGED_CONV,
ConseqConv.CHANGED_CONSEQ_CONV
QUANT_CONSEQ_CONV
QUANT_CONSEQ_CONV
ConseqConv.QUANT_CONSEQ_CONV : (conseq_conv -> conseq_conv)
Applies a consequence conversion to the body of an existentially or universally quantified term.
See also
Conv.QUANT_CONV,
ConseqConv.FORALL_CONSEQ_CONV,
ConseqConv.EXISTS_CONSEQ_CONV
REDEPTH_CONSEQ_CONV
REDEPTH_CONSEQ_CONV
ConseqConv.REDEPTH_CONSEQ_CONV : directed_conseq_conv -> directed_conseq_conv
Similar to DEPTH_CONSEQ_CONV, but revisits modified subterms.
See also
REFL_CONSEQ_CONV
REFL_CONSEQ_CONV
ConseqConv.REFL_CONSEQ_CONV : conseq_conv
Given a term t of type bool this consequence conversion returns the
theorem |- t ==> t.
See also
ConseqConv.TRUE_CONSEQ_CONV,
ConseqConv.FALSE_CONSEQ_CONV,
ConseqConv.TRUE_FALSE_REFL_CONSEQ_CONV
SPEC_ALL_TAC
SPEC_ALL_TAC
ConseqConv.SPEC_ALL_TAC : tactic
Generalizes a goal.
When applied to a goal A ?- t, the tactic SPEC_ALL_TAC generalizes
all variables that are free in t, but not in A. This results in a
goal of the form A ?- !x1 ... xn. t.
A ?- t
==================== SPEC_ALL_TAC
A ?- !x1 ... xn. t
Example
- val _ = set_goal ([``(P x):bool``], ``Q x /\ Z y``)
> Initial goal:
Q x /\ Z y
------------------------------------
P x
- e(SPEC_ALL_TAC)
>
!Q Z y. Q x /\ Z y
------------------------------------
P x
Failure
SPEC_ALL_TAC never fails. However, maybe no variable is generalized.
See also
STRENGTHEN_CONSEQ_CONV_RULE
STRENGTHEN_CONSEQ_CONV_RULE
ConseqConv.STRENGTHEN_CONSEQ_CONV_RULE : directed_conseq_conv -> thm -> thm
Tries to strengthen the antecedent of a theorem consisting of an implication.
Given a theorem of the form |- A ==> C and a directed consequence
conversion c a call of STRENGTHEN_CONSEQ_CONV_RULE c thm tries to
strengthen A to a predicate sA using c. If it succeeds it returns
the theorem |- sA ==> C.
See also
ConseqConv.WEAKEN_CONSEQ_CONV_RULE
THEN_CONSEQ_CONV
THEN_CONSEQ_CONV
ConseqConv.THEN_CONSEQ_CONV : (conseq_conv -> conseq_conv -> conseq_conv)
Applies two consequence conversions in sequence.
THEN_CONSEQ_CONV cc1 cc2 corresponds to c1 THENC c2 for classical
conversions. Thus, if cc1 returns |- t' ==> t when applied to t,
and cc2 returns |- t'' ==> t' when applied to t', then
(THEN_CONSEQ_CONV cc1 cc2) t returns |- t'' ==> t.
THEN_CONSEQ_CONV can handle weakening as well: If cc1 returns
|- t ==> t' when applied to t, and cc2 returns |- t' ==> t''
when applied to t', then (THEN_CONSEQ_CONV cc1 cc2) t returns
|- t ==> t''. Finally, if cc1 returns |- t = t' when applied to
t, and cc2 returns |- t' = t'' when applied to t', then
(THEN_CONSEQ_CONV cc1 cc2) t returns |- t = t''. If one of the
conversions returns an equation, while the other returns an implication,
the needed implication is automatically deduced.
See also
Conv.THENC,
ConseqConv.EVERY_CONSEQ_CONV
TRUE_CONSEQ_CONV
TRUE_CONSEQ_CONV
ConseqConv.TRUE_CONSEQ_CONV : conseq_conv
Given a term t of type bool this consequence conversion returns the
theorem |- t ==> T.
See also
ConseqConv.FALSE_CONSEQ_CONV,
ConseqConv.REFL_CONSEQ_CONV,
ConseqConv.TRUE_FALSE_REFL_CONSEQ_CONV
TRUE_FALSE_REFL_CONSEQ_CONV
TRUE_FALSE_REFL_CONSEQ_CONV
ConseqConv.TRUE_FALSE_REFL_CONSEQ_CONV : directed_conseq_conv
Given a term t of type bool this directed consequence conversion
returns the theorem |- F ==> t for CONSEQ_CONV_STRENGTHEN_direction,
the theorem |- t ==> T for CONSEQ_CONV_WEAKEN_direction and
|- t = t for CONSEQ_CONV_UNKNOWN_direction.
See also
ConseqConv.TRUE_CONSEQ_CONV,
ConseqConv.FALSE_CONSEQ_CONV,
ConseqConv.REFL_CONSEQ_CONV
WEAKEN_CONSEQ_CONV_RULE
WEAKEN_CONSEQ_CONV_RULE
ConseqConv.WEAKEN_CONSEQ_CONV_RULE : (directed_conseq_conv -> thm -> thm)
Tries to weaken the conclusion of a theorem consisting of an implication.
Given a theorem of the form |- A ==> C and a directed consequence
conversion c a call of WEAKEN_CONSEQ_CONV_RULE c thm tries to weaken
C to a predicate wC using c. If it succeeds it returns the theorem
|- A ==> wC.
See also
ConseqConv.STRENGTHEN_CONSEQ_CONV_RULE
ABS_CONV
ABS_CONV
Conv.ABS_CONV : conv -> conv
Applies a conversion to the body of an abstraction.
If c is a conversion that maps a term tm to the theorem
|- tm = tm', then the conversion ABS_CONV c maps abstractions of the
form \x.tm to theorems of the form:
|- (\x.tm) = (\x.tm')
That is, ABS_CONV c (\x.t) applies c to the body of the abstraction
\x.t.
Failure
ABS_CONV c tm fails if tm is not an abstraction or if tm has the
form \x.t but the conversion c fails when applied to the term t.
The function returned by ABS_CONV c may also fail if the ML function
c:term->thm is not, in fact, a conversion (i.e. a function that maps a
term M to a theorem |- M = N).
Example
> ABS_CONV SYM_CONV (Term `\x. 1 = x`)
val it = ⊢ (λx. 1 = x) = (λx. x = 1): thm
See also
Conv.RAND_CONV,
Conv.RATOR_CONV,
Conv.SUB_CONV,
Conv.BINDER_CONV,
Conv.QUANT_CONV,
Conv.STRIP_BINDER_CONV,
Conv.STRIP_QUANT_CONV
AC_CONV
AC_CONV
Conv.AC_CONV : (thm * thm) -> conv
Proves equality of terms using associative and commutative laws.
Suppose _ is a function, which is assumed to be infix in the following
syntax, and ath and cth are theorems expressing its associativity
and commutativity; they must be of the following form, except that any
free variables may have arbitrary names and may be universally
quantified:
ath = |- m _ (n _ p) = (m _ n) _ p
cth = |- m _ n = n _ m
Then the conversion AC_CONV(ath,cth) will prove equations whose left
and right sides can be made identical using these associative and
commutative laws.
Failure
Fails if the associative or commutative law has an invalid form, or if the term is not an equation between AC-equivalent terms.
Example
Consider the terms x + SUC t + ((3 + y) + z) and
3 + SUC t + x + y + z. AC_CONV proves them equal.
- AC_CONV(ADD_ASSOC,ADD_SYM)
(Term `x + (SUC t) + ((3 + y) + z) = 3 + (SUC t) + x + y + z`);
> val it =
|- (x + ((SUC t) + ((3 + y) + z)) = 3 + ((SUC t) + (x + (y + z)))) = T
Comments
Note that the preproved associative and commutative laws for the
operators +, *, /\ and \/ are already in the right form to give
to AC_CONV.
See also
ALL_CONV
ALL_CONV
Conv.ALL_CONV : conv
Conversion that always raises the UNCHANGED exception.
When applied to a term t, the conversion ALL_CONV raises the special
UNCHANGED exception, which indicates to leave t unchanged.
Failure
Always raises the UNCHANGED exception.
Identity element for THENC.
See also
Conv.UNCHANGED, Conv.NO_CONV,
Thm.REFL
AND_EXISTS_CONV
AND_EXISTS_CONV
Conv.AND_EXISTS_CONV : conv
Moves an existential quantification outwards through a conjunction.
When applied to a term of the form (?x.P) /\ (?x.Q), where x is free
in neither P nor Q, AND_EXISTS_CONV returns the theorem:
|- (?x. P) /\ (?x. Q) = (?x. P /\ Q)
Failure
AND_EXISTS_CONV fails if it is applied to a term not of the form
(?x.P) /\ (?x.Q), or if it is applied to a term (?x.P) /\ (?x.Q) in
which the variable x is free in either P or Q.
Comments
It may be easier to use higher order rewriting with some of
BOTH_EXISTS_AND_THM, LEFT_EXISTS_AND_THM, and
RIGHT_EXISTS_AND_THM.
See also
Conv.EXISTS_AND_CONV,
Conv.LEFT_AND_EXISTS_CONV,
Conv.RIGHT_AND_EXISTS_CONV
AND_FORALL_CONV
AND_FORALL_CONV
Conv.AND_FORALL_CONV : conv
Moves a universal quantification outwards through a conjunction.
When applied to a term of the form (!x.P) /\ (!x.Q), the conversion
AND_FORALL_CONV returns the theorem:
|- (!x.P) /\ (!x.Q) = (!x. P /\ Q)
Failure
Fails if applied to a term not of the form (!x.P) /\ (!x.Q).
Comments
It may be easier to use higher order rewriting with FORALL_AND_THM.
See also
Conv.FORALL_AND_CONV,
Conv.LEFT_AND_FORALL_CONV,
Conv.RIGHT_AND_FORALL_CONV
ANTE_CONJ_CONV
ANTE_CONJ_CONV
Conv.ANTE_CONJ_CONV : conv
Eliminates a conjunctive antecedent in favour of implication.
When applied to a term of the form (t1 /\ t2) ==> t, the conversion
ANTE_CONJ_CONV returns the theorem:
|- (t1 /\ t2 ==> t) = (t1 ==> t2 ==> t)
Failure
Fails if applied to a term not of the form "(t1 /\ t2) ==> t".
Somewhat ad-hoc, but can be used (with CONV_TAC) to transform a goal
of the form ?- (P /\ Q) ==> R into the subgoal ?- P ==> (Q ==> R),
so that only the antecedent P is moved into the assumptions by
DISCH_TAC.
See also
Tactic.CONV_TAC,
Tactic.DISCH_TAC
BETA_RULE
BETA_RULE
Conv.BETA_RULE : (thm -> thm)
Beta-reduces all the beta-redexes in the conclusion of a theorem.
When applied to a theorem A |- t, the inference rule BETA_RULE
beta-reduces all beta-redexes, at any depth, in the conclusion t.
Variables are renamed where necessary to avoid free variable capture.
A |- ....((\x. s1) s2)....
---------------------------- BETA_RULE
A |- ....(s1[s2/x])....
Failure
Never fails, but will have no effect if there are no beta-redexes.
Example
The following example is a simple reduction which illustrates variable renaming:
> Globals.show_assums := true;
val it = (): unit
> local val tm = “f = ((\x y. x + y) y)”
in
val x = ASSUME tm
end;
val x = [f = (λx y. x + y) y] ⊢ f = (λx y. x + y) y: thm
> BETA_RULE x;
val it = [f = (λx y. x + y) y] ⊢ f = (λy'. y + y'): thm
See also
Thm.BETA_CONV,
Tactic.BETA_TAC,
PairedLambda.PAIRED_BETA_CONV,
Drule.RIGHT_BETA
BINDER_CONV
BINDER_CONV
Conv.BINDER_CONV : conv -> conv
Applies a conversion underneath a binder.
If conv N returns A |- N = P, then BINDER_CONV conv (M (\v.N))
returns A |- M (\v.N) = M (\v.P) and BINDER_CONV conv (\v.N) returns
A |- (\v.N) = (\v.P)
Failure
If conv N fails, or if v is free in A.
Example
> BINDER_CONV SYM_CONV (Term `\x. x + 0 = x`);
val it = ⊢ (λx. x + 0 = x) = (λx. x = x + 0): thm
Comments
For deeply nested quantifiers, STRIP_BINDER_CONV and
STRIP_QUANT_CONV are more efficient than iterated application of
BINDER_CONV, BINDER_CONV, or ABS_CONV.
See also
Conv.QUANT_CONV,
Conv.STRIP_QUANT_CONV,
Conv.STRIP_BINDER_CONV,
Conv.ABS_CONV
BINOP_CONV
BINOP_CONV
Conv.BINOP_CONV : conv -> conv
Applies a conversion to both arguments of a binary operator.
If c is a conversion that when applied to t1 returns the theorem
|- t1 = t1' and when applied to t2 returns the theorem
|- t2 = t2', then BINOP_CONV c (Term`f t1 t2`) will return the
theorem
|- f t1 t2 = f t1' t2'
Failure
BINOP_CONV c t will fail if t is not of the general form f t1 t2,
or if c fails when applied to either t1 or t2, or if c fails to
return theorems of the form |- t1 = t1' and |- t2 = t2' when applied
to those arguments. (The latter case would imply that c wasn't a
conversion at all.)
Example
> BINOP_CONV reduceLib.REDUCE_CONV (Term`3 * 4 + 6 * 7`);
val it = ⊢ 3 * 4 + 6 * 7 = 12 + 42: thm
See also
Conv.FORK_CONV,
Conv.LAND_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV,
numLib.REDUCE_CONV
bool_EQ_CONV
bool_EQ_CONV
Conv.bool_EQ_CONV : conv
Simplifies expressions involving boolean equality.
The conversion bool_EQ_CONV simplifies equations of the form
t1 = t2, where t1 and t2 are of type bool. When applied to a
term of the form t = t, the conversion bool_EQ_CONV returns the
theorem
|- (t = t) = T
When applied to a term of the form t = T, the conversion returns
|- (t = T) = t
And when applied to a term of the form T = t, it returns
|- (T = t) = t
Failure
Fails unless applied to a term of the form t1 = t2, where t1 and
t2 are boolean, and either t1 and t2 are syntactically identical
terms or one of t1 and t2 is the constant T.
Example
> bool_EQ_CONV (Parse.Term `T = F`);
val it = ⊢ (T ⇔ F) ⇔ F: thm
> bool_EQ_CONV (Parse.Term `(0 < n) = T`);
val it = ⊢ (0 < n ⇔ T) ⇔ 0 < n: thm
CHANGED_CONV
CHANGED_CONV
Conv.CHANGED_CONV : (conv -> conv)
Makes a conversion fail if applying it leaves a term unchanged.
If c is a conversion that maps a term ``t`` to a theorem
|- t = t', where t' is alpha-equivalent to t, or if c raises the
UNCHANGED exception when applied to ``t``, then
CHANGED_CONV c is a conversion that fails when applied to the term
``t``. If c maps ``t`` to |- t = t', where t' is
not alpha-equivalent to t, then CHANGED_CONV c also maps
``t`` to |- t = t'. That is, CHANGED_CONV c is the
conversion that behaves exactly like c, except that it fails whenever
the conversion c would leave its input term unchanged (up to
alpha-equivalence).
When CHANGED_CONV c t fails, it raises an exception HOL_ERR ..., not
UNCHANGED, since some enclosing functions handle the UNCHANGED
exception as though c had succeeded by returning the theorem
|- t = t.
Failure
CHANGED_CONV c ``t`` fails if c maps ``t`` to
|- t = t', where t' is alpha-equivalent to t, or if c raises the
UNCHANGED exception when applied to ``t``, or if c fails
when applied to ``t``. The function returned by CHANGED_CONV c
may also fail if the ML function c:term->thm is not, in fact, a
conversion (i.e. a function that maps a term t to a theorem
|- t = t').
CHANGED_CONV is used to transform a conversion that may leave terms
unchanged, and therefore may cause a nonterminating computation if
repeated, into one that can safely be repeated until application of it
fails to substantially modify its input term.
See also
Conv.UNCHANGED,
Conv.QCHANGED_CONV
COMB2_CONV
COMB2_CONV
Conv.COMB2_CONV : conv * conv -> conv
Applies two conversions to an application's subterms.
A call to COMB2_CONV(c1,c2) t, when t is an application term of the
form f x, causes conversion c1 to be applied to term f, and
conversion c2 to be applied to term x. If the results of these calls
are theorems of the form |- f = f’ and |- x = x’, then the result of
the call to COMB2_CONV is the theorem |- f x = f’ x’.
If one of the two sub-calls raises the UNCHANGED exception, then the
result of that call is taken to be the reflexive theorem (|- x = x if
c2 raises the exception, for example). If both conversions raise the
UNCHANGED exception, then so too does COMB2_CONV(c1,c2) t.
Failure
Fails if the term is not a combination term, or if either conversion fails when applied to the respective sub-terms.
Example
> COMB2_CONV (ALL_CONV, numLib.REDUCE_CONV) ``f (10 * 3)``;
<<HOL message: inventing new type variable names: 'a>>
val it = ⊢ f (10 * 3) = f 30: thm
See also
Conv.ABS_CONV, Conv.COMB_CONV,
Conv.FORK_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV
COMB_CONV
COMB_CONV
Conv.COMB_CONV : conv -> conv
Applies a conversion to both immediate sub-terms of an application.
If t is an application term of the form f x, and c is a
conversion, such that c maps f to |- f = f' and x to
|- x = x', then COMB_CONV c maps t to |- f x = f' x'.
If one of the two sub-calls raises the UNCHANGED exception, then the
result of that call is taken to be the reflexive theorem (|- x = x if
c x raises the exception, for example). If both conversions raise the
UNCHANGED exception, then so too does COMB_CONV c t.
Failure
COMB_CONV c t fails if t is not an application term, or if c fails
when applied to the rator and rand of t, or if c is not in fact a
conversion (i.e., a function which maps terms t to a theorem
|- t = t').
See also
Conv.ABS_CONV,
Conv.COMB2_CONV, Conv.SUB_CONV
COND_CONV
COND_CONV
Conv.COND_CONV : conv
Simplifies conditional terms.
The conversion COND_CONV simplifies a conditional term "c => u | v"
if the condition c is either the constant T or the constant F or
if the two terms u and v are equivalent up to alpha-conversion. The
theorems returned in these three cases have the forms:
|- (T => u | v) = u
|- (F => u | v) = u
|- (c => u | u) = u
Failure
COND_CONV tm fails if tm is not a conditional "c => u | v", where
c is T or F, or u and v are alpha-equivalent.
CONTRAPOS_CONV
CONTRAPOS_CONV
Conv.CONTRAPOS_CONV : conv
Proves the equivalence of an implication and its contrapositive.
When applied to an implication P ==> Q, the conversion
CONTRAPOS_CONV returns the theorem:
|- (P ==> Q) = (~Q ==> ~P)
Failure
Fails if applied to a term that is not an implication.
See also
CONV_RULE
CONV_RULE
Conv.CONV_RULE : (conv -> thm -> thm)
Makes an inference rule from a conversion.
If c is a conversion, then CONV_RULE c is an inference rule that
applies c to the conclusion of a theorem. That is, if c maps a term
"t" to the theorem |- t = t', then the rule CONV_RULE c infers
|- t' from the theorem |- t. More precisely, if c "t" returns
A' |- t = t', then:
A |- t
-------------- CONV_RULE c
A u A' |- t'
Note that if the conversion c returns a theorem with assumptions, then
the resulting inference rule adds these to the assumptions of the
theorem it returns.
If c raises UNCHANGED then CONV_RULE c th returns th.
Failure
CONV_RULE c th fails if c fails (other than by raising UNCHANGED)
when applied to the conclusion of th. The function returned by
CONV_RULE c will also fail if the ML function c:term->thm is not, in
fact, a conversion (i.e. a function that maps a term t to a theorem
|- t = t').
See also
Abbrev.conv, Conv.UNCHANGED,
Tactic.CONV_TAC,
Conv.HYP_CONV_RULE,
Conv.RIGHT_CONV_RULE
DEPTH_CONV
DEPTH_CONV
Conv.DEPTH_CONV : conv -> conv
Applies a conversion repeatedly to all the sub-terms of a term, in bottom-up order.
DEPTH_CONV c tm repeatedly applies the conversion c to all the
subterms of the term tm, including the term tm itself. The supplied
conversion is applied repeatedly (zero or more times, as is done by
REPEATC) to each subterm until it fails. The conversion is applied to
subterms in bottom-up order.
Failure
DEPTH_CONV c tm never fails but can diverge if the conversion c can
be applied repeatedly to some subterm of tm without failing.
Example
The following example shows how DEPTH_CONV applies a conversion to all
subterms to which it applies:
- DEPTH_CONV BETA_CONV (Term `(\x. (\y. y + x) 1) 2`);
> val it = |- (\x. (\y. y + x)1)2 = 1 + 2 : thm
Here, there are two beta-redexes in the input term, one of which occurs
within the other. DEPTH_CONV BETA_CONV applies beta-conversion to
innermost beta-redex (\y. y + x) 1 first. The outermost beta-redex is
then (\x. 1 + x) 2, and beta-conversion of this redex gives 1 + 2.
Because DEPTH_CONV applies a conversion bottom-up, the final result
may still contain subterms to which the supplied conversion applies. For
example, in:
- DEPTH_CONV BETA_CONV (Term `(\f x. (f x) + 1) (\y.y) 2`);
> val it = |- (\f x. (f x) + 1)(\y. y)2 = ((\y. y)2) + 1 : thm
the right-hand side of the result still contains a beta-redex, because
the redex (\y.y)2 is introduced by virtue of an application of
BETA_CONV higher-up in the structure of the input term. By contrast,
in the example:
- DEPTH_CONV BETA_CONV (Term `(\f x. (f x)) (\y.y) 2`);
> val it = |- (\f x. f x)(\y. y)2 = 2 : thm
all beta-redexes are eliminated, because DEPTH_CONV repeats the
supplied conversion (in this case, BETA_CONV) at each subterm (in this
case, at the top-level term).
If the conversion c implements the evaluation of a function in logic,
then DEPTH_CONV c will do bottom-up evaluation of nested applications
of it. For example, the conversion ADD_CONV implements addition of
natural number constants within the logic. Thus, the effect of:
- DEPTH_CONV reduceLib.ADD_CONV (Term `(1 + 2) + (3 + 4 + 5)`);
> val it = |- (1 + 2) + (3 + (4 + 5)) = 15 : thm
is to compute the sum represented by the input term.
Comments
The implementation of this function uses failure to avoid rebuilding
unchanged subterms. That is to say, during execution the exception
QConv.UNCHANGED may be generated and later trapped. The behaviour of
the function is dependent on this use of failure. So, if the conversion
given as an argument happens to generate the same exception, the
operation of DEPTH_CONV will be unpredictable.
See also
Conv.ONCE_DEPTH_CONV,
Conv.REDEPTH_CONV,
Conv.TOP_DEPTH_CONV
EVERY_CONJ_CONV
EVERY_CONJ_CONV
Conv.EVERY_CONJ_CONV : conv -> conv
Applies a conversion to every top-level conjunct in a term.
The term EVERY_CONJ_CONV c t takes the conversion c and applies this
to every top-level conjunct within term t. A top-level conjunct is a
sub-term that can be reached from the root of the term by breaking apart
only conjunctions. The terms affected by c are those that would be
returned by a call to strip_conj c. In particular, if the term as a
whole is not a conjunction, then the conversion will be applied to the
whole term.
If the result of the application of the conversion to one of the conjuncts is one of the constants true or false, then one of two standard rewrites is applied, simplifying the resulting term. If one of the conjuncts is converted to false, then the conversion will not be applied to the remaining conjuncts (the conjuncts are worked on from left to right), and the result of the whole application will simply be false. Alternatively, conjuncts that are converted to true will not appear in the final result at all.
Failure
Fails if the conversion argument fails when applied to one of the top-level conjuncts in a term.
Example
> EVERY_CONJ_CONV BETA_CONV (Term`(\x. x /\ y) p`);
val it = ⊢ (λx. x ∧ y) p ⇔ p ∧ y: thm
> EVERY_CONJ_CONV BETA_CONV (Term`(\y. y /\ p) q /\ (\z. z) r`);
val it = ⊢ (λy. y ∧ p) q ∧ (λz. z) r ⇔ (q ∧ p) ∧ r: thm
Useful for applying a conversion to all of the "significant" sub-terms within a term without having to worry about the exact structure of its conjunctive skeleton.
See also
Conv.EVERY_DISJ_CONV,
Conv.RATOR_CONV,
Conv.RAND_CONV, Conv.LAND_CONV
EVERY_CONV
EVERY_CONV
Conv.EVERY_CONV : (conv list -> conv)
Applies in sequence all the conversions in a given list of conversions.
EVERY_CONV [c1;...;cn] "t" returns the result of applying the
conversions c1, ..., cn in sequence to the term "t". The
conversions are applied in the order in which they are given in the
list. In particular, if ci "ti" returns |- ti=ti+1 for i from 1
to n, then EVERY_CONV [c1;...;cn] "t1" returns |- t1=t(n+1). If
the supplied list of conversions is empty, then EVERY_CONV returns the
identity conversion. That is, EVERY_CONV [] "t" raises UNCHANGED,
which indicates the result |- t=t.
Failure
EVERY_CONV [c1;...;cn] "t" fails if any one of the conversions c1,
..., cn fails (other than by raising UNCHANGED) when applied in
sequence as specified above.
See also
EVERY_DISJ_CONV
EVERY_DISJ_CONV
Conv.EVERY_DISJ_CONV : conv -> conv
Applies a conversion to every top-level disjunct in a term.
The term EVERY_DISJ_CONV c t takes the conversion c and applies this
to every top-level disjunct within term t. A top-level disjunct is a
sub-term that can be reached from the root of the term by breaking apart
only disjunctions. The terms affected by c are those that would be
returned by a call to strip_disj c. In particular, if the term as a
whole is not a disjunction, then the conversion will be applied to the
whole term.
If the result of the application of the conversion to one of the disjuncts is one of the constants true or false, then one of two standard rewrites is applied, simplifying the resulting term. If one of the disjuncts is converted to true, then the conversion will not be applied to the remaining disjuncts (the disjuncts are worked on from left to right), and the result of the whole application will simply be true. Alternatively, disjuncts that are converted to false will not appear in the final result at all.
Failure
Fails if the conversion argument fails when applied to one of the top-level disjuncts in the term.
Example
> EVERY_DISJ_CONV BETA_CONV
(Term`(\x. x /\ p) q \/ (\x. x) r \/ (\y. s /\ y) u`);
val it = ⊢ (λx. x ∧ p) q ∨ (λx. x) r ∨ (λy. s ∧ y) u ⇔ q ∧ p ∨ r ∨ s ∧ u: thm
> EVERY_DISJ_CONV reduceLib.REDUCE_CONV ``3 < x \/ 2 < 3 \/ 2 EXP 1000 < 10``;
val it = ⊢ 3 < x ∨ 2 < 3 ∨ 2 ** 1000 < 10 ⇔ T: thm
Useful for applying a conversion to all of the "significant" sub-terms within a term without having to worry about the exact structure of its disjunctive skeleton.
See also
Conv.EVERY_CONJ_CONV,
Conv.RATOR_CONV,
Conv.RAND_CONV,
Conv.LAND_CONV,
numLib.REDUCE_CONV
EXISTENCE
EXISTENCE
Conv.EXISTENCE : (thm -> thm)
Deduces existence from unique existence.
When applied to a theorem with a unique-existentially quantified
conclusion, EXISTENCE returns the same theorem with normal existential
quantification over the same variable.
A |- ?!x. p
------------- EXISTENCE
A |- ?x. p
Failure
Fails unless the conclusion of the theorem is unique-existentially quantified.
See also
EXISTS_AND_CONV
EXISTS_AND_CONV
Conv.EXISTS_AND_CONV : conv
Moves an existential quantification inwards through a conjunction.
When applied to a term of the form ?x. P /\ Q, where x is not free
in both P and Q, EXISTS_AND_CONV returns a theorem of one of three
forms, depending on occurrences of the variable x in P and Q. If
x is free in P but not in Q, then the theorem:
|- (?x. P /\ Q) = (?x.P) /\ Q
is returned. If x is free in Q but not in P, then the result is:
|- (?x. P /\ Q) = P /\ (?x.Q)
And if x is free in neither P nor Q, then the result is:
|- (?x. P /\ Q) = (?x.P) /\ (?x.Q)
Failure
EXISTS_AND_CONV fails if it is applied to a term not of the form
?x. P /\ Q, or if it is applied to a term ?x. P /\ Q in which the
variable x is free in both P and Q.
See also
Conv.AND_EXISTS_CONV,
Conv.EXISTS_AND_REORDER_CONV,
Conv.LEFT_AND_EXISTS_CONV,
Conv.RIGHT_AND_EXISTS_CONV
EXISTS_AND_REORDER_CONV
EXISTS_AND_REORDER_CONV
Conv.EXISTS_AND_REORDER_CONV : conv
Moves an existential quantification inwards through a conjunction, sorting the body.
When applied to a term of the form ?x. c1 /\ c2 /\ .. /\ cn, where x
is not free in at least one of the conjuncts ci, then
EXISTS_AND_REORDER_CONV returns a theorem of the form
|- (?x. ...) = (ci /\ cj /\ ck /\ ...) /\ (?x. cm /\ cn /\ cp /\ ...)
where the conjuncts ci, cj and ck do not have the bound variable
x free, and where the conjuncts cm, cn and cp do.
Failure
EXISTS_AND_REORDER_CONV fails if it is applied to a term that is not
an existential. It raises UNCHANGED if the existential's body is not a
conjunction, or if the body does not have any conjuncts where the bound
variable does not occur, or if none of the body's conjuncts have free
occurrences of the bound variable.
Comments
The conjuncts in the resulting term are kept in the same relative order
as in the input term, but will all be right-associated in the two groups
(because they are re-assembled with list_mk_conj), possibly destroying
structure that existed in the original.
See also
EXISTS_IMP_CONV
EXISTS_IMP_CONV
Conv.EXISTS_IMP_CONV : conv
Moves an existential quantification inwards through an implication.
When applied to a term of the form ?x. P ==> Q, where x is not free
in both P and Q, EXISTS_IMP_CONV returns a theorem of one of three
forms, depending on occurrences of the variable x in P and Q. If
x is free in P but not in Q, then the theorem:
|- (?x. P ==> Q) = (!x.P) ==> Q
is returned. If x is free in Q but not in P, then the result is:
|- (?x. P ==> Q) = P ==> (?x.Q)
And if x is free in neither P nor Q, then the result is:
|- (?x. P ==> Q) = (!x.P) ==> (?x.Q)
Failure
EXISTS_IMP_CONV fails if it is applied to a term not of the form
?x. P ==> Q, or if it is applied to a term ?x. P ==> Q in which the
variable x is free in both P and Q.
See also
Conv.LEFT_IMP_FORALL_CONV,
Conv.RIGHT_IMP_EXISTS_CONV
EXISTS_NOT_CONV
EXISTS_NOT_CONV
Conv.EXISTS_NOT_CONV : conv
Moves an existential quantification inwards through a negation.
When applied to a term of the form ?x.~P, the conversion
EXISTS_NOT_CONV returns the theorem:
|- (?x.~P) = ~(!x. P)
Failure
Fails if applied to a term not of the form ?x.~P.
See also
Conv.FORALL_NOT_CONV,
Conv.NOT_EXISTS_CONV,
Conv.NOT_FORALL_CONV
EXISTS_OR_CONV
EXISTS_OR_CONV
Conv.EXISTS_OR_CONV : conv
Moves an existential quantification inwards through a disjunction.
When applied to a term of the form ?x. P \/ Q, the conversion
EXISTS_OR_CONV returns the theorem:
|- (?x. P \/ Q) = (?x.P) \/ (?x.Q)
Failure
Fails if applied to a term not of the form ?x. P \/ Q.
See also
Conv.OR_EXISTS_CONV,
Conv.LEFT_OR_EXISTS_CONV,
Conv.RIGHT_OR_EXISTS_CONV
EXISTS_UNIQUE_CONV
EXISTS_UNIQUE_CONV
Conv.EXISTS_UNIQUE_CONV : conv
Expands with the definition of unique existence.
Given a term of the form "?!x.P[x]", the conversion
EXISTS_UNIQUE_CONV proves that this assertion is equivalent to the
conjunction of two statements, namely that there exists at least one
value x such that P[x], and that there is at most one value x for
which P[x] holds. The theorem returned is:
|- (?! x. P[x]) = (?x. P[x]) /\ (!x x'. P[x] /\ P[x'] ==> (x = x'))
where x' is a primed variant of x that does not appear free in the
input term. Note that the quantified variable x need not in fact
appear free in the body of the input term. For example,
EXISTS_UNIQUE_CONV "?!x.T" returns the theorem:
|- (?! x. T) = (?x. T) /\ (!x x'. T /\ T ==> (x = x'))
Failure
EXISTS_UNIQUE_CONV tm fails if tm does not have the form "?!x.P".
See also
FIRST_CONV
FIRST_CONV
Conv.FIRST_CONV : conv list -> conv
Apply the first of the conversions in a given list that succeeds.
FIRST_CONV [c1,...,cn] t returns the result of applying to the term
t the first conversion ci that succeeds (or raises UNCHANGED) when
applied to t. The conversions are tried in the order in which they are
given in the list.
Failure
FIRST_CONV [c1,...,cn] t fails if all the conversions c1, ..., cn
fail when applied to the term t. FIRST_CONV cs t also fails if cs
is the empty list.
See also
FORALL_AND_CONV
FORALL_AND_CONV
Conv.FORALL_AND_CONV : conv
Moves a universal quantification inwards through a conjunction.
When applied to a term of the form !x. P /\ Q, the conversion
FORALL_AND_CONV returns the theorem:
|- (!x. P /\ Q) = (!x.P) /\ (!x.Q)
Failure
Fails if applied to a term not of the form !x. P /\ Q.
See also
Conv.AND_FORALL_CONV,
Conv.LEFT_AND_FORALL_CONV,
Conv.RIGHT_AND_FORALL_CONV
FORALL_IMP_CONV
FORALL_IMP_CONV
Conv.FORALL_IMP_CONV : conv
Moves a universal quantification inwards through an implication.
When applied to a term of the form !x. P ==> Q, where x is not free
in both P and Q, FORALL_IMP_CONV returns a theorem of one of three
forms, depending on occurrences of the variable x in P and Q. If
x is free in P but not in Q, then the theorem:
|- (!x. P ==> Q) = (?x.P) ==> Q
is returned. If x is free in Q but not in P, then the result is:
|- (!x. P ==> Q) = P ==> (!x.Q)
And if x is free in neither P nor Q, then the result is:
|- (!x. P ==> Q) = (?x.P) ==> (!x.Q)
Failure
FORALL_IMP_CONV fails if it is applied to a term not of the form
!x. P ==> Q, or if it is applied to a term !x. P ==> Q in which the
variable x is free in both P and Q.
See also
Conv.LEFT_IMP_EXISTS_CONV,
Conv.RIGHT_IMP_FORALL_CONV
FORALL_NOT_CONV
FORALL_NOT_CONV
Conv.FORALL_NOT_CONV : conv
Moves a universal quantification inwards through a negation.
When applied to a term of the form !x.~P, the conversion
FORALL_NOT_CONV returns the theorem:
|- (!x.~P) = ~(?x. P)
Failure
Fails if applied to a term not of the form !x.~P.
See also
Conv.EXISTS_NOT_CONV,
Conv.NOT_EXISTS_CONV,
Conv.NOT_FORALL_CONV
FORALL_OR_CONV
FORALL_OR_CONV
Conv.FORALL_OR_CONV : conv
Moves a universal quantification inwards through a disjunction.
When applied to a term of the form !x. P \/ Q, where x is not free
in both P and Q, FORALL_OR_CONV returns a theorem of one of three
forms, depending on occurrences of the variable x in P and Q. If
x is free in P but not in Q, then the theorem:
|- (!x. P \/ Q) = (!x.P) \/ Q
is returned. If x is free in Q but not in P, then the result is:
|- (!x. P \/ Q) = P \/ (!x.Q)
And if x is free in neither P nor Q, then the result is:
|- (!x. P \/ Q) = (!x.P) \/ (!x.Q)
Failure
FORALL_OR_CONV fails if it is applied to a term not of the form
!x. P \/ Q, or if it is applied to a term !x. P \/ Q in which the
variable x is free in both P and Q.
See also
Conv.OR_FORALL_CONV,
Conv.LEFT_OR_FORALL_CONV,
Conv.RIGHT_OR_FORALL_CONV
FORK_CONV
FORK_CONV
Conv.FORK_CONV : (conv * conv) -> conv
Applies a pair of conversions to the arguments of a binary operator.
If the conversion c1 maps a term t1 to the theorem |- t1 = t1',
and the conversion c2 maps t2 to |- t2 = t2', then the conversion
FORK_CONV (c1,c2) maps terms of the form f t1 t2 to theorems of the
form |- f t1 t2 = f t1' t2'.
Failure
FORK_CONV (c1,c2) t will fail if t is not of the general form
f t1 t2, or if c1 fails when applied to t1, or if c2 fails when
applied to t2, or if c1 or c2 aren't really conversions, and
thereby fail to return appropriate equational theorems.
Example
> FORK_CONV (BETA_CONV,reduceLib.REDUCE_CONV) (Term`(\x. x + 1)y * (10 DIV 3)`);
val it = ⊢ (λx. x + 1) y * (10 DIV 3) = (y + 1) * 3: thm
See also
Conv.BINOP_CONV,
Conv.LAND_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV,
numLib.REDUCE_CONV
FUN_EQ_CONV
FUN_EQ_CONV
Conv.FUN_EQ_CONV : conv
Equates normal and extensional equality for two functions.
The conversion FUN_EQ_CONV embodies the fact that two functions are
equal precisely when they give the same results for all values to which
they can be applied. When supplied with a term argument of the form
f = g, where f and g are functions of type ty1->ty2,
FUN_EQ_CONV returns the theorem:
|- (f = g) = (!x. f x = g x)
where x is a variable of type ty1 chosen by the conversion.
Failure
FUN_EQ_CONV tm fails if tm is not an equation f = g, where f and
g are functions.
Used for proving equality of functions.
See also
GSYM
GSYM
Conv.GSYM : thm -> thm
Reverses the first equation(s) encountered in a top-down search.
The inference rule GSYM reverses the first equation(s) encountered in
a top-down search of the conclusion of the argument theorem. An equation
will be reversed iff it is not a proper subterm of another equation. If
a theorem contains no equations, it will be returned unchanged.
A |- ..(s1 = s2)...(t1 = t2)..
-------------------------------- GSYM
A |- ..(s2 = s1)...(t2 = t1)..
Failure
Never fails, and never loops infinitely.
Example
> arithmeticTheory.ADD;
val it = ⊢ (∀n. 0 + n = n) ∧ ∀m n. SUC m + n = SUC (m + n): thm
> GSYM arithmeticTheory.ADD;
val it = ⊢ (∀n. n = 0 + n) ∧ ∀m n. SUC (m + n) = SUC m + n: thm
See also
Drule.NOT_EQ_SYM, Thm.REFL,
Thm.SYM
HYP_CONV_RULE
HYP_CONV_RULE
Conv.HYP_CONV_RULE : (term -> bool) -> (conv -> thm -> thm)
Makes an inference rule by applying a conversion to hypotheses of a theorem.
If conv is a conversion, then HYP_CONV_RULE sel conv is an inference
rule that applies conv to those hypotheses of a theorem which are
selected by sel. That is, if conv maps a term "h" to the theorem
|- h = h', then the rule HYP_CONV_RULE sel conv infers A, h' |- c
from the theorem A, h |- c. More precisely, if conv "h" returns
A' |- h = h', then:
A, h |- c
---------------- HYP_CONV_RULE sel conv
A u A', h' |- c
Note that if the conversion conv returns a theorem with assumptions,
then the resulting inference rule adds these to the assumptions of the
theorem it returns.
Failure
HYP_CONV_RULE sel conv th fails if sel fails when applied to a
hypothesis of th, or if conv fails when applied to a hypothesis
selected by sel. The function returned by HYP_CONV_RULE sel conv
will also fail if the ML function conv:term->thm is not, in fact, a
conversion (i.e. a function that maps a term h to a theorem
|- h = h').
See also
Conv.CONV_RULE,
Tactic.CONV_TAC,
Conv.RIGHT_CONV_RULE
IFC
IFC
Conv.IFC : conv -> conv -> conv -> conv
Apply a conversion and branch to next conversion.
A call to IFC c1 c2 c3 t applies the conversion c1 to t. If this
application succeeds (or raises UNCHANGED) then c2 is applied next.
Otherwise, c3 is applied to t.
Failure
Fails when c1 succeeds and c2 fails, or when c1 fails and c3
fails.
Example
> IFC (RATOR_CONV BETA_CONV) BETA_CONV NO_CONV ``(\x y. x ==> y) T F``;
val it = |- T ==> F : thm
The first RATOR_CONV BETA_CONV succeeds and chains successfully with
the second BETA_CONV.
> IFC ALL_CONV BETA_CONV (RATOR_CONV BETA_CONV) ``(\x y. x ==> y) T F``;
Exception - BETA_CONV: not a beta redex
Although ALL_CONV succeeds, it does nothing, so BETA_CONV is not
applicable.
> IFC NO_CONV BETA_CONV (RATOR_CONV BETA_CONV) ``(\x y. x ==> y) T F``;
val it = |- (\y. T ==> y) F : thm
The NO_CONV fails, so RATOR_CONV BETA_CONV applies.
See also
LAND_CONV
LAND_CONV
Conv.LAND_CONV : conv -> conv
Applies a conversion to the left-hand argument of a binary operator.
If c is a conversion that maps a term t1 to the theorem
|- t1 = t1', then the conversion LAND_CONV c maps applications of
the form f t1 t2 to theorems of the form:
|- f t1 t2 = f t1' t2
Failure
LAND_CONV c tm fails if tm is not an application where the rator of
the application is in turn another application, as f t1 t2, or if tm
has this form but the conversion c fails when applied to the term
t1. The function returned by LAND_CONV c may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
Example
> LAND_CONV reduceLib.REDUCE_CONV (Term`(3 + 5) * 7`);
val it = ⊢ (3 + 5) * 7 = 8 * 7: thm
See also
Conv.ABS_CONV,
Conv.BINOP_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV,
numLib.REDUCE_CONV,
Conv.LHS_CONV
LAST_EXISTS_CONV
LAST_EXISTS_CONV
Conv.LAST_EXISTS_CONV : conv -> conv
Applies a conversion to the last existential quantifier (and its body) in a chain.
Application of LAST_EXISTS_CONV c to the term
``?x1 .. xn x. body`` will apply c to the term
``?x. body``. If the result of this application is the theorem
|- (?x. body) = t, then the result of the whole will be
|- (?x1 .. xn x. body) = (?x1 .. xn. t)
Failure
Fails if the term is not existentially quantified, or if the conversion
c fails when it is applied.
See also
Conv.BINDER_CONV,
Conv.LAST_FORALL_CONV,
Conv.STRIP_QUANT_CONV
LAST_FORALL_CONV
LAST_FORALL_CONV
Conv.LAST_FORALL_CONV : conv -> conv
Applies a conversion to the last universal quantifier (and its body) in a chain.
Application of LAST_FORALL_CONV v to the term
``!x1 .. xn x. body`` will apply c to the term
``!x. body``. If the result of this application is the theorem
|- (!x. body) = t, then the result of the whole will be
|- (?x1 .. xn x. body) = (?x1 .. xn. t)
Failure
Fails if the term is not universally quantified, or if the conversion
c fails when it is applied.
See also
Conv.BINDER_CONV,
Conv.LAST_EXISTS_CONV,
Conv.STRIP_QUANT_CONV
LEFT_AND_EXISTS_CONV
LEFT_AND_EXISTS_CONV
Conv.LEFT_AND_EXISTS_CONV : conv
Moves an existential quantification of the left conjunct outwards through a conjunction.
When applied to a term of the form (?x.P) /\ Q, the conversion
LEFT_AND_EXISTS_CONV returns the theorem:
|- (?x.P) /\ Q = (?x'. P[x'/x] /\ Q)
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (?x.P) /\ Q.
See also
Conv.AND_EXISTS_CONV,
Conv.EXISTS_AND_CONV,
Conv.RIGHT_AND_EXISTS_CONV
LEFT_AND_FORALL_CONV
LEFT_AND_FORALL_CONV
Conv.LEFT_AND_FORALL_CONV : conv
Moves a universal quantification of the left conjunct outwards through a conjunction.
When applied to a term of the form (!x.P) /\ Q, the conversion
LEFT_AND_FORALL_CONV returns the theorem:
|- (!x.P) /\ Q = (!x'. P[x'/x] /\ Q)
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (!x.P) /\ Q.
See also
Conv.AND_FORALL_CONV,
Conv.FORALL_AND_CONV,
Conv.RIGHT_AND_FORALL_CONV
LEFT_IMP_EXISTS_CONV
LEFT_IMP_EXISTS_CONV
Conv.LEFT_IMP_EXISTS_CONV : conv
Moves an existential quantification of the antecedent outwards through an implication.
When applied to a term of the form (?x.P) ==> Q, the conversion
LEFT_IMP_EXISTS_CONV returns the theorem:
|- (?x.P) ==> Q = (!x'. P[x'/x] ==> Q)
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (?x.P) ==> Q.
See also
Conv.FORALL_IMP_CONV,
Conv.RIGHT_IMP_FORALL_CONV
LEFT_IMP_FORALL_CONV
LEFT_IMP_FORALL_CONV
Conv.LEFT_IMP_FORALL_CONV : conv
Moves a universal quantification of the antecedent outwards through an implication.
When applied to a term of the form (!x.P) ==> Q, the conversion
LEFT_IMP_FORALL_CONV returns the theorem:
|- (!x.P) ==> Q = (?x'. P[x'/x] ==> Q)
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (!x.P) ==> Q.
See also
Conv.EXISTS_IMP_CONV,
Conv.RIGHT_IMP_FORALL_CONV
LEFT_OR_EXISTS_CONV
LEFT_OR_EXISTS_CONV
Conv.LEFT_OR_EXISTS_CONV : conv
Moves an existential quantification of the left disjunct outwards through a disjunction.
When applied to a term of the form (?x.P) \/ Q, the conversion
LEFT_OR_EXISTS_CONV returns the theorem:
|- (?x.P) \/ Q = (?x'. P[x'/x] \/ Q)
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (?x.P) \/ Q.
See also
Conv.EXISTS_OR_CONV,
Conv.OR_EXISTS_CONV,
Conv.RIGHT_OR_EXISTS_CONV
LEFT_OR_FORALL_CONV
LEFT_OR_FORALL_CONV
Conv.LEFT_OR_FORALL_CONV : conv
Moves a universal quantification of the left disjunct outwards through a disjunction.
When applied to a term of the form (!x.P) \/ Q, the conversion
LEFT_OR_FORALL_CONV returns the theorem:
|- (!x.P) \/ Q = (!x'. P[x'/x] \/ Q)
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (!x.P) \/ Q.
See also
Conv.OR_FORALL_CONV,
Conv.FORALL_OR_CONV,
Conv.RIGHT_OR_FORALL_CONV
LHS_CONV
LHS_CONV
Conv.LHS_CONV : conv -> conv
Applies a conversion to the left-hand argument of an equality.
If c is a conversion that maps a term t1 to the theorem
|- t1 = t1', then the conversion LHS_CONV c maps applications of the
form t1 = t2 to theorems of the form:
|- (t1 = t2) = (t1' = t2)
Failure
LHS_CONV c tm fails if tm is not an an equality t1 = t2, or if
tm has this form but the conversion c fails when applied to the term
t1. The function returned by LHS_CONV c may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
Example
> LHS_CONV reduceLib.REDUCE_CONV (Term`(3 + 5) = 7`);
val it = ⊢ 3 + 5 = 7 ⇔ 8 = 7: thm
Comments
LAND_CONV is similar, but works for any binary operator
See also
Conv.BINOP_CONV,
Conv.RHS_CONV,
numLib.REDUCE_CONV,
Conv.LAND_CONV
MP_CONV
MP_CONV
Conv.MP_CONV : conv -> conv
Eliminate the antecedent of a theorem using a conversion/proof rule.
If c is a conversion that when applied to P returns the theorem
|- P = T or |- P, and th is a theorem of the general form
|- P ==> Q, then MP_CONV c th will return the theorem |- Q,
i.e. the antecedent of th is eliminated by the conversion c. This is
done by calling MP on |- P ==> Q and |- P.
Failure
MP_CONV c th will fail if th is not of the form |- P ==> Q or if
c fails when applied to P.
Example
> load "realLib"; open realTheory realLib;
<<HOL message: inventing new type variable names: 'a>>
val it = (): unit
> MP_CONV REAL_ARITH (Q.SPEC `1` REAL_DOWN);
val it = ⊢ ∃y. 0 < y ∧ y < 1: thm
Comments
This conversion is ported from HOL-Light (drule.ml). MP_CONV is
useful when a universal theorem, after instantiating some of its
quantifiers, the antecedent becomes a tautology that can be eliminated
by a conversion.
See also
NO_CONV
NO_CONV
Conv.NO_CONV : conv
Conversion that always fails.
Failure
NO_CONV always fails.
See also
NOT_EXISTS_CONV
NOT_EXISTS_CONV
Conv.NOT_EXISTS_CONV : conv
Moves negation inwards through an existential quantification.
When applied to a term of the form ~(?x.P), the conversion
NOT_EXISTS_CONV returns the theorem:
|- ~(?x.P) = !x.~P
Failure
Fails if applied to a term not of the form ~(?x.P).
See also
Conv.EXISTS_NOT_CONV,
Conv.FORALL_NOT_CONV,
Conv.NOT_FORALL_CONV
NOT_FORALL_CONV
NOT_FORALL_CONV
Conv.NOT_FORALL_CONV : conv
Moves negation inwards through a universal quantification.
When applied to a term of the form ~(!x.P), the conversion
NOT_FORALL_CONV returns the theorem:
|- ~(!x.P) = ?x.~P
It is irrelevant whether x occurs free in P.
Failure
Fails if applied to a term not of the form ~(!x.P).
See also
Conv.EXISTS_NOT_CONV,
Conv.FORALL_NOT_CONV,
Conv.NOT_EXISTS_CONV
ONCE_DEPTH_CONV
ONCE_DEPTH_CONV
Conv.ONCE_DEPTH_CONV : (conv -> conv)
Applies a conversion once to the first suitable sub-term(s) encountered in top-down order.
ONCE_DEPTH_CONV c tm applies the conversion c once to the first
subterm or subterms encountered in a top-down 'parallel' search of the
term tm for which c succeeds. If the conversion c fails on all
subterms of tm, the theorem returned is |- tm = tm.
Failure
Never fails.
Example
The following example shows how ONCE_DEPTH_CONV applies a conversion
to only the first suitable subterm(s) found in a top-down search:
- ONCE_DEPTH_CONV BETA_CONV (Term `(\x. (\y. y + x) 1) 2`);
> val it = |- (\x. (\y. y + x)1)2 = (\y. y + 2) 1 : thm
Here, there are two beta-redexes in the input term. One of these occurs
within the other, so BETA_CONV is applied only to the outermost one.
Note that the supplied conversion is applied by ONCE_DEPTH_CONV to all
independent subterms at which it succeeds. That is, the conversion is
applied to every suitable subterm not contained in some other subterm
for which the conversions also succeeds, as illustrated by the following
example:
- ONCE_DEPTH_CONV numLib.num_CONV (Term `(\x. (\y. y + x) 1) 2`);
> val it = |- (\x. (\y. y + x)1)2 = (\x. (\y. y + x)(SUC 0))(SUC 1) : thm
Here num_CONV is applied to both 1 and 2, since neither term
occurs within a larger subterm for which the conversion num_CONV
succeeds.
ONCE_DEPTH_CONV is frequently used when there is only one subterm to
which the desired conversion applies. This can be much faster than using
other functions that attempt to apply a conversion to all subterms of a
term (e.g. DEPTH_CONV). If, for example, the current goal in a
goal-directed proof contains only one beta-redex, and one wishes to
apply BETA_CONV to it, then the tactic
CONV_TAC (ONCE_DEPTH_CONV BETA_CONV)
may, depending on where the beta-redex occurs, be much faster than
CONV_TAC (TOP_DEPTH_CONV BETA_CONV)
ONCE_DEPTH_CONV c may also be used when the supplied conversion c
never fails, in which case using a conversion such as DEPTH_CONV c,
which applies c repeatedly would never terminate.
Comments
The implementation of this function uses failure to avoid rebuilding
unchanged subterms. That is to say, during execution the exception
QConv.UNCHANGED may be generated and later trapped. The behaviour of
the function is dependent on this use of failure. So, if the conversion
given as an argument happens to generate the same exception, the
operation of ONCE_DEPTH_CONV will be unpredictable.
See also
Conv.DEPTH_CONV,
Conv.REDEPTH_CONV,
Conv.TOP_DEPTH_CONV
OR_EXISTS_CONV
OR_EXISTS_CONV
Conv.OR_EXISTS_CONV : conv
Moves an existential quantification outwards through a disjunction.
When applied to a term of the form (?x.P) \/ (?x.Q), the conversion
OR_EXISTS_CONV returns the theorem:
|- (?x.P) \/ (?x.Q) = (?x. P \/ Q)
Failure
Fails if applied to a term not of the form (?x.P) \/ (?x.Q).
See also
Conv.EXISTS_OR_CONV,
Conv.LEFT_OR_EXISTS_CONV,
Conv.RIGHT_OR_EXISTS_CONV
OR_FORALL_CONV
OR_FORALL_CONV
Conv.OR_FORALL_CONV : conv
Moves a universal quantification outwards through a disjunction.
When applied to a term of the form (!x.P) \/ (!x.Q), where x is free
in neither P nor Q, OR_FORALL_CONV returns the theorem:
|- (!x. P) \/ (!x. Q) = (!x. P \/ Q)
Failure
OR_FORALL_CONV fails if it is applied to a term not of the form
(!x.P) \/ (!x.Q), or if it is applied to a term (!x.P) \/ (!x.Q) in
which the variable x is free in either P or Q.
See also
Conv.FORALL_OR_CONV,
Conv.LEFT_OR_FORALL_CONV,
Conv.RIGHT_OR_FORALL_CONV
ORELSEC
ORELSEC
op Conv.ORELSEC : (conv -> conv -> conv)
Applies the first of two conversions that succeeds.
(c1 ORELSEC c2) ``t`` returns the result of applying the
conversion c1 to the term ``t`` if this succeeds. Otherwise
(c1 ORELSEC c2) ``t`` returns the result of applying the
conversion c2 to the term ``t``. If either conversion raises
the UNCHANGED exception when applied, this is passed on to ORELSEC's
caller.
Failure
(c1 ORELSEC c2) ``t`` fails if both c1 and c2 fail when
applied to ``t``. (This refers to failure other than by raising
UNCHANGED).
See also
Conv.UNCHANGED,
Conv.FIRST_CONV
PAT_CONV
PAT_CONV
Conv.PAT_CONV : term -> conv -> conv
Applies a conversion at specific sub-terms, following a pattern
The call PAT_CONV ``\x1 ... xn. t[x1,...,xn]`` cnv returns a new
conversion that applies cnv to subterms of the target term
corresponding to the free instances of any xi in the pattern
t[x1,...,xn]. The fact that the pattern is a function has no logical
significance; it is just used as a convenient format for the pattern.
Failure
Never fails until applied to a term, but then it may fail if the core conversion does on the chosen subterms, or if the pattern doesn't match the structure of the term.
Example
Here we choose to evaluate just two subterms:
> PAT_CONV ``\x. x + a + x`` numLib.REDUCE_CONV
``(1 + 2) + (3 + 4) + (5 + 6)``;
val it : thm = |- 1 + 2 + (3 + 4) + (5 + 6) = 3 + (3 + 4) + 11
while here we swap two particular quantifiers in a long chain:
> PAT_CONV ``\x. !x1 x2 x3 x4 x5. x`` SWAP_FORALL_CONV
``!a b c d e f g h. something``
<<HOL message: inventing new type variable names: ...>>
val it =
|- (!a b c d e f g h. something) <=>
!a b c d e g f h. something: thm
Comments
Multiple bound variables will only be necessary if the conversion needs to be applied to sub-terms of different types.
See also
Conv.ABS_CONV, Conv.COMB_CONV,
Conv.PATH_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV, Conv.SUB_CONV
PATH_CONV
PATH_CONV
Conv.PATH_CONV : string -> conv -> conv
Applies a conversion to the subterm indicated by a path string.
A call to PATH_CONV p c returns a new conversion that applies c to
the subterm of a term identified by the path string p. This path
string is interpreted as a sequence of direction indications: "a":
take the body of an abstraction; "b": take the body of an abstraction
or binder (such as universal or existential quantification); "l": take
the left (rator) path in an application; "r": take the right (rand)
path in an application.
Failure
The call to the path string and conversion fails if the provided string
includes characters other than a, b, l or r. When applied to a
term the resulting conversion will fail if the path is not meaningful or
if the conversion itself fails on the indicated subterm.
Example
> PATH_CONV "lrr" numLib.REDUCE_CONV ``(1 + 2) + (3 + 4) + (5 + 6)``;
val it = ⊢ 1 + 2 + (3 + 4) + (5 + 6) = 1 + 2 + 7 + (5 + 6): thm
> PATH_CONV "br" numLib.REDUCE_CONV ``!x. x > 10 + 3``;
val it = ⊢ (∀x. x > 10 + 3) ⇔ ∀x. x > 13: thm
Comments
This function provides a more concise indication of sub-conversion
application than by composing RATOR_CONV, RAND_CONV and ABS_CONV.
See also
Conv.ABS_CONV,
Conv.BINDER_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV
QCHANGED_CONV
QCHANGED_CONV
Conv.QCHANGED_CONV : conv -> conv
Makes a conversion fail if applying it raises the UNCHANGED exception.
If c is a conversion that maps a term t to a theorem |- t = t',
then so too is QCHANGED_CONV c. If c applied to t raises the
special UNCHANGED exception used by conversions to indicate that they
haven't changed an input, then QCHANGED_CONV c will fail, raising a
different exception HOL_ERR ... when applied to t.
The purpose of this is that some enclosing functions handle the
UNCHANGED exception as though c had succeeded by returning the
theorem |- t = t.
This behaviour is similar to that of CHANGED_CONV, except that that
conversion also fails if the conversion c returns a theorem when
applied to t, and if that theorem has alpha-convertible left and right
hand sides.
Failure
QCHANGED_CONV c t fails (other than by raising UNCHANGED) if c
applied t raises the UNCHANGED exception, or if c fails otherwise
when applied to t.
QCHANGED_CONV can be used in places where CHANGED_CONV is
appropriate, and where one knows that the conversion argument will not
return an instance of reflexivity, or if one does not mind this
occurring and not being trapped. Because it is no more than an exception
handler, QCHANGED_CONV is very efficient.
See also
Conv.UNCHANGED,
Conv.CHANGED_CONV
QCONV
QCONV
Conv.QCONV : conv -> conv
Stops a conversion raising the UNCHANGED exception.
If conversion c applied to term t raises the UNCHANGED exception,
then QCONV c t instead returns the theorem |- t = t.
Failure
QCONV c t fails if the application of c to t fails.
See also
Conv.UNCHANGED,
Conv.CHANGED_CONV,
Conv.QCHANGED_CONV
QUANT_CONV
QUANT_CONV
Conv.QUANT_CONV : conv -> conv
Applies a conversion underneath a quantifier.
If conv N returns A |- N = P, then QUANT_CONV conv (M (\v.N))
returns A |- M (\v.N) = M (\v.P).
Failure
If conv N fails, or if v is free in A.
Example
> QUANT_CONV SYM_CONV (Term `!x. x + 0 = x`);
val it = ⊢ (∀x. x + 0 = x) ⇔ ∀x. x = x + 0: thm
Comments
For deeply nested quantifiers, STRIP_QUANT_CONV and
STRIP_BINDER_CONV are more efficient than iterated application of
QUANT_CONV, BINDER_CONV, or ABS_CONV.
See also
Conv.BINDER_CONV,
Conv.STRIP_QUANT_CONV,
Conv.STRIP_BINDER_CONV,
Conv.ABS_CONV
RAND_CONV
RAND_CONV
Conv.RAND_CONV : (conv -> conv)
Applies a conversion to the operand of an application.
If c is a conversion that maps a term "t2" to the theorem
|- t2 = t2', then the conversion RAND_CONV c maps applications of
the form "t1 t2" to theorems of the form:
|- (t1 t2) = (t1 t2')
That is, RAND_CONV c "t1 t2" applies c to the operand of the
application "t1 t2".
Failure
RAND_CONV c tm fails if tm is not an application or if tm has the
form "t1 t2" but the conversion c fails when applied to the term
t2. The function returned by RAND_CONV c may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
Example
> RAND_CONV numLib.num_CONV (Term `SUC 2`);
val it = ⊢ SUC 2 = SUC (SUC 1): thm
See also
Conv.ABS_CONV,
Conv.BINOP_CONV,
Conv.LAND_CONV,
Conv.RATOR_CONV,
Conv.SUB_CONV, Conv.RHS_CONV
RATOR_CONV
RATOR_CONV
Conv.RATOR_CONV : (conv -> conv)
Applies a conversion to the operator of an application.
If c is a conversion that maps a term "t1" to the theorem
|- t1 = t1', then the conversion RATOR_CONV c maps applications of
the form "t1 t2" to theorems of the form:
|- (t1 t2) = (t1' t2)
That is, RATOR_CONV c "t1 t2" applies c to the operand of the
application "t1 t2".
Failure
RATOR_CONV c tm fails if tm is not an application or if tm has the
form "t1 t2" but the conversion c fails when applied to the term
t1. The function returned by RATOR_CONV c may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
Example
> RATOR_CONV BETA_CONV (Term `(\x y. x + y) 1 2`);
val it = ⊢ (λx y. x + y) 1 2 = (λy. 1 + y) 2: thm
See also
Conv.ABS_CONV, Conv.RAND_CONV,
Conv.SUB_CONV
REDEPTH_CONV
REDEPTH_CONV
Conv.REDEPTH_CONV : (conv -> conv)
Applies a conversion bottom-up to all subterms, retraversing changed ones.
REDEPTH_CONV c tm applies the conversion c repeatedly to all
subterms of the term tm and recursively applies REDEPTH_CONV c to
each subterm at which c succeeds, until there is no subterm remaining
for which application of c succeeds.
More precisely, REDEPTH_CONV c tm repeatedly applies the conversion
c to all the subterms of the term tm, including the term tm
itself. The supplied conversion c is applied to the subterms of tm
in bottom-up order and is applied repeatedly (zero or more times, as is
done by REPEATC) to each subterm until it fails. If c is
successfully applied at least once to a subterm, t say, then the term
into which t is transformed is retraversed by applying
REDEPTH_CONV c to it.
Failure
REDEPTH_CONV c tm never fails but can diverge if the conversion c
can be applied repeatedly to some subterm of tm without failing.
Example
The following example shows how REDEPTH_CONV retraverses subterms:
- REDEPTH_CONV BETA_CONV (Term `(\f x. (f x) + 1) (\y.y) 2`);
val it = |- (\f x. (f x) + 1)(\y. y)2 = 2 + 1 : thm
Here, BETA_CONV is first applied successfully to the (beta-redex)
subterm:
(\f x. (f x) + 1) (\y.y)
This application reduces this subterm to:
(\x. ((\y.y) x) + 1)
REDEPTH_CONV BETA_CONV is then recursively applied to this transformed
subterm, eventually reducing it to (\x. x + 1). Finally, a
beta-reduction of the top-level term, now the simplified beta-redex
(\x. x + 1) 2, produces 2 + 1.
Comments
The implementation of this function uses failure to avoid rebuilding
unchanged subterms. That is to say, during execution the exception
QConv.UNCHANGED may be generated and later trapped. The behaviour of
the function is dependent on this use of failure. So, if the conversion
given as an argument happens to generate the same exception, the
operation of REDEPTH_CONV will be unpredictable.
See also
Conv.DEPTH_CONV,
Conv.ONCE_DEPTH_CONV,
Conv.TOP_DEPTH_CONV
RENAME_VARS_CONV
RENAME_VARS_CONV
Conv.RENAME_VARS_CONV : string list -> conv
Renames variables underneath a binder.
RENAME_VARS_CONV takes a list of strings specifying new names for
variables under a binder. More precisely, it will rename variables in
abstractions, or bound by universal, existential, unique existence or
the select (or Hilbert-choice) "quantifier".
More than one variable can be renamed at once. If variables occur past the first, then the renaming continues on the appropriate sub-term of the first. (That is, if the term is an abstraction, then renaming will continue on the body of the abstraction. If it is one of the supported quantifiers, then renaming will continue on the body of the abstraction that is the argument of the "binder constant".)
If RENAME_VARS_CONV is passed the empty list, it is equivalent to
ALL_CONV. The binders do not need to be of the same type all the way
into the term.
Failure
Fails if an attempt is made to rename a variable in a term that is not an abstraction, or is not one of the accepted quantifiers. Also fails if all of the names in the list are not distinct.
Example
> RENAME_VARS_CONV ["a", "b"] ``\x y. x /\ y``;
val it = ⊢ (λx y. x ∧ y) = (λa b. a ∧ b): thm
> RENAME_VARS_CONV ["a", "b"] ``!x:'a y. P x /\ P y``;
val it = ⊢ (∀x y. P x ∧ P y) ⇔ ∀a b. P a ∧ P b: thm
> RENAME_VARS_CONV ["a", "b"] ``!x:'a. ?y. P x /\ P y``;
val it = ⊢ (∀x. ∃y. P x ∧ P y) ⇔ ∀a. ∃b. P a ∧ P b: thm
Post-processing mangling of names in code implementing derived logical procedures to make names look more appropriate. Changing names can only affect the presentation of terms, not their semantics.
See also
REPEATC
REPEATC
Conv.REPEATC : conv -> conv
Repeatedly apply a conversion (zero or more times) until it fails.
If c is a conversion effects a transformation of a term t to a term
t', that is if c maps t to the theorem |- t = t`, then
REPEATC c is the conversion that repeats this transformation as often
as possible. More exactly, if c maps the term ``ti`` to
|- ti=t(i+1) for i from 1 to n, but fails when applied to the
n+1th term ``t(n+1)``, then REPEATC c ``t1`` returns
|- t1 = t(n+1). And if c ``t`` fails, them
REPEATC c ``t`` returns |- t = t.
Further, if c ``t`` raises the UNCHANGED exception, then
REPEATC c ``t`` also raises the same exception (rather than go
into an infinite loop).
Failure
Never fails, but can diverge if the supplied conversion never fails.
RESORT_EXISTS_CONV
RESORT_EXISTS_CONV
Conv.RESORT_EXISTS_CONV : (term list -> term list) -> conv
Reorders bound variables under existential quantifiers.
A call to RESORT_EXISTS_CONV f t strips the outer
existentially-quantified variables of t, giving a list vs, such that
t is of the form ?vs. body. The list vs is then passed to the
function argument f. The result of the call f vs is expected to be a
new list of variables vs', and the result of the conversion is the
theorem
|- (?vs. body) <=> (?vs'. body)
The function f is generally expected to return a permutation of the
variables appearing in the term vs, but may in fact introduce fresh
variables that are fresh for body, and may also remove variables from
vs that also don't appear in body.
Failure
Given a term t, fails if t is not of boolean type. Fails if when
applied to the outermost existentially quantified variables (permitted
to be the empty list) the function f returns a list of terms that are
not all variables. Also fails if either f returns a list that does not
include variables from vs that appear in the body of t, or if it
includes variables that are in the body, but which were not originally
bound.
See also
Conv.RESORT_FORALL_CONV,
HolKernel.sort_vars
RESORT_FORALL_CONV
RESORT_FORALL_CONV
Conv.RESORT_FORALL_CONV : (term list -> term list) -> conv
Reorders bound variables under universal quantifiers.
A call to RESORT_FORALL_CONV f t strips the outer
universally-quantified variables of t, giving a list vs, such that
t is of the form !vs. body. The list vs is then passed to the
function argument f. The result of the call f vs is expected to be a
new list of variables vs', and the result of the conversion is the
theorem
|- (!vs. body) <=> (!vs'. body)
The function f is generally expected to return a permutation of the
variables appearing in the term vs, but may in fact introduce fresh
variables that are fresh for body, and may also remove variables from
vs that also don't appear in body.
Failure
Given a term t, fails if t is not of boolean type. Fails if when
applied to the outermost universally quantified variables (permitted to
be the empty list) the function f returns a list of terms that are not
all variables. Also fails if either f returns a list that does not
include variables from vs that appear in the body of t, or if it
includes variables that are in the body, but which were not originally
bound.
See also
Conv.RESORT_EXISTS_CONV,
HolKernel.sort_vars
REWR_CONV
REWR_CONV
Conv.REWR_CONV : (thm -> conv)
Uses an instance of a given equation to rewrite a term.
REWR_CONV is one of the basic building blocks for the implementation
of rewriting in the HOL system. In particular, the term replacement or
rewriting done by all the built-in rewriting rules and tactics is
ultimately done by applications of REWR_CONV to appropriate subterms.
The description given here for REWR_CONV may therefore be taken as a
specification of the atomic action of replacing equals by equals that is
used in all these higher level rewriting tools.
The first argument to REWR_CONV is expected to be an equational
theorem which is to be used as a left-to-right rewrite rule. The general
form of this theorem is:
A |- t[x1,...,xn] = u[x1,...,xn]
where x1, ..., xn are all the variables that occur free in the
left-hand side of the conclusion of the theorem but do not occur free in
the assumptions. Any of these variables may also be universally
quantified at the outermost level of the equation, as for example in:
A |- !x1...xn. t[x1,...,xn] = u[x1,...,xn]
Note that REWR_CONV will also work, but will give a generally
undesirable result (see below), if the right-hand side of the equation
contains free variables that do not also occur free on the left-hand
side, as for example in:
A |- t[x1,...,xn] = u[x1,...,xn,y1,...,ym]
where the variables y1, ..., ym do not occur free in t[x1,...,xn].
If th is an equational theorem of the kind shown above, then
REWR_CONV th returns a conversion that maps terms of the form
t[e1,...,en/x1,...,xn], in which the terms e1, ..., en are free
for x1, ..., xn in t, to theorems of the form:
A |- t[e1,...,en/x1,...,xn] = u[e1,...,en/x1,...,xn]
That is, REWR_CONV th tm attempts to match the left-hand side of the
rewrite rule th to the term tm. If such a match is possible, then
REWR_CONV returns the corresponding substitution instance of th.
If REWR_CONV is given a theorem th:
A |- t[x1,...,xn] = u[x1,...,xn,y1,...,ym]
where the variables y1, ..., ym do not occur free in the left-hand
side, then the result of applying the conversion REWR_CONV th to a
term t[e1,...,en/x1,...,xn] will be:
A |- t[e1,...,en/x1,...,xn] = u[e1,...,en,v1,...,vm/x1,...,xn,y1,...,ym]
where v1, ..., vm are variables chosen so as to be free nowhere in
th or in the input term. The user has no control over the choice of
the variables v1, ..., vm, and the variables actually chosen may
well be inconvenient for other purposes. This situation is, however,
relatively rare; in most equations the free variables on the right-hand
side are a subset of the free variables on the left-hand side.
In addition to doing substitution for free variables in the supplied
equational theorem (or 'rewrite rule'), REWR_CONV th tm also does type
instantiation, if this is necessary in order to match the left-hand side
of the given rewrite rule th to the term argument tm. If, for
example, th is the theorem:
A |- t[x1,...,xn] = u[x1,...,xn]
and the input term tm is (a substitution instance of) an instance of
t[x1,...,xn] in which the types ty1, ..., tyi are substituted for
the type variables vty1, ..., vtyi, that is if:
tm = t[ty1,...,tyn/vty1,...,vtyn][e1,...,en/x1,...,xn]
then REWR_CONV th tm returns:
A |- (t = u)[ty1,...,tyn/vty1,...,vtyn][e1,...,en/x1,...,xn]
Note that, in this case, the type variables vty1, ..., vtyi must not
occur anywhere in the hypotheses A. Otherwise, the conversion will
fail.
Failure
REWR_CONV th fails if th is not an equation or an equation
universally quantified at the outermost level. If th is such an
equation:
th = A |- !v1....vi. t[x1,...,xn] = u[x1,...,xn,y1,...,yn]
then REWR_CONV th tm fails unless the term tm is alpha-equivalent to
an instance of the left-hand side t[x1,...,xn] which can be obtained
by instantiation of free type variables (i.e. type variables not
occurring in the assumptions A) and substitution for the free
variables x1, ..., xn.
As noted, REWR_CONV th will fail rather than substitute for variables
or type variables which appear in the hypotheses A. To allow
substitution in the hypotheses, use REWR_CONV_A th.
Example
The following example illustrates a straightforward use of REWR_CONV.
The supplied rewrite rule is polymorphic, and both substitution for free
variables and type instantiation may take place. EQ_SYM_EQ is the
theorem:
|- !x:'a. !y. (x = y) = (y = x)
and REWR_CONV EQ_SYM_EQ behaves as follows:
- REWR_CONV EQ_SYM_EQ (Term `1 = 2`);
> val it = |- (1 = 2) = (2 = 1) : thm
- REWR_CONV EQ_SYM_EQ (Term `1 < 2`);
! Uncaught exception:
! HOL_ERR
The second application fails because the left-hand side x = y of the
rewrite rule does not match the term to be rewritten, namely 1 < 2.
In the following example, one might expect the result to be the theorem
A |- f 2 = 2, where A is the assumption of the supplied rewrite
rule:
- REWR_CONV (ASSUME (Term `!x:'a. f x = x`)) (Term `f 2:num`);
! Uncaught exception:
! HOL_ERR
The application fails, however, because the type variable 'a appears
in the assumption of the theorem returned by
ASSUME (Term `!x:'a. f x = x`).
Failure will also occur in situations like:
- REWR_CONV (ASSUME (Term `f (n:num) = n`)) (Term `f 2:num`);
! Uncaught exception:
! HOL_ERR
where the left-hand side of the supplied equation contains a free
variable (in this case n) which is also free in the assumptions, but
which must be instantiated in order to match the input term.
See also
Conv.REWR_CONV_A,
Rewrite.REWRITE_CONV
REWR_CONV_A
REWR_CONV_A
Conv.REWR_CONV_A : (thm -> conv)
Uses an instance of a given equation to rewrite a term.
REWR_CONV_A th behaves as REWR_CONV th except that it allows
substitution of variables or type variables which appear in the
hypotheses of th.
Example
Consider the theorem th
[0 < n] |- (a * n = b * (n : int)) <=> (a = b)
and the term tm
f (a * m = b * (m : int)) x
Then DEPTH_CONV (REWR_CONV_A th) tm returns
[0 < m] |- f (a * m = b * m) x <=> f (a = b) x
Likewise, when the goal is tm above,
e (VALIDATE (CONV_TAC (DEPTH_CONV (REWR_CONV_A th)))) gives the two
subgoals:
f (a = b) x
0 < m
See also
Conv.REWR_CONV,
Rewrite.REWRITE_CONV,
Conv.DEPTH_CONV,
Tactic.CONV_TAC,
Tactical.VALIDATE
RHS_CONV
RHS_CONV
Conv.RHS_CONV : conv -> conv
Applies a conversion to the right-hand argument of an equality.
If c is a conversion that maps a term t2 to the theorem
|- t2 = t2', then the conversion RHS_CONV c maps applications of the
form t1 = t2 to theorems of the form:
|- (t1 = t2) = (t1 = t2')
Failure
RHS_CONV c tm fails if tm is not an an equality t1 = t2, or if
tm has this form but the conversion c fails when applied to the term
t2. The function returned by RHS_CONV c may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
Example
> RHS_CONV reduceLib.REDUCE_CONV (Term`7 = (3 + 5)`);
val it = ⊢ 7 = 3 + 5 ⇔ 7 = 8: thm
Comments
RAND_CONV is similar, but works for any binary operator
See also
Conv.BINOP_CONV,
Conv.LHS_CONV,
numLib.REDUCE_CONV,
Conv.RAND_CONV
RIGHT_AND_EXISTS_CONV
RIGHT_AND_EXISTS_CONV
Conv.RIGHT_AND_EXISTS_CONV : conv
Moves an existential quantification of the right conjunct outwards through a conjunction.
When applied to a term of the form P /\ (?x.Q), the conversion
RIGHT_AND_EXISTS_CONV returns the theorem:
|- P /\ (?x.Q) = (?x'. P /\ (Q[x'/x]))
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form P /\ (?x.Q).
See also
Conv.AND_EXISTS_CONV,
Conv.EXISTS_AND_CONV,
Conv.LEFT_AND_EXISTS_CONV
RIGHT_AND_FORALL_CONV
RIGHT_AND_FORALL_CONV
Conv.RIGHT_AND_FORALL_CONV : conv
Moves a universal quantification of the right conjunct outwards through a conjunction.
When applied to a term of the form P /\ (!x.Q), the conversion
RIGHT_AND_FORALL_CONV returns the theorem:
|- P /\ (!x.Q) = (!x'. P /\ (Q[x'/x]))
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form P /\ (!x.Q).
See also
Conv.AND_FORALL_CONV,
Conv.FORALL_AND_CONV,
Conv.LEFT_AND_FORALL_CONV
RIGHT_CONV_RULE
RIGHT_CONV_RULE
Conv.RIGHT_CONV_RULE : (conv -> thm -> thm)
Applies a conversion to the right-hand side of an equational theorem.
If c is a conversion that maps a term "t2" to the theorem
|- t2 = t2', then the rule RIGHT_CONV_RULE c infers |- t1 = t2'
from the theorem |- t1 = t2. That is, if c "t2" returns
A' |- t2 = t2', then:
A |- t1 = t2
--------------------- RIGHT_CONV_RULE c
A u A' |- t1 = t2'
Note that if the conversion c returns a theorem with assumptions, then
the resulting inference rule adds these to the assumptions of the
theorem it returns.
Failure
RIGHT_CONV_RULE c th fails if the conclusion of the theorem th is
not an equation, or if th is an equation but c fails when applied
its right-hand side. The function returned by RIGHT_CONV_RULE c will
also fail if the ML function c:term->thm is not, in fact, a conversion
(i.e. a function that maps a term t to a theorem |- t = t').
See also
RIGHT_IMP_EXISTS_CONV
RIGHT_IMP_EXISTS_CONV
Conv.RIGHT_IMP_EXISTS_CONV : conv
Moves an existential quantification of the consequent outwards through an implication.
When applied to a term of the form P ==> (?x.Q), the conversion
RIGHT_IMP_EXISTS_CONV returns the theorem:
|- P ==> (?x.Q) = (?x'. P ==> (Q[x'/x]))
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form P ==> (?x.Q).
See also
Conv.EXISTS_IMP_CONV,
Conv.LEFT_IMP_FORALL_CONV
RIGHT_IMP_FORALL_CONV
RIGHT_IMP_FORALL_CONV
Conv.RIGHT_IMP_FORALL_CONV : conv
Moves a universal quantification of the consequent outwards through an implication.
When applied to a term of the form P ==> (!x.Q), the conversion
RIGHT_IMP_FORALL_CONV returns the theorem:
|- P ==> (!x.Q) = (!x'. P ==> (Q[x'/x]))
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form P ==> (!x.Q).
See also
Conv.FORALL_IMP_CONV,
Conv.LEFT_IMP_EXISTS_CONV
RIGHT_OR_EXISTS_CONV
RIGHT_OR_EXISTS_CONV
Conv.RIGHT_OR_EXISTS_CONV : conv
Moves an existential quantification of the right disjunct outwards through a disjunction.
When applied to a term of the form P \/ (?x.Q), the conversion
RIGHT_OR_EXISTS_CONV returns the theorem:
|- P \/ (?x.Q) = (?x'. P \/ (Q[x'/x]))
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form P \/ (?x.Q).
See also
Conv.OR_EXISTS_CONV,
Conv.EXISTS_OR_CONV,
Conv.LEFT_OR_EXISTS_CONV
RIGHT_OR_FORALL_CONV
RIGHT_OR_FORALL_CONV
Conv.RIGHT_OR_FORALL_CONV : conv
Moves a universal quantification of the right disjunct outwards through a disjunction.
When applied to a term of the form P \/ (!x.Q), the conversion
RIGHT_OR_FORALL_CONV returns the theorem:
|- P \/ (!x.Q) = (!x'. P \/ (Q[x'/x]))
where x' is a primed variant of x that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form P \/ (!x.Q).
See also
Conv.OR_FORALL_CONV,
Conv.FORALL_OR_CONV,
Conv.LEFT_OR_FORALL_CONV
SELECT_CONV
SELECT_CONV
Conv.SELECT_CONV : conv
Eliminates an epsilon term by introducing an existential quantifier.
The conversion SELECT_CONV expects a boolean term of the form
P[@x.P[x]/x], which asserts that the epsilon term @x.P[x] denotes a
value, x say, for which P[x] holds. This assertion is equivalent to
saying that there exists such a value, and SELECT_CONV applied to a
term of this form returns the theorem |- P[@x.P[x]/x] = ?x. P[x].
Failure
Fails if applied to a term that is not of the form P[@x.P[x]/x].
Example
SELECT_CONV (Term `(@n. n < m) < m`);
val it = |- (@n. n < m) < m = (?n. n < m) : thm
Particularly useful in conjunction with CONV_TAC for proving
properties of values denoted by epsilon terms. For example, suppose that
one wishes to prove the goal
([0 < m], (@n. n < m) < SUC m)
Using the built-in arithmetic theorem
LESS_SUC |- !m n. m < n ==> m < (SUC n)
this goal may be reduced by the tactic MATCH_MP_TAC LESS_SUC to the
subgoal
([0 < m], (@n. n < m) < m)
This is now in the correct form for using CONV_TAC SELECT_CONV to
eliminate the epsilon term, resulting in the existentially quantified
goal
([0 < m], ?n. n < m)
which is then straightforward to prove.
See also
Drule.SELECT_ELIM,
Drule.SELECT_INTRO,
Drule.SELECT_RULE
SKOLEM_CONV
SKOLEM_CONV
Conv.SKOLEM_CONV : conv
Proves the existence of a Skolem function.
When applied to an argument of the form !x1...xn. ?y. P, the
conversion SKOLEM_CONV returns the theorem:
|- (!x1...xn. ?y. P) = (?y'. !x1...xn. P[y' x1 ... xn/y])
where y' is a primed variant of y not free in the input term.
Failure
SKOLEM_CONV tm fails if tm is not a term of the form
!x1...xn. ?y. P.
See also
SPLICE_CONJ_CONV
SPLICE_CONJ_CONV
Conv.SPLICE_CONJ_CONV : conv
Partially normalize a conjunction.
Normalize to right associativity a conjunction without recursing in the right conjunct.
Failure
Fails if the user-provided term is not a conjunction.
Example
> SPLICE_CONJ_CONV ``(a1 /\ a2 /\ a3) /\ b /\ c``;
val it = ⊢ (a1 ∧ a2 ∧ a3) ∧ b ∧ c ⇔ a1 ∧ a2 ∧ a3 ∧ b ∧ c: thm
> SPLICE_CONJ_CONV ``(a1 /\ a2) /\ (b1 /\ b2) /\ c``;
val it = ⊢ (a1 ∧ a2) ∧ (b1 ∧ b2) ∧ c ⇔ a1 ∧ a2 ∧ (b1 ∧ b2) ∧ c: thm
STRIP_BINDER_CONV
STRIP_BINDER_CONV
Conv.STRIP_BINDER_CONV : term option -> conv -> conv
Applies a conversion underneath a binder prefix.
If the application of conv to M yields |- M = N, then
STRIP_BINDER_CONV (SOME c) conv (c(\v1. ... (c(\vn.M))...)) returns
|- c(\v1. ... (c(\vn.M))...) = c(\v1. ... (c(\vn.N))...) and
STRIP_BINDER_CONV NONE conv (\v1 ... vn.M) returns
|- (\v1 ... vn.M) = (\v1 ... vn.N).
Failure
If conv M fails. Also fails if some of [v1,...,vn] are free in the
hypotheses of conv M.
Example
> STRIP_BINDER_CONV NONE BETA_CONV (Term `\u v w. (\a. a + v * w) u`);
val it = ⊢ (λu v w. (λa. a + v * w) u) = (λu v w. u + v * w): thm
> STRIP_BINDER_CONV (SOME existential) SYM_CONV
(Term `?u v w x y. u + v = w + x + y`);
val it = ⊢ (∃u v w x y. u + v = w + x + y) ⇔ ∃u v w x y. w + x + y = u + v:
thm
Comments
STRIP_BINDER_CONV is more efficient than iterated application of
BINDER_CONV or ABS_CONV or QUANT_CONV.
See also
Conv.BINDER_CONV,
Conv.ABS_CONV,
Conv.QUANT_CONV,
Conv.STRIP_BINDER_CONV,
Conv.STRIP_QUANT_CONV
STRIP_QUANT_CONV
STRIP_QUANT_CONV
Conv.STRIP_QUANT_CONV : conv -> conv
Applies a conversion underneath a quantifier prefix.
If tm has the form Q(\v1. ... (Q(\vn.M))...) and the application of
conv to M yields |- M = N, then STRIP_QUANT_CONV conv tm returns
|- Q(\v1. ... (Q(\vn.M))...) = Q(\v1. ... (Q(\vn.N))...), provided Q
is Hilbert's choice operator or a universal, existential, or
unique-existence quantifer.
Otherwise, STRIP_QUANT_CONV conv tm returns conv tm.
Failure
If conv M fails. Or if conv tm fails when tm is not a quantified
term. Also fails if some of [v1,...,vn] are free in the hypotheses of
conv M.
Example
> STRIP_QUANT_CONV (STRIP_QUANT_CONV SYM_CONV)
(Term `!x y z. ?!p q r. x + y*z = p*q + r`);
val it =
⊢ (∀x y z. ∃!p q r. x + y * z = p * q + r) ⇔
∀x y z. ∃!p q r. p * q + r = x + y * z: thm
Comments
To deal with binders not in the above list, e.g., newly introduced ones,
use STRIP_BINDER_CONV.
For deeply nested quantifiers, STRIP_QUANT_CONV and
STRIP_BINDER_CONV are more efficient than iterated application of
QUANT_CONV, BINDER_CONV, or ABS_CONV.
See also
Conv.STRIP_BINDER_CONV,
Conv.QUANT_CONV,
Conv.BINDER_CONV,
Conv.ABS_CONV
SUB_CONV
SUB_CONV
Conv.SUB_CONV : conv -> conv
Applies a conversion to the top-level subterms of a term.
For any conversion c, the function returned by SUB_CONV c is a
conversion that applies c to all the top-level subterms of a term. Its
implementation is
fun SUB_CONV c = TRY_CONV (COMB_CONV c ORELSEC ABS_CONV c)
Example
If the conversion c maps t to |- t = t', then SUB_CONV c maps an
abstraction ``\x.t`` to the theorem:
|- (\x.t) = (\x.t')
That is, SUB_CONV c ``\x.t`` applies c to the body of the
abstraction ``\x.t``. If c is a conversion that maps
``t1`` to the theorem |- t1 = t1' and ``t2`` to the
theorem |- t2 = t2', then the conversion SUB_CONV c maps an
application ``t1 t2`` to the theorem:
|- (t1 t2) = (t1' t2')
That is, SUB_CONV c ``t1 t2`` applies c to the both the
operator t1 and the operand t2 of the application ``t1 t2``.
Finally, for any conversion c, the function returned by SUB_CONV c
acts as the identity conversion on variables and constants. That is, if
``t`` is a variable or constant, then SUB_CONV c ``t``
raises the UNCHANGED exception.
Failure
SUB_CONV c tm fails if tm is an abstraction ``\x.t`` and the
conversion c fails when applied to t, or if tm is an application
``t1 t2`` and the conversion c fails when applied to either
t1 or t2. The function returned by SUB_CONV c may also fail if the
ML function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
See also
Conv.ABS_CONV, Conv.COMB_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV
SWAP_EXISTS_CONV
SWAP_EXISTS_CONV
Conv.SWAP_EXISTS_CONV : conv
Interchanges the order of two existentially quantified variables.
When applied to a term argument of the form ?x y. P, the conversion
SWAP_EXISTS_CONV returns the theorem:
|- (?x y. P) = (?y x. P)
Failure
SWAP_EXISTS_CONV fails if applied to a term that is not of the form
?x y. P.
SYM_CONV
SYM_CONV
Conv.SYM_CONV : conv
Interchanges the left and right-hand sides of an equation.
When applied to an equational term t1 = t2, the conversion SYM_CONV
returns the theorem:
|- (t1 = t2) = (t2 = t1)
Failure
Fails if applied to a term that is not an equation.
See also
THENC
THENC
op Conv.THENC : (conv -> conv -> conv)
Applies two conversions in sequence.
If the conversion c1 returns |- t = t' when applied to a term
``t``, and c2 returns |- t' = t'' when applied to
``t'``, then the composite conversion
(c1 THENC c2) ``t`` returns |- t = t''. That is,
(c1 THENC c2) ``t`` has the effect of transforming the term
``t`` first with the conversion c1 and then with the
conversion c2.
THENC also handles the possibility that either of its arguments might
return the UNCHANGED exception. If the first conversion returns
UNCHANGED when applied to its argument, THENC just returns the
result of the second conversion applied to the same initial term. If the
second conversion raises UNCHANGED (and the first did not), then the
result will be the theorem returned by the first conversion. In this
way, unnecessary calls to TRANS can be avoided.
Failure
(This refers to failure other than by raising UNCHANGED).
(c1 THENC c2) ``t`` fails if either the conversion c1 fails
when applied to ``t``, or if c1 ``t`` succeeds and
returns |- t = t' but c2 fails when applied to ``t'``.
(c1 THENC c2) ``t`` may also fail if either of c1 or c2 is
not, in fact, a conversion (i.e. a function that maps a term t to a
theorem |- t = t').
See also
Conv.UNCHANGED,
Conv.EVERY_CONV
TOP_DEPTH_CONV
TOP_DEPTH_CONV
Conv.TOP_DEPTH_CONV : (conv -> conv)
Applies a conversion top-down to all subterms, retraversing changed ones.
TOP_DEPTH_CONV c tm repeatedly applies the conversion c to all the
subterms of the term tm, including the term tm itself. The supplied
conversion c is applied to the subterms of tm in top-down order and
is applied repeatedly (zero or more times, as is done by REPEATC) at
each subterm until it fails. If a subterm t is changed (up to
alpha-equivalence) by virtue of the application of c to its own
subterms, then the term into which t is transformed is retraversed by
applying TOP_DEPTH_CONV c to it.
Failure
TOP_DEPTH_CONV c tm never fails but can diverge.
Comments
The implementation of this function uses failure to avoid rebuilding
unchanged subterms. That is to say, during execution the exception
QConv.UNCHANGED may be generated and later trapped. The behaviour of
the function is dependent on this use of failure. So, if the conversion
given as an argument happens to generate the same exception, the
operation of TOP_DEPTH_CONV will be unpredictable.
See also
Conv.DEPTH_CONV,
Conv.ONCE_DEPTH_CONV,
Conv.REDEPTH_CONV
TRY_CONV
TRY_CONV
Conv.TRY_CONV : conv -> conv
Attempts to apply a conversion; applies identity conversion in case of failure.
TRY_CONV c t attempts to apply the conversion c to the term t; if
this fails, then the identity conversion is applied instead. That is, if
c is a conversion that maps a term t to the theorem |- t = t',
then the conversion TRY_CONV c also maps t to |- t = t'. But if
c fails when applied to t, then TRY_CONV c t raises the
UNCHANGED exception (which is understood to mean the instance of
reflexivity, |- t = t). If c applied to t raises the UNCHANGED
exception, then so too does TRY_CONV c t.
Failure
Never fails, except that the UNCHANGED exception can be raised.
See also
Conv.UNCHANGED,
Conv.QCHANGED_CONV,
Conv.ALL_CONV, Conv.QCONV
UNBETA_CONV
UNBETA_CONV
Conv.UNBETA_CONV : term -> conv
Returns a reversed instance of beta-reduction.
UNBETA_CONV t1 t2 returns a theorem of the form
|- t2 = (\v. t') t1
The choice of v and the nature of t' depend on whether or t1 is a
variable. If so, then v will be t1 and t' will be t2. Otherwise,
v will be generated with genvar and t' will be the result of
substituting v for t1, wherever it occurs.
Failure
Never fails.
Comments
Very useful for setting up a higher-order match by hand. The use of
genvar is predicated on the assumption that it will later be
eliminated through the application of the function term to some other
argument.
See also
UNCHANGED
UNCHANGED
Conv.UNCHANGED : exception
Raised by a conversion to indicate that a term should remain unchanged.
When a conversion c is applied to a term t this can raise the
exception UNCHANGED to indicate that t should not be changed to
another term t'.
Since in this case we have a function raising an exception, we describe
this as failure of the function c. However it may be the intended
result (as used, for example, by ALL_CONV or TRY_CONV).
When conversions are combined using THENC or ORELSEC, raising
UNCHANGED is treated as though |- t = t were returned.
When a conversion c is used to produce an inference rule CONV_RULE c
or a tactic CONV_TAC c, and c raises UNCHANGED, the rule
CONV_RULE c or tactic CONV_TAC c succeeds, returning the theorem or
goal unchanged.
See also
Abbrev.conv, Conv.QCONV,
Conv.QCHANGED_CONV,
Conv.ALL_CONV, Conv.TRY_CONV,
Conv.CONV_RULE,
Tactic.CONV_TAC, Conv.THENC,
Conv.ORELSEC
X_FUN_EQ_CONV
X_FUN_EQ_CONV
Conv.X_FUN_EQ_CONV : (term -> conv)
Performs extensionality conversion for functions (function equality).
The conversion X_FUN_EQ_CONV embodies the fact that two functions are
equal precisely when they give the same results for all values to which
they can be applied. For any variable "x" and equation "f = g",
where x is of type ty1 and f and g are functions of type
ty1->ty2, a call to X_FUN_EQ_CONV "x" "f = g" returns the theorem:
|- (f = g) = (!x. f x = g x)
Failure
X_FUN_EQ_CONV x tm fails if x is not a variable or if tm is not an
equation f = g where f and g are functions. Furthermore, if f
and g are functions of type ty1->ty2, then the variable x must
have type ty1; otherwise the conversion fails. Finally, failure also
occurs if x is free in either f or g.
See also
X_SKOLEM_CONV
X_SKOLEM_CONV
Conv.X_SKOLEM_CONV : (term -> conv)
Introduces a user-supplied Skolem function.
X_SKOLEM_CONV takes two arguments. The first is a variable f, which
must range over functions of the appropriate type, and the second is a
term of the form !x1...xn. ?y. P. Given these arguments,
X_SKOLEM_CONV returns the theorem:
|- (!x1...xn. ?y. P) = (?f. !x1...xn. tm[f x1 ... xn/y])
which expresses the fact that a skolem function f of the universally
quantified variables x1...xn may be introduced in place of the the
existentially quantified value y.
Failure
X_SKOLEM_CONV f tm fails if f is not a variable, or if the input
term tm is not a term of the form !x1...xn. ?y. P, or if the
variable f is free in tm, or if the type of f does not match its
intended use as an n-place curried function from the variables
x1...xn to a value having the same type as y.
See also
apply
apply
Count.apply : ('a -> 'b) -> 'a -> 'b
Counts primitive inferences performed when a function is applied.
The apply function provides a way of counting the primitive inferences
that are performed when a function is applied to its argument. The
reporting of the count is done when the function terminates (normally,
or with an exception). The reporting also includes timing information
about the function call.
Example
> Count.apply (CONJUNCTS o SPEC_ALL) AND_CLAUSES;
runtime: 0.00001s, gctime: 0.00000s, systime: 0.00000s.
Axioms: 0, Defs: 0, Disk: 0, Orcl: 0, Prims: 9; Total: 9
val it = [⊢ T ∧ t ⇔ t, ⊢ t ∧ T ⇔ t, ⊢ F ∧ t ⇔ F, ⊢ t ∧ F ⇔ F, ⊢ t ∧ t ⇔ t]:
thm list
Failure
The call to apply f x will raise an exception if f x would. It will
still report elapsed time and inference counts up to the point of the
exception being raised.
See also
inferences
inferences
Count.inferences : ('a -> 'b) -> 'a -> 'b
Counts primitive inferences performed when a function is applied.
The inferences function provides a way of counting the primitive
inferences that are performed when a function is applied to its
argument. The reporting of the count is done when the function
terminates (normally, or with an exception).
Example
> Count.apply (CONJUNCTS o SPEC_ALL) AND_CLAUSES;
runtime: 0.00001s, gctime: 0.00000s, systime: 0.00000s.
Axioms: 0, Defs: 0, Disk: 0, Orcl: 0, Prims: 9; Total: 9
val it = [⊢ T ∧ t ⇔ t, ⊢ t ∧ T ⇔ t, ⊢ F ∧ t ⇔ F, ⊢ t ∧ F ⇔ F, ⊢ t ∧ t ⇔ t]:
thm list
Failure
The call to inferences f x will raise an exception if f x would. It
will still report inference counts up to the point of the exception
being raised.
See also
thm_count
thm_count
Count.thm_count :
unit ->
{ASSUME : int, REFL : int, BETA_CONV : int, SUBST : int,
ABS : int, DISCH : int, MP : int, INST_TYPE : int,
MK_COMB : int, AP_TERM : int, AP_THM : int, ALPHA : int,
ETA_CONV : int, SYM : int, TRANS : int, EQ_MP : int,
EQ_IMP_RULE : int, INST : int, SPEC : int, GEN : int,
EXISTS : int, CHOOSE : int, CONJ : int, CONJUNCT1 : int,
CONJUNCT2 : int, DISJ1 : int, DISJ2 : int, DISJ_CASES : int,
NOT_INTRO : int, NOT_ELIM : int, CCONTR : int, GEN_ABS : int,
definition : int, axiom : int, from_disk : int, oracle :int,
total :int }
Returns the current value of the theorem counter.
If enabled, HOL maintains a counter which is incremented every time a
primitive inference is performed (or an axiom or definition set up). A
call to thm_count() returns the current value of this counter.
Inference counting needs to be enabled with the call
Count.counting_thms true. Counting can be turned off by calling
counting_thms false.
The default is for inference counting not to be enabled.
Failure
Never fails.
See also
cv_auto_trans
cv_auto_trans
cv_transLib.cv_auto_trans : thm -> unit
Translates functional definitions to the cv_compute subset of HOL.
This is a recursive version of cv_transLib.cv_trans. During
translation of the given HOL function, cv_transLib.cv_auto_trans will
call itself recursively on the definitions of any not-yet-translated
constants it encounters.
As with all auto variants, cv_transLib.cv_auto_trans can sometimes
translate uses of higher-order functions, such as MAP.
Failure
When the translation produces a precondition that
cv_transLib.cv_auto_trans cannot prove automatically, or
cv_transLib.cv_termination_tac fails to prove the termination goal of
either a recursively translated function or the top-level
translator-defined :cv function. For a failure on the top-level
function, the termination goal is pushed onto the goal stack.
Example
> Definition list_add1_def:
list_add1 xs = MAP SUC xs
End
val list_add1_def = ⊢ ∀xs. list_add1 xs = MAP SUC xs: thm
> cv_transLib.cv_auto_trans list_add1_def;
Starting translation of list_add1 from fooTheory.
Starting translation of MAP_SUC from fooTheory.
Finished translating MAP_SUC, stored in cv_MAP_SUC_thm
Starting translation of list_add1 from fooTheory.
Finished translating list_add1, stored in cv_list_add1_thm
val it = (): unit
> cv_transLib.cv_eval “list_add1 [5; 6; 7]”;
val it = ⊢ list_add1 [5; 6; 7] = [6; 7; 8]: thm
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_auto_trans_pre
cv_auto_trans_pre
cv_transLib.cv_auto_trans_pre : string -> thm -> thm
Translates functional definitions to the cv_compute subset of HOL.
This is a recursive version of cv_transLib.cv_trans_pre. During
translation of the given HOL function, cv_transLib.cv_auto_trans_pre
will call itself recursively on the definitions of any
not-yet-translated constants it encounters.
As with all auto variants, cv_transLib.cv_auto_trans_pre can
sometimes translate uses of higher-order functions, such as MAP.
Failure
When the translation produces a precondition that
cv_transLib.cv_auto_trans_pre cannot prove automatically, or
cv_transLib.cv_termination_tac fails to prove the termination goal of
either a recursively translated function or the top-level
translator-defined :cv function. For a failure on the top-level
function, the termination goal is pushed onto the goal stack.
Example
See cv_transLib.cv_auto_trans and cv_transLib.cv_trans_pre for
relevant examples.
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_auto_trans_pre_rec
cv_auto_trans_pre_rec
cv_transLib.cv_auto_trans_pre_rec : string -> thm -> tactic -> thm
Translates functional definitions to the cv_compute subset of HOL.
This is a recursive version of cv_transLib.cv_trans_pre_rec. During
translation of the given HOL function,
cv_transLib.cv_auto_trans_pre_rec will call itself recursively on the
definitions of any not-yet-translated constants it encounters.
As with all auto variants, cv_transLib.cv_auto_trans_pre_rec can
sometimes translate uses of higher-order functions, such as MAP.
Failure
When the translation produces a precondition that
cv_transLib.cv_auto_trans_pre_rec cannot prove automatically, or
cv_transLib.cv_termination_tac fails to prove the termination goal of
any recursively translated function, or the provided tactic fails to
prove the termination goal of the top-level translator-defined :cv
function.
Example
See cv_transLib.cv_auto_trans and cv_transLib.cv_trans_pre_rec for
relevant examples.
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_auto_trans_rec
cv_auto_trans_rec
cv_transLib.cv_auto_trans_rec : thm -> tactic -> unit
Translates functional definitions to the cv_compute subset of HOL.
This is a recursive version of cv_transLib.cv_trans_rec. During
translation of the given HOL function,
cv_transLib.cv_auto_trans_pre_rec will call itself recursively on the
definitions of any not-yet-translated constants it encounters.
As with all auto variants, cv_transLib.cv_auto_trans_rec can
sometimes translate uses of higher-order functions, such as MAP.
Failure
When the translation produces a precondition that
cv_transLib.cv_auto_trans_rec cannot prove automatically, or
cv_transLib.cv_termination_tac fails to prove the termination goal of
any recursively translated function, or the provided tactic fails to
prove the termination goal of the top-level translator-defined :cv
function.
Example
See cv_transLib.cv_auto_trans and cv_transLib.cv_trans_rec for
relevant examples.
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_eval
cv_eval
cv_transLib.cv_eval : term -> thm
Uses cv_computeLib to evaluate closed terms, equipped with
translations from cv_transLib.
Provides a user-friendly interface to cv_computeLib.cv_compute, as
long as cv_transLib has been used to translate all constants in the
given input term.
Failure
When the input term contains either free variables or constants which have not yet been translated.
Example
> cv_transLib.cv_trans arithmeticTheory.FACT;
Finished translating FACT, stored in cv_FACT_thm
val it = (): unit
> cv_transLib.cv_eval “FACT 50”;
val it =
⊢ FACT 50 =
30414093201713378043612608166064768844377641568960512000000000000: thm
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval_raw,
cv_transLib.cv_termination_tac
cv_eval_raw
cv_eval_raw
cv_transLib.cv_eval_raw : term -> thm
Uses cv_computeLib to evaluate closed terms, equipped with
translations from cv_transLib.
Like cv_transLib.cv_eval, except it omits the potentially expensive
evaluation out of the :cv type.
Failure
Fails in the same ways as cv_transLib.cv_eval.
Example
> cv_transLib.cv_trans rich_listTheory.REPLICATE;
Finished translating REPLICATE, stored in cv_REPLICATE_thm
val it = (): unit
> cv_transLib.cv_eval “REPLICATE 3 (3:num)”;
val it = ⊢ REPLICATE 3 3 = [3; 3; 3]: thm
> cv_transLib.cv_eval_raw “REPLICATE 3 (3:num)”;
val it =
⊢ REPLICATE 3 3 =
cv_type$to_list cv$c2n
(cv$Pair (cv$Num 3)
(cv$Pair (cv$Num 3) (cv$Pair (cv$Num 3) (cv$Num 0)))): thm
See also
cv_termination_tac
cv_termination_tac
cv_transLib.cv_termination_tac : tactic
A tactic for simplifying goals concerning cv_depth_sum.
This tactic is used by cv_transLib.cv_trans (and siblings) when
attempting to prove termination goals of translated :cv functions.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval
cv_trans
cv_trans
cv_transLib.cv_trans : thm -> unit
Translates functional definitions to the cv_compute subset of HOL.
This function is the same as cv_transLib.cv_trans_pre, except that it
tries to discharge any preconditions automatically.
Failure
When translation produces a precondition that cv_transLib.cv_trans
cannot prove automatically, or encounters a sub-term containing a
constant that has not already been translated, or
cv_transLib.cv_termination_tac fails to prove the termination goal of
the translator-defined :cv function. In the latter case, the
termination goal is pushed onto the goal stack.
Example
> cv_transLib.cv_trans arithmeticTheory.FACT;
Finished translating FACT, stored in cv_FACT'_thm
val it = (): unit
> cv_transLib.cv_eval “FACT 50”;
val it =
⊢ FACT 50 =
30414093201713378043612608166064768844377641568960512000000000000: thm
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_trans_deep_embedding
cv_trans_deep_embedding
cv_transLib.cv_trans_deep_embedding : conv -> thm -> unit
Translates equations defining a deeply embedded AST to the cv_compute
subset of HOL.
This function is similar to cv_transLib.cv_trans, but can only
translate constants. It is designed for the translation of large deep
embeddings to :cv functions. It takes as an argument a conversion
which must evaluate terms such as from <deep_embedding>
(e.g. computeLib.EVAL).
Failure
When the input term is not a constant defining a suitable deep embedding.
Example
> Datatype:
exp = Const num | Add exp exp
End
> Definition sem_def:
sem (Const n) = n ∧
sem (Add e1 e2) = sem e1 + sem e2
End
val sem_def =
⊢ (∀n. sem (Const n) = n) ∧ ∀e1 e2. sem (Add e1 e2) = sem e1 + sem e2: thm
> Definition deep_def:
deep = Add (Const 5) (Add (Const 2) (Const 3))
End
val deep_def = ⊢ deep = Add (Const 5) (Add (Const 2) (Const 3)): thm
> cv_transLib.cv_trans sem_def;
Finished translating sem, stored in cv_sem_thm
val it = (): unit
> cv_transLib.cv_trans_deep_embedding EVAL deep_def;
val it = (): unit
> cv_transLib.cv_eval “sem deep”;
val it = ⊢ sem deep = 10: thm
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_eval
cv_trans_pre
cv_trans_pre
cv_transLib.cv_trans_pre : string -> thm -> thm
Translates functional definitions to the cv_compute subset of HOL.
Accepts a theorem describing a functional definition. Attempts to
translate this to a function operating over the :cv type, used by
cv_computeLib.cv_compute. Returns a precondition representing the
proof obligation which must be discharged before this translated
function can be evaluated with cv_transLib.cv_eval.
Failure
When the translation does not produce a precondition, or encounters a
sub-term containing a constant that has not already been translated, or
cv_transLib.cv_termination_tac fails to prove the termination goal of
the translator-defined :cv function.
Example
> cv_transLib.cv_trans_pre "HD_pre" listTheory.HD;
Finished translating HD, stored in cv_HD_thm
WARNING: definition of cv_HD has a precondition.
You can set up the precondition proof as follows:
Theorem HD_pre[cv_pre]:
∀v. HD_pre v
Proof
ho_match_mp_tac listTheory.HD_ind (* for example *)
...
QED
val it = ⊢ ∀v. HD_pre v ⇔ (∃t h. v = h::t) ∧ v ≠ []: thm
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_trans_pre_rec
cv_trans_pre_rec
cv_transLib.cv_trans_pre_rec : string -> thm -> tactic -> thm
Translates functional definitions to the cv_compute subset of HOL.
This function is the same as cv_transLib.cv_trans_pre, except that it
also takes a user-provided tactic for proving termination of the
translator-defined :cv function.
Failure
When the translation encounters a sub-term containing a constant that
has not already been translated, or the provided tactic fails to prove
the termination goal of the translator-defined :cv function.
Example
> Definition count_up_def:
count_up m k = if m < k:num then 1 + count_up (m+1) k else 0:num
Termination
WF_REL_TAC ‘measure $ λ(m,k). k - m:num’
End;
val count_up_def =
⊢ ∀m k. count_up m k = if m < k then 1 + count_up (m + 1) k else 0: thm
> val cv_count_up_pre = cv_transLib.cv_trans_pre_rec "count_pre" count_up_def
(WF_REL_TAC ‘measure $ λ(m,k). cv$c2n k - cv$c2n m’
\\ Cases \\ Cases \\ gvs [] \\ rw [] \\ gvs []);
Finished translating count_up, stored in cv_count_up_thm
WARNING: definition of cv_count_up has a precondition.
You can set up the precondition proof as follows:
Theorem count_pre[cv_pre]:
∀m k. count_pre m k
Proof
ho_match_mp_tac count_up_ind (* for example *)
...
QED
val cv_count_up_pre = ⊢ ∀m k. count_pre m k ⇔ m < k ⇒ count_pre (m + 1) k:
thm
> Theorem count_up_pre[cv_pre]:
∀m k. count_up_pre m k
Proof
ho_match_mp_tac count_up_ind \\ rw []
\\ simp [Once cv_count_up_pre]
QED
Exception- HOL_ERR
(at Q.store_thm:
at boolLib.store_thm_at:
at Tactic.HO_MATCH_MP_TAC:
at HolKernel.ho_match_term:
at ??.failwith:
Failed to prove theorem "count_up_pre":
match: safe_insert) raised
> cv_transLib.cv_eval “count_up 5 100”;
val it = ⊢ count_pre 5 100 ⇒ count_up 5 100 = 95: thm
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
cv_trans_rec
cv_trans_rec
cv_transLib.cv_trans_rec : thm -> tactic -> unit
Translates functional definitions to the cv_compute subset of HOL.
This function is the same as cv_transLib.cv_trans, except that it also
takes a user-provided tactic for proving termination of the
translator-defined :cv function.
Failure
When translation produces a precondition that cv_transLib.cv_trans
cannot prove automatically, or encounters a sub-term containing a
constant that has not already been translated, or the provided tactic
fails to prove the termination goal of the translator-defined :cv
function.
Example
> Definition count_up_def:
count_up m k = if m < k:num then 1 + count_up (m+1) k else 0:num
Termination
WF_REL_TAC ‘measure $ λ(m,k). k - m:num’
End;
val count_up_def =
⊢ ∀m k. count_up m k = if m < k then 1 + count_up (m + 1) k else 0: thm
> cv_transLib.cv_trans_rec count_up_def
(WF_REL_TAC ‘measure $ λ(m,k). cv$c2n k - cv$c2n m’
\\ Cases \\ Cases \\ gvs [] \\ rw [] \\ gvs []);
Finished translating count_up, stored in cv_count_up'_thm
val it = (): unit
> cv_transLib.cv_eval “count_up 5 100”;
val it = ⊢ count_up 5 100 = 95: thm
Comments
Designed to produce definitions suitable for evaluation by
cv_transLib.cv_eval.
See also
cv_transLib.cv_trans,
cv_transLib.cv_trans_pre,
cv_transLib.cv_trans_pre_rec,
cv_transLib.cv_auto_trans,
cv_transLib.cv_auto_trans_pre,
cv_transLib.cv_auto_trans_pre_rec,
cv_transLib.cv_auto_trans_rec,
cv_transLib.cv_eval,
cv_transLib.cv_termination_tac
apropos
apropos
DB.apropos : term -> data list
Attempt to find matching theorems in the currently loaded theories.
An invocation DB.apropos M collects all theorems, definitions, and
axioms of the currently loaded theories that have a subterm that matches
M. If there are no matches, the empty list is returned.
Failure
Never fails.
Example
> DB.apropos (Term `(!x y. P x y) ==> Q`);
<<HOL message: inventing new type variable names: 'a, 'b>>
val it =
[(("bool", "LCOMM_THM"),
(⊢ ∀f. (∀x y z. f x (f y z) = f (f x y) z) ⇒
(∀x y. f x y = f y x) ⇒
∀x y z. f x (f y z) = f y (f x z), Thm,
Located
{exact = true, linenum = 4225, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"})),
(("ind_type", "INJ_INVERSE2"),
(⊢ ∀P. (∀x1 y1 x2 y2. P x1 y1 = P x2 y2 ⇔ x1 = x2 ∧ y1 = y2) ⇒
∃X Y. ∀x y. X (P x y) = x ∧ Y (P x y) = y, Thm,
Located
{exact = true, linenum = 20, scriptpath =
"$(HOLDIR)/src/datatype/ind_typeScript.sml"})),
[...Output elided...]
Comments
The notion of matching is a restricted version of higher-order matching.
For finer control over the theories searched, use DB.match.
See also
DB.match, DB.find,
DB.apropos_in, DB.matches
apropos_in
apropos_in
DB.apropos_in : term -> data list -> data list
Attempt to select matching theorems among a given list.
An invocation DB.apropos_in M data_list selects all theorems,
definitions, and axioms within data_list that have a subterm that
matches M. If there are no matches, the empty list is returned.
Failure
Never fails.
Example
> DB.apropos (Term `(!x y. P x y) ==> Q`);
<<HOL message: inventing new type variable names: 'a, 'b>>
val it =
[(("bool", "LCOMM_THM"),
(⊢ ∀f. (∀x y z. f x (f y z) = f (f x y) z) ⇒
(∀x y. f x y = f y x) ⇒
∀x y z. f x (f y z) = f y (f x z), Thm,
Located
{exact = true, linenum = 4225, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"})),
(("ind_type", "INJ_INVERSE2"),
(⊢ ∀P. (∀x1 y1 x2 y2. P x1 y1 = P x2 y2 ⇔ x1 = x2 ∧ y1 = y2) ⇒
∃X Y. ∀x y. X (P x y) = x ∧ Y (P x y) = y, Thm,
Located
{exact = true, linenum = 20, scriptpath =
"$(HOLDIR)/src/datatype/ind_typeScript.sml"})),
[...Output elided...]
> DB.apropos_in (Term `(x, y)`) it ;
[(("pair", "pair_induction"),
(|- (!p_1 p_2. P (p_1,p_2)) ==> !p. P p, Thm))] :
((string * string) * (thm * class)) list
Exception- unknown symbol .
unknown symbol .
Fail "Static Errors" raised
Comments
The notion of matching is a restricted version of higher-order matching.
It uses DB.matches.
Finding theorems in interactive proof sessions. The second argument will
normally be the result of a previous call to
DB.find, DB.match, DB.apropos, DB.listDB, DB.thy etc.
See also
DB.apropos, DB.match,
DB.matches, DB.find,
DB.find_in, DB.listDB,
DB.thy, DB.theorems
axioms
axioms
DB.axioms : string -> (string * thm) list
All the axioms stored in the named theory.
An invocation axioms thy, where thy is the name of a currently
loaded theory segment, will return a list of the axioms stored in that
theory. Each theorem is paired with its name in the result. The string
"-" may be used to denote the current theory segment.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> axioms "bool";
val it =
[("SELECT_AX", ⊢ ∀P x. P x ⇒ P ($@ P)),
("INFINITY_AX", ⊢ ∃f. ONE_ONE f ∧ ¬ONTO f),
("ETA_AX", ⊢ ∀t. (λx. t x) = t),
("BOOL_CASES_AX", ⊢ ∀t. (t ⇔ T) ∨ (t ⇔ F))]: (string * thm) list
See also
DB.thy, DB.fetch, DB.thms,
DB.theorems, DB.definitions,
DB.listDB
class
class
DB.datatype class
Datatype for classifying theory elements.
Many of the functions in the DB structure return answers that involve
the class type, which is declared as
datatype class = Thm | Axm | Def
When occurring with th, an ML value of type thm, Axm means that
th has been asserted as an axiom; Def means that th is a constant
definition; and Thm means that th is a plain old theorem, i.e,. not
an axiom or a definition.
See also
data
data
DB.type data
Type abbreviation used in DB structure.
When functions from the DB structure are used to query the current
theory, answer are often phrased in terms of the data type, which is a
type abbreviation declared as
type data = (string * string) * (thm * class)
An element ((thy,name), (th,cl)) means that th is a theorem with
classification class, stored in theory segment thy under name.
Example
> DB.find "BOOL_CASES_AX";
val it =
[(("bool", "BOOL_CASES_AX"),
(⊢ ∀t. (t ⇔ T) ∨ (t ⇔ F), Axm,
Located
{exact = true, linenum = 228, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"}))]: public_data list
See also
DB.class, DB.thy, DB.find,
DB.match, DB.apropos,
DB.listDB
definitions
definitions
DB.definitions : string -> (string * thm) list
All the definitions stored in the named theory.
An invocation definitions thy, where thy is the name of a currently
loaded theory segment, will return a list of the definitions stored in
that theory. Each definition is paired with its name in the result. The
string "-" may be used to denote the current theory segment.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> definitions "combin";
val it =
[("W_DEF", ⊢ W = (λf x. f x x)),
("UPDATE_def", ⊢ ∀a b. (a =+ b) = (λf c. if a = c then b else f c)),
("S_DEF", ⊢ S = (λf g x. f x (g x))),
("RIGHT_ID_DEF", ⊢ ∀f e. RIGHT_ID f e ⇔ ∀x. f x e = x),
("RESTRICTION", ⊢ ∀s f x. RESTRICTION s f x = if x ∈ s then f x else ARB),
("o_DEF", ⊢ ∀f g. f ∘ g = (λx. f (g x))),
("MONOID_DEF", ⊢ ∀f e. MONOID f e ⇔ ASSOC f ∧ RIGHT_ID f e ∧ LEFT_ID f e),
("LEFT_ID_DEF", ⊢ ∀f e. LEFT_ID f e ⇔ ∀x. f e x = x),
("K_DEF", ⊢ K = (λx y. x)), ("I_DEF", ⊢ I = S K K),
("FCOMM_DEF", ⊢ ∀f g. FCOMM f g ⇔ ∀x y z. g x (f y z) = f (g x y) z),
("FAIL_DEF", ⊢ FAIL = (λx y. x)),
("EXTENSIONAL_def", ⊢ ∀s f. EXTENSIONAL s f ⇔ ∀x. x ∉ s ⇒ f x = ARB),
("COMM_DEF", ⊢ ∀f. COMM f ⇔ ∀x y. f x y = f y x),
("C_DEF", ⊢ flip = (λf x y. f y x)),
[...Output elided...]
See also
DB.thy, DB.fetch, DB.thms,
DB.theorems, DB.axioms,
DB.listDB
dest_theory
dest_theory
DB.dest_theory : string -> theory
Return the contents of a theory.
An invocation dest_theory s returns a structure
THEORY(s,{types, consts, parents, axioms, definitions, theorems})
where types is a list of (string,int) pairs that contains all the
type operators declared in s, consts is a list of
(string,hol_type) pairs enumerating all the term constants declared in
s, parents is a list of strings denoting the parents of s,
axioms is a list of (string,thm) pairs denoting the axioms asserted
in s, definitions is a list of (string,thm) pairs denoting the
definitions of s, and theorems is a list of (string,thm) pairs
denoting the theorems proved and stored in s.
The call dest_theory "-" may be used to access the contents of the
current theory.
Failure
If s is not the name of a loaded theory.
Example
> dest_theory "option";
val it =
Theory: option
Parents:
one
sum
Type constants:
option 1
Term constants:
IS_NONE :α option -> bool
IS_SOME :α option -> bool
NONE :α option
OPTION_ALL :(α -> bool) -> α option -> bool
OPTION_APPLY :(β -> α) option -> β option -> α option
OPTION_BIND :β option -> (β -> α option) -> α option
OPTION_CHOICE :α option -> α option -> α option
OPTION_GUARD :bool -> unit option
OPTION_IGNORE_BIND :β option -> α option -> α option
OPTION_JOIN :α option option -> α option
OPTION_MAP :(α -> β) -> α option -> β option
OPTION_MAP2 :(β -> γ -> α) ->
β option -> γ option -> α option
OPTION_MCOMP :(β -> α option) ->
(γ -> β option) -> γ -> α option
OPTREL :(α -> β -> bool) -> α option -> β option -> bool
SOME :α -> α option
THE :α option -> α
option_ABS :α + unit -> α option
option_CASE :α option -> β -> (α -> β) -> β
option_REP :α option -> α + unit
some :(α -> bool) -> α option
Definitions:
NONE_DEF
⊢ NONE = option_ABS (INR ())
OPTION_ALL_def
⊢ (∀P. OPTION_ALL P NONE ⇔ T) ∧ ∀P x. OPTION_ALL P (SOME x) ⇔ P x
OPTION_APPLY_def
⊢ (∀x. NONE <*> x = NONE) ∧ ∀f x. SOME f <*> x = OPTION_MAP f x
OPTION_BIND_def
⊢ (∀f. OPTION_BIND NONE f = NONE) ∧
∀x f. OPTION_BIND (SOME x) f = f x
OPTION_CHOICE_def
⊢ (∀m2. OPTION_CHOICE NONE m2 = m2) ∧
∀x m2. OPTION_CHOICE (SOME x) m2 = SOME x
OPTION_GUARD_def
⊢ OPTION_GUARD T = SOME () ∧ OPTION_GUARD F = NONE
OPTION_IGNORE_BIND_def
[...Output elided...]
Comments
A prettyprinter is installed for the type theory, but the contents may
still be accessed via pattern matching.
See also
fetch
fetch
DB.fetch : string -> string -> thm
Fetch a theorem by theory and name.
An invocation fetch thy name searches through the currently loaded
theory segments in an attempt to find a theorem, axiom, or definition
stored under name in theory thy.
Failure
If the specified theorem, axiom, or definition cannot be located.
Example
> DB.fetch "bool" "NOT_FORALL_THM";
val it = ⊢ ∀P. ¬(∀x. P x) ⇔ ∃x. ¬P x: thm
See also
DB.thms, DB.thy,
DB.theorems, DB.axioms,
DB.definitions
find
find
DB.find : string -> data list
Search for theory element by name fragment.
An invocation DB.find s returns a list of theory elements which have
been stored with a name containing a substring matching the regular
expression s, ignoring case distinctions. All currently loaded theory
segments are searched. The regular expression notation allows
parentheses, dot (.) to match any character, Kleene star (*),
alternation (|) and a special form of intersection (~).
The tilde form r~s is defined to be equal to (.*r.*)&(.*s.*), where
& is regular expression intersection. This allows one to require
multiple sub-string matches: in a string such as s1~s2, matches will
be found if the name contains both s1 and s2, in either order.
Failure
Never fails. If nothing suitable can be found, the empty list is returned.
Example
> DB.find "inc";
val it =
[(("arithmetic", "MULT_INCREASES"),
(⊢ ∀m n. 1 < m ∧ 0 < n ⇒ SUC n ≤ m * n, Thm,
Located
{exact = true, linenum = 3572, scriptpath =
"$(HOLDIR)/src/num/theories/arithmeticScript.sml"})),
(("arithmetic", "STRICTLY_INCREASING_ONE_ONE"),
(⊢ ∀f. (∀n. f n < f (SUC n)) ⇒ ONE_ONE f, Thm,
Located
{exact = true, linenum = 4282, scriptpath =
"$(HOLDIR)/src/num/theories/arithmeticScript.sml"})),
(("arithmetic", "STRICTLY_INCREASING_TC"),
(⊢ ∀f. (∀n. f n < f (SUC n)) ⇒ ∀m n. m < n ⇒ f m < f n, Thm,
Located
{exact = true, linenum = 4275, scriptpath =
[...Output elided...]
Finding theorems in interactive proof sessions.
See also
DB.find_in, DB.match,
DB.apropos, DB.selectDB,
DB.thy, DB.theorems
find_consts
find_consts
DB.find_consts : hol_type -> term list
Searches the current theory and its ancestors for constants matching given type.
Given a type ty searches the current theory and its ancestors for
constants whose type matches the ("pattern") type ty.
Failure
Never fails.
Example
If we run
> find_consts ``:'a -> 'a set -> bool``;
val it = [“$IN”]: term list
and with
> find_consts ``:num -> num -> num``;
val it =
[“napp”, “ncons”, “$*,”, “internal_mult”, “numeral$onecount”,
“numeral$texp_help”, “$*”, “$+”, “$-”, “ABS_DIFF”, “$DIV”,
“$**”, “MAX”, “MIN”, “$MOD”, “ind_type$NUMPAIR”]: term list
The fact that type-matching is performed is apparent with this call:
> find_consts ``:'a -> 'a``;
val it =
[“TL_T”, “common_prefixes”, “FRONT”, “REVERSE”, “TL”, “nub”,
“COMPL”, “REST”, “tri⁻¹”, “nfst”, “nlen”, “nmap”, “nsnd”,
“tri”, “numeral$exactlog”, “numeral$iDUB”, “numeral$iSQR”,
“numeral$iZ”, “numeral$iiSUC”, “BIT1”, “BIT2”, “DIV2”, “FACT”,
“NUMERAL”, “$&”, “PRE”, “SUC”, “SUC_REP”, “Abbrev”, “Cong”,
“stmarker”, “unint”, “BOUNDED”, “LET”, “literal_case”, “$~”,
“EQC”, “RC”, “RCOMPL”, “RTC”, “SC”, “STRORD”, “TC”, “I”,
“NUMFST”, “NUMRIGHT”, “NUMSND”]: term list
where both SUC and $~ (boolean negation) are among the list
returned.
See also
bossLib.find_consts_thy,
DB.apropos, DB.find
find_consts_thy
find_consts_thy
DB.find_consts_thy : string list -> hol_type -> term list
Searches in the theories in list thl for a constant matching given
type ty.
A call to find_consts_thy thl ty searches the theories with names from
thl for constants whose types match type ty, and returns that list.
Failure
Never fails.
Example
If we run
> find_consts_thy ["bool"] ``:'a -> 'a set -> bool``;
val it = [“$IN”]: term list
and
> find_consts_thy ["arithmetic"] ``:num -> num -> num``;
val it = [“$*”, “$+”, “$-”, “ABS_DIFF”, “$DIV”, “$**”, “MAX”, “MIN”,
“$MOD”]: term list
See also
bossLib.find_consts,
DB.apropos, DB.find
find_in
find_in
DB.find_in : string -> data list -> data list
Search for theory element by name fragment, among a given list.
An invocation DB.find_in s data_list selects from data_list those
theory elements which have been stored with a name in which s occurs
as a proper substring, ignoring case distinctions.
Failure
Never fails. If nothing suitable can be found, the empty list is returned.
Example
> DB.find "inc";
val it =
[(("arithmetic", "MULT_INCREASES"),
(⊢ ∀m n. 1 < m ∧ 0 < n ⇒ SUC n ≤ m * n, Thm,
Located
{exact = true, linenum = 3572, scriptpath =
"$(HOLDIR)/src/num/theories/arithmeticScript.sml"})),
(("arithmetic", "STRICTLY_INCREASING_ONE_ONE"),
(⊢ ∀f. (∀n. f n < f (SUC n)) ⇒ ONE_ONE f, Thm,
Located
{exact = true, linenum = 4282, scriptpath =
"$(HOLDIR)/src/num/theories/arithmeticScript.sml"})),
(("arithmetic", "STRICTLY_INCREASING_TC"),
(⊢ ∀f. (∀n. f n < f (SUC n)) ⇒ ∀m n. m < n ⇒ f m < f n, Thm,
Located
{exact = true, linenum = 4275, scriptpath =
[...Output elided...]
> DB.find_in "sum" it;
val it =
[(("sum", "sum_distinct"),
(⊢ ∀x y. INL x ≠ INR y, Thm,
Located
{exact = true, linenum = 259, scriptpath =
"$(HOLDIR)/src/coretypes/sumScript.sml"})),
(("sum", "sum_distinct1"),
(⊢ ∀x y. INR y ≠ INL x, Thm,
Located
{exact = true, linenum = 269, scriptpath =
"$(HOLDIR)/src/coretypes/sumScript.sml"}))]:
DB_dtype.public_data_value named list
Finding theorems in interactive proof sessions. The second argument will
normally be the result of a previous call to
DB.find, DB.match, DB.apropos, DB.listDB, DB.thy etc.
See also
DB.find, DB.match,
DB.apropos, DB.listDB,
DB.thy, DB.theorems
listDB
listDB
DB.listDB : unit -> data list
All theorems, axioms, and definitions in the currently loaded theory segments.
An invocation listDB() returns everything that has been stored in all
theory segments currently loaded.
Example
> length (listDB());
val it = 5489: int
See also
DB.thy, DB.theorems,
DB.definitions, DB.axioms,
DB.find, DB.match
match
match
DB.match : string list -> term -> data list
Attempt to find matching theorems in the specified theories.
An invocation DB.match [s1,...,sn] M collects all theorems,
definitions, and axioms of the theories designated by s1,...,sn that
have a subterm that matches M. If there are no matches, the empty list
is returned.
The strings s1,...,sn should be a subset of the currently loaded
theory segments. The string "-" may be used to designate the current
theory segment. If the list of theories is empty, then all currently
loaded theories are searched.
Failure
Never fails.
Example
> DB.match ["bool","pair"] (Term `(a = b) = c`);
<<HOL message: inventing new type variable names: 'a>>
val it =
[(("bool", "bool_case_eq"),
(⊢ (if x then t1 else t2) = v ⇔ (x ⇔ T) ∧ t1 = v ∨ (x ⇔ F) ∧ t2 = v,
Thm,
Located
{exact = true, linenum = 3552, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"})),
(("bool", "EQ_CLAUSES"),
(⊢ ∀t. ((T ⇔ t) ⇔ t) ∧ ((t ⇔ T) ⇔ t) ∧ ((F ⇔ t) ⇔ ¬t) ∧ ((t ⇔ F) ⇔ ¬t),
Thm,
Located
{exact = true, linenum = 1310, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"})),
(("bool", "EQ_EXPAND"),
[...Output elided...]
Comments
The notion of matching is a restricted version of higher-order matching.
For locating theorems when doing interactive proof.
See also
DB.matcher, DB.matchp,
DB.find, DB.theorems,
DB.thy, DB.listDB
matcher
matcher
DB.matcher : (term -> term -> 'a) -> string list -> term -> data list
All theory elements matching a given term.
An invocation matcher pm [thy1,...,thyn] M collects all elements of
the theory segments thy1,...,thyn that have a subterm N such that
pm M does not fail (raise an exception) when applied to N. Thus
matcher potentially traverses all subterms of all theorems in all the
listed theories in its search for 'matches'.
If the list of theory segments is empty, then all currently loaded
segments are examined. The string "-" may be used to designate the
current theory segment.
Failure
Never fails, but may return an empty list.
Example
> DB.matcher match_term ["relation"] (Term `P \/ Q`);
val it =
[(("relation", "IN_RDOM_RUNION"),
(⊢ x ∈ RDOM (R1 ∪ᵣ R2) ⇔ x ∈ RDOM R1 ∨ x ∈ RDOM R2, Thm,
Located
{exact = true, linenum = 2392, scriptpath =
"$(HOLDIR)/src/relation/relationScript.sml"})),
(("relation", "RC_DEF"),
(⊢ ∀R x y. RC R x y ⇔ x = y ∨ R x y, Def, Unknown)),
(("relation", "RINSERT"),
(⊢ ∀R a b. RINSERT R a b = (λx y. R x y ∨ x = a ∧ y = b), Def, Unknown)),
(("relation", "RTC_cases"),
(⊢ ∀R a0 a1. R꙳ a0 a1 ⇔ a1 = a0 ∨ ∃y. R a0 y ∧ R꙳ y a1, Thm, Unknown)),
(("relation", "RTC_CASES1"),
(⊢ ∀R x y. R꙳ x y ⇔ x = y ∨ ∃u. R x u ∧ R꙳ u y, Thm,
Located
[...Output elided...]
> DB.matcher (ho_match_term [] empty_varset) [] (Term `?x. P x \/ Q x`);
<<HOL message: inventing new type variable names: 'a>>
val it =
[(("arithmetic", "ODD_OR_EVEN"),
(⊢ ∀n. ∃m. n = SUC (SUC 0) * m ∨ n = SUC (SUC 0) * m + 1, Thm,
Located
{exact = true, linenum = 1571, scriptpath =
"$(HOLDIR)/src/num/theories/arithmeticScript.sml"})),
(("bool", "EXISTS_OR_THM"),
(⊢ ∀P Q. (∃x. P x ∨ Q x) ⇔ (∃x. P x) ∨ ∃x. Q x, Thm,
Located
{exact = true, linenum = 1604, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"})),
(("bool", "LEFT_OR_EXISTS_THM"),
(⊢ ∀P Q. (∃x. P x) ∨ Q ⇔ ∃x. P x ∨ Q, Thm,
Located
[...Output elided...]
Comments
Usually, pm will be a pattern-matcher, but it need not be.
See also
DB.match, DB.apropos,
DB.matchp, DB.find
matches
matches
DB.matches : term -> thm -> bool
Tells whether part of a theorem matches a pattern.
An invocation DB.match pat th tells whether the conclusion of th has
a subterm matching pat.
Failure
Never fails.
Example
> DB.matches (Term `(a = b) = c`) EQ_CLAUSES ;
<<HOL message: inventing new type variable names: 'a>>
val it = true: bool
> DB.matches (Term `(a = b) = c`) EQ_TRANS ;
<<HOL message: inventing new type variable names: 'a>>
val it = false: bool
Comments
The notion of matching is a restricted version of higher-order matching,
as used by DB.apropos, DB.apropos_in, DB.match, etc.
For locating theorems relevant to a given pattern.
See also
DB.matcher, DB.matchp,
DB.apropos, DB.apropos_in
matchp
matchp
DB.matchp : (thm -> bool) -> string list -> data list
All theory elements satisfying a predicate.
An invocation matchp P [thy1,...,thyn] collects all elements of the
theory segments thy1,...,thyn that P holds of. If the list of
theory segments is empty, then all currently loaded segments are
examined. The string "-" may be used to designate the current theory
segment.
Failure
Fails if P fails when applied to a theorem in one of the theories
being searched.
Example
The following query returns all unconditional rewrite rules in the
theory pair.
> matchp (is_eq o snd o strip_forall o concl) ["pair"];
val it =
[(("pair", "C_UNCURRY_L"),
(⊢ flip (UNCURRY f) x = UNCURRY (flip (flip ∘ f) x), Thm,
Located
{exact = true, linenum = 608, scriptpath =
"$(HOLDIR)/src/coretypes/pairScript.sml"})),
(("pair", "CLOSED_PAIR_EQ"),
(⊢ ∀x y a b. (x,y) = (a,b) ⇔ x = a ∧ y = b, Thm,
Located
{exact = true, linenum = 108, scriptpath =
"$(HOLDIR)/src/coretypes/pairScript.sml"})),
(("pair", "COMMA_DEF"),
(⊢ ∀x y. (x,y) = ABS_prod (λa b. a = x ∧ b = y), Def, Unknown)),
(("pair", "CURRY_DEF"), (⊢ ∀f x y. CURRY f x y = f (x,y), Def, Unknown)),
(("pair", "CURRY_DEF_lazyfied"),
[...Output elided...]
See also
DB.match, DB.matcher,
DB.apropos, DB.find
selectDB
selectDB
DB.selectDB : DB.selector list -> DB.public_data list
Searches the theorem database with multiple conjoined selectors
A call to DB.selectDB [sel1, sel2, ..., seln] returns a list of
theorems from the theorem database that match all of the criteria
embodied by sel1, sel2, etc. The selectors are of three different
forms:
SelTM term | SelNM string | SelTHY string
The selector SelTM t matches any theorem that has a sub-term matching
the term t. The selector SelNM s matches any theorem whose name
matches the string s, using the regular-expression-like matching
syntax described in the documentation for DB.find. Finally,
SelThy thy matches a theorem if that theorem comes from theory thy.
Failure
Never fails.
Example
> DB.selectDB [SelTM “_ /\ _”, SelTHY "bool", SelNM "ASSOC"];
val it =
[(("bool", "CONJ_ASSOC"),
(⊢ ∀t1 t2 t3. t1 ∧ t2 ∧ t3 ⇔ (t1 ∧ t2) ∧ t3, Thm,
Located
{exact = true, linenum = 766, scriptpath =
"$(HOLDIR)/src/bool/boolScript.sml"}))]: public_data list
Comments
Allows for more powerful searches than other entrypoints in DB.
See also
theorems
theorems
DB.theorems : string -> (string * thm) list
All the theorems stored in the named theory.
An invocation theorems thy, where thy is the name of a currently
loaded theory segment, will return a list of the theorems stored in that
theory. Axioms and definitions are excluded. Each theorem is paired with
its name in the result. The string "-" may be used to denote the
current theory segment.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> theorems "combin";
val it =
[("W_THM", ⊢ ∀f x. W f x = f x x),
("UPDATE_EQ", ⊢ ∀f a b c. f⦇a ↦ c; a ↦ b⦈ = f⦇a ↦ c⦈),
("UPDATE_COMMUTES",
⊢ ∀f a b c d. a ≠ b ⇒ f⦇a ↦ c; b ↦ d⦈ = f⦇b ↦ d; a ↦ c⦈),
("UPDATE_APPLY_IMP_ID", ⊢ ∀f b a. f a = b ⇒ f⦇a ↦ b⦈ = f),
("UPDATE_APPLY_ID_RWT",
⊢ (∀f a b. f⦇a ↦ b⦈ = f ⇔ f a = b) ∧ ∀f a b. f = f⦇a ↦ b⦈ ⇔ f a = b),
("UPDATE_APPLY_ID", ⊢ ∀f a b. f a = b ⇔ f⦇a ↦ b⦈ = f),
("UPDATE_APPLY1", ⊢ ∀a x f. f⦇a ↦ x⦈ a = x),
("UPDATE_APPLY",
⊢ (∀a x f. f⦇a ↦ x⦈ a = x) ∧ ∀a b x f. a ≠ b ⇒ f⦇a ↦ x⦈ b = f b),
("UPD_SAME_KEY_UNWIND",
⊢ ∀f1 f2 a b c.
f1⦇a ↦ b⦈ = f2⦇a ↦ c⦈ ⇒ b = c ∧ ∀v. f1⦇a ↦ v⦈ = f2⦇a ↦ v⦈),
[...Output elided...]
See also
DB.thy, DB.fetch, DB.thms,
DB.definitions, DB.axioms,
DB.listDB
thms
thms
DB.thms : string -> (string * thm) list
All the theorems, definitions, and axioms stored in the named theory.
An invocation thms thy, where thy is the name of a currently loaded
theory segment, will return a list of the theorems, definitions, and
axioms stored in that theory. Each theorem is paired with its name in
the result. The string "-" may be used to denote the current theory
segment.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> thms "combin";
val it =
[("W_THM", ⊢ ∀f x. W f x = f x x), ("W_DEF", ⊢ W = (λf x. f x x)),
("UPDATE_EQ", ⊢ ∀f a b c. f⦇a ↦ c; a ↦ b⦈ = f⦇a ↦ c⦈),
("UPDATE_def", ⊢ ∀a b. (a =+ b) = (λf c. if a = c then b else f c)),
("UPDATE_COMMUTES",
⊢ ∀f a b c d. a ≠ b ⇒ f⦇a ↦ c; b ↦ d⦈ = f⦇b ↦ d; a ↦ c⦈),
("UPDATE_APPLY_IMP_ID", ⊢ ∀f b a. f a = b ⇒ f⦇a ↦ b⦈ = f),
("UPDATE_APPLY_ID_RWT",
⊢ (∀f a b. f⦇a ↦ b⦈ = f ⇔ f a = b) ∧ ∀f a b. f = f⦇a ↦ b⦈ ⇔ f a = b),
("UPDATE_APPLY_ID", ⊢ ∀f a b. f a = b ⇔ f⦇a ↦ b⦈ = f),
("UPDATE_APPLY1", ⊢ ∀a x f. f⦇a ↦ x⦈ a = x),
("UPDATE_APPLY",
⊢ (∀a x f. f⦇a ↦ x⦈ a = x) ∧ ∀a b x f. a ≠ b ⇒ f⦇a ↦ x⦈ b = f b),
("UPD_SAME_KEY_UNWIND",
⊢ ∀f1 f2 a b c.
[...Output elided...]
See also
DB.thy, DB.theorems,
DB.axioms, DB.definitions,
DB.fetch, DB.listDB
thy
thy
DB.thy : string -> data list
Return the contents of a theory.
An invocation DB.thy s returns the contents of the specified theory
segment s in a list of (thy,name),(thm,class) tuples. In a tuple,
(thy,name) designate the theory and the name given to the object in
the theory. The thm element is the named object, and class its
classification (one of Thm (theorem), Axm (axiom), or Def
(definition)).
Case distinctions are ignored when determining the segment. The current
segment may be specified, either by the distinguished literal "-", or
by the name given when creating the segment with new_theory.
Failure
Never fails, but will return an empty list when s does not designate a
currently loaded theory segment.
Example
> List.take (DB.thy "pair", 3);
val it =
[(("pair", "WF_RPROD"),
(⊢ ∀R Q. WF R ∧ WF Q ⇒ WF (R ### Q),
{class = Thm, loc =
Located
{exact = true, linenum = 857, scriptpath =
"$(HOLDIR)/src/coretypes/pairScript.sml"}, private = false})),
(("pair", "WF_LEX"),
(⊢ ∀R Q. WF R ∧ WF Q ⇒ WF (R LEX Q),
{class = Thm, loc =
Located
{exact = true, linenum = 814, scriptpath =
"$(HOLDIR)/src/coretypes/pairScript.sml"}, private = false})),
(("pair", "UNCURRY_VAR"),
(⊢ ∀f v. UNCURRY f v = f (FST v) (SND v),
{class = Thm, loc =
Located
{exact = true, linenum = 222, scriptpath =
"$(HOLDIR)/src/coretypes/pairScript.sml"}, private = false}))]:
data list
See also
DB.class, DB.data,
DB.listDB, DB.theorems,
DB.match, Theory.new_theory
gen_new_specification
gen_new_specification
Definition.gen_new_specification : string * thm -> thm
Introduce a constant or constants satisfying a given property.
The ML function gen_new_specification implements the generalised
primitive rule of constant specification for the HOL logic.
Evaluating:
gen_new_specification (name, [x1=t1,...,xn=tn] |- t)
simultaneously introduces new constants named x1,...,xn satisfying
the property:
|- t
where the variables x1,...,xn in t are replaced by the new
constants.
This theorem is stored, with name name, as a definition in the current
theory segment. It is also returned by the call to
gen_new_specification.
Failure
gen_new_specification fails if any of the hypotheses of the input
theorem are not of the right form: they must be equations each with a
variable on the left-hand side and no free variables on the right-hand
side. It also fails if the supplied variables (equivalently, the desired
constant names) x1,...,xn are not distinct. Finally, failure occurs
if the type of some ti does not contain all the type variables
occurring in the term ti itself.
Comments
The generalised version is described in Rob Arthan's ITP 2014 paper, HOL
Constant Definition Done Right, available from
http://www.lemma-one.com/papers/hcddr.pdf.
See also
new_definition
new_definition
Definition.new_definition : string * term -> thm
Declare a new constant and install a definitional axiom in the current theory.
The function new_definition provides a facility for definitional
extensions to the current theory. It takes a pair argument consisting of
the name under which the resulting definition will be saved in the
current theory segment, and a term giving the desired definition. The
value returned by new_definition is a theorem which states the
definition requested by the user.
Let v_1,...,v_n be tuples of distinct variables, containing the
variables x_1,...,x_m. Evaluating
new_definition (name, c v_1 ... v_n = t), where c is not already a
constant, declares the sequent ({},\v_1 ... v_n. t) to be a definition
in the current theory, and declares c to be a new constant in the
current theory with this definition as its specification. This constant
specification is returned as a theorem with the form
|- !x_1 ... x_m. c v_1 ... v_n = t
and is saved in the current theory under name. Optionally, the
definitional term argument may have any of its variables universally
quantified.
Failure
new_definition fails if t contains free variables that are not in
x_1, ..., x_m (this is equivalent to requiring \v_1 ... v_n. t to
be a closed term). Failure also occurs if any variable occurs more than
once in v_1, ..., v_n. Finally, failure occurs if there is a type
variable in v_1, ..., v_n or t that does not occur in the type of
c.
Example
A NAND relation can be defined as follows.
- new_definition (
"NAND2",
Term`NAND2 (in_1,in_2) out = !t:num. out t = ~(in_1 t /\ in_2 t)`);
> val it =
|- !in_1 in_2 out.
NAND2 (in_1,in_2) out = !t. out t = ~(in_1 t /\ in_2 t)
: thm
See also
Definition.new_specification,
boolSyntax.new_binder_definition,
boolSyntax.new_infixl_definition,
boolSyntax.new_infixr_definition,
Prim_rec.new_recursive_definition,
TotalDefn.Define
new_specification
new_specification
Definition.new_specification : string * string list * thm -> thm
Introduce a constant or constants satisfying a given property.
The ML function new_specification implements the primitive rule of
constant specification for the HOL logic. Evaluating:
new_specification (name, ["c1",...,"cn"], |- ?x1...xn. t)
simultaneously introduces new constants named c1,...,cn satisfying
the property:
|- t[c1,...,cn/x1,...,xn]
This theorem is stored, with name name, as a definition in the current
theory segment. It is also returned by the call to new_specification.
Failure
new_specification fails if the theorem argument has assumptions or
free variables. It also fails if the supplied constant names c1, ...,
cn are not distinct. It also fails if the length of the existential
prefix of the theorem is not at least n. Finally, failure occurs if
some ci does not contain all the type variables that occur in the term
?x1...xn. t.
new_specification can be used to introduce constants that satisfy a
given property without having to make explicit equational constant
definitions for them. For example, the built-in constants MOD and
DIV are defined in the system by first proving the theorem:
th |- ?MOD DIV.
!n. 0 < n ==> !k. (k = (DIV k n * n) + MOD k n) /\ MOD k n < n
and then making the constant specification:
new_specification ("DIVISION", ["MOD","DIV"], th)
This introduces the constants MOD and DIV with the defining property
shown above.
Comments
The introduced constants have a prefix parsing status. To alter this,
use set_fixity. Typical fixity values are Binder, Infixl n,
Infixr n, Prefix n, Suffix n, or Closefix.
See also
Definition.gen_new_specification,
Definition.new_definition,
boolSyntax.new_binder_definition,
boolSyntax.new_infixl_definition,
boolSyntax.new_infixr_definition,
TotalDefn.Define,
Parse.set_fixity
new_type_definition
new_type_definition
Definition.new_type_definition : string * thm -> thm
Defines a new type constant or type operator.
The ML function new_type_definition implements the primitive HOL rule
of definition for introducing new type constants or type operators into
the logic. If t is a term of type ty->bool containing n distinct
type variables, then evaluating:
new_type_definition (tyop, |- ?x. t x)
results in tyop being declared as a new n-ary type operator in the
current theory and returned by the call to new_type_definition. This
new type operator is characterized by a definitional axiom of the form:
|- ?rep:('a,...,'n)op->tyop. TYPE_DEFINITION t rep
which is stored as a definition in the current theory segment under the
automatically-generated name op_TY_DEF. The arguments to the new type
operator occur in the order given by an alphabetic ordering of the name
of the corresponding type variables. The constant TYPE_DEFINITION in
this axiomatic characterization of tyop is defined by:
|- TYPE_DEFINITION (P:'a->bool) (rep:'b->'a) =
(!x' x''. (rep x' = rep x'') ==> (x' = x'')) /\
(!x. P x = (?x'. x = rep x'))
Thus |- ?rep. TYPE_DEFINITION P rep asserts that there is a bijection
between the newly defined type ('a,...,'n)tyop and the set of values
of type ty that satisfy P.
Failure
Executing new_type_definition(tyop,th) fails if th is not an
assumption-free theorem of the form |- ?x. t x, if the type of t is
not of the form ty->bool, or if there are free variables in the term
t.
Example
In this example, a type containing three elements is defined. The
predicate defining the type is over the type bool # bool.
app load ["PairedLambda", "Q"]; open PairedLambda pairTheory;
- val tyax =
new_type_definition ("three",
Q.prove(`?p. (\(x,y). ~(x /\ y)) p`,
Q.EXISTS_TAC `(F,F)` THEN GEN_BETA_TAC THEN REWRITE_TAC []));
> val tyax = |- ?rep. TYPE_DEFINITION (\(x,y). ~(x /\ y)) rep : thm
Comments
Usually, once a type has been defined, maps between the representation
type and the new type need to be proved. This may be accomplished using
define_new_type_bijections. In the example, the two functions are
named abs3 and rep3.
- val three_bij = define_new_type_bijections
{name="three_tybij", ABS="abs3", REP="rep3", tyax=tyax};
> val three_bij =
|- (!a. abs3 (rep3 a) = a) /\
(!r. (\(x,y). ~(x /\ y)) r = (rep3 (abs3 r) = r))
Properties of the maps may be conveniently proved with
prove_abs_fn_one_one, prove_abs_fn_onto, prove_rep_fn_one_one, and
prove_rep_fn_onto. In this case, we need only prove_abs_fn_one_one.
- val abs_11 = GEN_BETA_RULE (prove_abs_fn_one_one three_bij);
> val abs_11 =
|- !r r'.
~(FST r /\ SND r) ==>
~(FST r' /\ SND r') ==>
((abs3 r = abs3 r') = (r = r')) : thm
Now we address how to define constants designating the three elements of
our example type. We will use new_specification to create these
constants (say e1, e2, and e3) and their characterizing property,
which is
~(e1 = e2) /\ ~(e2 = e3) /\ ~(e3 = e1)
A simple lemma stating that the abstraction function doesn't confuse any of the representations is required:
- val abs_distinct =
REWRITE_RULE (PAIR_EQ::pair_rws)
(LIST_CONJ (map (C Q.SPECL abs_11)
[[`(F,F)`,`(F,T)`],
[`(F,T)`,`(T,F)`],
[`(T,F)`,`(F,F)`]]));
> val abs_distinct =
|- ~(abs3 (F,F) = abs3 (F,T)) /\
~(abs3 (F,T) = abs3 (T,F)) /\
~(abs3 (T,F) = abs3 (F,F)) : thm
Finally, we can introduce the constants and their property.
- val THREE = new_specification
("THREE", ["e1", "e2", "e3"],
PROVE [abs_distinct]
(Term`?x y z:three. ~(x=y) /\ ~(y=z) /\ ~(z=x)`));
> val THREE = |- ~(e1 = e2) /\ ~(e2 = e3) /\ ~(e3 = e1) : thm
See also
Drule.define_new_type_bijections,
Prim_rec.prove_abs_fn_one_one,
Prim_rec.prove_abs_fn_onto,
Drule.prove_rep_fn_one_one,
Drule.prove_rep_fn_onto,
Definition.new_specification
Hol_defn
Hol_defn
Defn.Hol_defn : string -> term quotation -> defn
Re-exported from bossLib.Hol_defn. See that
entry for full documentation.
tgoal
tgoal
Defn.tgoal : defn -> proofs
Set up a termination proof.
tgoal defn sets up a termination proof for the function represented by
defn. It creates a new goalstack and makes it the focus of subsequent
goalstack operations.
Failure
tgoal defn fails if defn represents a non-recursive or primitive
recursive function.
Example
> val qsort_defn =
Hol_defn "qsort"
`(qsort ___ [] = []) /\
(qsort ord (x::rst) =
APPEND (qsort ord (FILTER ($~ o ord x) rst))
(x :: qsort ord (FILTER (ord x) rst)))`;
<<HOL message: inventing new type variable names: 'a>>
val qsort_defn =
HOL function definition (recursive)
Equation(s) :
[...] ⊢ qsort v0 [] = []
[...]
⊢ qsort ord (x::rst) =
qsort ord (FILTER ($¬ ∘ ord x) rst) ⧺ x::qsort ord (FILTER (ord x) rst)
Induction :
[...]
⊢ ∀P. (∀v0. P v0 []) ∧
(∀ord x rst.
P ord (FILTER (ord x) rst) ∧ P ord (FILTER ($¬ ∘ ord x) rst) ⇒
P ord (x::rst)) ⇒
∀v v1. P v v1
Termination conditions :
0. ∀rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)
1. ∀rst x ord. R (ord,FILTER ($¬ ∘ ord x) rst) (ord,x::rst)
2. WF R: DefnBase.defn
> Defn.tgoal qsort_defn;
val it =
Proof manager status: 1 proof.
1. Incomplete goalstack:
Initial goal:
∃R. WF R ∧ (∀rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)) ∧
∀rst x ord. R (ord,FILTER ($¬ ∘ ord x) rst) (ord,x::rst)
See also
TotalDefn.WF_REL_TAC,
Defn.tprove, Defn.Hol_defn
tprove
tprove
Defn.tprove : defn * tactic -> thm * thm
Prove termination of a defn.
tprove takes a defn and a tactic, and uses the tactic to prove the
termination constraints of the defn. A pair of theorems (eqns,ind)
is returned: eqns is the unconstrained recursion equations of the
defn, and ind is the corresponding induction theorem for the
equations, also unconstrained.
tprove and tgoal can be seen as analogues of prove and set_goal
in the specialized domain of proving termination of recursive functions.
It is up to the user to store the results of tprove in the current
theory segment.
Failure
tprove (defn,tac) fails if tac fails to prove the termination
conditions of defn.
tprove (defn,tac) fails if defn represents a non-recursive or
primitive recursive function.
Example
Suppose that we have defined a version of Quicksort as follows:
- val qsort_defn =
Hol_defn "qsort"
`(qsort ___ [] = []) /\
(qsort ord (x::rst) =
APPEND (qsort ord (FILTER ($~ o ord x) rst))
(x :: qsort ord (FILTER (ord x) rst)))`
Also suppose that a tactic tac proves termination of qsort. (This
tactic has probably been built by interactive proof after starting a
goalstack with tgoal qsort_defn.) Then
- val (qsort_eqns, qsort_ind) = tprove(qsort_defn, tac);
> val qsort_eqns =
|- (qsort v0 [] = []) /\
(qsort ord (x::rst) =
APPEND (qsort ord (FILTER ($~ o ord x) rst))
(x::qsort ord (FILTER (ord x) rst))) : thm
val qsort_ind =
|- !P.
(!v0. P v0 []) /\
(!ord x rst.
P ord (FILTER ($~ o ord x) rst) /\
P ord (FILTER (ord x) rst) ==> P ord (x::rst))
==>
!v v1. P v v1 : thm
Comments
The recursion equations returned by a successful invocation of tprove
are automatically added to the global compset accessed by EVAL.
See also
Defn.tgoal, Defn.Hol_defn,
bossLib.EVAL
DEP_ASM_REWRITE_TAC
DEP_ASM_REWRITE_TAC
dep_rewrite.DEP_ASM_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_ASM_REWRITE_TAC is to DEP_REWRITE_TAC what ASM_REWRITE_TAC is
to REWRITE_TAC.
The tactics with ASM in their name add the assumption list to the list of theorems used for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_LIST_ASM_REWRITE_TAC
DEP_LIST_ASM_REWRITE_TAC
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC : thm list list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_LIST_ASM_REWRITE_TAC is a variant of DEP_REWRITE_TAC.
The tactics with LIST take a list of lists of theorems, and uses each list of theorems once in order, left-to-right. For each list of theorems, the goal is rewritten as much as possible, until no further changes can be achieved in the goal. Hypotheses are collected from all rewriting and added to the goal, but they are not themselves rewritten.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
The tactics with ASM in their name add the assumption list to the list of theorems used for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_LIST_REWRITE_TAC
DEP_LIST_REWRITE_TAC
dep_rewrite.DEP_LIST_REWRITE_TAC : thm list list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_LIST_REWRITE_TAC is a variant of DEP_REWRITE_TAC.
The tactics with LIST take a list of lists of theorems, and uses each list of theorems once in order, left-to-right. For each list of theorems, the goal is rewritten as much as possible, until no further changes can be achieved in the goal. Hypotheses are collected from all rewriting and added to the goal, but they are not themselves rewritten.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_ONCE_ASM_REWRITE_TAC
DEP_ONCE_ASM_REWRITE_TAC
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_ONCE_ASM_REWRITE_TAC is to DEP_REWRITE_TAC what
ONCE_ASM_REWRITE_TAC is to REWRITE_TAC.
The tactics including ONCE in their name attempt to use each theorem in the list, only once, in order, left to right. The hypotheses added in the process of dependent rewriting are not rewritten by the ONCE tactics. This gives a more restrained version of dependent rewriting.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
The tactics with ASM in their name add the assumption list to the list of theorems used for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_ONCE_REWRITE_TAC
DEP_ONCE_REWRITE_TAC
dep_rewrite.DEP_ONCE_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_ONCE_REWRITE_TAC is to DEP_REWRITE_TAC what ONCE_REWRITE_TAC
is to REWRITE_TAC.
The tactics including ONCE in their name attempt to use each theorem in the list, only once, in order, left to right. The hypotheses added in the process of dependent rewriting are not rewritten by the ONCE tactics. This gives a more restrained version of dependent rewriting.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_PURE_ASM_REWRITE_TAC
DEP_PURE_ASM_REWRITE_TAC
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_PURE_ASM_REWRITE_TAC is to DEP_REWRITE_TAC what
PURE_ASM_REWRITE_TAC is to REWRITE_TAC.
The tactics including PURE in their name will only use the listed theorems for all rewriting; otherwise, the standard rewrites are used for normal rewriting, but they are not considered for dependent rewriting.
The tactics with ASM in their name add the assumption list to the list of theorems used for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_PURE_LIST_ASM_REWRITE_TAC
DEP_PURE_LIST_ASM_REWRITE_TAC
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_PURE_LIST_ASM_REWRITE_TAC is a variant of DEP_REWRITE_TAC.
The tactics including PURE in their name will only use the listed theorems for all rewriting; otherwise, the standard rewrites are used for normal rewriting, but they are not considered for dependent rewriting.
The tactics with LIST take a list of lists of theorems, and uses each list of theorems once in order, left-to-right. For each list of theorems, the goal is rewritten as much as possible, until no further changes can be achieved in the goal. Hypotheses are collected from all rewriting and added to the goal, but they are not themselves rewritten.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
The tactics with ASM in their name add the assumption list to the list of theorems used for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_PURE_LIST_REWRITE_TAC
DEP_PURE_LIST_REWRITE_TAC
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC : thm list list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_PURE_LIST_REWRITE_TAC is a variant of DEP_REWRITE_TAC.
The tactics including PURE in their name will only use the listed theorems for all rewriting; otherwise, the standard rewrites are used for normal rewriting, but they are not considered for dependent rewriting.
The tactics with LIST take a list of lists of theorems, and uses each list of theorems once in order, left-to-right. For each list of theorems, the goal is rewritten as much as possible, until no further changes can be achieved in the goal. Hypotheses are collected from all rewriting and added to the goal, but they are not themselves rewritten.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_PURE_ONCE_ASM_REWRITE_TAC
DEP_PURE_ONCE_ASM_REWRITE_TAC
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_PURE_ONCE_ASM_REWRITE_TAC is to DEP_REWRITE_TAC what
PURE_ONCE_ASM_REWRITE_TAC is to REWRITE_TAC.
The tactics including PURE in their name will only use the listed theorems for all rewriting; otherwise, the standard rewrites are used for normal rewriting, but they are not considered for dependent rewriting.
The tactics including ONCE in their name attempt to use each theorem in the list, only once, in order, left to right. The hypotheses added in the process of dependent rewriting are not rewritten by the ONCE tactics. This gives a more restrained version of dependent rewriting.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
The tactics with ASM in their name add the assumption list to the list of theorems used for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_PURE_ONCE_REWRITE_TAC
DEP_PURE_ONCE_REWRITE_TAC
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_PURE_ONCE_REWRITE_TAC is to DEP_REWRITE_TAC what
PURE_ONCE_REWRITE_TAC is to REWRITE_TAC.
The tactics including PURE in their name will only use the listed theorems for all rewriting; otherwise, the standard rewrites are used for normal rewriting, but they are not considered for dependent rewriting.
The tactics including ONCE in their name attempt to use each theorem in the list, only once, in order, left to right. The hypotheses added in the process of dependent rewriting are not rewritten by the ONCE tactics. This gives a more restrained version of dependent rewriting.
The tactics without ONCE or LIST attempt to reuse all theorems repeatedly, continuing to rewrite until no changes can be achieved in the goal. Hypotheses are rewritten as well, and their hypotheses as well, ad infinitum.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_PURE_REWRITE_TAC
DEP_PURE_REWRITE_TAC
dep_rewrite.DEP_PURE_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
DEP_PURE_REWRITE_TAC is to DEP_REWRITE_TAC what PURE_REWRITE_TAC
is to REWRITE_TAC.
The tactics including PURE in their name will only use the listed theorems for all rewriting; otherwise, the standard rewrites are used for normal rewriting, but they are not considered for dependent rewriting.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
DEP_REWRITE_TAC
DEP_REWRITE_TAC
dep_rewrite.DEP_REWRITE_TAC : thm list -> tactic
Rewrites a goal using implications of equalites, adding proof obligations as required.
In a call DEP_REWRITE_TAC [thm1,...], the argument theorems thm1,...
are typically implications. The tactic identifies the consequents of the
argument theorems, and attempt to match these against the current goal.
If a match is found, the goal is rewritten according to the matched
instance of the consequent, after which the corresponding hypotheses of
the argument theorems are added to the goal as new conjuncts on the
left.
Care needs to be taken that the implications will match the goal
properly, that is, instances where the hypotheses in fact can be proven.
Also, even more commonly than with REWRITE_TAC, the rewriting process
may diverge.
Each implication theorem for rewriting may have a number of layers of universal quantification and implications. At the bottom of these layers is the base, which will either be an equality, a negation, or a general term. The pattern for matching will be the left-hand-side of an equality, the term negated of a negation, or the term itself in the third case. The search is top-to-bottom left-to-right, depending on the quantifications of variables.
To assist in focusing the matching to useful cases, the goal is searched
for a subterm matching the pattern. The matching of the pattern to
subterms is performed by higher-order matching, so for example,
!x. P x will match the term !n. (n+m) < 4*n.
The argument theorems may each be either an implication or not. For those which are implications, the hypotheses of the instance of each theorem which matched the goal are added to the goal as conjuncts on the left side. For those argument theorems which are not implications, the goal is simply rewritten with them. This rewriting is also higher order.
Comments
Deep inner universal quantifications of consequents are supported. Thus,
an argument theorem like EQ_LIST:
|- !h1 h2. (h1 = h2) ==> (!l1 l2. (l1 = l2) ==>
(CONS h1 l1 = CONS h2 l2))
before it is used, is internally converted to appear as
|- !h1 h2 l1 l2. (h1 = h2) /\ (l1 = l2) ==>
(CONS h1 l1 = CONS h2 l2)
As much as possible, the newly added hypotheses are analyzed to remove duplicates; thus, several theorems with the same hypothesis, or several uses of the same theorem, will generate a minimal additional proof burden.
The new hypotheses are added as conjuncts rather than as a separate
subgoal to reduce the user's burden of subgoal splits when creating
tactics to prove theorems. If a separate subgoal is desired, simply use
CONJ_TAC after the dependent rewriting to split the goal into two,
where the first contains the hypotheses and the second contains the
rewritten version of the original goal.
See also
dep_rewrite.DEP_PURE_ONCE_REWRITE_TAC,
dep_rewrite.DEP_ONCE_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ONCE_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_ONCE_SUBST_TAC,
dep_rewrite.DEP_ONCE_SUBST_TAC,
dep_rewrite.DEP_PURE_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_ONCE_ASM_SUBST_TAC,
dep_rewrite.DEP_PURE_LIST_REWRITE_TAC,
dep_rewrite.DEP_LIST_REWRITE_TAC,
dep_rewrite.DEP_PURE_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_LIST_ASM_REWRITE_TAC,
dep_rewrite.DEP_PURE_REWRITE_TAC,
dep_rewrite.DEP_REWRITE_TAC,
dep_rewrite.DEP_PURE_ASM_REWRITE_TAC,
dep_rewrite.DEP_ASM_REWRITE_TAC,
dep_rewrite.DEP_FIND_THEN,
dep_rewrite.DEP_LIST_FIND_THEN,
dep_rewrite.DEP_ONCE_FIND_THEN
ADD_ASSUM
ADD_ASSUM
Drule.ADD_ASSUM : term -> thm -> thm
Adds an assumption to a theorem.
When applied to a boolean term s and a theorem A |- t, the inference
rule ADD_ASSUM returns the theorem A u {s} |- t.
A |- t
-------------- ADD_ASSUM s
A u {s} |- t
Failure
Fails unless the given term has type bool.
See also
ALPHA_CONV
ALPHA_CONV
Drule.ALPHA_CONV : term -> conv
Renames the bound variable of a lambda-abstraction.
If x is a variable of type ty and M is an abstraction (with bound
variable y of type ty and body t), then ALPHA_CONV x M returns
the theorem:
|- (\y.t) = (\x'. t[x'/y])
where the variable x':ty is a primed variant of x chosen so as not
to be free in \y.t.
Failure
ALPHA_CONV x tm fails if x is not a variable, if tm is not an
abstraction, or if x is a variable v and tm is a lambda
abstraction \y.t but the types of v and y differ.
See also
Thm.ALPHA,
Drule.GEN_ALPHA_CONV
ASSUME_CONJS
ASSUME_CONJS
Drule.ASSUME_CONJS : term -> thm
Constructs a theorem proving a conjunction from its individual conjuncts
Takes a term which should be a conjunction, and returns a theorem whose hypotheses are the individual conjuncts, and whose conclusion is the argument term, the conjunction.
Failure
Never fails.
Example
ASSUME_CONJS (``t1 /\ t2 /\ ... /\ tn``) returns
[t1, t2, ..., tn] |- t1 /\ t2 /\ ... /\ tn
To split up conjuncts in selected hypotheses hyps of a theorem th,
use Lib.itlist (PROVE_HYP o ASSUME_CONJS) hyps th
See also
Drule.CONJUNCTS, Thm.CONJ,
Drule.CONJUNCTS_AC,
Drule.UNDISCH_SPLIT
BODY_CONJUNCTS
BODY_CONJUNCTS
Drule.BODY_CONJUNCTS : (thm -> thm list)
Splits up conjuncts recursively, stripping away universal quantifiers.
When applied to a theorem, BODY_CONJUNCTS recursively strips off
universal quantifiers by specialization, and breaks conjunctions into a
list of conjuncts.
A |- !x1...xn. t1 /\ (!y1...ym. t2 /\ t3) /\ ...
-------------------------------------------------- BODY_CONJUNCTS
[A |- t1, A |- t2, A |- t3, ...]
Failure
Never fails, but has no effect if there are no top-level universal quantifiers or conjuncts.
Example
The following illustrates how a typical term will be split:
- local val tm = Parser.term_parser
`!x:bool. A /\ (B \/ (C /\ D)) /\ ((!y:bool. E) /\ F)`
in
val x = ASSUME tm
end;
val x = . |- !x. A /\ (B \/ C /\ D) /\ (!y. E) /\ F : thm
- BODY_CONJUNCTS x;
val it = [. |- A, . |- B \/ C /\ D, . |- E, . |- F] : thm list
See also
Thm.CONJ, Thm.CONJUNCT1,
Thm.CONJUNCT2,
Drule.CONJUNCTS,
Tactic.CONJ_TAC
cj
cj
Drule.cj : int -> thm -> thm
Returns the i'th conjunct of a "guarded" theorem
A call to cj i th, where th has the form
|- !x1 .. xn. p1 /\ .. /\ pm ==> !y... q1 /\ .. ==> ... ==>
c1 /\ c2 /\ ... ck
returns the theorem
|- !x1 .. xn. p1 /\ .. /\ pm ==> !y... q1 /\ .. ==> ... ==> ci
Note that the indexing starts at 1. The conjuncts are stripped apart
without regard to the way in which they are associated, as per the
behaviour of CONJUNCTS.
Failure
Fails if the conclusion of the guarded theorem does not contain at least
i conjuncts. A bare term is always considered to be 1 conjunct.
See also
Drule.BODY_CONJUNCTS,
Drule.CONJUNCTS,
Drule.underAIs
CONJ_DISCH
CONJ_DISCH
Drule.CONJ_DISCH : (term -> thm -> thm)
Discharges an assumption and conjoins it to both sides of an equation.
Given an term t and a theorem A |- t1 = t2, which is an equation
between boolean terms, CONJ_DISCH returns
A - {t} |- (t /\ t1) = (t /\ t2), i.e. conjoins t to both sides of
the equation, removing t from the assumptions if it was there.
A |- t1 = t2
------------------------------ CONJ_DISCH "t"
A - {t} |- t /\ t1 = t /\ t2
Failure
Fails unless the theorem is an equation, both sides of which, and the
term provided are of type bool.
See also
CONJ_DISCHL
CONJ_DISCHL
Drule.CONJ_DISCHL : (term list -> thm -> thm)
Conjoins multiple assumptions to both sides of an equation.
Given a term list [t1;...;tn] and a theorem whose conclusion is an
equation between boolean terms, CONJ_DISCHL conjoins all the terms in
the list to both sides of the equation, and removes any of the terms
which were in the assumption list.
A |- s = t
-------------------------------------------------------- CONJ_DISCHL
A - {t1,...,tn} |- (t1/\.../\tn/\s) = (t1/\.../\tn/\t) [t1,...,tn]
Failure
Fails unless the theorem is an equation, both sides of which, and all
the terms provided, are of type bool.
See also
CONJ_LIST
CONJ_LIST
Drule.CONJ_LIST : (int -> thm -> thm list)
Extracts a list of conjuncts from a theorem (non-flattening version).
CONJ_LIST is the proper inverse of LIST_CONJ. Unlike CONJUNCTS
which recursively splits as many conjunctions as possible both to the
left and to the right, CONJ_LIST splits the top-level conjunction and
then splits (recursively) only the right conjunct. The integer argument
is required because the term tn may itself be a conjunction. A list of
n theorems is returned.
A |- t1 /\ (t2 /\ ( ... /\ tn)...)
------------------------------------ CONJ_LIST n (A |- t1 /\ ... /\ tn)
A |- t1 A |- t2 ... A |- tn
Failure
Fails if the integer argument (n) is less than one, or if the input
theorem has less than n conjuncts.
Example
Suppose the identifier th is bound to the theorem:
A |- (x /\ y) /\ z /\ w
Here are some applications of CONJ_LIST to th:
- CONJ_LIST 0 th;
! Uncaught exception:
! HOL_ERR
- CONJ_LIST 1 th;
> val it = [[A] |- (x /\ y) /\ z /\ w] : thm list
- CONJ_LIST 2 th;
> val it = [ [A] |- x /\ y, [A] |- z /\ w] : thm list
- CONJ_LIST 3 th;
> val it = [ [A] |- x /\ y, [A] |- z, [A] |- w] : thm list
- CONJ_LIST 4 th;
! Uncaught exception:
! HOL_ERR
See also
Drule.BODY_CONJUNCTS,
Drule.LIST_CONJ,
Drule.CONJUNCTS, Thm.CONJ,
Thm.CONJUNCT1, Thm.CONJUNCT2,
Drule.CONJ_PAIR
CONJ_PAIR
CONJ_PAIR
Drule.CONJ_PAIR : thm -> thm * thm
Extracts both conjuncts of a conjunction.
A |- t1 /\ t2
---------------------- CONJ_PAIR
A |- t1 A |- t2
The two resultant theorems are returned as a pair.
Failure
Fails if the input theorem is not a conjunction.
See also
Drule.BODY_CONJUNCTS,
Thm.CONJUNCT1, Thm.CONJUNCT2,
Thm.CONJ, Drule.LIST_CONJ,
Drule.CONJ_LIST,
Drule.CONJUNCTS
CONJUNCTS
CONJUNCTS
Drule.CONJUNCTS : (thm -> thm list)
Recursively splits conjunctions into a list of conjuncts.
Flattens out all conjuncts, regardless of grouping. Returns a singleton list if the input theorem is not a conjunction.
A |- t1 /\ t2 /\ ... /\ tn
----------------------------------- CONJUNCTS
A |- t1 A |- t2 ... A |- tn
Failure
Never fails.
Example
Suppose the identifier th is bound to the theorem:
A |- (x /\ y) /\ z /\ w
Application of CONJUNCTS to th returns the following list of
theorems:
[A |- x, A |- y, A |- z, A |- w] : thm list
See also
Drule.BODY_CONJUNCTS,
Drule.CONJ_LIST,
Drule.LIST_CONJ, Thm.CONJ,
Thm.CONJUNCT1, Thm.CONJUNCT2,
Drule.CONJ_PAIR
CONJUNCTS_AC
CONJUNCTS_AC
Drule.CONJUNCTS_AC : term * term -> thm
Prove equivalence under idempotence, symmetry and associativity of conjunction.
CONJUNCTS_AC takes a pair of terms (t1, t2) and proves |- t1 = t2
if t1 and t2 are equivalent up to idempotence, symmetry and
associativity of conjunction. That is, if t1 and t2 are two
(different) arbitrarily-nested conjunctions of the same set of terms,
then CONJUNCTS_AC (t1,t2) returns |- t1 = t2. Otherwise, it fails.
Failure
Fails if t1 and t2 are not equivalent, as described above.
Example
> CONJUNCTS_AC (Term `(P /\ Q) /\ R`, Term `R /\ (Q /\ R) /\ P`);
val it = ⊢ (P ∧ Q) ∧ R ⇔ R ∧ (Q ∧ R) ∧ P: thm
Used to reorder a conjunction. First sort the conjuncts in a term t1
into the desired order (e.g., lexicographic order, for normalization) to
get a new term t2, then call CONJUNCTS_AC(t1,t2).
See also
CONTR
CONTR
Drule.CONTR : term -> thm -> thm
Implements the intuitionistic contradiction rule.
When applied to a term t and a theorem A |- F, the inference rule
CONTR returns the theorem A |- t.
A |- F
-------- CONTR t
A |- t
Failure
Fails unless the term has type bool and the theorem has F as its
conclusion.
See also
Thm.CCONTR, Drule.CONTRAPOS,
Tactic.CONTR_TAC, Thm.NOT_ELIM
CONTRAPOS
CONTRAPOS
Drule.CONTRAPOS : (thm -> thm)
Deduces the contrapositive of an implication.
When applied to a theorem A |- s ==> t, the inference rule CONTRAPOS
returns its contrapositive, A |- ~t ==> ~s.
A |- s ==> t
---------------- CONTRAPOS
A |- ~t ==> ~s
Failure
Fails unless the theorem is an implication.
See also
Thm.CCONTR, Drule.CONTR,
Conv.CONTRAPOS_CONV,
Thm.NOT_ELIM
define_new_type_bijections
define_new_type_bijections
Drule.define_new_type_bijections :
{name:string, ABS:string, REP:string, tyax:thm} -> thm
Introduces abstraction and representation functions for a defined type.
The result of making a type definition using new_type_definition is a
theorem of the following form:
|- ?rep:nty->ty. TYPE_DEFINITION P rep
which asserts only the existence of a bijection from the type it defines
(in this case, nty) to the corresponding subset of an existing type
(here, ty) whose characteristic function is specified by P. To
automatically introduce constants that in fact denote this bijection and
its inverse, the ML function define_new_type_bijections is provided.
name is the name under which the constant definition (a constant
specification, in fact) made by define_new_type_bijections will be
stored in the current theory segment. tyax must be a definitional
axiom of the form returned by new_type_definition. ABS and REP are
the user-specified names for the two constants that are to be defined.
These constants are defined so as to denote mutually inverse bijections
between the defined type, whose definition is given by tyax, and the
representing type of this defined type.
If th is a theorem of the form returned by new_type_definition:
|- ?rep:newty->ty. TYPE_DEFINITION P rep
then evaluating:
define_new_type_bijections{name="name",ABS="abs",REP="rep",tyax=th} th
automatically defines two new constants abs:ty->newty and
rep:newty->ty such that:
|- (!a. abs(rep a) = a) /\ (!r. P r = (rep(abs r) = r))
This theorem, which is the defining property for the constants abs and
rep, is stored under the name name in the current theory segment. It
is also the value returned by define_new_type_bijections. The theorem
states that abs is the left inverse of rep and, for values
satisfying P, that rep is the left inverse of abs.
Failure
A call define_new_type_bijections{name,ABS,REP,tyax} fails if tyax
is not a theorem of the form returned by new_type_definition.
See also
Definition.new_type_definition,
Drule.prove_abs_fn_one_one,
Drule.prove_abs_fn_onto,
Drule.prove_rep_fn_one_one,
Drule.prove_rep_fn_onto
DISCH_ALL
DISCH_ALL
Drule.DISCH_ALL : thm -> thm
Discharges all hypotheses of a theorem.
A1, ..., An |- t
---------------------------- DISCH_ALL
|- A1 ==> ... ==> An ==> t
Failure
DISCH_ALL never fails. If there are no hypotheses to discharge, it
will simply return the theorem unchanged.
Comments
Users should not rely on the hypotheses being discharged in any particular order.
See also
Thm.DISCH, Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Drule.NEG_DISCH,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
DISJ_CASES_UNION
DISJ_CASES_UNION
Drule.DISJ_CASES_UNION : thm -> thm -> thm -> thm
Makes an inference for each arm of a disjunct.
Given a disjunctive theorem, and two additional theorems each having one disjunct as a hypothesis, a new theorem with a conclusion that is the disjunction of the conclusions of the last two theorems is produced. The hypotheses include the union of hypotheses of all three theorems less the two disjuncts.
A |- t1 \/ t2 A1 u {t1} |- t3 A2 u {t2} |- t4
------------------------------------------------------ DISJ_CASES_UNION
A u A1 u A2 |- t3 \/ t4
Failure
Fails if the first theorem is not a disjunction.
Example
The built-in theorem LESS_CASES can be specialized to:
th1 = |- m < n \/ n <= m
and used with two additional theorems:
th2 = (m < n |- (m MOD n = m))
th3 = ({0 < n, n <= m} |- (m MOD n) = ((m - n) MOD n))
to derive a new theorem:
- DISJ_CASES_UNION th1 th2 th3;
val it = [0 < n] |- (m MOD n = m) \/ (m MOD n = (m - n) MOD n) : thm
See also
Thm.DISJ_CASES,
Tactic.DISJ_CASES_TAC,
Thm.DISJ1, Thm.DISJ2
DISJ_IMP
DISJ_IMP
Drule.DISJ_IMP : (thm -> thm)
Converts a disjunctive theorem to an equivalent implicative theorem.
The left disjunct of a disjunctive theorem becomes the negated antecedent of the newly generated theorem.
A |- t1 \/ t2
----------------- DISJ_IMP
A |- ~t1 ==> t2
Failure
Fails if the theorem is not a disjunction.
Example
Specializing the built-in theorem LESS_CASES gives the theorem:
th = |- m < n \/ n <= m
to which DISJ_IMP may be applied:
- DISJ_IMP th;
> val it = |- ~m < n ==> n <= m : thm
See also
DISJUNCTS_AC
DISJUNCTS_AC
Drule.DISJUNCTS_AC : term * term -> thm
Prove equivalence under idempotence, symmetry and associativity of disjunction.
DISJUNCTS_AC takes a pair of terms (t1, t2) and proves |- t1 = t2
if t1 and t2 are equivalent up to idempotence, symmetry and
associativity of disjunction. That is, if t1 and t2 are two
(different) arbitrarily-nested disjunctions of the same set of terms,
then DISJUNCTS_AC (t1,t2) returns |- t1 = t2. Otherwise, it fails.
Failure
Fails if t1 and t2 are not equivalent, as described above.
Example
> DISJUNCTS_AC (Term `(P \/ Q) \/ R`, Term `R \/ (Q \/ R) \/ P`);
val it = ⊢ (P ∨ Q) ∨ R ⇔ R ∨ (Q ∨ R) ∨ P: thm
Used to reorder a disjunction. First sort the disjuncts in a term t1
into the desired order (e.g., lexicographic order, for normalization) to
get a new term t2, then call DISJUNCTS_AC(t1,t2).
See also
EQF_ELIM
EQF_ELIM
Drule.EQF_ELIM : (thm -> thm)
Replaces equality with F by negation.
A |- tm = F
------------- EQF_ELIM
A |- ~tm
Failure
Fails if the argument theorem is not of the form A |- tm = F.
See also
Drule.EQF_INTRO,
Drule.EQT_ELIM,
Drule.EQT_INTRO
EQF_INTRO
EQF_INTRO
Drule.EQF_INTRO : (thm -> thm)
Converts negation to equality with F.
A |- ~tm
------------- EQF_INTRO
A |- tm = F
Failure
Fails if the argument theorem is not a negation.
See also
Drule.EQF_ELIM,
Drule.EQT_ELIM,
Drule.EQT_INTRO
EQT_ELIM
EQT_ELIM
Drule.EQT_ELIM : (thm -> thm)
Eliminates equality with T.
A |- tm = T
------------- EQT_ELIM
A |- tm
Failure
Fails if the argument theorem is not of the form A |- tm = T.
See also
Drule.EQT_INTRO,
Drule.EQF_ELIM,
Drule.EQF_INTRO
EQT_INTRO
EQT_INTRO
Drule.EQT_INTRO : thm -> thm
Introduces equality with T.
A |- tm
------------- EQT_INTRO
A |- tm = T
Failure
Never fails.
See also
Drule.EQT_ELIM,
Drule.EQF_ELIM,
Drule.EQF_INTRO
ETA_CONV
ETA_CONV
Drule.ETA_CONV : conv
Performs a toplevel eta-conversion.
ETA_CONV maps an eta-redex \x. (t x), where x does not occur free
in t, to the theorem |- (\x. (t x)) = t.
Failure
Fails if the input term is not an eta-redex.
See also
Drule.RIGHT_ETA, Term.eta_conv
EXISTS_EQ
EXISTS_EQ
Drule.EXISTS_EQ : (term -> thm -> thm)
Existentially quantifies both sides of an equational theorem.
When applied to a variable x and a theorem whose conclusion is
equational, A |- t1 = t2, the inference rule EXISTS_EQ returns the
theorem A |- (?x. t1) = (?x. t2), provided the variable x is not
free in any of the assumptions.
A |- t1 = t2
------------------------ EXISTS_EQ "x" [where x is not free in A]
A |- (?x.t1) = (?x.t2)
Failure
Fails unless the theorem is equational with both sides having type
bool, or if the term is not a variable, or if the variable to be
quantified over is free in any of the assumptions.
See also
Thm.AP_TERM, Drule.EXISTS_IMP,
Drule.FORALL_EQ,
Drule.MK_EXISTS,
Drule.SELECT_EQ
EXISTS_IMP
EXISTS_IMP
Drule.EXISTS_IMP : (term -> thm -> thm)
Existentially quantifies both the antecedent and consequent of an implication.
When applied to a variable x and a theorem A |- t1 ==> t2, the
inference rule EXISTS_IMP returns the theorem
A |- (?x. t1) ==> (?x. t2), provided x is not free in the
assumptions.
A |- t1 ==> t2
-------------------------- EXISTS_IMP "x" [where x is not free in A]
A |- (?x.t1) ==> (?x.t2)
Failure
Fails if the theorem is not implicative, or if the term is not a variable, or if the term is a variable but is free in the assumption list.
See also
EXISTS_LEFT
EXISTS_LEFT
Drule.EXISTS_LEFT : term list -> thm -> thm
Existentially quantifes hypotheses of a theorem.
In this example, assume that h1 and h3 (only) involve the free
variable x.
h1, h2, h3 |- t
--------------------- EXISTS_LEFT [``x``]
?x. h1 /\ h3, h2 |- t
Failure
EXISTS_LEFT will fail if the term list supplied does not consist only
of free variables
Example
Where th is [p, q, g x, h y, f x y] |- r, and fvx and fvy are
``x`` and ``y``,
EXISTS_LEFT [fvx, fvy] th is
[p, q, ?y. (?x. g x /\ f x y) /\ h y] |- r
EXISTS_LEFT [fvy, fvx] th is
[p, q, ?x. (?y. h y /\ f x y) /\ g x] |- r
Where EQ_TRANS is [] |- !x y z. (x = y) /\ (y = z) ==> (x = z) and
the current goal is a = b, the tactic MATCH_MP_TAC EQ_TRANS gives a
new goal ?y. (a = y) /\ (y = b) by virtue of the smart features built
into MATCH_MP_TAC.
Where trans_thm is [] |- !x y z. (x = y) ==> (y = z) ==> (x = z) the
same result could of course be achieved by rewriting it with
AND_IMP_INTRO. But more generally, EXISTS_LEFT could be used as a
building-block for a more flexible tactic. In this instance, one might
start with
val trans_thm_h = UNDISCH_ALL (SPEC_ALL trans_thm) ;
EXISTS_LEFT (thm_frees trans_thm_h) trans_thm_h ;
giving [?y. (x = y) /\ (y = z)] |- x = z
See also
Drule.EXISTS_LEFT1,
Thm.CHOOSE, Thm.EXISTS,
Tactic.CHOOSE_TAC,
Tactic.EXISTS_TAC
EXISTS_LEFT1
EXISTS_LEFT1
Drule.EXISTS_LEFT1 : term -> thm -> thm
Existentially quantifes hypotheses of a theorem.
In this example, assume that h1 and h3 (only) involve the free
variable x.
h1, h2, h3 |- t
--------------------- EXISTS_LEFT1 ``x``
?x. h1 /\ h3, h2 |- t
Failure
EXISTS_LEFT1 will fail unless the term supplied is a free variable
which appears in one or more hypotheses but not the conclusion of the
given theorem
Example
Where th is [p, q, g x, h y, f x y] |- r, and fvx and fvy are
``x`` and ``y``,
EXISTS_LEFT1 fvx th is [p, q, h y, ?x. g x /\ f x y] |- r
EXISTS_LEFT1 fvy th is [p, q, g x, ?y. h y /\ f x y] |- r
Comments
EXISTS_LEFT1 fv is just like EXISTS_LEFT [fv] except that
EXISTS_LEFT1 fv fails where EXISTS_LEFT [fv] returns the theorem
unchanged
See EXISTS_LEFT for further discussion
See also
Drule.EXISTS_LEFT, Thm.CHOOSE,
Thm.EXISTS, Tactic.CHOOSE_TAC,
Tactic.EXISTS_TAC
EXT
EXT
Drule.EXT : thm -> thm
Derives equality of functions from extensional equivalence.
When applied to a theorem A |- !x. t1 x = t2 x, the inference rule
EXT returns the theorem A |- t1 = t2.
A |- !x. t1 x = t2 x
---------------------- EXT [where x is not free in t1 or t2]
A |- t1 = t2
Failure
Fails if the theorem does not have the form indicated above, or if the
variable x is free in either of the functions t1 or t2.
Comments
This rule is expressed as an equivalence in the theorem
boolTheory.FUN_EQ_THM.
See also
Thm.AP_THM, Drule.ETA_CONV,
Conv.FUN_EQ_CONV
FORALL_EQ
FORALL_EQ
Drule.FORALL_EQ : (term -> thm -> thm)
Universally quantifies both sides of an equational theorem.
When applied to a variable x and a theorem A |- t1 = t2, whose
conclusion is an equation between boolean terms, FORALL_EQ returns the
theorem A |- (!x. t1) = (!x. t2), unless the variable x is free in
any of the assumptions.
A |- t1 = t2
------------------------ FORALL_EQ "x" [where x is not free in A]
A |- (!x.t1) = (!x.t2)
Failure
Fails if the theorem is not an equation between boolean terms, or if the supplied term is not simply a variable, or if the variable is free in any of the assumptions.
See also
Thm.AP_TERM, Drule.EXISTS_EQ,
Drule.SELECT_EQ
FULL_GEN_TYVARIFY
FULL_GEN_TYVARIFY
Drule.FULL_GEN_TYVARIFY : thm -> thm
Replace a theorem's type variables with fresh versions
A call to FULL_GEN_TYVARIFTY th replaces (with INST_TYPE) the type
variables occurring in theorem th. The new type variables are
generated by successive calls to gen_tyvar, so should not have been
seen before.
Failure
Never fails.
Comments
The derived rule GEN_TYVARIFY will only instantiate those type
variables that are exclusively found in the conclusion. This is
reasonable when handling theorems derived from a tactic goal's
assumptions.
See also
Drule.GEN_TYVARIFY,
Thm.INST_TYPE
GEN_ALL
GEN_ALL
Drule.GEN_ALL : thm -> thm
Generalizes the conclusion of a theorem over its own free variables.
When applied to a theorem A |- t, the inference rule GEN_ALL returns
the theorem A |- !x1...xn. t, where the xi are all the variables, if
any, which are free in t but not in the assumptions.
A |- t
------------------ GEN_ALL
A |- !x1...xn. t
Failure
Never fails.
Comments
Sometimes people write code that depends on the order of the quantification. They shouldn't.
See also
Thm.GEN, Thm.GENL, Thm.SPEC,
Drule.SPECL, Drule.SPEC_ALL,
Tactic.SPEC_TAC
GEN_ALPHA_CONV
GEN_ALPHA_CONV
Drule.GEN_ALPHA_CONV : term -> conv
Renames the bound variable of an abstraction, a quantified term, or other binder application.
The conversion GEN_ALPHA_CONV provides alpha conversion for lambda
abstractions of the form \y.t, quantified terms of the forms !y.t,
?y.t or ?!y.t, and epsilon terms of the form @y.t. In general, if
B is a binder constant, then GEN_ALPHA_CONV implements alpha
conversion for applications of the form B y.t.
If tm is an abstraction \y.t or an application of a binder to an
abstraction B y.t, where the bound variable y has type ty, and if
x is a variable also of type ty, then GEN_ALPHA_CONV x tm returns
one of the theorems:
|- (\y.t) = (\x'. t[x'/y])
|- (B y.t) = (B x'. t[x'/y])
depending on whether the input term is \y.t or B y.t respectively.
The variable x':ty in the resulting theorem is a primed variant of x
chosen so as not to be free in the term provided as the second argument
to GEN_ALPHA_CONV.
Failure
GEN_ALPHA_CONV x tm fails if x is not a variable, or if tm does
not have one of the forms \y.t or B y.t, where B is a binder.
GEN_ALPHA_CONV x tm also fails if tm does have one of these forms,
but types of the variables x and y differ.
See also
Thm.ALPHA, Drule.ALPHA_CONV,
boolSyntax.new_binder_definition
GEN_TYVARIFY
GEN_TYVARIFY
Drule.GEN_TYVARIFY : thm -> thm
Replace a theorem's type variables with fresh versions
A call to GEN_TYVARIFY th replaces (with INST_TYPE) the type
variables occurring in theorem th's conclusion that do not also appear
in any of th's hypotheses. The new type variables are generated by
successive calls to gen_tyvar, so should not have been seen before.
Failure
Never fails.
Comments
The derived rule FULL_GEN_TYVARIFY will instantiate all of a theorem's
type variables, whether or not they appear in the hypotheses.
See also
Drule.FULL_GEN_TYVARIFY,
boolSyntax.gen_tyvar_sigma,
Thm.INST_TYPE
GSPEC
GSPEC
Drule.GSPEC : (thm -> thm)
Specializes the conclusion of a theorem with unique variables.
When applied to a theorem A |- !x1...xn. t, where the number of
universally quantified variables may be zero, GSPEC returns
A |- t[g1/x1]...[gn/xn], where the gi are distinct variable names of
the appropriate type, chosen by genvar.
A |- !x1...xn. t
------------------------- GSPEC
A |- t[g1/x1]...[gn/xn]
Failure
Never fails.
GSPEC is useful in writing derived inference rules which need to
specialize theorems while avoiding using any variables that may be
present elsewhere.
See also
Thm.GEN, Thm.GENL,
Term.genvar, Drule.GEN_ALL,
Tactic.GEN_TAC, Thm.SPEC,
Drule.SPECL, Drule.SPEC_ALL,
Tactic.SPEC_TAC
iffLR
iffLR
Drule.iffLR : thm -> thm
Returns the left-to-right direction of a "guarded" iff theorem
A call to iffLR th, where th has the form
A |- !x1 .. xn. p1 /\ .. /\ pm ==> !y... q1 /\ .. ==> ... ==> (l <=> r)
returns the left-to-right implication
A |- !x1 .. xn. p1 /\ .. /\ pm ==> !y... q1 /\ .. ==> ... ==> l ==> r
The universal variables and various antecedents are said to "guard" the
if-and-only-if conclusion l <=> r in this situation. They may be
nested abitrarily deep, or not present at all. They are restored after a
call to EQ_IMP_RULE is made.
Failure
Fails if the theorem is not of the form specified above.
See also
Drule.EQ_IMP_RULE,
Drule.iffRL, Drule.underAIs
iffRL
iffRL
Drule.iffRL : thm -> thm
Returns the right-to-left direction of a "guarded" iff theorem
A call to iffRL th, where th has the form
A |- !x1 .. xn. p1 /\ .. /\ pm ==> !y... q1 /\ .. ==> ... ==> (l <=> r)
returns the right-to-left implication
A |- !x1 .. xn. p1 /\ .. /\ pm ==> !y... q1 /\ .. ==> ... ==> r ==> l
The universal variables and various antecedents are said to "guard" the
if-and-only-if conclusion l <=> r in this situation. They may be
nested abitrarily deep, or not present at all. They are restored after a
call to EQ_IMP_RULE is made.
Failure
Fails if the theorem is not of the form specified above.
See also
Drule.EQ_IMP_RULE,
Drule.iffLR, Drule.underAIs
IMP_ANTISYM_RULE
IMP_ANTISYM_RULE
Drule.IMP_ANTISYM_RULE : thm -> thm -> thm
Deduces equality of boolean terms from forward and backward implications.
When applied to the theorems A1 |- t1 ==> t2 and A2 |- t2 ==> t1,
the inference rule IMP_ANTISYM_RULE returns the theorem
A1 u A2 |- t1 = t2.
A1 |- t1 ==> t2 A2 |- t2 ==> t1
------------------------------------- IMP_ANTISYM_RULE
A1 u A2 |- t1 = t2
Failure
Fails unless the theorems supplied are a complementary implicative pair as indicated above.
See also
Thm.EQ_IMP_RULE, Thm.EQ_MP,
Tactic.EQ_TAC
IMP_CANON
IMP_CANON
Drule.IMP_CANON : (thm -> thm list)
Puts theorem into a 'canonical' form.
IMP_CANON puts a theorem in 'canonical' form by removing quantifiers
and breaking apart conjunctions, as well as disjunctions which form the
antecedent of implications. It applies the following transformation
rules:
A |- t1 /\ t2 A |- !x. t A |- (t1 /\ t2) ==> t
------------------- ------------ ------------------------
A |- t1 A |- t2 A |- t A |- t1 ==> (t2 ==> t)
A |- (t1 \/ t2) ==> t A |- (?x. t1) ==> t2
------------------------------- ----------------------
A |- t1 ==> t A |- t2 ==> t A |- t1[x'/x] ==> t2
Failure
Never fails, but if there is no scope for one of the above reductions, merely gives a list whose only member is the original theorem.
Comments
This is a rather ad-hoc inference rule, and its use is not recommended.
See also
Thm.CONJUNCT1, Thm.CONJUNCT2,
Drule.CONJUNCTS, Thm.DISJ1,
Thm.DISJ2, Thm.EXISTS,
Thm.SPEC
IMP_CONJ
IMP_CONJ
Drule.IMP_CONJ : (thm -> thm -> thm)
Conjoins antecedents and consequents of two implications.
When applied to theorems A1 |- p ==> r and A2 |- q ==> s, the
IMP_CONJ inference rule returns the theorem
A1 u A2 |- p /\ q ==> r /\ s.
A1 |- p ==> r A2 |- q ==> s
-------------------------------- IMP_CONJ
A1 u A2 |- p /\ q ==> r /\ s
Failure
Fails unless the conclusions of both theorems are implicative.
See also
IMP_ELIM
IMP_ELIM
Drule.IMP_ELIM : (thm -> thm)
Transforms |- s ==> t into |- ~s \/ t.
When applied to a theorem A |- s ==> t, the inference rule IMP_ELIM
returns the theorem A |- ~s \/ t.
A |- s ==> t
-------------- IMP_ELIM
A |- ~s \/ t
Failure
Fails unless the theorem is implicative.
See also
IMP_TRANS
IMP_TRANS
Drule.IMP_TRANS : (thm -> thm -> thm)
Implements the transitivity of implication.
When applied to theorems A1 |- t1 ==> t2 and A2 |- t2 ==> t3, the
inference rule IMP_TRANS returns the theorem A1 u A2 |- t1 ==> t3.
A1 |- t1 ==> t2 A2 |- t2 ==> t3
----------------------------------- IMP_TRANS
A1 u A2 |- t1 ==> t3
Failure
Fails unless the theorems are both implicative, with the consequent of the first being the same as the antecedent of the second (up to alpha-conversion).
See also
Drule.IMP_ANTISYM_RULE,
Thm.SYM, Thm.TRANS
INST_TT_HYPS
INST_TT_HYPS
Drule.INST_TT_HYPS :
(term,term)subst * (hol_type,hol_type)subst -> thm -> thm * term list
Instantiates terms and types of a theorem.
INST_TT_HYPS instantiates types and terms in a theorem thm, in the
same way INST_TY_TERM does. It also returns a list of the instantiated
hypotheses, in the same order as the uninstantiated hypotheses appear in
the list hyp thm.
Failure
INST_TT_HYPS fails under the same conditions as INST_TY_TERM.
See also
INST_TY_TERM
INST_TY_TERM
Drule.INST_TY_TERM :
(term,term)subst * (hol_type,hol_type)subst -> thm -> thm
Instantiates terms and types of a theorem.
INST_TY_TERM instantiates types in a theorem, in the same way
INST_TYPE does. Then it instantiates some or all of the free variables
in the resulting theorem, in the same way as INST.
Comments
Because the types are instantiated first, the terms (redexes as well as
residues) in the term substitution must contain the substituted types,
not the original ones. Use norm_subst to achieve this.
Failure
INST_TY_TERM fails under the same conditions as either INST or
INST_TYPE fail.
See also
Thm.INST, Thm.INST_TYPE,
Drule.ISPEC, Thm.SPEC,
Drule.SUBS, Thm.SUBST,
Term.norm_subst,
Drule.INST_TT_HYPS
IRULE_CANON
IRULE_CANON
Drule.IRULE_CANON : thm -> thm
Canonicalises a theorem for use as an introduction rule.
A call to IRULE_CANON th returns a theorem th' that is equivalent to
th, but syntactically rearranged to be in the form
!v1 .. vn. c1 /\ c2 ... /\ cm ==> c
(also allowing for no conjuncts at all). The variables v1 to vn all
occur in the conclusion c, which is not universally quantified, nor an
implication.
Each of the conjuncts is of the form
?ev1 .. evi. ec1 /\ .. ecj
where it is possible that there are not existentially quantified
variables. The existential quantification ensures that there are no free
variables in the output theorem th'.
Failure
Never fails.
Comments
This function is used within the implementation of irule. The output
theorem th' is appropriate for use as an argument to MATCH_MP_TAC
(if the output is a quantified implication), or MATCH_ACCEPT_TAC if
the output is not an implication.
See also
Tactic.irule,
Tactic.MATCH_MP_TAC,
Drule.RES_CANON
ISPEC
ISPEC
Drule.ISPEC : (term -> thm -> thm)
Specializes a theorem, with type instantiation if necessary.
This rule specializes a quantified variable as does SPEC; it differs
from it in also instantiating the type if needed:
A |- !x:ty.tm
----------------------- ISPEC "t:ty'"
A |- tm[t/x]
(where t is free for x in tm, and ty' is an instance of ty).
Failure
ISPEC fails if the input theorem is not universally quantified, if the
type of the given term is not an instance of the type of the quantified
variable, or if the type variable is free in the assumptions.
See also
Drule.INST_TY_TERM,
Thm.INST_TYPE, Drule.ISPECL,
Thm.SPEC, Term.match_term
ISPECL
ISPECL
Drule.ISPECL : term list -> thm -> thm
Specializes a theorem zero or more times, with type instantiation if necessary.
ISPECL is an iterative version of ISPEC
A |- !x1...xn.t
---------------------------- ISPECL [t1,...,tn]
A |- t[t1,...tn/x1,...,xn]
(where ti is free for xi in tm).
Failure
ISPECL fails if the list of terms is longer than the number of
quantified variables in the term, if the type instantiation fails, or if
the type variable being instantiated is free in the assumptions.
See also
Thm.INST_TYPE,
Drule.INST_TY_TERM,
Drule.ISPEC, Drule.PART_MATCH,
Thm.SPEC, Drule.SPECL
LIST_BETA_CONV
LIST_BETA_CONV
Drule.LIST_BETA_CONV : conv
Performs an iterated beta conversion.
The conversion LIST_BETA_CONV maps terms of the form
"(\x1 x2 ... xn. u) v1 v2 ... vn"
to the theorems of the form
|- (\x1 x2 ... xn. u) v1 v2 ... vn = u[v1/x1][v2/x2] ... [vn/xn]
where u[vi/xi] denotes the result of substituting vi for all free
occurrences of xi in u, after renaming sufficient bound variables to
avoid variable capture.
Failure
LIST_BETA_CONV tm fails if tm does not have the form
"(\x1 ... xn. u) v1 ... vn" for n greater than 0.
Example
> LIST_BETA_CONV (Term `(\x y. x+y) 1 2`);
val it = ⊢ (λx y. x + y) 1 2 = 1 + 2: thm
See also
Thm.BETA_CONV, Conv.BETA_RULE,
Tactic.BETA_TAC,
Drule.RIGHT_BETA,
Drule.RIGHT_LIST_BETA
LIST_CONJ
LIST_CONJ
Drule.LIST_CONJ : thm list -> thm
Conjoins the conclusions of a list of theorems.
A1 |- t1 ... An |- tn
---------------------------------- LIST_CONJ
A1 u ... u An |- t1 /\ ... /\ tn
Failure
LIST_CONJ fails if applied to an empty list of theorems.
See also
Drule.BODY_CONJUNCTS,
Thm.CONJ, Thm.CONJUNCT1,
Thm.CONJUNCT2,
Drule.CONJUNCTS,
Drule.CONJ_PAIR,
Tactic.CONJ_TAC
LIST_MK_EXISTS
LIST_MK_EXISTS
Drule.LIST_MK_EXISTS : (term list -> thm -> thm)
Multiply existentially quantifies both sides of an equation using the given variables.
When applied to a list of terms [x1;...;xn], where the xi are all
variables, and a theorem A |- t1 = t2, the inference rule
LIST_MK_EXISTS existentially quantifies both sides of the equation
using the variables given, none of which should be free in the
assumption list.
A |- t1 = t2
-------------------------------------- LIST_MK_EXISTS ["x1";...;"xn"]
A |- (?x1...xn. t1) = (?x1...xn. t2)
Failure
Fails if any term in the list is not a variable or is free in the assumption list, or if the theorem is not equational.
See also
Drule.EXISTS_EQ,
Drule.MK_EXISTS
LIST_MP
LIST_MP
Drule.LIST_MP : thm list -> thm -> thm
Performs a chain of Modus Ponens inferences.
When applied to theorems A1 |- t1, ..., An |- tn and a theorem which
is a chain of implications with the successive antecedents the same as
the conclusions of the theorems in the list (up to alpha-conversion),
A |- t1 ==> ... ==> tn ==> t, the LIST_MP inference rule performs a
chain of MP inferences to deduce A u A1 u ... u An |- t.
A1 |- t1 ... An |- tn A |- t1 ==> ... ==> tn ==> t
--------------------------------------------------------- LIST_MP
A u A1 u ... u An |- t
Failure
Fails unless the theorem is a chain of implications whose consequents are the same as the conclusions of the list of theorems (up to alpha-conversion), in sequence.
See also
Thm.EQ_MP, Drule.MATCH_MP,
Tactic.MATCH_MP_TAC, Thm.MP,
Tactic.MP_TAC
MATCH_MP
MATCH_MP
Drule.MATCH_MP : thm -> thm -> thm
Modus Ponens inference rule with automatic matching.
When applied to theorems A1 |- !x1...xn. t1 ==> t2 and A2 |- t1',
the inference rule MATCH_MP matches t1 to t1' by instantiating
free or universally quantified variables in the first theorem (only),
and returns a theorem A1 u A2 |- !xa..xk. t2', where t2' is a
correspondingly instantiated version of t2. Polymorphic types are also
instantiated if necessary.
Variables free in the consequent but not the antecedent of the first argument theorem will be replaced by variants if this is necessary to maintain the full generality of the theorem, and any which were universally quantified over in the first argument theorem will be universally quantified over in the result, and in the same order.
A1 |- !x1..xn. t1 ==> t2 A2 |- t1'
-------------------------------------- MATCH_MP
A1 u A2 |- !xa..xk. t2'
As with MP and the underlying syntactic function dest_imp, negated
terms (of the form ~p) are treated as if they were implications from
the argument of the negation to falsity.
Failure
Fails unless the first theorem is a (possibly repeatedly universally
quantified) implication (in the sense of dest_imp) whose antecedent
can be instantiated to match the conclusion of the second theorem,
without instantiating any variables which are free in A1, the first
theorem's assumption list.
Example
In this example, automatic renaming occurs to maintain the most general
form of the theorem, and the variant corresponding to z is universally
quantified over, since it was universally quantified over in the first
argument theorem.
- val ith = (GENL [Term `x:num`, Term `z:num`]
o DISCH_ALL
o AP_TERM (Term `$+ (w + z)`))
(ASSUME (Term `x:num = y`));
> val ith = |- !x z. (x = y) ==> (w + z + x = w + z + y) : thm
- val th = ASSUME (Term `w:num = z`);
> val th = [w = z] |- w = z : thm
- MATCH_MP ith th;
> val it = [w = z] |- !z'. w' + z' + w = w' + z' + z : thm
See also
boolSyntax.dest_imp,
Thm.EQ_MP,
Tactic.MATCH_MP_TAC, Thm.MP,
Tactic.MP_TAC,
ConseqConv.CONSEQ_REWRITE_CONV
MK_ABS
MK_ABS
Drule.MK_ABS : (thm -> thm)
Abstracts both sides of an equation.
When applied to a theorem A |- !x. t1 = t2, whose conclusion is a
universally quantified equation, MK_ABS returns the theorem
A |- \x. t1 = \x. t2.
A |- !x. t1 = t2
-------------------------- MK_ABS
A |- (\x. t1) = (\x. t2)
Failure
Fails unless the theorem is a (singly) universally quantified equation.
See also
Thm.ABS, jrhUtils.HALF_MK_ABS,
Thm.MK_COMB, Drule.MK_EXISTS
MK_EXISTS
MK_EXISTS
Drule.MK_EXISTS : (thm -> thm)
Existentially quantifies both sides of a universally quantified equational theorem.
When applied to a theorem A |- !x. t1 = t2, the inference rule
MK_EXISTS returns the theorem A |- (?x. t1) = (?x. t2).
A |- !x. t1 = t2
-------------------------- MK_EXISTS
A |- (?x. t1) = (?x. t2)
Failure
Fails unless the theorem is a singly universally quantified equation.
See also
Thm.AP_TERM, Drule.EXISTS_EQ,
Thm.GEN, Drule.LIST_MK_EXISTS,
Drule.MK_ABS
NEG_DISCH
NEG_DISCH
Drule.NEG_DISCH : term -> thm -> thm
Discharges an assumption, transforming |- s ==> F into |- ~s.
When applied to a term s and a theorem A |- t, the inference rule
NEG_DISCH returns the theorem A - {s} |- s ==> t, or if t is just
F, returns the theorem A - {s} |- ~s.
A |- F
-------------------- NEG_DISCH [special case]
A - {s} |- ~s
A |- t
-------------------- NEG_DISCH [general case]
A - {s} |- s ==> t
Failure
Fails unless the supplied term has type bool.
See also
Thm.DISCH, Thm.NOT_ELIM,
Thm.NOT_INTRO
NOT_EQ_SYM
NOT_EQ_SYM
Drule.NOT_EQ_SYM : (thm -> thm)
Swaps left-hand and right-hand sides of a negated equation.
When applied to a theorem A |- ~(t1 = t2), the inference rule
NOT_EQ_SYM returns the theorem A |- ~(t2 = t1).
A |- ~(t1 = t2)
----------------- NOT_EQ_SYM
A |- ~(t2 = t1)
Failure
Fails unless the theorem's conclusion is a negated equation.
See also
Conv.DEPTH_CONV, Thm.REFL,
Thm.SYM
PART_MATCH
PART_MATCH
Drule.PART_MATCH : (term -> term) -> thm -> term -> thm
Instantiates a theorem by matching part of it to a term.
When applied to a 'selector' function of type term -> term, a theorem
and a term:
PART_MATCH fn (A |- !x1...xn. t) tm
the function PART_MATCH applies fn to t' (the result of
specializing universally quantified variables in the conclusion of the
theorem), and attempts to match the resulting term to the argument term
tm. If it succeeds, the appropriately instantiated version of the
theorem is returned.
Failure
Fails if the selector function fn fails when applied to the
instantiated theorem, or if the match fails with the term it has
provided.
Since PART_MATCH will not instantiate variables which appear in the
hypotheses of the given theorem, it fails if the attempted match would
require instantiating these variables. To allow instantiation of these
variables, use PART_MATCH_A.
Example
Suppose that we have the following theorem:
th = |- !x. x==>x
then the following:
PART_MATCH (fst o dest_imp) th "T"
results in the theorem:
|- T ==> T
because the selector function picks the antecedent of the implication
(the inbuilt specialization gets rid of the universal quantifier), and
matches it to T.
See also
Drule.PART_MATCH',
Drule.PART_MATCH_A,
Thm.INST_TYPE,
Drule.INST_TY_TERM,
Term.match_term
PART_MATCH'
PART_MATCH'
Drule.PART_MATCH' : (term -> term) -> thm -> term -> thm
Version of PART_MATCH that only specialises necessary variables in
input
PART_MATCH' selfn th tm behaves similarly to PART_MATCH selfn th tm,
except that outermost, universally quantified variables in th are
retained in the result unless they are part of the matching.
Failure
Fails when PART_MATCH would fail.
Example
> IMP_DISJ_THM;
val it = ⊢ ∀A B. A ⇒ B ⇔ ¬A ∨ B: thm
> PART_MATCH (rand o lhs) IMP_DISJ_THM “p /\ A”;
val it = ⊢ A ⇒ p ∧ A ⇔ ¬A ∨ p ∧ A: thm
> PART_MATCH' (rand o lhs) IMP_DISJ_THM “p /\ A”;
val it = ⊢ ∀A'. A' ⇒ p ∧ A ⇔ ¬A' ∨ p ∧ A: thm
See also
PART_MATCH_A
PART_MATCH_A
Drule.PART_MATCH_A : (term -> term) -> thm -> term -> thm
Instantiates a theorem by matching part of its conclusion to a term.
PART_MATCH_A behaves as PART_MATCH except that it permits
instantiating variables which appear in the assumptions of the given
theorem.
See also
Drule.PART_MATCH,
Conv.REWR_CONV_A
pp
pp
Drule.pp : thmpos_dtype.match_position -> thm -> thm
Promotes the designated premise to the "top" of an implicational theorem.
A call to pp pos th finds the premise denoted by pos in th and
promotes it so that it occurs as the outermost antecedent of the
theorem. The theorem argument th is first normalised by a call to
MP_CANON.
Any theorem whose top level operator (after universal quantifiers are stripped away) is an implication can be viewed as being of the form
∀v1 .. vn. p1 /\ p2 /\ .. pn ==> c
where the variables v1 to vn may be free in some of the antecedents
and/or conclusion c. To promote a premise pi transforms the above
into
∀va .. vk. pi ==> ∀vx .. vz. pa /\ pb ... /\ pj ==> c
The four constructors of the match_position type can be used to
designate different premises. The Pos f form applies the function f
to the list of premises, and is expected to return a member of the given
list. The Pat q form finds the first premise that matches the given
quotation pattern. In this context, Any is viewed as a synonym for
Pos hd. Finally, the Concl form selects the conclusion of the
theorem, and "promotes" it by taking the contrapositive of the theorem.
After promotion some cleanup is performed. If a contrapositive was taken, double negations in the promoted premise are removed, and in all cases, universal quantifiers of variables not present in the promoted premise are pushed down to govern other premises.
Failure
Fails if the provided match position does not denote a premise present in the given theorem.
Example
> sortingTheory.ALL_DISTINCT_PERM;
val it = ⊢ ∀l1 l2. PERM l1 l2 ⇒ (ALL_DISTINCT l1 ⇔ ALL_DISTINCT l2): thm
> it |> iffLR |> pp (Pos last);
val it = ⊢ ∀l1. ALL_DISTINCT l1 ⇒ ∀l2. PERM l1 l2 ⇒ ALL_DISTINCT l2: thm
See also
Drule.MP_CANON, Tactic.mp_then
prove_abs_fn_one_one
prove_abs_fn_one_one
Drule.prove_abs_fn_one_one : thm -> thm
Proves that a type abstraction function is one-to-one (injective).
If th is a theorem of the form returned by the function
define_new_type_bijections:
|- (!a. abs(rep a) = a) /\ (!r. P r = (rep(abs r) = r))
then prove_abs_fn_one_one th proves from this theorem that the
function abs is one-to-one for values that satisfy P, returning the
theorem:
|- !r r'. P r ==> P r' ==> ((abs r = abs r') = (r = r'))
Failure
Fails if applied to a theorem not of the form shown above.
See also
Definition.new_type_definition,
Drule.define_new_type_bijections,
Drule.prove_abs_fn_onto,
Drule.prove_rep_fn_one_one,
Drule.prove_rep_fn_onto
prove_abs_fn_onto
prove_abs_fn_onto
Drule.prove_abs_fn_onto : thm -> thm
Proves that a type abstraction function is onto (surjective).
If th is a theorem of the form returned by the function
define_new_type_bijections:
|- (!a. abs(rep a) = a) /\ (!r. P r = (rep(abs r) = r))
then prove_abs_fn_onto th proves from this theorem that the function
abs is onto, returning the theorem:
|- !a. ?r. (a = abs r) /\ P r
Failure
Fails if applied to a theorem not of the form shown above.
See also
Definition.new_type_definition,
Drule.define_new_type_bijections,
Drule.prove_abs_fn_one_one,
Drule.prove_rep_fn_one_one,
Drule.prove_rep_fn_onto
PROVE_HYP
PROVE_HYP
Drule.PROVE_HYP : thm -> thm -> thm
Eliminates a provable assumption from a theorem.
When applied to two theorems, PROVE_HYP returns a theorem having the
conclusion of the second. The new hypotheses are the union of the two
hypothesis sets (first deleting, however, the conclusion of the first
theorem from the hypotheses of the second).
A1 |- t1 A2 |- t2
------------------------ PROVE_HYP
A1 u (A2 - {t1}) |- t2
Failure
Never fails.
Comments
This is the Cut rule. It is not necessary for the conclusion of the
first theorem to be the same as an assumption of the second, but
PROVE_HYP is otherwise of doubtful value.
See also
Thm.DISCH, Thm.MP,
Drule.UNDISCH
prove_rep_fn_one_one
prove_rep_fn_one_one
Drule.prove_rep_fn_one_one : thm -> thm
Proves that a type representation function is one-to-one (injective).
If th is a theorem of the form returned by the function
define_new_type_bijections:
|- (!a. abs(rep a) = a) /\ (!r. P r = (rep(abs r) = r))
then prove_rep_fn_one_one th proves from this theorem that the
function rep is one-to-one, returning the theorem:
|- !a a'. (rep a = rep a') = (a = a')
Failure
Fails if applied to a theorem not of the form shown above.
See also
Definition.new_type_definition,
Drule.define_new_type_bijections,
Drule.prove_abs_fn_one_one,
Drule.prove_abs_fn_onto,
Drule.prove_rep_fn_onto
prove_rep_fn_onto
prove_rep_fn_onto
Drule.prove_rep_fn_onto : thm -> thm
Proves that a type representation function is onto (surjective).
If th is a theorem of the form returned by the function
define_new_type_bijections:
|- (!a. abs(rep a) = a) /\ (!r. P r = (rep(abs r) = r))
then prove_rep_fn_onto th proves from this theorem that the function
rep is onto the set of values that satisfy P, returning the theorem:
|- !r. P r = (?a. r = rep a)
Failure
Fails if applied to a theorem not of the form shown above.
See also
Definition.new_type_definition,
Drule.define_new_type_bijections,
Drule.prove_abs_fn_one_one,
Drule.prove_abs_fn_onto,
Drule.prove_rep_fn_one_one
REORDER_ANTS
REORDER_ANTS
Drule.REORDER_ANTS : (term list -> term list) -> thm -> thm
Strips universal quantifiers and antecedents of implications and reorders the antecedents
|- !x. a1 ==> !y. a2 ==> !z. a3 ==> !u. t
----------------------------------------- REORDER_ANTS rev
|- a3 ==> a2 ==> a1 ==> t
Failure
No failure. Can leave the supplied theorem unchanged.
But a choice of f other than reordering a list of terms will give a
result with assumptions remaining or superfluous antecedents
Comments
For simplicity, doesn't try to reinsert quantifiers in appropriate places. If required, apply GEN_ALL to the resulting theorem.
See also
Drule.REORDER_ANTS_MOD,
Drule.SPEC_ALL, Drule.GEN_ALL,
Thm.UNDISCH, Drule.DISCH
REORDER_ANTS_MOD
REORDER_ANTS_MOD
Drule.REORDER_ANTS_MOD : (term list -> term list) -> (thm -> thm) -> thm -> thm
Strips universal quantifiers and antecedents of implications, modifies the conclusion, and reorders the antecedents
REORDER_ANTS_MOD f g combines the effects of REORDER_ANTS_MOD f and
applies the function g to the ultimate consequent of the theorem, as
does underAIs.
Failure
Fails if g fails when applied to the consequent
See also
Drule.DISCH, Drule.GEN_ALL,
Drule.REORDER_ANTS,
Drule.SPEC_ALL,
Drule.underAIs, Thm.UNDISCH
RES_CANON
RES_CANON
Drule.RES_CANON : (thm -> thm list)
Put an implication into canonical form for resolution.
All the HOL resolution tactics (e.g. IMP_RES_TAC) work by using modus
ponens to draw consequences from an implicative theorem and the
assumptions of the goal. Some of these tactics derive this implication
from a theorem supplied explicitly the user (or otherwise from 'outside'
the goal) and some obtain it from the assumptions of the goal itself.
But in either case, the supplied theorem or assumption is first
transformed into a list of implications in 'canonical' form by the
function RES_CANON.
The theorem argument to RES_CANON should be either be an implication
(which can be universally quantified) or a theorem from which an
implication can be derived using the transformation rules discussed
below. Given such a theorem, RES_CANON returns a list of implications
in canonical form. It is the implications in this resulting list that
are used by the various resolution tactics to infer consequences from
the assumptions of a goal.
The transformations done by RES_CANON th to the theorem th are as
follows. First, if th is a negation A |- ~t, this is converted to
the implication A |- t ==> F. The following inference rules are then
applied repeatedly, until no further rule applies. Conjunctions are
split into their components and equivalence (boolean equality) is split
into implication in both directions:
A |- t1 /\ t2 A |- t1 = t2
-------------------- ----------------------------------
A |- t1 A |- t2 A |- t1 ==> t2 A |- t2 ==> t1
Conjunctive antecedents are transformed by:
A |- (t1 /\ t2) ==> t
---------------------------------------------------
A |- t1 ==> (t2 ==> t) A |- t2 ==> (t1 ==> t)
and disjunctive antecedents by:
A |- (t1 \/ t2) ==> t
--------------------------------
A |- t1 ==> t A |- t2 ==> t
The scope of universal quantifiers is restricted, if possible:
A |- !x. t1 ==> t2
-------------------- [if x is not free in t1]
A |- t1 ==> !x. t2
and existentially-quantified antecedents are eliminated by:
A |- (?x. t1) ==> t2
--------------------------- [x' chosen so as not to be free in t2]
A |- !x'. t1[x'/x] ==> t2
Finally, when no further applications of the above rules are possible, and the theorem is an implication:
A |- !x1...xn. t1 ==> t2
then the theorem A u {t1} |- t2 is transformed by a recursive
application of RES_CANON to get a list of theorems:
[A u {t1} |- t21 , ... , A u {t1} |- t2n]
and the result of discharging t1 from these theorems:
[A |- !x1...xn. t1 ==> t21 , ... , A |- !x1...xn. t1 ==> t2n]
is returned. That is, the transformation rules are recursively applied to the conclusions of all implications.
Failure
RES_CANON th fails if no implication(s) can be derived from th using
the transformation rules shown above.
Example
The uniqueness of the remainder k MOD n is expressed in HOL by the
built-in theorem MOD_UNIQUE:
|- !n k r. (?q. (k = (q * n) + r) /\ r < n) ==> (k MOD n = r)
For this theorem, the canonical list of implications returned by
RES_CANON is as follows:
- RES_CANON MOD_UNIQUE;
> val it =
[|- !r n q k. (k = q * n + r) ==> r < n ==> (k MOD n = r),
|- !n r. r < n ==> !q k. (k = q * n + r) ==> (k MOD n = r)] : thm list
The existentially-quantified, conjunctive, antecedent has given rise to two implications, and the scope of universal quantifiers has been restricted to the conclusions of the resulting implications wherever possible.
The primary use of RES_CANON is for the (internal) pre-processing
phase of the built-in resolution tactics IMP_RES_TAC, IMP_RES_THEN,
RES_TAC, and RES_THEN. But the function RES_CANON is also made
available at top-level so that users can call it to see the actual form
of the implications used for resolution in any particular case.
See also
Tactic.IMP_RES_TAC,
Thm_cont.IMP_RES_THEN,
Tactic.RES_TAC,
Thm_cont.RES_THEN
RIGHT_BETA
RIGHT_BETA
Drule.RIGHT_BETA : (thm -> thm)
Beta-reduces a top-level beta-redex on the right-hand side of an equation.
When applied to an equational theorem, RIGHT_BETA applies
beta-reduction at top level to the right-hand side (only). Variables are
renamed if necessary to avoid free variable capture.
A |- s = (\x. t1) t2
---------------------- RIGHT_BETA
A |- s = t1[t2/x]
Failure
Fails unless the theorem is equational, with its right-hand side being a top-level beta-redex.
See also
Thm.BETA_CONV, Conv.BETA_RULE,
Tactic.BETA_TAC,
Drule.RIGHT_LIST_BETA
RIGHT_ETA
RIGHT_ETA
Drule.RIGHT_ETA : thm -> thm
Perform one step of eta-reduction on the right hand side of an equational theorem.
A |- M = (\x. (N x))
--------------------- x not free in N
A |- M = N
Failure
If the right hand side of the equation is not an eta-redex, or if the theorem is not an equation.
Example
> val INC_DEF = new_definition ("INC_DEF", Term`INC = \x. 1 + x`);
val INC_DEF = ⊢ INC = (λx. 1 + x): thm
> RIGHT_ETA INC_DEF;
val it = ⊢ INC = $+ 1: thm
See also
RIGHT_LIST_BETA
RIGHT_LIST_BETA
Drule.RIGHT_LIST_BETA : (thm -> thm)
Iteratively beta-reduces a top-level beta-redex on the right-hand side of an equation.
When applied to an equational theorem, RIGHT_LIST_BETA applies
beta-reduction over a top-level chain of beta-redexes to the right hand
side (only). Variables are renamed if necessary to avoid free variable
capture.
A |- s = (\x1...xn. t) t1 ... tn
---------------------------------- RIGHT_LIST_BETA
A |- s = t[t1/x1]...[tn/xn]
Failure
Fails unless the theorem is equational, with its right-hand side being a top-level beta-redex.
See also
Thm.BETA_CONV, Conv.BETA_RULE,
Tactic.BETA_TAC,
Drule.LIST_BETA_CONV,
Drule.RIGHT_BETA
SELECT_ELIM
SELECT_ELIM
Drule.SELECT_ELIM : thm -> term * thm -> thm
Eliminates an epsilon term, using deduction from a particular instance.
SELECT_ELIM expects two arguments, a theorem th1, and a pair
(v,th2): term * thm. The conclusion of th1 should have the form
P($@ P), which asserts that the epsilon term $@ P denotes some value
at which P holds. In th2, the variable v appears only in the
assumption P v. The conclusion of the resulting theorem matches that
of th2, and the hypotheses include the union of all hypotheses of the
premises excepting P v.
A1 |- P($@ P) A2 u {P v} |- t
----------------------------------- SELECT_ELIM th1 (v,th2)
A1 u A2 |- t
where v is not free in A2. The argument to P in the conclusion of
th1 may actually be any term x. If v appears in the conclusion of
th2, this argument x (usually the epsilon term) will NOT be
eliminated, and the conclusion will be t[x/v].
Failure
Fails if the first theorem is not of the form A1 |- P x, or if the
variable v occurs free in any other assumption of th2.
Example
If a property of functions is defined by:
INCR = |- !f. INCR f = (!t1 t2. t1 < t2 ==> (f t1) < (f t2))
The following theorem can be proved.
th1 = |- INCR(@f. INCR f)
Additionally, if such a function is assumed to exist, then one can prove that there also exists a function which is injective (one-to-one) but not surjective (onto).
th2 = [ INCR g ] |- ?h. ONE_ONE h /\ ~ONTO h
These two results may be combined using SELECT_ELIM to give a new
theorem:
- SELECT_ELIM th1 (``g:num->num``, th2);
val it = |- ?h. ONE_ONE h /\ ~ONTO h : thm
This rule is rarely used. The equivalence of P($@ P) and $? P makes
this rule fundamentally similar to the ?-elimination rule CHOOSE.
See also
Thm.CHOOSE, Conv.SELECT_CONV,
Tactic.SELECT_ELIM_TAC,
Drule.SELECT_INTRO,
Drule.SELECT_RULE
SELECT_EQ
SELECT_EQ
Drule.SELECT_EQ : (term -> thm -> thm)
Applies epsilon abstraction to both terms of an equation.
Effects the extensionality of the epsilon operator @.
A |- t1 = t2
------------------------ SELECT_EQ "x" [where x is not free in A]
A |- (@x.t1) = (@x.t2)
Failure
Fails if the conclusion of the theorem is not an equation, or if the
variable x is free in A.
Example
Given a theorem which shows the equivalence of two distinct forms of defining the property of being an even number:
th = |- (x MOD 2 = 0) = (?y. x = 2 * y)
A theorem giving the equivalence of the epsilon abstraction of each form is obtained:
- SELECT_EQ (Term `x:num`) th;
> val it = |- (@x. x MOD 2 = 0) = (@x. ?y. x = 2 * y) : thm
See also
Thm.ABS, Thm.AP_TERM,
Drule.EXISTS_EQ,
Drule.FORALL_EQ,
Conv.SELECT_CONV,
Drule.SELECT_ELIM,
Drule.SELECT_INTRO
SELECT_INTRO
SELECT_INTRO
Drule.SELECT_INTRO : (thm -> thm)
Introduces an epsilon term.
SELECT_INTRO takes a theorem with an applicative conclusion, say
P x, and returns a theorem with the epsilon term $@ P in place of
the original operand x.
A |- P x
-------------- SELECT_INTRO
A |- P($@ P)
The returned theorem asserts that $@ P denotes some value at which P
holds.
Failure
Fails if the conclusion of the theorem is not an application.
Example
Given the theorem
th1 = |- (\n. m = n)m
applying SELECT_INTRO replaces the second occurrence of m with the
epsilon abstraction of the operator:
- val th2 = SELECT_INTRO th1;
val th2 = |- (\n. m = n)(@n. m = n) : thm
This theorem could now be used to derive a further result:
- EQ_MP (BETA_CONV(concl th2)) th2;
val it = |- m = (@n. m = n) : thm
See also
Thm.EXISTS, Conv.SELECT_CONV,
Drule.SELECT_ELIM,
Drule.SELECT_RULE
SELECT_RULE
SELECT_RULE
Drule.SELECT_RULE : thm -> thm
Introduces an epsilon term in place of an existential quantifier.
The inference rule SELECT_RULE expects a theorem asserting the
existence of a value x such that P holds. The equivalent assertion
that the epsilon term @x.P denotes a value of x for which P holds
is returned as a theorem.
A |- ?x. P
------------------ SELECT_RULE
A |- P[(@x.P)/x]
Failure
Fails if applied to a theorem the conclusion of which is not existentially quantified.
Example
The axiom INFINITY_AX in the theory ind is of the form:
|- ?f. ONE_ONE f /\ ~ONTO f
Applying SELECT_RULE to this theorem returns the following.
- SELECT_RULE INFINITY_AX;
> val it =
|- ONE_ONE (@f. ONE_ONE f /\ ~ONTO f) /\ ~ONTO @f. ONE_ONE f /\ ~ONTO f
: thm
May be used to introduce an epsilon term to permit rewriting with a constant defined using the epsilon operator.
See also
Thm.CHOOSE, Conv.SELECT_CONV,
Drule.SELECT_ELIM,
Drule.SELECT_INTRO
SIMPLE_EXISTS
SIMPLE_EXISTS
Drule.SIMPLE_EXISTS : term -> thm -> thm
Introduces existential quantification using as witness a given free variable.
When applied to a free variable term and a theorem, SIMPLE_EXISTS
gives the theorem made by existentially quantifying the conclusion of
the given theorem over the given free variable.
A |- p
------------- SIMPLE_EXISTS ``x``
A |- ?x. p
Failure
Fails if the term argument is not a free variable.
Comments
The free variable need not appear in the conclusion of the theorem, and may appear in the hypotheses.
Example
- SIMPLE_EXISTS (Term `x`) (REFL (Term `x`));
> val it = |- ?x. x = x : thm
- SIMPLE_EXISTS (Term `x`) (REFL T);
> val it = |- ?x. T = T : thm
See also
Thm.EXISTS, Thm.CHOOSE,
Tactic.EXISTS_TAC
SPEC_ALL
SPEC_ALL
Drule.SPEC_ALL : thm -> thm
Specializes the conclusion of a theorem with its own quantified variables.
When applied to a theorem A |- !x1...xn. t, the inference rule
SPEC_ALL returns the theorem A |- t[x1'/x1]...[xn'/xn] where the
xi' are distinct variants of the corresponding xi, chosen to avoid
clashes with any variables free in the assumption list and with the
names of constants. Normally xi' is just xi, in which case
SPEC_ALL simply removes all universal quantifiers.
A |- !x1...xn. t
--------------------------- SPEC_ALL
A |- t[x1'/x1]...[xn'/xn]
Failure
Never fails.
Example
> SPEC_ALL CONJ_ASSOC;
val it = ⊢ t1 ∧ t2 ∧ t3 ⇔ (t1 ∧ t2) ∧ t3: thm
See also
Thm.GEN, Thm.GENL,
Drule.GEN_ALL, Tactic.GEN_TAC,
Thm.SPEC, Drule.SPECL,
Tactic.SPEC_TAC
SPEC_UNDISCH_EXL
SPEC_UNDISCH_EXL
Drule.SPEC_UNDISCH_EXL : thm -> thm
Strips universal quantifiers and antecedents of implications (splitting conjunctive antecedents), then where possible replaces the formerly quantified variables as existentials in the new hypotheses.
In this example, assume that a1 and a3 (only) involve the free
variable x.
|- !x. a1 ==> !y. a2 ==> !z. a3 ==> !u. t
----------------------------------------- SPEC_UNDISCH_EXL
?x. a1 /\ a3, a2 |- t
Failure
No failure. Can leave the supplied theorem unchanged.
Comments
See EXISTS_LEFT for more on the existential quantification aspect.
Note that the existential quantification happens only for variables
which were universally quantified in the supplied theorem (to get around
this limitation, first apply GEN_ALL to the supplied theorem).
Example
Where trans_thm is [] |- !x y z. (x = y) ==> (y = z) ==> (x = z)
SPEC_UNDISCH_EXL trans_thm is [?y. (x = y) /\ (y = z)] |- x = z
See also
Drule.EXISTS_LEFT,
Tactic.irule
SPEC_VAR
SPEC_VAR
Drule.SPEC_VAR : thm -> term * thm
Specializes the conclusion of a theorem, returning the chosen variant.
When applied to a theorem A |- !x. t, the inference rule SPEC_VAR
returns the term x' and the theorem A |- t[x'/x], where x' is a
variant of x chosen to avoid free variable capture.
A |- !x. t
-------------- SPEC_VAR
A |- t[x'/x]
Failure
Fails unless the theorem's conclusion is universally quantified.
Comments
This rule is very similar to plain SPEC, except that it returns the
variant chosen, which may be useful information under some
circumstances.
See also
Thm.GEN, Thm.GENL,
Drule.GEN_ALL, Tactic.GEN_TAC,
Thm.SPEC, Drule.SPECL,
Drule.SPEC_ALL
SPECL
SPECL
Drule.SPECL : term list -> thm -> thm
Specializes zero or more variables in the conclusion of a theorem.
When applied to a term list [u1;...;un] and a theorem
A |- !x1...xn. t, the inference rule SPECL returns the theorem
A |- t[u1/x1]...[un/xn], where the substitutions are made sequentially
left-to-right in the same way as for SPEC, with the same sort of
alpha-conversions applied to t if necessary to ensure that no
variables which are free in ui become bound after substitution.
A |- !x1...xn. t
-------------------------- SPECL [u1,...,un]
A |- t[u1/x1]...[un/xn]
It is permissible for the term-list to be empty, in which case the
application of SPECL has no effect.
Failure
Fails unless each of the terms is of the same type as that of the appropriate quantified variable in the original theorem.
Example
The following is a specialization of a theorem from theory arithmetic.
- arithmeticTheory.LESS_EQ_LESS_EQ_MONO;
> val it = |- !m n p q. m <= p /\ n <= q ==> m + n <= p + q : thm
- SPECL (map Term [`1`, `2`, `3`, `4`]) it;
> val it = |- 1 <= 3 /\ 2 <= 4 ==> 1 + 2 <= 3 + 4 : thm
See also
Thm.GEN, Thm.GENL,
Drule.GEN_ALL, Tactic.GEN_TAC,
Thm.SPEC, Drule.SPEC_ALL,
Tactic.SPEC_TAC
SUBS
SUBS
Drule.SUBS : (thm list -> thm -> thm)
Makes simple term substitutions in a theorem using a given list of theorems.
Term substitution in HOL is performed by replacing free subterms
according to the transformations specified by a list of equational
theorems. Given a list of theorems A1|-t1=v1,...,An|-tn=vn and a
theorem A|-t, SUBS simultaneously replaces each free occurrence of
ti in t with vi:
A1|-t1=v1 ... An|-tn=vn A|-t
--------------------------------------------- SUBS[A1|-t1=v1;...;An|-tn=vn]
A1 u ... u An u A |- t[v1,...,vn/t1,...,tn] (A|-t)
No matching is involved; the occurrence of each ti being substituted
for must be a free in t (see SUBST_MATCH). An occurrence which is
not free can be substituted by using rewriting rules such as
REWRITE_RULE, PURE_REWRITE_RULE and ONCE_REWRITE_RULE.
Failure
SUBS [th1,...,thn] (A|-t) fails if the conclusion of each theorem in
the list is not an equation. No change is made to the theorem A |- t
if no occurrence of any left-hand side of the supplied equations appears
in t.
Example
Substitutions are made with the theorems
- val thm1 = SPECL [Term`m:num`, Term`n:num`] arithmeticTheory.ADD_SYM
val thm2 = CONJUNCT1 arithmeticTheory.ADD_CLAUSES;
> val thm1 = |- m + n = n + m : thm
val thm2 = |- 0 + m = m : thm
depending on the occurrence of free subterms
- SUBS [thm1, thm2] (ASSUME (Term `(n + 0) + (0 + m) = m + n`));
> val it = [.] |- n + 0 + m = n + m : thm
- SUBS [thm1, thm2] (ASSUME (Term `!n. (n + 0) + (0 + m) = m + n`));
> val it = [.] |- !n. n + 0 + m = m + n : thm
SUBS can sometimes be used when rewriting (for example, with
REWRITE_RULE) would diverge and term instantiation is not needed.
Moreover, applying the substitution rules is often much faster than
using the rewriting rules.
See also
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE,
Thm.SUBST,
Rewrite.SUBST_MATCH,
Drule.SUBS_OCCS
SUBS_OCCS
SUBS_OCCS
Drule.SUBS_OCCS : (int list * thm) list -> thm -> thm
Makes substitutions in a theorem at specific occurrences of a term, using a list of equational theorems.
Given a list (l1,A1|-t1=v1),...,(ln,An|-tn=vn) and a theorem (A|-t),
SUBS_OCCS simultaneously replaces each ti in t with vi, at the
occurrences specified by the integers in the list li = [o1,...,ok] for
each theorem Ai|-ti=vi.
(l1,A1|-t1=v1) ... (ln,An|-tn=vn) A|-t
------------------------------------------- SUBS_OCCS[(l1,A1|-t1=v1),...,
A1 u ... An u A |- t[v1,...,vn/t1,...,tn] (ln,An|-tn=vn)] (A|-t)
Failure
SUBS_OCCS [(l1,th1),...,(ln,thn)] (A|-t) fails if the conclusion of
any theorem in the list is not an equation. No change is made to the
theorem if the supplied occurrences li of the left-hand side of the
conclusion of thi do not appear in t.
Example
The commutative law for addition
- val thm = SPECL [Term `m:num`, Term`n:num`] arithmeticTheory.ADD_SYM;
> val thm = |- m + n = n + m : thm
can be used for substituting only the second occurrence of the subterm
m + n
- SUBS_OCCS [([2],thm)]
(ASSUME (Term `(n + m) + (m + n) = (m + n) + (m + n)`));
> val it = [.] |- n + m + (m + n) = n + m + (m + n) : thm
SUBS_OCCS is used when rewriting at specific occurrences of a term,
and rules such as REWRITE_RULE, PURE_REWRITE_RULE,
ONCE_REWRITE_RULE, and SUBS are too extensive or would diverge.
See also
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE,
Drule.SUBS, Thm.SUBST,
Rewrite.SUBST_MATCH
SUBST_CONV
SUBST_CONV
Drule.SUBST_CONV : {redex :term, residue :thm} list -> term -> conv
Makes substitutions in a term at selected occurrences of subterms, using a list of theorems.
SUBST_CONV implements the following rule of simultaneous substitution
A1 |- t1 = v1 ... An |- tn = vn
------------------------------------------------------------------
A1 u ... u An |- t[t1,...,tn/x1,...,xn] = t[v1,...,vn/x1,...,xn]
The first argument to SUBST_CONV is a list
[{redex=x1, residue = A1|-t1=v1},...,{redex = xn, residue = An|-tn=vn}].
The second argument is a template term t[x1,...,xn], in which the
variables x1,...,xn are used to mark those places where occurrences of
t1,...,tn are to be replaced with the terms v1,...,vn, respectively.
Thus, evaluating
SUBST_CONV [{redex = x1, residue = A1|-t1=v1},...,
{redex = xn, residue = An|-tn=vn}]
t[x1,...,xn]
t[t1,...,tn/x1,...,xn]
returns the theorem
A1 u ... u An |- t[t1,...,tn/x1,...,xn] = t[v1,...,vn/x1,...,xn]
The occurrence of ti at the places marked by the variable xi must be
free (i.e. ti must not contain any bound variables). SUBST_CONV
automatically renames bound variables to prevent free variables in vi
becoming bound after substitution.
Failure
SUBST_CONV [{redex=x1,residue=th1},...,{redex=xn,residue=thn}] t[x1,...,xn] t'
fails if the conclusion of any theorem thi in the list is not an
equation; or if the template t[x1,...,xn] does not match the term
t'; or if and term ti in t' marked by the variable xi in the
template, is not identical to the left-hand side of the conclusion of
the theorem thi.
Example
The values
> val ADD1 = arithmeticTheory.ADD1
val ADD1 = ⊢ ∀m. SUC m = m + 1: thm
> val thm0 = SPEC (Term`0`) ADD1
and thm1 = SPEC (Term`1`) ADD1
and x = Term`x:num` and y = Term`y:num`;
val thm0 = ⊢ SUC 0 = 0 + 1: thm
val thm1 = ⊢ SUC 1 = 1 + 1: thm
val x = “x”: term
val y = “y”: term
can be used to substitute selected occurrences of the terms SUC 0 and
SUC 1
> SUBST_CONV [{redex=x, residue=thm0},{redex=y,residue=thm1}]
“x + y > SUC 1”
“SUC 0 + SUC 1 > SUC 1”;
val it = ⊢ SUC 0 + SUC 1 > SUC 1 ⇔ 0 + 1 + (1 + 1) > SUC 1: thm
The |-> syntax can also be used:
> SUBST_CONV [x |-> thm0, y |-> thm1]
“x + y > SUC 1”
“SUC 0 + SUC 1 > SUC 1”;
val it = ⊢ SUC 0 + SUC 1 > SUC 1 ⇔ 0 + 1 + (1 + 1) > SUC 1: thm
SUBST_CONV is used when substituting at selected occurrences of terms
and using rewriting rules/conversions is too extensive.
See also
Conv.REWR_CONV, Drule.SUBS,
Thm.SUBST, Drule.SUBS_OCCS,
Lib.|->
underAIs
underAIs
Drule.underAIs : (thm -> thm) -> (thm -> thm)
Applies a derived rule underneath external "guarding" of universal variables and implications.
A call to underAIs f th strips away external guarding in th, applies
the function f, and then restores the original guarding. In this
context, "guarding" is the presence of universal quantifications and
antecedents in implications. Thus, this function sees the theorem
∀x. p x ==> ∀y. q y ∧ r x y ==> s as the body s, guarded by the
universal variables x and y and the assumptions p x and
q y ∧ r x y. Negations in the body are not viewed as implications.
Failure
As all theorems are of this shape, the stripping and restoration of
guarding always succeeds. However, this function will fail if f fails
when applied to the theorem A' |- s, with s the body (as above), and
A' the original hypotheses of theorem augmented with the antecendents
of guarding implications.
Example
> underAIs (EXISTS (“∃m. (k * n) MOD m = 0”, “n:num”))
arithmeticTheory.MOD_EQ_0;
val it = ⊢ ∀n. 0 < n ⇒ ∀k. ∃m. k * n MOD m = 0: thm
See also
UNDISCH
UNDISCH
Drule.UNDISCH : thm -> thm
Undischarges the antecedent of an implicative theorem.
A |- t1 ==> t2
---------------- UNDISCH
A, t1 |- t2
Note that UNDISCH treats "~u" as "u ==> F".
Failure
UNDISCH will fail on theorems which are not implications or negations.
Comments
If the antecedent already appears in (or is alpha-equivalent to one of) the hypotheses, it will not be duplicated.
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Drule.NEG_DISCH,
Tactic.STRIP_TAC,
Drule.UNDISCH_ALL,
Drule.UNDISCH_SPLIT,
Drule.UNDISCH_TM,
Tactic.UNDISCH_TAC
UNDISCH_ALL
UNDISCH_ALL
Drule.UNDISCH_ALL : thm -> thm
Iteratively undischarges antecedents in a chain of implications.
A |- t1 ==> ... ==> tn ==> t
------------------------------ UNDISCH_ALL
A, t1, ..., tn |- t
Note that UNDISCH_ALL treats "~u" as "u ==> F".
Failure
UNDISCH_ALL never fails. When called on something other than an
implication or negation, it simply returns its argument unchanged.
Comments
Identical or alpha-equivalent terms which are repeated in
A, "t1", ..., "tn" will not be duplicated in the hypotheses of the
resulting theorem.
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Drule.NEG_DISCH,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Tactic.UNDISCH_TAC
UNDISCH_SPLIT
UNDISCH_SPLIT
Drule.UNDISCH_SPLIT : thm -> thm
Undischarges the antecedent of an implicative theorem, and splits it into its conjuncts.
A |- t1a /\ t1b /\ t1c ==> t2
------------------------------ UNDISCH_SPLIT
A, t1a, t1b, t1c |- t2
Note that UNDISCH_SPLIT treats "~u" as "u ==> F".
Failure
UNDISCH_SPLIT will fail on theorems which are not implications or
negations.
Comments
If a conjunct of the antecedent already appears in (or is alpha-equivalent to one of) the hypotheses, it will not be duplicated.
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Drule.NEG_DISCH,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Drule.UNDISCH_TM,
Tactic.UNDISCH_TAC,
Drule.ASSUME_CONJS
UNDISCH_TM
UNDISCH_TM
Drule.UNDISCH_TM : thm -> term * thm
Undischarges the antecedent of an implicative theorem, also returning that antecedent.
A |- t1 ==> t2
---------------- UNDISCH_TM
A, t1 |- t2
Note that UNDISCH_TM treats "~u" as "u ==> F".
Failure
UNDISCH_TM will fail on theorems which are not implications or
negations.
Comments
If the antecedent already appears in (or is alpha-equivalent to one of) the hypotheses, it will not be duplicated.
UNDISCH_TM is similar to UNDISCH except that it also returns the
antecedent concerned, which may be useful, for example, when the new
assumption is subsequently to be discharged
See also
datatype_theorems
datatype_theorems
EmitTeX.datatype_theorems : string -> (string * thm) list
All the datatype theorems stored in the named theory.
An invocation datatype_theorems thy, where thy is the name of a
currently loaded theory segment, will return a list of the datatype
theorems stored in that theory. Each theorem is paired with the name of
the datatype in the result. The string "-" may be used to denote the
current theory segment.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> new_theory "example";
Exporting theory "scratch" ... done.
Theory "scratch" took 0.00866s to build
<<HOL message: Created theory "example">>
val it = (): unit
> val _ = Hol_datatype `example = First | Second`;
<<HOL message: Defined type: "example">>
> EmitTeX.datatype_theorems "example";
val it = [("example", ⊢ DATATYPE (example First Second))]:
(string * thm) list
See also
DB.theorems,
bossLib.Hol_datatype
datatype_thm_to_string
datatype_thm_to_string
EmitTeX.datatype_thm_to_string : thm -> string
Converts a datatype theorem to a string.
An invocation of datatype_thm_to_string thm, where thm is a datatype
theorem produced by Hol_datatype, will return a string that
corresponds with the orginal datatype declaration.
Failure
Will fail if the supplied theorem is not a datatype theorem, as created
by Hol_datatype.
Example
> new_theory "example";
<<HOL message: Restarting theory "example">>
<<HOL warning: Theory.callhooks: Hook Parse.clear_consts_from_grammar failed on event NewTheory{oldseg = "example", newseg = "example"} with problem
Exception raised at Term.dest_thy_const: not a const
>>
val it = (): unit
> val _ = Hol_datatype `example = First | Second`;
<<HOL message: Defined type: "example">>
> EmitTeX.datatype_thm_to_string (theorem "datatype_example");
val it = "example = First | Second": string
See also
non_type_definitions
non_type_definitions
EmitTeX.non_type_definitions : string -> (string * thm) list
A versions of definitions that attempts to filter out definitions
created by Hol_datatype.
An invocation non_type_definitions thy, where thy is the name of a
currently loaded theory segment, will return a list of the definitions
stored in that theory. Each definition is paired with its name in the
result.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> new_theory "example";
<<HOL message: Restarting theory "example">>
<<HOL warning: Theory.callhooks: Hook Parse.clear_consts_from_grammar failed on event NewTheory{oldseg = "example", newseg = "example"} with problem
Exception raised at Term.dest_thy_const: not a const
>>
val it = (): unit
> val _ = Hol_datatype `example = First | Second`;
<<HOL message: Defined type: "example">>
> val example_def = Define
`(example First = Second) /\ (example Second = First)`;
Definition has been stored under "example_def"
val example_def = ⊢ example First = Second ∧ example Second = First: thm
> definitions "example";
val it =
[("example_TY_DEF", ⊢ ∃rep. TYPE_DEFINITION (λn. n < 2) rep),
("example_size_def", ⊢ ∀x. example_size x = 0),
("example_def", ⊢ example First = Second ∧ example Second = First),
("example_CASE",
⊢ ∀x v0 v1.
(case x of First => v0 | Second => v1) =
(λm. if m = 0 then v0 else v1) (example2num x)),
("example_BIJ",
⊢ (∀a. num2example (example2num a) = a) ∧
∀r. (λn. n < 2) r ⇔ example2num (num2example r) = r)]:
(string * thm) list
> EmitTeX.non_type_definitions "example";
val it =
[("example_def", ⊢ example First = Second ∧ example Second = First)]:
(string * thm) list
See also
DB.definitions,
bossLib.Hol_datatype
non_type_theorems
non_type_theorems
EmitTeX.non_type_theorems : string -> (string * thm) list
A versions of theorems that attempts to filter out theorems created by
Hol_datatype.
An invocation non_type_theorems thy, where thy is the name of a
currently loaded theory segment, will return a list of the theorems
stored in that theory. Axioms and definitions are excluded. Each theorem
is paired with its name in the result.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment, the empty list is returned.
Example
> new_theory "example";
<<HOL message: Restarting theory "example">>
<<HOL warning: Theory.callhooks: Hook Parse.clear_consts_from_grammar failed on event NewTheory{oldseg = "example", newseg = "example"} with problem
Exception raised at Term.dest_thy_const: not a const
>>
val it = (): unit
> val _ = Hol_datatype `example = First | Second`;
<<HOL message: Defined type: "example">>
> val example_def = Define
`(example First = Second) /\ (example Second = First)`;
Definition has been stored under "example_def"
val example_def = ⊢ example First = Second ∧ example Second = First: thm
> save_thm("example_thm",
METIS_PROVE [example_def, theorem "example_nchotomy"]
``!x. example (example x) = x``);
metis: r[+0+5]+1+0+0+0+6+2+1+0+1+1#
val it = ⊢ ∀x. example (example x) = x: thm
> theorems "example";
val it =
[("num2example_thm", ⊢ num2example 0 = First ∧ num2example 1 = Second),
("num2example_ONTO", ⊢ ∀a. ∃r. a = num2example r ∧ r < 2),
("num2example_example2num", ⊢ ∀a. num2example (example2num a) = a),
("num2example_11",
⊢ ∀r r'. r < 2 ⇒ r' < 2 ⇒ (num2example r = num2example r' ⇔ r = r')),
("example_thm", ⊢ ∀x. example (example x) = x),
("example_nchotomy", ⊢ ∀a. a = First ∨ a = Second),
("example_induction", ⊢ ∀P. P First ∧ P Second ⇒ ∀a. P a),
("example_EQ_example", ⊢ ∀a a'. a = a' ⇔ example2num a = example2num a'),
("example_distinct", ⊢ First ≠ Second),
("example_case_eq",
⊢ (case x of First => v0 | Second => v1) = v ⇔
x = First ∧ v0 = v ∨ x = Second ∧ v1 = v),
("example_case_def",
⊢ (∀v0 v1. (case First of First => v0 | Second => v1) = v0) ∧
∀v0 v1. (case Second of First => v0 | Second => v1) = v1),
("example_case_cong",
⊢ ∀M M' v0 v1.
M = M' ∧ (M' = First ⇒ v0 = v0') ∧ (M' = Second ⇒ v1 = v1') ⇒
(case M of First => v0 | Second => v1) =
case M' of First => v0' | Second => v1'),
("example_Axiom", ⊢ ∀x0 x1. ∃f. f First = x0 ∧ f Second = x1),
("example2num_thm", ⊢ example2num First = 0 ∧ example2num Second = 1),
("example2num_ONTO", ⊢ ∀r. r < 2 ⇔ ∃a. r = example2num a),
("example2num_num2example",
⊢ ∀r. r < 2 ⇔ example2num (num2example r) = r),
("example2num_11", ⊢ ∀a a'. example2num a = example2num a' ⇔ a = a'),
("datatype_example", ⊢ DATATYPE (example First Second))]:
(string * thm) list
> EmitTeX.non_type_theorems "example";
val it =
[("example_case_eq",
⊢ (case x of First => v0 | Second => v1) = v ⇔
x = First ∧ v0 = v ∨ x = Second ∧ v1 = v),
("example_thm", ⊢ ∀x. example (example x) = x)]: (string * thm) list
See also
DB.theorems,
bossLib.Hol_datatype
print_datatypes
print_datatypes
EmitTeX.print_datatypes : string -> unit
Prints datatype declarations for the named theory to the screeen (standard out).
An invocation of print_datatypes thy, where thy is the name of a
currently loaded theory segment, will print the datatype declarations
made in that theory.
Failure
Never fails. If thy is not the name of a currently loaded theory
segment then no output will be produced.
Example
> new_theory "example";
<<HOL message: Restarting theory "example">>
<<HOL warning: Theory.callhooks: Hook Parse.clear_consts_from_grammar failed on event NewTheory{oldseg = "example", newseg = "example"} with problem
Exception raised at Term.dest_thy_const: not a const
>>
val it = (): unit
> val _ = Hol_datatype `example = First | Second`;
<<HOL message: Defined type: "example">>
> EmitTeX.print_datatypes "example";
example = First | Second
val it = (): unit
See also
EmitTeX.datatype_thm_to_string,
bossLib.Hol_datatype
print_term_as_tex
print_term_as_tex
EmitTeX.print_term_as_tex : term -> unit
Prints a term as LaTeX.
An invocation of print_term_as_tex tm will print the term tm,
replacing various character patterns (e.g. /\ and \/) with LaTeX
commands. The translation is controlled by the string to string function
EmitTeX.hol_to_tex.
Failure
Should never fail.
Example
- EmitTeX.print_term_as_tex ``\l h. {x | l <= x /\ x <= h}`` before print "\n";
\HOLTokenLambda{}l h. \HOLTokenLeftbrace{}x | l \HOLTokenLeq{} x \HOLTokenConj{} x \HOLTokenLeq{} h\HOLTokenRightbrace{}
> val it = () : unit
Comments
The LaTeX style file holtexbasic.sty (or holtex.sty) should be used
and the output should be pasted into a Verbatim environment.
See also
EmitTeX.print_type_as_tex,
EmitTeX.print_theorem_as_tex,
EmitTeX.print_theory_as_tex,
EmitTeX.print_theories_as_tex_doc,
EmitTeX.tex_theory
print_theorem_as_tex
print_theorem_as_tex
EmitTeX.print_theorem_as_tex : thm -> unit
Prints a theorem as LaTeX.
An invocation of print_theorem_as_tex thm will print the term thm,
replacing various character patterns (e.g. /\ and \/) with LaTeX
commands. The translation is controlled by the string to string function
EmitTeX.hol_to_tex. If the theorem is for a datatype then the function
datatype_thm_to_string is used to produce the orginal declaration.
Failure
Should never fail.
Example
- EmitTeX.print_theorem_as_tex listTheory.CONS before print "\n";
\HOLTokenTurnstile{} \HOLTokenForall{}l. \HOLTokenNeg{}NULL l \HOLTokenImp{} (HD l::TL l = l)
> val it = () : unit
- EmitTeX.print_theorem_as_tex listTheory.datatype_list before print "\n";
list = [] | CONS of \HOLTokenQuote{}a \HOLTokenImp{} \HOLTokenQuote{}a list
> val it = () : unit
Comments
The LaTeX style file holtexbasic.sty (or holtex.sty) should be used
and the output should be pasted into a Verbatim environment.
See also
EmitTeX.print_term_as_tex,
EmitTeX.print_type_as_tex,
EmitTeX.print_theory_as_tex,
EmitTeX.print_theories_as_tex_doc,
EmitTeX.tex_theory
print_theories_as_tex_doc
print_theories_as_tex_doc
EmitTeX.print_theories_as_tex_doc : string list -> string -> unit
Emits theories as LaTeX commands and creates a document template.
An invocation of print_theories_as_tex_doc thys name will export the
named theories thys as a collection of LaTeX commands and it will also
generate a document, whose file name is given by name, that presents
all of the theories. The theories are exported with
print_theory_as_tex.
Failure
Will fail if there is a system error when trying to write the files. It
will not overwite the file name, however, the theories may be
overwritten.
Example
The invocation
- EmitTeX.print_theories_as_tex_doc ["arithmetic", "list", "words"] "report";
> val it = () : unit
will generate four files "HOLarithmetic.tex", "HOLlist.tex", "HOLwords.tex" and "report.tex".
The document can be built as follows:
$ cp $HOLHOME/src/emit/holtex.sty .
$ pdflatex report
$ makeindex report
$ pdflatex report
See also
EmitTeX.print_term_as_tex,
EmitTeX.print_type_as_tex,
EmitTeX.print_theorem_as_tex,
EmitTeX.print_theory_as_tex,
EmitTeX.tex_theory
print_theory_as_tex
print_theory_as_tex
EmitTeX.print_theory_as_tex : string -> unit
Emits a theory as LaTeX commands.
An invocation of print_theory_as_tex thy will export the named theory
as a collection of LaTeX commands. The output file is named
"HOLthy.tex", where thy is the named theory. The prefix "HOL" can be
changed by setting holPrefix. The file is stored in the directory
emitTeXDir. By default the current working directory is used.
The LaTeX file will contain commands for displaying the theory's datatypes, definitions and theorems.
Failure
Will fail if there is a system error when trying to write the file. If the theory is not loaded then a message will be printed and an empty file will be created.
Example
The list theory is exported with:
- EmitTeX.print_theory_as_tex "list";
> val it = () : unit
The resulting file can be included in a LaTeX document with
\input{HOLlist}
Some examples of the available LaTeX commands are listed below:
\HOLlistDatatypeslist
\HOLlistDefinitionsALLXXDISTINCT
\HOLlistTheoremsALLXXDISTINCTXXFILTER
Underscores in HOL names are replaced by "XX"; quotes become "YY" and numerals are expanded out e.g. "1" becomes "One".
Complete listings of the datatypes, definitions and theorems are displayed with:
\HOLlistDatatypes
\HOLlistDefinitions
\HOLlistTheorems
The date the theory was build can be displayed with:
\HOLlistDate
The generated LaTeX will reflect the output of Parse.thm_to_string,
which is under the control of the user. For example, the line width can
be changed by setting Globals.linewidth.
The Verbatim display environment is used, however, "boxed" versions can be constructed. For example,
\BUseVerbatim{HOLlistDatatypeslist}
can be used inside tables and figures.
Comments
The LaTeX style file holtexbasic.sty (or holtex.sty) should be used.
These style files can be modified by the user. For example, the font can
be changed to Helvetica with
\fvset{fontfamily=helvetica}
However, note that this will adversely effect the alignment of the output.
See also
EmitTeX.print_term_as_tex,
EmitTeX.print_type_as_tex,
EmitTeX.print_theorem_as_tex,
EmitTeX.print_theories_as_tex_doc,
EmitTeX.tex_theory
print_type_as_tex
print_type_as_tex
EmitTeX.print_type_as_tex : hol_type -> unit
Prints a type as LaTeX.
An invocation of print_type_as_tex ty will print the type ty,
replacing various character patterns (e.g. # and ->) with LaTeX
commands. The translation is controlled by the string to string function
EmitTeX.hol_to_tex.
Failure
Should never fail.
Example
- EmitTeX.print_type_as_tex ``:bool # bool -> num`` before print "\n";
:bool \HOLTokenProd{} bool \HOLTokenMap{} num
> val it = () : unit
Comments
The LaTeX style file holtexbasic.sty (or holtex.sty) should be used
and the output should be pasted into a Verbatim environment.
See also
EmitTeX.print_term_as_tex,
EmitTeX.print_theorem_as_tex,
EmitTeX.print_theory_as_tex,
EmitTeX.print_theories_as_tex_doc,
EmitTeX.tex_theory
tex_theory
tex_theory
EmitTeX.tex_theory : string -> unit
Emits theory as LaTeX commands and creates a document template.
An invocation of tex_theory thy will export the named theory thy as
a collection of LaTeX commands and it will also generate a document
"thy.tex" that presents the theory. The string "-" may be used to
denote the current theory segment. The theory is exported with
print_theory_as_tex.
Failure
Will fail if there is a system error when trying to write the files. It
will not overwite the file name, however, "HOLname.tex" may be
overwritten.
Example
The invocation
- EmitTeX.tex_theory "list";
> val it = () : unit
will generate two files "HOLlist.tex" and "list.tex".
See also
EmitTeX.print_term_as_tex,
EmitTeX.print_type_as_tex,
EmitTeX.print_theorem_as_tex,
EmitTeX.print_theory_as_tex,
EmitTeX.print_theories_as_tex_doc
FCP_ss
FCP_ss
fcpLib.FCP_ss : ssfrag
A simpset fragment for simplifying finite Cartesian product expressions.
Example
simpLib.SSFRAG{ac = [], congs = [], convs = [], dprocs = [], filter = NONE,
rewrs =
[|- !i. i < dimindex (:'b) ==> ($FCP g ' i = g i),
|- !g. (FCP i. g ' i) = g,
|- !x y. (x = y) = !i. i < dimindex (:'b) ==> (x ' i = y ' i)]}
: ssfrag
See also
Feedback
Feedback
structure Feedback
Module for messages, warnings, errors, and tracing of HOL functions.
The Feedback structure provides facilities for raising and viewing
HOL errors, and also for monitoring tools as they run.
current_trace
current_trace
Feedback.current_trace : string -> int
Returns the current value of the tracing variable specified.
Failure
Fails if the name given is not associated with a registered tracing variable.
See also
Feedback.register_trace,
Feedback.reset_trace,
Feedback.reset_traces,
Feedback.trace,
Feedback.traces
emit_ERR
emit_ERR
Feedback.emit_ERR : bool ref
Flag controlling output of HOL_ERR exceptions.
The boolean flag emit_ERR tells whether an application of HOL_ERR
should be printed. Its value is consulted by Raise when it attempts to
print a textual representation of its argument exception. This flag is
not commonly used, and it may disappear or change in the future.
The default value of emit_ERR is true.
Example
> Raise (mk_HOL_ERR "Module" "function" "message");
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
Exception raised at Module.function: message
HOL_ERR (at Module.function: message) raised
> emit_ERR := false;
val it = (): unit
> Raise (mk_HOL_ERR "Module" "function" "message");
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
HOL_ERR (at Module.function: message) raised
See also
Feedback, Feedback.Raise,
Feedback.emit_MESG,
Feedback.emit_WARNING
emit_MESG
emit_MESG
Feedback.emit_MESG : bool ref
Flag controlling output of HOL_MESG function.
The boolean flag emit_MESG is consulted by HOL_MESG when it attempts
to print its argument. This flag is not commonly used, and it may
disappear or change in the future.
The default value of emit_MESG is true.
Example
> HOL_MESG "Joy to the world.";
<<HOL message: Joy to the world.>>
val it = (): unit
> emit_MESG := false;
val it = (): unit
> HOL_MESG "Peace on Earth.";
val it = (): unit
See also
Feedback, Feedback.HOL_MESG,
Feedback.emit_ERR,
Feedback.emit_WARNING
emit_WARNING
emit_WARNING
Feedback.emit_WARNING : bool ref
Flag controlling output of HOL_WARNING function.
The boolean flag emit_WARNING is consulted by HOL_WARNING when it
attempts to print its argument. This flag is not commonly used, and it
may disappear or change in the future.
The default value of emit_WARNING is true.
Example
> HOL_WARNING "Clock" "watcher" "Time is running out.";
<<HOL warning: Clock.watcher: Time is running out.>>
val it = (): unit
> emit_WARNING := false;
val it = (): unit
> HOL_WARNING "Clock" "watcher" "Time is running out.";
val it = (): unit
See also
Feedback,
Feedback.HOL_WARNING,
Feedback.emit_ERR,
Feedback.emit_MESG
ERR_outstream
ERR_outstream
Feedback.ERR_outstream : (string -> unit) ref
Reference to output stream used when printing HOL_ERR
The value of reference cell ERR_outstream controls where Raise
prints its argument.
The default value of ERR_outstream is a function that prints its argument to TextIO.stdErr.
Example
> val outputs = ref ([] : string list);
val outputs = ref []: string list ref
> ERR_outstream := (fn s => outputs := !outputs @ [s]);
val it = (): unit
> Raise (mk_HOL_ERR "Foo" "bar" "incomprehensible input");
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
HOL_ERR (at Foo.bar: incomprehensible input) raised
> outputs;
val it = ref ["\nException raised at Foo.bar: incomprehensible input\n"]:
string list ref
See also
Feedback, Feedback.HOL_ERR,
Feedback.Raise,
Feedback.MESG_outstream,
Feedback.WARNING_outstream
ERR_to_string
ERR_to_string
Feedback.ERR_to_string : (error_record -> string) ref
Alterable function for formatting HOL_ERR.
ERR_to_string is a reference to a function for formatting the argument
to an application of HOL_ERR. It can be used to customize Raise.
The default value of ERR_to_string is format_ERR.
Example
> fun alt_ERR_report {origin_structure,origin_function,message} =
String.concat["This just in from ",origin_function, " at ",
origin_structure, " : ", message, "\n"];
val alt_ERR_report = fn:
{message: string, origin_function: string, origin_structure: string} ->
string
> ERR_to_string := alt_ERR_report;
Exception- Type error in function application.
Function: := :
(hol_error -> string) ref * (hol_error -> string) -> unit
Argument: (ERR_to_string, alt_ERR_report) :
(hol_error -> string) ref *
({message: string,
origin_function: string, origin_structure: string} -> string)
Reason:
Can't unify hol_error to
{message: string,
origin_function: string, origin_structure: string}
(Incompatible types)
Fail "Static Errors" raised
> Raise (HOL_ERR {origin_structure = "Foo",
origin_function = "bar",
message = "incomprehensible input"});
Exception- Type error in function application.
Function: HOL_ERR : hol_error -> exn
Argument:
{origin_structure = "Foo", origin_function = "bar",
message = "incomprehensible input"} :
{message: string,
origin_function: string, origin_structure: string}
Reason:
Can't unify hol_error to
{message: string,
origin_function: string, origin_structure: string}
(Incompatible types)
Fail "Static Errors" raised
See also
Feedback,
Feedback.error_record,
Feedback.HOL_ERR,
Feedback.Raise,
Feedback.MESG_to_string,
Feedback.WARNING_to_string
error_record
error_record
Feedback.type error_record = {origin_structure : string,
origin_function : string,
message : string}
Type abbreviation for HOL exceptions in Feedback module.
The type abbreviation error_record declares the standard format of HOL
exceptions. The origin_structure field denotes the module that the
exception has been raised in, the origin_function field gives the name
of the function the exception has been raised in, and the message
field should give an explanation of why the exception has been raised.
See also
Feedback, Feedback.HOL_ERR,
Feedback.format_ERR,
Feedback.ERR_to_string
exn_to_string
exn_to_string
Feedback.exn_to_string : exn -> string
Map an exception into a string.
The function exn_to_string maps an exception to a string. However, in
the case of the Interrupt exception, it is not mapped to a string, but
is instead raised. This avoids the possibility of suppressing the
propagation of Interrupt to the top level.
Failure
Never fails.
Example
> exn_to_string Interrupt;
Exception- Interrupt raised
> exn_to_string Div;
val it = "Div": string
> exn_to_string (mk_HOL_ERR "Foo" "bar" "incomprehensible input");
val it = "\nException raised at Foo.bar: incomprehensible input\n": string
See also
Feedback, Feedback.HOL_ERR,
Feedback.ERR_to_string
fail
fail
Feedback.fail : unit -> 'a
Raise a HOL_ERR.
The function fail raises a HOL_ERR with default values. This is
useful when detailed error tracking is not necessary.
Failure
Always fails.
Example
> fail() handle e => Raise e;
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
HOL_ERR (at ??.??: fail) raised
See also
Feedback, Feedback.failwith,
Feedback.Raise,
Feedback.HOL_ERR
failwith
failwith
Feedback.failwith : string -> 'a
Raise a HOL_ERR.
The function failwith raises a HOL_ERR with default values. This is
useful when detailed error tracking is not necessary.
failwith differs from fail in that it takes an extra string
argument, which is typically used to tell which function failwith is
being called from.
Failure
Always fails.
Example
> failwith "foo" handle e => Raise e;
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
HOL_ERR (at ??.failwith: foo) raised
See also
Feedback, Feedback.fail,
Feedback.Raise,
Feedback.HOL_ERR
format_ERR
format_ERR
Feedback.format_ERR : error_record -> string
Maps argument record of HOL_ERR to a string.
The format_ERR function maps the argument of an application of
HOL_ERR to a string. It is the default function used by
ERR_to_string.
Failure
Never fails.
Example
> print
(format_ERR {origin_structure = "Foo",
origin_function = "bar",
message = "incomprehensible input"});
Exception- Type error in function application.
Function: format_ERR : hol_error -> string
Argument:
{origin_structure = "Foo", origin_function = "bar",
message = "incomprehensible input"} :
{message: string,
origin_function: string, origin_structure: string}
Reason:
Can't unify hol_error to
{message: string,
origin_function: string, origin_structure: string}
(Incompatible types)
Fail "Static Errors" raised
See also
Feedback,
Feedback.ERR_to_string,
Feedback.format_MESG,
Feedback.format_WARNING
format_MESG
format_MESG
Feedback.format_MESG : string -> string
Maps argument of HOL_MESG to a string.
The format_MESG function maps a string to a string. Usually, the input
string is the argument of an invocation of HOL_MESG. format_MESG is
the default function used by MESG_to_string.
Failure
Never fails.
Example
> format_MESG "Hello world.";
val it = "<<HOL message: Hello world.>>\n": string
See also
Feedback,
Feedback.MESG_to_string,
Feedback.format_ERR,
Feedback.format_WARNING
format_WARNING
format_WARNING
Feedback.format_WARNING : string -> string -> string -> string
Maps arguments of HOL_WARNING to a string.
The format_WARNING function maps three strings to a string. Usually,
the input strings are the arguments to an invocation of HOL_WARNING.
format_WARNING is the default function used by WARNING_to_string.
Failure
Never fails.
Example
> format_WARNING "Module" "function" "Gadzooks!";
val it = "<<HOL warning: Module.function: Gadzooks!>>\n": string
See also
Feedback,
Feedback.WARNING_to_string,
Feedback.format_ERR,
Feedback.format_MESG
HOL_ERR
HOL_ERR
HOL_ERR : hol_error -> exn
Standard HOL exception.
HOL_ERR is the exception that HOL functions are expected to raise
when they encounter an anomalous situation.
Example
A HOL_ERR value is built from a hol_error value, which is
typically created with mk_hol_error.
> val test_exn =
HOL_ERR (mk_hol_error "Foo" "bar"
locn.Loc_Unknown "unexpected input")
> raise test_exn;
Exception- HOL_ERR (at Foo.Bar: unexpected input) raised
HOL_ERR values can also be directly constructed by mk_HOL_ERR or
mk_HOL_ERRloc.
> val test_exn_again =
mk_HOL_ERR "Foo" "bar" "unexpected input"
> raise test_exn_again;
Exception- HOL_ERR (at Foo.Bar: unexpected input) raised
Usage patterns
Constructing backtraces
Information can be added to a HOL_ERR with wrap_exn:
> raise wrap_exn "structA" "fnB" test_exn;
Exception-
HOL_ERR
(at structA.fnB:
at Foo.bar: unexpected input) raised
Location information can be included with wrap_exn_loc.
A common HOL programming idiom using wrap_exn has the following
pattern (assume function bar is being defined in structure Foo):
fun bar x y =
let val z = ...
in
...
end
handle e as HOL_ERR _ => raise wrap_exn "Foo" "bar" e
If HOL_ERR <holerr> happens to be raised inside an invocation of
bar, the handler will extend the origins of holerr with Foo
and bar and raise the augmented HOL_ERR.
Scrutinizing and setting the payload
The payload of a HOL_ERR can be accessed by pattern matching and the
contents accessed by functions over hol_error such as
top_structure_of, top_function_of, and message_of:
> val HOL_ERR holerr = test_exn
> val (s,f,m) = (top_structure_of holerr,
top_function_of holerr,
message_of holerr)
val f = "bar": string
val m = "unexpected input": string
val s = "Foo": string
Portions of the payload can also be set by set_top_function and
set_message.
Branching on the interaction mode
The variable Globals.interactive is used by programs to tell whether
the HOL4 system is running interactively (i.e. is in the
Read-Eval-Print loop) or not (is running in batch mode under
Holmake). In the REPL, an uncaught HOL_ERR propagates to the top
level and gets prettyprinted. In batch mode, in contrast, uncaught
exceptions are not prettyprinted and can be rendered quite
messily. The function render_exn can be used to write code that
displays HOL_ERR properly in either mode.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.mk_HOL_ERR,
Feedback.mk_HOL_ERRloc,
Feedback.wrap_exn,
Feedback.top_structure_of,
Feedback.top_function_of,
Feedback.top_location_of,
Feedback.message_of,
Feedback.set_top_function,
Feedback.set_message,
Globals.interactive,
Feedback.render_exn
HOL_MESG
HOL_MESG
Feedback.HOL_MESG : string -> unit
Prints out a message in a special format.
HOL_MESG prints out its argument after formatting it a bit. The
formatting is controlled by the function held in MESG_to_string, which
is format_MESG by default. The output stream that the message is
printed on is controlled by MESG_outstream, and is TextIO.stdOut by
default.
There are three kinds of informative messages that the Feedback
structure supports: errors, warnings, and messages. Errors are signalled
by the raising of an exception built from HOL_ERR; warnings, which are
printed by HOL_WARNING, are less severe than errors, and lead to a
warning message being printed; finally, messages have no pejorative
weight at all, and may be freely employed, via HOL_MESG, to keep users
informed in the normal course of processing.
Failure
The invocation fails if the formatting or output routines fail.
Example
- HOL_MESG "Ack.";
<<HOL message: Ack.>>
See also
Feedback, Feedback.HOL_ERR,
Feedback.Raise,
Feedback.HOL_WARNING,
Feedback.MESG_to_string,
Feedback.format_MESG,
Feedback.MESG_outstream
HOL_WARNING
HOL_WARNING
Feedback.HOL_WARNING : string -> string -> string -> unit
Prints out a message in a special format.
There are three kinds of informative messages that the Feedback
structure supports: errors, warnings, and messages. Errors are signalled
by the raising of an exception built from HOL_ERR; warnings, which are
printed by HOL_WARNING, are less severe than errors, and lead only to
a formatted message being printed; finally, messages have no pejorative
weight at all, and may be freely employed, via HOL_MESG, to keep users
informed in the normal course of processing.
HOL_WARNING prints out its arguments after formatting them. The
formatting is controlled by the function held in WARNING_to_string,
which is format_WARNING by default. The output stream that the message
is printed on is controlled by WARNING_outstream, and is
TextIO.stdOut by default.
A call HOL_WARNING s1 s2 s3 is formatted with the assumption that s1
and s2 are the names of the module and function, respectively, from
which the warning is emitted. The string s3 is the actual warning
message.
Failure
The invocation fails if the formatting or output routines fail.
Example
> HOL_WARNING "Module" "function" "stern message.";
<<HOL warning: Module.function: stern message.>>
val it = (): unit
See also
Feedback, Feedback.HOL_ERR,
Feedback.Raise,
Feedback.HOL_MESG,
Feedback.WARNING_to_string,
Feedback.format_WARNING,
Feedback.WARNING_outstream
MESG_outstream
MESG_outstream
Feedback.MESG_outstream : TextIO.outstream ref
Reference to output stream used when printing HOL_MESG.
The value of reference cell MESG_outstream controls where HOL_MESG
prints its argument.
The default value of MESG_outstream is a function that prints its argument to TextIO.stdOut.
Example
> val outputs = ref ([] : string list);
val outputs = ref []: string list ref
> MESG_outstream := (fn s => outputs := !outputs @ [s]);
val it = (): unit
> HOL_MESG "Nattering nabobs of negativity.";
val it = (): unit
> outputs;
val it = ref ["<<HOL message: Nattering nabobs of negativity.>>\n"]:
string list ref
See also
Feedback, Feedback.HOL_MESG,
Feedback.ERR_outstream,
Feedback.WARNING_outstream,
Feedback.emit_MESG
MESG_to_string
MESG_to_string
Feedback.MESG_to_string : (string -> string) ref
Alterable function for formatting HOL_MESG.
MESG_to_string is a reference to a function for formatting the
argument to an application of HOL_MESG.
The default value of MESG_to_string is format_MESG.
Example
- fun alt_MESG_report s = String.concat["Dear HOL user: ", s, "\n"];
- MESG_to_string := alt_MESG_report;
- HOL_MESG "Hi there."
Dear HOL user: Hi there.
> val it = () : unit
See also
Feedback, Feedback.HOL_MESG,
Feedback.format_MESG,
Feedback.ERR_to_string,
Feedback.WARNING_to_string
message_of
message_of
message_of : hol_error -> string
Extract message from a hol_error.
An invocation message_of holerr returns the message component of holerr.
Example
> message_of (mk_hol_error "Foo" "bar" locn.Loc_Unknown "bad input");
val it = "bad input": string
Failure
Never fails.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.origins_of,
Feedback.top_structure_of,
Feedback.top_function_of
mk_HOL_ERR
mk_HOL_ERR
Feedback.mk_HOL_ERR : string -> string -> string -> exn
Creates an application of HOL_ERR.
mk_HOL_ERR provides a curried version of the HOL_ERR
exception.
Failure
Never fails.
Example
> mk_HOL_ERR "<Module>" "<function>" "<message>";
val it = HOL_ERR (at <Module>.<function>: <message>): exn
See also
Feedback,
Feedback.HOL_ERR,
Feedback.mk_HOL_ERRloc
mk_HOL_ERRloc
mk_HOL_ERRloc
Feedback.mk_HOL_ERRloc : string -> string -> locn.locn -> string -> exn
Creates an application of HOL_ERR with location information.
mk_HOL_ERRloc provides a curried version of the HOL_ERR
exception including spcified location information.
Failure
Never fails.
Example
> val exloc = let open locn in Loc (LocA(0,0), LocA(3,42)) end;
val exloc = 1:0-4:42: locn.locn
> mk_HOL_ERRloc "<Module>" "<function>" exloc "<message>";
val it =
HOL_ERR
(at <Module>.<function>:
between line 1, character 0 and line 4, character 42: <message>):
exn
See also
Feedback,
Feedback.HOL_ERR,
Feedback.mk_HOL_ERR
mk_hol_error
mk_hol_error
mk_hol_error : string -> string -> locn.locn -> string -> hol_error
Create a hol_error value.
An invocation mk_hol_error sname fname loc m builds an initial
hol_error value where sname is the enclosing module name, fname
is the enclosing function name, loc is the location in the file
where the error is detected, and m is the error message.
hol_error values are used to build HOL_ERR exceptions.
Example
> val holerr =
mk_hol_error "Foo" "bar" locn.Loc_Unknown "unexpected input"
val holerr = at Foo.bar: unexpected input: hol_error
> val holexn = HOL_ERR holerr;
val holexn = HOL_ERR (at Foo.bar: unexpected input): exn
Representation
The representation of the hol_error type includes
- a message
- a list of
originelements.
Each origin value includes source information such as the enclosing
SML module and function, plus the source location where the error
originated. The list of origins is typically used as a stack, and can
be used to provide a backtrace facility. The function wrap_hol_error
is used to push an origin onto the existing origins of a hol_error,
however it is more common to use wrap_exn on HOL_ERR values.
See also
Feedback,
Feedback.HOL_ERR,
Feedback.origins_of,
Feedback.message_of,
Feedback.top_structure_of,
Feedback.top_function_of,
Feedback.top_location_of,
Feedback.set_top_function,
Feedback.set_message,
Feedback.wrap_hol_error
origins_of
origins_of
origins_of : hol_error -> origin list
Extract origin stack from a hol_error.
An invocation origins_of holerr returns the list of origin
elements held in holerr.
Example
> origins_of (mk_hol_error "Foo" "bar" locn.Loc_Unknown "bad input");
val it =
[{origin_function = "bar", origin_structure = "Foo",
source_location = <??>}]: origin list
Failure
Never fails.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.message_of,
Feedback.top_structure_of,
Feedback.top_function_of
Raise
Raise
Feedback.Raise : exn -> 'a
Print an exception before re-raising it.
The Raise function prints out information about its argument exception
before re-raising it. It uses the value of ERR_to_string to format the
message, and prints the information on the outstream held in
ERR_outstream.
Failure
Never fails, since it always succeeds in raising the supplied exception.
Example
> Raise (mk_HOL_ERR "Foo" "bar" "incomprehensible input");
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
Exception raised at Foo.bar: incomprehensible input
HOL_ERR (at Foo.bar: incomprehensible input) raised
See also
Feedback,
Feedback.ERR_to_string,
Feedback.ERR_outstream,
Lib.try, Lib.trye
register_btrace
register_btrace
Feedback.register_btrace : string * bool ref -> unit
Registers a trace variable for a boolean reference.
A call to register_btrace(nm, bref) registers a trace variable called
nm that can take on two different values (0 and 1), which correspond
to the state of the boolean variable bref.
Failure
Fails if the given name is already in use as a trace variable.
Comments
This function uses register_ftrace to make a boolean variable appear
as an integer value.
See also
Feedback,
Feedback.current_trace,
Feedback.register_trace,
Feedback.register_ftrace,
Feedback.set_trace,
Feedback.trace,
Feedback.traces
register_ftrace
register_ftrace
Feedback.register_ftrace :
(string * ((unit -> int) * (int -> unit)) * int) -> unit
Registers a trace that is accessed by a set/get pair of functions.
A call to register_ftrace(nm, (g,s), m) registers an integer-valued
trace variable that is updated with the s function and whose value is
read with the g function. The variable is given the name nm and the
variable's maximum allowed value is m. The trace's default is the
value of g(), which is called just once as part of the registration
procedure.
Failure
Fails if the given name is already in use as a trace variable, or if the
maximum or the default value (returned by g()) is less than zero.
Comments
The two functions provide a more general way of accessing something that may not be actually be an integer reference, even though this is the interface that the various trace functions present.
See also
Feedback,
Feedback.current_trace,
Feedback.register_trace,
Feedback.register_btrace,
Feedback.set_trace,
Feedback.trace,
Feedback.traces
register_trace
register_trace
Feedback.register_trace : (string * int ref * int) -> unit
Registers a new tracing variable.
A call to register_trace(n, r, m) registers the integer reference
variable r as a tracing variable associated with name n. The integer
m is its maximum value. Its value at the time of registration is
considered its default value, which will be restored by a call to
reset_trace n or reset_traces.
Failure
Fails if there is already a tracing variable registered under the name given, or if either the maximum value or the value in the reference is less than zero.
See also
Feedback,
Feedback.register_btrace,
Feedback.register_ftrace,
Feedback.reset_trace,
Feedback.reset_traces,
Feedback.trace,
Feedback.traces
render_exn
render_exn
Feedback.render_exn : exn -> 'a
Print HOL_ERR exception then recover, or not, according to
Globals.interactive.
The variable Globals.interactive is used by programs to tell whether
the HOL4 system is running interactively (i.e. is in the
Read-Eval-Print loop) or not (is running in batch mode under
Holmake). When the contents of Globals.interactive is true
render_exn raises the given exception. If the exception is not
otherwise dealt with in user code, the REPL will handle it and print
the message contents before resuming the top-level loop.
When the contents of Globals.interactive is false, render_exn
prints a message derived from the contents of its argument exception
then exits to the host operating system.
Example
> val () = render_exn (mk_HOL_ERR "S" "f" "-");
Exception- HOL_ERR (at S.f: -) raised
> Globals.interactive := false; (* for example purposes only! *)
val it = (): unit
> val () = render_exn (mk_HOL_ERR "S" "f" "-");
Exception raised at S.f: -
Process HOL exited abnormally with code 1
Comment
render_exn attempts to display non-HOL_ERR exceptions sensibly.
See also
Feedback,
Feedback.HOL_ERR,
Globals.interactive
reset_trace
reset_trace
Feedback.reset_trace : string -> unit
Resets a tracing variable to its default value.
A call to reset_trace n resets the tracing variable associated with
the name n to its default value, i.e., the value of the expression
!r when n was registered with register_trace n r.
Failure
Fails if the name given is not associated with a registered tracing
variable, or if a set function associated with a "functional" trace
(see register_ftrace) fails.
See also
Feedback,
Feedback.register_trace,
Feedback.set_trace,
Feedback.reset_traces,
Feedback.trace,
Feedback.traces
reset_traces
reset_traces
Feedback.reset_traces : unit -> unit
Resets all registered tracing variables to their default values.
Failure
Fails if a set function associated with a "functional" trace (see
register_ftrace) fails.
See also
Feedback, Feedback.set_trace,
Feedback.register_trace,
Feedback.reset_trace,
Feedback.trace,
Feedback.traces
set_message
set_message
set_message : string -> hol_error -> hol_error
Overwrite message component of a hol_error value.
Example
> set_message "BIG problem!"
(mk_hol_error "Foo" "bar" locn.Loc_Unknown "bad input");
val it = at Foo.bar: BIG problem!: hol_error
Failure
Never fails.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.message_of,
Feedback.set_top_function
set_top_function
set_top_function
set_top_function : string -> hol_error -> hol_error
Overwrite last function name added to a hol_error.
An invocation set_top_function holerr replaces the function name of
the top origin element held in holerr.
Example
> set_top_function "new_name"
(mk_hol_error "Foo" "bar" locn.Loc_Unknown "bad input");
val it = at Foo.new_name: bad input: hol_error
Failure
The call fails if the origin stack of the hol_error is empty.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.top_function_of,
Feedback.set_message
set_trace
set_trace
Feedback.set_trace : string -> int -> unit
Set a tracing level for a registered trace.
Invoking set_trace n i sets the level of the tracing mechanism
registered under n to be i. These settings control the verboseness
of various tools within the system. This can be useful both when
debugging proofs (with the simplifier for example), and also as a guide
to how an automatic proof is proceeding (with mesonLib for example).
There is no single interpretation of what activity a tracing level should evoke: each tool registered for tracing can treat its trace level in its own way.
Failure
A call to set_trace n i fails if n has not previously been
registered via register_trace. It also fails if i is less than zero,
or if it is greater than the trace's specified maximum value.
Example
- set_trace "Rewrite" 1;
- PURE_REWRITE_CONV [AND_CLAUSES] (Term `x /\ T /\ y`);
<<HOL message: Rewrite:
|- T /\ y = y.>>
> val it = |- x /\ T /\ y = x /\ y : thm
See also
Feedback,
Feedback.register_trace,
Feedback.reset_trace,
Feedback.reset_traces,
Feedback.trace,
Feedback.traces
top_function_of
top_function_of
top_function_of : hol_error -> string
Extract last function name added to a hol_error.
An invocation top_function_of holerr returns the function name of
the top origin element held in holerr.
Example
> top_function_of
(mk_hol_error "Foo" "bar" locn.Loc_Unknown "bad input")
val it = "bar": string
Failure
The call fails if the origin stack of the hol_error is empty.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.origins_of,
Feedback.message_of,
Feedback.top_structure_of,
Feedback.top_location_of,
Feedback.set_top_function
top_location_of
top_location_of
top_location_of : hol_error -> locn.locn
Extract last location added to a hol_error.
An invocation top_location_of holerr returns the location of
the top origin element held in holerr.
Example
> val exloc = let open locn in Loc (LocA(0,0), LocA(3,42)) end;
val exloc = 1:0-4:42: locn.locn
> top_location_of (mk_hol_error "Foo" "bar" exloc "bad input");
val it = 1:0-4:42: locn.locn
Failure
The call fails if the origin stack of the hol_error is empty.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.origins_of,
Feedback.message_of,
Feedback.top_structure_of,
Feedback.top_function_of
top_structure_of
top_structure_of
top_structure_of : hol_error -> string
Extract last structure name added to a hol_error.
An invocation top_structure_of holerr returns the structure name of
the top origin element held in holerr.
Example
> top_structure_of
(mk_hol_error "Foo" "bar" locn.Loc_Unknown "bad input")
val it = "Foo": string
Failure
The call fails if the origin stack of the hol_error is empty.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.origins_of,
Feedback.message_of,
Feedback.top_function_of,
Feedback.top_location_of,
Feedback.set_top_structure
trace
trace
Feedback.trace : string * int -> ('a -> 'b) -> 'a -> 'b
Invoke a function with a specified level of tracing.
The trace function is used to set the value of a tracing variable for
the duration of one top-level function call.
A call to trace (nm,i) f x attempts to set the tracing variable
associated with the string nm to value i. Then it evaluates f x
and returns the resulting value after restoring the trace level of nm.
Failure
Fails if the name given is not associated with a registered tracing variable. Also fails if the function invocation fails.
Example
> load "mesonLib";
val it = (): unit
> trace ("meson",2) prove
(concl SKOLEM_THM,mesonLib.MESON_TAC []);
0 inferences so far. Searching with maximum size 0.
0 inferences so far. Searching with maximum size 1.
Internal goal solved with 2 MESON inferences.
2 inferences so far. Searching with maximum size 0.
2 inferences so far. Searching with maximum size 1.
Internal goal solved with 4 MESON inferences.
4 inferences so far. Searching with maximum size 0.
4 inferences so far. Searching with maximum size 1.
Internal goal solved with 6 MESON inferences.
6 inferences so far. Searching with maximum size 0.
6 inferences so far. Searching with maximum size 1.
Internal goal solved with 8 MESON inferences.
solved with 8 MESON inferences.
val it = ⊢ ∀P. (∀x. ∃y. P x y) ⇔ ∃f. ∀x. P x (f x): thm
> traces();
val it =
[BasicProvers.var_eq_old: 0 [0..1], Definition.TC extraction: 0 [0..5],
Definition.allow_schema_definition: 0 [0..1],
Definition.auto Defn.tgoal: 1 [0..1],
Definition.delete support defs: 1 [0..1],
Definition.induction derivation: 0 [0..1],
Definition.storage_message: 1 [0..1],
Definition.termination candidates: 0 [0..4],
EmitTeX: K&R record type defns: 1 [0..1],
EmitTeX: dollar parens: 1 [0..1],
EmitTeX: print datatype names as types: 0 [0..1],
EmitTeX: print datatypes compactly: 0 [0..1],
EmitTeX: print thm turnstiles: 1 [0..1],
Goalstack.howmany_printed_assums: 1000000 [0..1000000],
Goalstack.howmany_printed_subgoals: 10 [0..10000],
Goalstack.other_subgoals_pretty_limit: 100 [0..100000],
Goalstack.print_assums_reversed: 0 [0..1],
Goalstack.print_goal_at_top: 0 [0..1],
Goalstack.print_goal_fvs: 0 [0..1],
Goalstack.show_proved_subtheorems: 1 [0..1],
Goalstack.show_stack_subgoal_count: 1 [0..1], Greek tyvars: 1 [0..1],
Ho_Rewrite: 0 [0..1], HolSatLib_warn: 1 [0..1],
PAT_ABBREV_TAC: match var/const: 1 [0..1], PP.avoid_unicode: 0 [0..1],
PP.catch_withpp_err: 1 [0..1], PP.print_firstcasebar: 0 [0..1],
PP.qblock_smash_limit: 4 [0..1000], PPBackEnd show types: 1 [0..1],
PPBackEnd use annotations: 1 [0..1], PPBackEnd use css: 1 [0..1],
PPBackEnd use styles: 1 [0..1],
Parse.unicode_trace_off_complaints: 1 [0..1], QUANT_INST_DEBUG: 0 [0..3],
QUANT_INST_DEBUG_DEPTH: 5 [0..2000],
QUANT_INST___REC_DEPTH: 250 [0..20000],
QUANT_INST___print_term_length: 2000 [0..2000], RealArith dp: 0 [0..1],
Rewrite: 0 [0..1], Theory.allow_rebinds: 0 [0..1],
Theory.debug: 0 [0..1], Theory.save_thm_reporting: 1 [0..2],
TheoryPP.include_html_docs: 1 [0..1], Unicode: 1 [0..1],
Unicode Univ printing: 1 [0..1], Univ pretty-printing: 1 [0..1],
Vartype Format Complaint: 1 [0..1], ambiguous grammar warning: 1 [0..2],
assumptions: 0 [0..1], computeLib.auto_import_definitions: 1 [0..1],
guess overloads: 1 [0..1], inddef strict: 0 [0..1], meson: 1 [0..2],
metis: 1 [0..10], normalForms: 0 [0..10],
notify type variable guesses: 1 [0..1], numeral types: 0 [0..1],
paranoid string literal printing: 0 [0..1], pp_annotations: 1 [0..1],
pp_array_types: 1 [0..1], pp_avoids_symbol_merges: 1 [0..1],
pp_cases: 1 [0..1], pp_dollar_escapes: 1 [0..1], pp_num_types: 1 [0..1],
pp_unambiguous_comprehensions: 0 [0..2], print_tyabbrevs: 1 [0..1],
report_thy_times: 1 [0..1], show_alias_printing_choices: 1 [0..1],
show_typecheck_errors: 0 [0..1], simplifier: 0 [0..7],
syntax_error: 1 [0..1], types: 0 [0..2], use pmatch_pp: 1 [0..1]]:
trace_elt list
See also
Feedback,
Feedback.register_trace,
Feedback.reset_trace,
Feedback.reset_traces,
Feedback.set_trace,
Feedback.traces, Lib.with_flag
traces
traces
Feedback.traces : unit -> {name : string, max : int, aliases : string list,
trace_level : int, default : int} list
Returns a list of registered tracing variables.
The function traces is part of the interface to a collection of
variables that control the verboseness of various tools within the
system. Tracing can be useful both when debugging proofs (with the
simplifier for example), and also as a guide to how an automatic proof
is proceeding (with mesonLib for example).
Failure
Never fails.
See also
Feedback.register_trace,
Feedback.set_trace,
Feedback.reset_trace,
Feedback.reset_traces,
Feedback.trace
WARNING_outstream
WARNING_outstream
Feedback.WARNING_outstream : TextIO.outstream ref
Controlling output stream used when printing HOL_WARNING
The value of reference cell WARNING_outstream controls where
HOL_WARNING prints its argument.
The default value of WARNING_outstream is a function that prints its argument to TextIO.stdOut.
Example
> val outputs = ref ([] : string list);
val outputs = ref []: string list ref
> WARNING_outstream := (fn s => outputs := !outputs @ [s]);
val it = (): unit
> HOL_WARNING "Module" "Function" "Sufferin' Succotash!";
val it = (): unit
> outputs;
val it = ref ["<<HOL warning: Module.Function: Sufferin' Succotash!>>\n"]:
string list ref
See also
Feedback,
Feedback.HOL_WARNING,
Feedback.ERR_outstream,
Feedback.MESG_outstream,
Feedback.emit_WARNING
WARNING_to_string
WARNING_to_string
Feedback.WARNING_to_string : (string -> string -> string -> string) ref
Alterable function for formatting HOL_WARNING.
WARNING_to_string is a reference to a function for formatting the
argument to HOL_WARNING.
The default value of WARNING_to_string is format_WARNING.
Example
- fun alt_WARNING_report s t u =
String.concat["WARNING---", s,".",t,": ",u,"---END WARNING\n"];
- WARNING_to_string := alt_WARNING_report;
- HOL_WARNING "Foo" "bar" "Look out";
WARNING---Foo.bar: Look out---END WARNING
> val it = () : unit
See also
Feedback,
Feedback.HOL_WARNING,
Feedback.format_WARNING,
Feedback.ERR_to_string,
Feedback.MESG_to_string
with_traces
with_traces
Feedback.with_traces : (string * int) list -> ('a -> 'b) -> 'a -> 'b
Invoke a function with specified levels for traces.
The with_traces function is used to set values of a collection of
tracing variables for the duration of one top-level function call.
In a state where trace variables designated by nm_1,...,nm_k have
corresponding values i_1,...,i_k, a call
with_traces [(nm_1,j_1),...,(nm_k,j_k)] f x
first sets the trace variables designated by nm_1,...,nm_k to the
corresponding values j_1,...,j_k. Then the call evaluates f x and
returns the result, but only after restoring the original
i_1,...,i_k values for the trace variables.
Failure
Fails if any of the designations fails to be associated with a registered tracing variable. Also fails if an attempt is made to set a trace variable outside of its specified range of values. Also fails if the function invocation fails.
Example
First we define a convenience function.
> fun pr_thm th = Feedback.HOL_INFO (thm_to_string th ^ "\n");
val pr_thm = fn: thm -> unit
Now we examine a theorem with and without traces set to local values.
> map current_trace ["assumptions", "types"] ;
val it = [0, 0]: int list
> pr_thm EQ_SYM_EQ;
⊢ ∀x y. x = y ⇔ y = x
val it = (): unit
> with_traces [("assumptions",1), ("types",1)] pr_thm EQ_SYM_EQ;
[] ⊢ ∀(x :α) (y :α). x = y ⇔ y = x
val it = (): unit
> map current_trace ["assumptions", "types"] ;
val it = [0, 0]: int list
See also
Feedback,
Feedback.traces,
Feedback.register_trace,
Feedback.reset_trace,
Feedback.reset_traces,
Feedback.set_trace,
Feedback.trace,
Lib.with_flag
wrap_exn
wrap_exn
Feedback.wrap_exn : string -> string -> exn -> exn
Adds supplementary information to a HOL_ERR exception.
wrap_exn s1 s2 (HOL_ERR e) where s1 is typically the name of a
structure and s2 is typically the name of a function, augments e
by pushing (s1,s2) on to the stack of origin elements held in
e. This can be used to achieve a kind of backtrace when an error
occurs. wrap_exn can be applied to any exception.
Almost every non-HOL_ERR exception is mapped into an application of
HOL_ERR by wrap_exn, but there is one special case: interrupts. A
Unix interrupt signal is mapped into the Interrupt exception. If
wrap_exn were to translate an Interrupt exception into a HOL_ERR
exception, crucial information might be lost. For this reason,
wrap_exn s1 s2 Interrupt raises the Interrupt exception.
Failure
Raises the exception argument when the exception argument is
Interrupt.
Example
In the following example, the original HOL_ERR is from Foo.bar.
After wrap_exn is called, the HOL_ERR is from Fred.barney and its
message field has been augmented to reflect the original source of the
exception.
> val orig_exn = mk_HOL_ERR "Foo" "bar" "incomprehensible input";
val orig_exn = HOL_ERR (at Foo.bar: incomprehensible input): exn
> wrap_exn "Fred" "barney" orig_exn;
val it =
HOL_ERR
(at Fred.barney:
at Foo.bar: incomprehensible input): exn
The following example shows how wrap_exn treats the Interrupt
exception.
> wrap_exn "Fred" "barney" Interrupt;
Exception- Interrupt raised
The following example shows how wrap_exn translates all exceptions
that aren't either HOL_ERR or Interrupt into applications of
HOL_ERR.
> wrap_exn "Fred" "barney" Div;
val it = HOL_ERR (at Fred.barney: Div): exn
See also
Feedback,
Feedback.HOL_ERR,
Feedback.wrap_exn_loc
wrap_exn_loc
wrap_exn_loc
Feedback.wrap_exn_loc : string -> string -> locn.locn -> exn -> exn
Adds supplementary information to a HOL_ERR exception, with location.
wrap_exn_loc s1 s2 loc holerr behaves like wrap_exn except that it
includes the given location information with the other data pushed on
to the origins stack.
Failure
Raises the exception argument when the exception argument is
Interrupt.
Example
In the following example, the original HOL_ERR is from Foo.bar.
After wrap_exn_loc is called, the HOL_ERR is from Fred.barney and its
message field has been augmented to reflect the original source of the
exception.
> val orig_exn = mk_HOL_ERR "Foo" "bar" "incomprehensible input";
val orig_exn = HOL_ERR (at Foo.bar: incomprehensible input): exn
> val exloc = let open locn in Loc (LocA(0,0), LocA(3,42)) end;
val exloc = 1:0-4:42: locn.locn
> wrap_exn_loc "Fred" "barney" exloc orig_exn;
val it =
HOL_ERR
(at Fred.barney: between line 1, character 0 and line 4, character 42:
at Foo.bar: incomprehensible input): exn
See also
Feedback,
Feedback.HOL_ERR,
Feedback.wrap_exn
wrap_hol_error
wrap_hol_error
wrap_hol_error : string -> string -> locn.locn -> hol_error -> hol_error
Add supplementary information to a hol_error value.
wrap_hol_error s1 s2 loc holerr where s1 is typically the name of
a structure and s2 is typically the name of a function and loc is
a location, augments holerr by pushing (s1,s2,loc) on to the stack of
origin elements held in holerr.
Failure
Never fails.
Example
> val orig = mk_hol_error "Foo" "bar" locn.Loc_Unknown "mucho badness";
val orig = at Foo.bar: mucho badness: hol_error
> wrap_hol_error "Fred" "barney" locn.Loc_Unknown orig;
val it =
at Fred.barney:
at Foo.bar: mucho badness: hol_error
See also
Feedback,
Feedback.mk_hol_error
hol_error
hol_error
type Feedback.origin =
{origin_structure:string,
origin_function:string,
source_location : locn.locn}
datatype Feedback.hol_error =
HOL_ERROR of
{origins : origin list,
message : string}
Payload of HOL_ERR.
The payload of the HOL_ERR exception, hol_error, is a single
constructor datatype that groups a list of "origins" with a
message. An origin provides information about where (host structure,
calling function, source location) an exception has been raised. Since
exceptions can be re-raised, the origin list can be used to
construct a useful backtrace to help track down program errors.
Example
A hol_error can be directly constructed but it is preferable to use
the higher level entrypoint mk_hol_error:
> val holerr =
mk_hol_error "Struct" "Fn" locn.Loc_Unknown "<Msg>"
# val holerr = at Struct.Fn: <Msg>: hol_error
A builtin prettyprinter is used to display hol_error values.
Accessing hol_error components
The message and origins of a hol_error value can be obtained via
message_of and origins_of. The subcomponents of the head of the
origins list can be obtained with top_structure_of,
top_function_of, and top_location_of
Changing hol_error components
To augment an existing hol_error with new origin information, use
wrap_hol_error. However, it is usually preferable to use
wrap_exn. To set the message to a new value, use set_message, and
to set the function component of the head origin, use
set_top_function.
Comment
For obscure reasons, hol_error is defined in structure
Feedback_dtype and duplicated in Feedback.
See also
Feedback,
Feedback.mk_hol_error,
Feedback.top_structure_of,
Feedback.top_function_of,
Feedback.top_location_of,
Feedback.origins_of,
Feedback.message_of,
Feedback.set_message,
Feedback.set_top_function,
Feedback.wrap_exn
interactive
interactive
Globals.interactive : bool ref
Variable specifying whether system is in interaction mode or batch mode.
The HOL system is either running via the "Read-Eval-Print" loop of the
host SML system, or it is running in batch mode, for example via
Holmake. Some system facilities, for example error handling, need
to access this knowledge.
See also
Feedback,
Feedback.HOL_ERR,
Feedback.render_exn
max_print_depth
max_print_depth
Globals.max_print_depth : int ref
Sets depth bound on prettyprinting.
The reference variable max_print_depth is used to define the maximum
depth of printing for the pretty printer. If the number of blocks (an
internal notion used by the prettyprinter) becomes greater than the
value set by max_print_depth then the blocks are abbreviated by the
holophrast .... By default, the value of max_print_depth is ~1.
This is interpreted to mean 'print everything'.
Failure
Never fails.
Example
To change the maximum depth setting to 10, the command will be:
- max_print_depth := 10;
> val it = () : unit
The theorem numeralTheory.numeral_distrib then prints as follows:
> numeralTheory.numeral_distrib;
val it =
⊢ (∀n. 0 + n = n) ∧ (∀n. n + 0 = n) ∧
(∀n m. NUMERAL n + NUMERAL m = NUMERAL (numeral$iZ (n + m))) ∧
(∀n. 0 * n = 0) ∧ (∀n. n * 0 = 0) ∧
(∀n m. NUMERAL n * NUMERAL m = NUMERAL (n * m)) ∧ (∀n. 0 − n = 0) ∧
(∀n. n − 0 = n) ∧ (∀n m. NUMERAL n − NUMERAL m = NUMERAL (n − m)) ∧
(∀n. 0 ** NUMERAL (BIT1 n) = 0) ∧ (∀n. 0 ** NUMERAL (BIT2 n) = 0) ∧
(∀n. n ** 0 = 1) ∧ (∀n m. NUMERAL n ** NUMERAL m = NUMERAL (n ** m)) ∧
SUC 0 = 1 ∧ (∀n. SUC (NUMERAL n) = NUMERAL (SUC n)) ∧ PRE 0 = 0 ∧
(∀n. PRE (NUMERAL n) = NUMERAL (PRE n)) ∧
(∀n. NUMERAL n = 0 ⇔ n = ZERO) ∧ (∀n. 0 = NUMERAL n ⇔ n = ZERO) ∧
(∀n m. NUMERAL n = NUMERAL m ⇔ n = m) ∧ (∀n. n < 0 ⇔ F) ∧
(∀n. 0 < NUMERAL n ⇔ ZERO < n) ∧ (∀n m. NUMERAL n < NUMERAL m ⇔ n < m) ∧
(∀n. 0 > n ⇔ F) ∧ (∀n. NUMERAL n > 0 ⇔ ZERO < n) ∧
(∀n m. NUMERAL n > NUMERAL m ⇔ m < n) ∧ (∀n. 0 ≤ n ⇔ T) ∧
(∀n. NUMERAL n ≤ 0 ⇔ n ≤ ZERO) ∧ (∀n m. NUMERAL n ≤ NUMERAL m ⇔ n ≤ m) ∧
(∀n. n ≥ 0 ⇔ T) ∧ (∀n. 0 ≥ n ⇔ n = 0) ∧
(∀n m. NUMERAL n ≥ NUMERAL m ⇔ m ≤ n) ∧ (∀n. ODD (NUMERAL n) ⇔ ODD n) ∧
(∀n. EVEN (NUMERAL n) ⇔ EVEN n) ∧ ¬ODD 0 ∧ EVEN 0: thm
max_print_length
max_print_length
Globals.max_print_length : int ref
Sets a length bound on pretty printing for list forms.
Defines the maximum number of elements that the pretty printer will
print for list forms. This closely mirrors Globals.max_print_depth:
remaining elements are abbreviated by ..., and the default value of
~1 means 'print all elements'.
Failure
Never fails.
See also
release
release
Globals.release : string
The name of the release series of the HOL system being run.
Example
> Globals.release;
val it = "Trindemossen": string
See also
show_tags
show_tags
Globals.show_tags : bool ref
Flag for controlling display of tags in theorem prettyprinter.
The flag show_tags controls the display of values of type thm. When
set to true, the tag attached to a theorem will be printed when the
theorem is printed. When set to false, no indication of the presence
or absence of a tag will be displayed.
Example
> show_tags := false;
val it = (): unit
> pairTheory.PAIR_MAP_THM;
val it = ⊢ ∀f g x y. (f ## g) (x,y) = (f x,g y): thm
> mk_thm ([],F);
val it = ⊢ F: thm
> show_tags := true;
val it = (): unit
> pairTheory.PAIR_MAP_THM;
val it =
[oracles: DISK_THM] [axioms: ] [] ⊢ ∀f g x y. (f ## g) (x,y) = (f x,g y):
thm
> mk_thm ([],F);
val it = [oracles: MK_THM] [axioms: ] [] ⊢ F: thm
Comments
The initial value of show_tags is false.
See also
Thm.tag, Thm.mk_oracle_thm,
Thm.mk_thm
show_types
show_types
Globals.show_types : bool ref
Flag controlling printing of HOL types (in terms).
Normally HOL types in terms are not printed, since this makes terms hard
to read. Type printing is enabled by show_types := true, and disabled
by show_types := false. When printing of types is enabled, not all
variables and constants are annotated with a type. The intention is to
provide sufficient type information to remove any ambiguities without
swamping the term with type information.
Failure
Never fails.
Example
> BOOL_CASES_AX;;
val it = ⊢ ∀t. (t ⇔ T) ∨ (t ⇔ F): thm
> show_types := true;
val it = (): unit
> BOOL_CASES_AX;;
val it = ⊢ ∀(t :bool). (t ⇔ T) ∨ (t ⇔ F): thm
Comments
It is possible to construct an abstraction in which the bound variable has the same name but a different type to a variable in the body. In such a case the two variables are considered to be distinct. Without type information such a term can be very misleading, so it might be a good idea to provide type information for the free variable whether or not printing of types is enabled.
See also
version
version
Globals.version : int
The version number of the HOL system being run.
Example
> Globals.version;
val it = 2: int
See also
note_tac
note_tac
goalStack.note_tac : string -> tactic
Prints a message; does not change the goal.
The tactic note_tac s prints the string s followed by a newline
(using the standard SML print function). The effect on the goal is
as if the tactic ALL_TAC had been applied (i.e., the state of the
goal is not changed).
Failure
Never fails.
Comments
This is useful for tracking progress through a proof by printing
messages at various stages. Unlike print_tac, this function only
prints the provided message without printing the goal state.
See also
goalStack.print_tac,
Tactical.ALL_TAC.
print_tac
print_tac
goalStack.print_tac : string -> tactic
Prints the goal; does not change it.
The tactic print_tac s prints the string s followed by (the
pretty-printed string of) the goal to which it is applied (using the
standard SML print function). The effect on the goal is as if the
tactic ALL_TAC had been applied (i.e., the state of the goal is not
changed).
Failure
Never fails.
Comments
This is useful for debugging tactic applications in contexts where the usual interactive goal-stack is not available.
See also
goalStack.note_tac,
Tactical.ALL_TAC.
assoc
assoc
hol88Lib.assoc : ''a -> (''a * 'b) list -> ''a * 'b
Searches a list of pairs for a pair whose first component equals a specified value.
assoc x [(x1,y1),...,(xn,yn)] returns the first (xi,yi) in the list
such that xi equals x. The lookup is done on an eqtype, i.e., the
SML implementation must be able to decide equality for the type of x.
Failure
Fails if no matching pair is found. This will always be the case if the list is empty.
Example
- assoc 2 [(1,4),(3,2),(2,5),(2,6)];
(2, 5) : (int * int)
Comments
Superseded by Lib.assoc and Lib.assoc1.
See also
hol88Lib.rev_assoc, Lib.assoc,
Lib.assoc1
frees
frees
hol88Lib.frees : term -> term list
Returns a list of the variables which are free in a term.
frees is equivalent to rev o Term.free_vars.
Failure
Never fails.
Comments
Superseded by Term.free_vars.
See also
hol88Lib.freesl,
Term.free_vars
GEN_ALL
GEN_ALL
hol88Lib.GEN_ALL : thm -> thm
Generalizes the conclusion of a theorem over its own free variables.
When applied to a theorem A |- t, the inference rule GEN_ALL returns
the theorem A |- !x1...xn. t, where the xi are all the variables, if
any, which are free in t but not in the assumptions.
A |- t
------------------ GEN_ALL
A |- !x1...xn. t
Failure
Never fails.
Comments
Superseded by Drule.GEN_ALL, which, however, may return a different
result. That is why GEN_ALL is in hol88Lib. Sometimes people write
code that depends on the order of the quantification. They shouldn't.
See also
match
match
hol88Lib.match : term -> term -> (term * term) list * (hol_type * hol_type) list
Finds instantiations to match one term to another.
When applied to two terms, match_term attempts to find a set of type
and term instantiations for the first term (only) to make it equal the
second. If it succeeds, it returns the instantiations in the form of a
pair containing a hol88 term substitution and a hol88 type substitution.
If the first term represents the conclusion of a theorem, the returned
instantiations are of the appropriate form to be passed to
INST_TY_TERM.
Failure
Fails if the term cannot be matched by one-way instantiation.
Comments
Note that INST_TY_TERM may still fail (when a variable that is
instantiated occurs free in the theorem's assumptions).
Superseded by Term.match_term.
See also
rev_assoc
rev_assoc
hol88Lib.rev_assoc : ''a -> ('b * ''a) list -> 'b * ''a
Searches a list of pairs for a pair whose second component equals a specified value.
rev_assoc y [(x1,y1),...,(xn,yn)] returns the first (xi,yi) in the
list such that yi equals y. The lookup is done on an eqtype, i.e.,
the SML implementation must be able to decide equality for the type of
y.
Failure
Fails if no matching pair is found. This will always be the case if the list is empty.
Example
- rev_assoc 2 [(1,4),(3,2),(2,5),(2,6)];
(3, 2) : (int * int)
Comments
Superseded by Lib.rev_assoc and Lib.assoc2.
See also
hol88Lib.assoc, Lib.rev_assoc,
Lib.assoc2
print_theory
print_theory
Hol_pp.print_theory : string -> unit
Print a theory on the standard output.
An invocation print_theory s will display the contents of the theory
segment s on the standard output. The string "-" may be used to
denote the current theory segment.
Failure
If s is not the name of a loaded theory.
Example
> print_theory "combin";
Theory: combin
Parents:
marker
Term constants:
:> :β -> (β -> α) -> α
ASSOC :(α -> α -> α) -> bool
C :(α -> β -> γ) -> β -> α -> γ
COMM :(α -> α -> β) -> bool
EXTENSIONAL :(α -> bool) -> (α -> β) -> bool
FAIL :α -> β -> α
FCOMM :(α -> β -> α) -> (γ -> α -> α) -> bool
I :α -> α
K :α -> β -> α
LEFT_ID :(α -> β -> β) -> α -> bool
MONOID :(α -> α -> α) -> α -> bool
RESTRICTION :(α -> bool) -> (α -> β) -> α -> β
RIGHT_ID :(α -> β -> α) -> β -> bool
S :(α -> β -> γ) -> (α -> β) -> α -> γ
UPDATE :α -> β -> (α -> β) -> α -> β
W :(α -> α -> β) -> α -> β
o :(γ -> β) -> (α -> γ) -> α -> β
Definitions:
APP_DEF
⊢ ∀x f. (x :> f) = f x
ASSOC_DEF
⊢ ∀f. ASSOC f ⇔ ∀x y z. f x (f y z) = f (f x y) z
COMM_DEF
⊢ ∀f. COMM f ⇔ ∀x y. f x y = f y x
C_DEF
⊢ flip = (λf x y. f y x)
EXTENSIONAL_def
⊢ ∀s f. EXTENSIONAL s f ⇔ ∀x. x ∉ s ⇒ f x = ARB
FAIL_DEF
⊢ FAIL = (λx y. x)
FCOMM_DEF
⊢ ∀f g. FCOMM f g ⇔ ∀x y z. g x (f y z) = f (g x y) z
I_DEF
⊢ I = S K K
K_DEF
⊢ K = (λx y. x)
LEFT_ID_DEF
⊢ ∀f e. LEFT_ID f e ⇔ ∀x. f e x = x
MONOID_DEF
⊢ ∀f e. MONOID f e ⇔ ASSOC f ∧ RIGHT_ID f e ∧ LEFT_ID f e
RESTRICTION
⊢ ∀s f x. RESTRICTION s f x = if x ∈ s then f x else ARB
RIGHT_ID_DEF
[...Output elided...]
See also
bvk_find_term
bvk_find_term
HolKernel.bvk_find_term : (term list * term -> bool) -> (term -> 'a) -> term -> 'a option
Finds a sub-term satisfying predicate argument; applies a continuation.
A call to bvk_find_term P k tm searches tm for a sub-term satisfying
P and calls the continuation k on the first that it finds. If k
succeeds on this sub-term, the result is wrapped in SOME and returned
to the caller. If k raises a HOL_ERR exception on the sub-term,
control returns to bvk_find_term, which continues to look for a
sub-term satisfying P. Other exceptions are returned to the caller. If
there is no sub-term that both satisfies P and on which k operates
successfully, the result is NONE.
The search order is top-down, left-to-right (i.e., rators of combs are examined before rands).
As with find_term, P should be total. In addition, P is given not
just the sub-term of interest, but also the stack of bound variables
that have scope over the sub-term, with the innermost bound variables
appearing earlier in the list.
Failure
Fails if the predicate argument fails (i.e., raises an exception;
returning false is acceptable) on a sub-term, or if the contination
argument raises a non-HOL_ERR exception on a sub-term on which the
predicate has returned true.
Example
The RED_CONV function from reduceLib reduces a ground arithmetic
term over the natural numbers, failing if the term is not of the right
shape.
- val find = bvk_find_term (equal ``:num`` o type_of o #2)
reduceLib.RED_CONV;
> val find = fn : term -> thm option
- find ``SUC n``;
> val it = NONE : thm option
- find ``2 * 3 + SUC n``;
> val it = SOME |- 2 * 3 = 6 : thm option
- find ``SUC n + 2 * 3``;
> val it = SOME |- 2 * 3 = 6 : thm option
- find ``2 + 1 + SUC n + 2 * 3``;
> val it = SOME |- 2 + 1 = 3 : thm option
See also
HolKernel.find_term,
HolKernel.find_terms
disch
disch
HolKernel.disch : ((term * term list) -> term list)
Removes those elements of a list of terms that are alpha equivalent to a given term.
Given a pair (t,tl) of term t and term list tl, disch removes
those elements of tl that are alpha equivalent to t.
Example
> disch (``\x:bool.T``, [``A = T``, ``B = 3``, ``\y:bool.T``]);
val it = [“A ⇔ T”, “B = 3”]: term list
See also
find_term
find_term
HolKernel.find_term : (term -> bool) -> term -> term
Finds a sub-term satisfying a predicate.
A call to find_term P t returns a sub-term of t that satisfies the
predicate P if there is one. Otherwise it raises a HOL_ERR
exception. The search is done in a top-down, left-to-right order (i.e.,
rators of combs are examined before rands).
Failure
Fails if the predicate fails when applied to any of the sub-terms of the term argument. Also fails if there is no sub-term satisfying the predicate.
Example
> find_term Literal.is_numeral ``2 + x + 3``;
val it = “2”: term
> find_term Literal.is_numeral ``x + y``;
Exception- HOL_ERR at HolKernel.find_term: raised
See also
HolKernel.bvk_find_term,
HolKernel.find_terms
find_terms
find_terms
HolKernel.find_terms : (term -> bool) -> term -> term list
Traverses a term, returning a list of sub-terms satisfying a predicate.
A call to find_terms P t returns a list of sub-terms of t that
satisfy P. The resulting list is ordered as if the traversal had been
bottom-up and right-to-left (i.e., the rands of combs visited before
their rators). The term t is itself considered a possible sub-term of
t.
Failure
Only fails if the predicate fails on one of the term's sub-terms.
Example
> find_terms (fn _ => true) ``x + y``;
val it = [“y”, “x”, “$+”, “$+ x”, “x + y”]: term list
> find_terms Literal.is_numeral ``x + y``;
val it = []: term list
> find_terms Literal.is_numeral ``1 + x + 2 + y``;
val it = [“2”, “1”]: term list
See also
HolKernel.bvk_find_term,
HolKernel.find_term
gen_find_term
gen_find_term
HolKernel.gen_find_term : (term list * term -> 'a option) -> term -> 'a option
Finds first value in range of partial function mapped over sub-terms of a term.
If a call to gen_find_term f t returns SOME v, then that result is
the first value returned by a call of function f to one of the
sub-terms of term t. The function f is successively passed sub-terms
of t starting with t itself and then proceeding in a top-down,
left-to-right traversal.
The additional list of terms passed to the function f is the list of
bound variables "governing" the sub-term in question, with the innermost
bound variable first in the list.
Failure
A call to gen_find_term f t will fail if f fails when applied to any
of the sub-terms of t.
Example
> gen_find_term (fn x => SOME x) ``SUC x``;
val it = SOME ([], “SUC x”): (term list * term) option
> gen_find_term
(fn (bvs,t) => if null bvs andalso
(is_var t orelse numSyntax.is_numeral t)
then
Lib.total (match_term ``x:num``) t
else NONE)
``SUC z + (\y. y) 5``;
val it = SOME ([{redex = “x”, residue = “z”}], []):
((term, term) Term.subst * (hol_type, hol_type) Term.subst) option
Comments
This function is used to implement bvk_find_term. This function could
itself be approximated by returning the last value in the list returned
by gen_find_terms. Such an implementation would be less efficient
because it would unnecessarily construct a list of all possible results.
It would also be semantically different if f had side effects.
See also
HolKernel.bvk_find_term,
HolKernel.find_term,
HolKernel.gen_find_terms
gen_find_terms
gen_find_terms
HolKernel.gen_find_terms : (term list * term -> 'a option) -> term -> 'a list
Maps a partial function over sub-terms of a term.
A call to gen_find_terms f t returns a list of values derived from
sub-terms of term t. The values are those generated by the function
f when it returns SOME v. The function f is successively passed
sub-terms of t starting with t itself and then proceeding in a
top-down, left-to-right traversal. The list of results returned in the
reverse of this order (but the fact that the traversal is done in the
described order is observable if f has side effects).
The additional list of terms passed to the function f is the list of
bound variables "governing" the sub-term in question, with the innermost
bound variable first in the list.
Failure
A call to gen_find_terms f t will fail if f fails when applied to
any of the sub-terms of t.
Example
> gen_find_terms (fn x => SOME x) ``SUC x``;
val it = [([], “x”), ([], “SUC”), ([], “SUC x”)]: (term list * term) list
> gen_find_terms
(fn (bvs,t) => if null bvs andalso
(is_var t orelse numSyntax.is_numeral t)
then
Lib.total (match_term ``x:num``) t
else NONE)
``SUC z + (\y. y) 5``;
val it =
[([{redex = “x”, residue = “5”}], []),
([{redex = “x”, residue = “z”}], [])]:
((term, term) Term.subst * (hol_type, hol_type) Term.subst) list
See also
HolKernel.bvk_find_term,
HolKernel.find_term,
HolKernel.gen_find_term
sort_vars
sort_vars
HolKernel.sort_vars : string list -> term list -> term list
Sorts a list of variables according to first argument.
A call to sort_vars [s1,s2,..sn] vs will return a permutation of vs
such that variables with the name s1 will appears first, followed by
those with the name s2 etc.
Failure
Never fails.
Example
> sort_vars ["a", "b", "d"] [``b:bool``, ``c:num``, ``d:bool``, ``a:'a``];
val it = [“a”, “b”, “d”, “c”]: term list
See also
Conv.RESORT_EXISTS_CONV,
Conv.RESORT_FORALL_CONV
subst_occs
subst_occs
HolKernel.subst_occs : int list list -> (term,term) subst -> term -> term
Substitutes for particular occurrences of subterms of a given term.
For each {redex,residue} in the second argument, there should be a
corresponding integer list l_i in the first argument that specifies
which free occurrences of redex_i in the third argument should be
substituted by residue_i.
Failure
Failure occurs if any substitution fails, or if the length of the first argument is not equal to the length of the substitution. In other words, every substitution pair should be accompanied by a list specifying when the substitution is applicable.
Example
> subst_occs [[1,3]] [Term `SUC 0` |-> Term `1`]
(Term `SUC 0 + SUC 0 = SUC(SUC 0)`);
val it = “1 + SUC 0 = SUC 1”: term
> subst_occs [[1],[1]] [Term `SUC 0` |-> Term `1`,
Term `SUC 1` |-> Term `2`]
(Term `SUC(SUC 0) = SUC 1`);
val it = “SUC 1 = 2”: term
> subst_occs [[1],[1]] [Term`SUC(SUC 0)` |-> Term `2`,
Term`SUC 0` |-> Term `1`]
(Term`SUC(SUC 0) = SUC 0`);
val it = “2 = 1”: term
See also
syntax_fns
syntax_fns
HolKernel.syntax_fns : {dest: term -> exn -> term -> 'a, make: term -> 'b -> term, n: int} -> string -> string ->
term * ('b -> term) * (term -> 'a) * (term -> bool)
Helps in providing syntax support for theory constants.
syntax_fns syntax thy name returns a 4-tuple, consisting of: a term, a
term destructor function, a term constructor function and a term
recogniser function. These provide syntax support for operation name
from theory thy. The record argument syntax consists of
dest: term -> exn -> term -> 'a and make: term -> 'b -> term
functions, together with an "expected arity" value n. Through a
sequence of instantiations, the syntax_fns function can be used to
quickly and reliably write a thySyntax.sml file.
Example
To provide syntax support for unary operations from the theory num,
one can use the following function:
> val num1 = HolKernel.syntax_fns {n = 1, make = HolKernel.mk_monop, dest = HolKernel.dest_monop} "num";
val num1 = fn:
string -> term * (term -> term) * (term -> term) * (term -> bool)
The following call then provides support for the SUC constant:
> val (suc_tm, mk_suc, dest_suc, is_suc) = num1 "SUC";
val dest_suc = fn: term -> term
val is_suc = fn: term -> bool
val mk_suc = fn: term -> term
val suc_tm = “SUC”: term
A SUC term can be constructed with
> val tm = mk_suc ``4n``;
val tm = “SUC 4”: term
The resulting term tm can be identified and destructed as follows:
> is_suc tm;
val it = true: bool
> val v = dest_suc tm;
val v = “4”: term
A standard error message is raised when dest_suc fails, e.g.
> is_suc ``SUC``;
val it = false: bool
> val v = dest_suc ``SUC``;
Exception- HOL_ERR at numSyntax.dest_SUC: raised
The value n in the call to syntax_fns acts purely as a sanity check.
For example, the following fails because SUC is not a binary
operation:
> HolKernel.syntax_fns {n = 2, make = HolKernel.mk_binop, dest = HolKernel.dest_binop} "num" "SUC";
Exception- HOL_ERR (at numSyntax.syntax_fns: bad number of arguments) raised
Typically, the dest and make functions will be complementary (with
type variables 'a and 'b being the same), however this need not be
the case. Advanced uses of syntax_fns can take types into
consideration. For example, the constant bitstring$v2w with type
bitstring->'a word is supported as follows:
> val tm = bitstringSyntax.mk_v2w (``l:bitstring``, ``:32``);
val tm = “v2w l”: term
> type_of tm;
val it = “:word32”: hol_type
> bitstringSyntax.dest_v2w tm;
val it = (“l”, “:32”): term * hol_type
This is implemented as follows:
val (v2w_tm, mk_v2w, dest_v2w, is_v2w) =
HolKernel.syntax_fns
{n = 1,
dest = fn tm1 => fn e => fn w => (HolKernel.dest_monop tm1 e w, wordsSyntax.dim_of w),
make = fn tm => fn (v, ty) => Term.mk_comb (Term.inst [Type.alpha |-> ty] tm, v)}
"bitstring" "v2w"
SAT_PROVE
SAT_PROVE
HolSatLib.SAT_PROVE : Term.term -> Thm.thm
Proves that the supplied term is a tautology, or provides a counterexample.
The supplied term should be purely propositional, i.e., atoms must be
Boolean variables or constants, and conditionals must be Boolean-valued.
SAT_PROVE uses the MiniSat SAT solver's proof logging feature to
construct and verify a resolution refutation for the negation of the
supplied term.
Failure
Fails if the supplied term is not a tautology. In this case, a theorem providing a satisfying assignment for the negation of the input term is returned, wrapped in an exception.
Example
> load "HolSatLib"; open HolSatLib;
val it = (): unit
> SAT_PROVE ``(a ==> b) /\ (b ==> a) ==> (a=b)``;
val it = ⊢ (a ⇒ b) ∧ (b ⇒ a) ⇒ (a ⇔ b): thm
> SAT_PROVE ``~((a ==> b) /\ (b ==> a) ==> (a=b))``
handle HolSatLib.SAT_cex th => th;
val it = ⊢ ¬b ∧ a ⇒ ¬¬((a ⇒ b) ∧ (b ⇒ a) ⇒ (a ⇔ b)): thm
Comments
If MiniSat terminates abnormally, or if the MiniSat binary cannot be located or executed, SAT_PROVE falls back to a slower propositional tautology prover implemented in SML. For low-level use of SAT solver facilities and other details, see the section on the HolSat library in the HOL Description.
export_mono
export_mono
IndDefLib.export_mono : string -> unit
Records a theorem as a monotonicity theorem for inductive definitions.
A call to export_mono "thm_name" causes the theorem of that name to be
stored as a monotonicity theorem, to be used when an inductive
definition is made. See the DESCRIPTION manual for more on the required
form of the theorem being exported in this way.
Failure
Fails if the string argument is not the name of a stored theorem. The name can be qualified (preceded) with the name of an ancestral theory segment and a full-stop, or can be "bare", in which case it must be the name of a theorem in the current segment.
See also
Hol_reln
Hol_reln
IndDefLib.Hol_reln : term quotation -> thm * thm * thm
Re-exported from bossLib.Hol_reln. See that
entry for full documentation.
IndDefRules
IndDefRules
structure IndDefRules
Tom Melham's inference support for inductive definitions.
IndDefRules provides support for reasoning about inductively defined
relations, including a general induction tactic, and an entrypoint for
deriving so-called 'strong' rule induction.
deprecate_int
deprecate_int
intLib.deprecate_int : unit -> unit
Makes the parser never consider integers as a numeric possibility.
Calling deprecate_int() causes the parser to remove all of the
standard numeric constants over the integers from consideration. In
addition to the standard operators (+, -, * and others), this also
affects numerals; after the call to deprecate_int these will never be
parsed as integers.
This function, by affecting the global grammar, also affects the
behaviour of the pretty-printer. A term that includes affected constants
will print with those constants in "fully qualified form", typically as
integer$op, and numerals will print with a trailing i.
(Incidentally, the parser will always read integer terms if they are
presented to it in this form.)
Failure
Never fails.
Example
First we load the integer library, ensuring that integers and natural numbers both are possible when we type numeric expressions:
- load "intLib";
> val it = () : unit
Then, when we type such an expression, we're warned that this is strictly ambiguous, and a type is silently chosen for us:
- val t = ``2 + x``;
<<HOL message: more than one resolution of overloading was possible>>
> val t = ``2 + x`` : term
- type_of t;
> val it = ``:int`` : hol_type
Now we can use deprecate_int to stop this happening, and make sure
that we just get natural numbers:
- intLib.deprecate_int();
> val it = () : unit
- ``2 + x``;
> val it = ``2 + x`` : term
- type_of it;
> val it = ``:num`` : hol_type
The term we started out with is now printed in rather ugly fashion:
- t;
> val it = ``integer$int_add 2i x`` : term
Comments
If one wishes to simply prefer the natural numbers, say, to the
integers, and yet still retain integers as a possibility, use
numLib.prefer_num rather than this function. This function only brings
about a "temporary" effect; it does not cause the change to be exported
with the current theory.
See also
prefer_int
prefer_int
intLib.prefer_int : unit -> unit
Makes the parser favour integer possibilities in ambiguous terms.
Calling prefer_int() causes the global grammar to be altered so that
the standard arithmetic operator symbols (+, *, etc.), as well as
numerals, are given integral types if possible. This effect is brought
about through the application of multiple calls to temp_overload_on,
so that the "arithmetic symbols" need not have been previously mapping
to integral possibilities at all (as would be the situation after a call
to deprecate_int).
Failure
Never fails.
See also
intLib.deprecate_int,
Parse.overload_on
HALF_MK_ABS
HALF_MK_ABS
jrhUtils.HALF_MK_ABS : (thm -> thm)
Converts a function definition to lambda-form.
When applied to a theorem A |- !x. t1 x = t2, whose conclusion is a
universally quantified equation, HALF_MK_ABS returns the theorem
A |- t1 = \x. t2.
A |- !x. t1 x = t2
-------------------- HALF_MK_ABS [where x is not free in t1]
A |- t1 = (\x. t2)
Failure
Fails unless the theorem is a singly universally quantified equation whose left-hand side is a function applied to the quantified variable, or if the variable is free in that function.
See also
Drule.ETA_CONV, Drule.MK_ABS,
Thm.MK_COMB, Drule.MK_EXISTS
allowed_term_constant
allowed_term_constant
Lexis.allowed_term_constant : string -> bool
Tests if a string has a permissible name for a term constant.
When applied to a string, allowed_term_constant returns true if the
string is a permissible constant name for a term, that is, if it is an
identifier (see the DESCRIPTION for more details), and false
otherwise.
Failure
Never fails.
Example
The following gives a sample of some allowed and disallowed constant names:
- map Lexis.allowed_term_constant ["pi", "@", "a name", "+++++", "10"];
> val it = [true, true, false, true, false] : bool list
Comments
Note that this function only performs a lexical test; it does not check whether there is already a constant of that name in the current theory.
See also
Theory.constants,
Lexis.allowed_type_constant
allowed_type_constant
allowed_type_constant
Lexis.allowed_type_constant : string -> bool
Tests if a string has a permissible name for a type constant.
When applied to a string, allowed_type_constant returns true if the
string is a permissible constant name for a type operator, and false
otherwise.
Failure
Never fails.
Example
The following gives a sample of some allowed and disallowed names for type operators:
- map Lexis.allowed_type_constant ["list", "'a", "fun", "->", "#", "fun2"];
> val it = [true, false, true, false, false, true] : bool list
Comments
Note that this function only performs a lexical test; it does not check whether there is already a type operator of that name in the current theory.
This function is not currently enforced by the system, as it was found that more flexibilty in naming was preferable.
See also
Lib
Lib
structure Lib
Collection of commonly used functions.
Lib is a collection of functions that have been found useful in
writing the HOL system.
Comments
The SML Basis Library offers alternatives to some of the functions found
in Lib.
$
$
Lib.$ : ('a -> 'b) * 'a -> 'b
Right-associated infix function application operator
Writing f $ x is another way of writing f x.
Failure
Fails if f x would fail.
Comments
Because $ is right-associated, this can be a convenient way to avoid
parentheses. For example,
first_x_assum $ qspec_then ‘m’ $ qx_choose_then ‘z’ strip_assume_tac
instead of
first_x_assum (qspec_then ‘m’ (qx_choose_then ‘z’ strip_assume_tac))
Note also that $ is tighter than the various THEN infixes, so a
tactic such as the one above can be used in a proof without needing
protection by extra parentheses.
all
all
Lib.all : ('a -> bool) -> 'a list -> bool
Tests whether a predicate holds throughout a list.
all P [x1,...,xn] equals P x1 andalso .... andalso P xn. all P []
yields true.
Failure
If P x0,...,P x(j-1) all evaluate to true and P xj raises an
exception e, then all P [x0,...,x(j-1),xj,...,xn] raises e.
Example
> all (equal 3) [3,3,3];
val it = true: bool
> all (equal 3) [];
val it = true: bool
> all (fn _ => raise Fail "") [];
val it = true: bool
> all (fn _ => raise Fail "") [1];
Exception- Fail "" raised
See also
Lib.all2, Lib.exists,
Lib.first
all2
all2
Lib.all2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool
Tests whether a predicate holds pairwise throughout two lists.
An invocation
all2 P [x1,...,xn] [y1,...,yn]
equals
P x1 y1 andalso .... andalso P xn yn
Also, all2 P [] [] yields true.
Failure
If P x0,...,P x(j-1) all evaluate to true and P xj raises an
exception e, then
all2 P [x0,...,x(j-1),xj,...,xn]
raises e. An invocation all2 P l1 l2 will also raise an exception if
the length of l1 is not equal to the length of l2.
Example
> all2 equal [1,2,3] [1,2,3];
val it = true: bool
> all2 equal [1,2,3] [1,2,3,4] handle e => Raise e;
Exception- HOL_ERR (at Lib.all2: different length lists) raised
> all2 (fn _ => fn _ => raise Fail "") [] [];
val it = true: bool
> all2 (fn _ => fn _ => raise Fail "") [1] [1];
Exception- Fail "" raised
See also
append
append
Lib.append : 'a list -> 'a list -> 'a list
Curried form of list append.
The function append is a curried form of the standard operation for
appending two ML lists.
Failure
Never fails.
Example
> append [1] [2,3] = [1] @ [2,3];
val it = true: bool
assert
assert
Lib.assert : ('a -> bool) -> 'a -> 'a
Checks that a value satisfies a predicate.
assert p x returns x if the application p x yields true.
Otherwise, assert p x fails.
Failure
assert p x fails with exception HOL_ERR if the predicate p yields
false when applied to the value x. If the application p x raises
an exception e, then assert p x raises e.
Example
> null [];
val it = true: bool
> assert null ([]:int list);
val it = []: int list
> null [1];
val it = false: bool
> assert null [1];
Exception- HOL_ERR (at Lib.assert: predicate not true) raised
See also
assert_exn
assert_exn
Lib.assert_exn : ('a -> bool) -> 'a -> exn -> 'a
Checks that a value satisfies a predicate.
assert_exn p x e returns x if the application p x evaluates to
true. Otherwise, assert_exn p x e raises e
Failure
assert_exn p x e fails with exception e if the predicate p yields
false when applied to the value x. If the application p x raises
an exception ex, then assert_exn p x e raises ex.
Example
> null [];
val it = true: bool
> assert_exn null ([]:int list) (Fail "non-empty list");
val it = []: int list
> null [1];
val it = false: bool
> assert_exn null [1] (Fail "non-empty list");;
Exception- Fail "non-empty list" raised
See also
assoc
assoc
Lib.assoc : ''a -> (''a * 'b) list -> 'b
Searches a list of pairs for a pair whose first component equals a specified value, then returns the second component of the pair.
assoc x [(x1,y1),...,(xn,yn)] locates the first (xi,yi) in a
left-to-right scan of the list such that xi equals x. Then yi is
returned. The lookup is done on an eqtype, i.e., the SML implementation
must be able to decide equality for the type of x.
Failure
Fails if no matching pair is found. This will always be the case if the list is empty.
Example
> assoc 2 [(1,4),(3,2),(2,5),(2,6)];
val it = 5: int
See also
Lib.assoc1, Lib.assoc2,
Lib.rev_assoc, Lib.mem,
Lib.tryfind, Lib.exists,
Lib.all
assoc1
assoc1
Lib.assoc1 : ''a -> (''a * 'b) list -> (''a * 'b)option
Searches a list of pairs for a pair whose first component equals a specified value.
assoc1 x [(x1,y1),...,(xn,yn)] returns SOME (xi,yi) for the first
pair (xi,yi) in the list such that xi equals x. Otherwise, NONE
is returned. The lookup is done on an eqtype, i.e., the SML
implementation must be able to decide equality for the type of x.
Failure
Never fails.
Example
> assoc1 2 [(1,4),(3,2),(2,5),(2,6)];
val it = SOME (2, 5): (int * int) option
See also
Lib.assoc, Lib.assoc2,
Lib.rev_assoc, Lib.mem,
Lib.tryfind, Lib.exists,
Lib.all
assoc2
assoc2
Lib.assoc2 : ''a -> ('b * ''a) list -> ('b * ''a)option
Searches a list of pairs for a pair whose second component equals a specified value.
An invocation assoc2 y [(x1,y1),...,(xn,yn)] returns SOME (xi,yi)
for the first (xi,yi) in the list such that yi equals y.
Otherwise, NONE is returned. The lookup is done on an eqtype, i.e.,
the SML implementation must be able to decide equality for the type of
y.
Failure
Never fails.
Example
> assoc2 2 [(1,4),(3,2),(2,5),(2,6)];
val it = SOME (3, 2): (int * int) option
See also
Lib.assoc, Lib.assoc1,
Lib.rev_assoc, Lib.mem,
Lib.tryfind, Lib.exists,
Lib.all
butlast
butlast
Lib.butlast : 'a list -> 'a list
Computes the sub-list of a list consisting of all but the last element.
butlast [x1,...,xn] returns [x1,...,x(n-1)].
Failure
Fails if the list is empty.
See also
Lib.last, Lib.el,
Lib.front_last
C
C
Lib.C : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c
Permutes first two arguments to curried function: C f x y equals
f y x.
Failure
C f never fails and C f x never fails, but C f x y fails if
f y x fails.
Example
> map (C cons []) [1,2,3];
val it = [[1], [2], [3]]: int list list
See also
Lib.##, Lib.I, Lib.K,
Lib.S, Lib.W
can
can
Lib.can : ('a -> 'b) -> 'a -> bool
Tests for failure.
can f x evaluates to true if the application of f to x succeeds.
It evaluates to false if the application fails.
Failure
Only fails if f x raises the Interrupt exception.
Example
> hd [];
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
Empty raised
> can hd [];
val it = false: bool
> can (fn _ => raise Interrupt) 3;
Exception- Interrupt raised
See also
Lib.assert, Lib.trye,
Lib.partial, Lib.total,
Lib.assert_exn
combine
combine
Lib.combine : 'a list * 'b list -> ('a * 'b) list
Transforms a pair of lists into a list of pairs.
combine ([x1,...,xn],[y1,...,yn]) returns [(x1,y1),...,(xn,yn)].
Failure
Fails if the two lists are of different lengths.
Comments
Has much the same effect as the SML Basis function ListPair.zip except
that it fails if the arguments are not of equal length. Also note that
zip is a curried version of combine
See also
commafy
commafy
Lib.commafy : string list -> string list
Add commas into a list of strings.
An application commafy [s1,...,sn] yields [s1, ",", ..., ",", sn].
Failure
Never fails.
Example
> commafy ["donkey", "mule", "horse", "camel", "llama"];
val it =
["donkey", ", ", "mule", ", ", "horse", ", ", "camel", ", ", "llama"]:
string list
> String.concat it;
val it = "donkey, mule, horse, camel, llama": string
> commafy ["foo"];
val it = ["foo"]: string list
cons
cons
Lib.cons : 'a -> 'a list -> 'a list
Curried form of list cons operation.
In some programming situations it is handy to use the "cons" operation
in a curried form. Although it is easy to code up on demand, the cons
function is provided for convenience.
Failure
Never fails.
Example
> map (cons 1) [[],[2],[2,3]];
val it = [[1], [1, 2], [1, 2, 3]]: int list list
curry
curry
Lib.curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'c
Converts a function on a pair to a corresponding curried function.
The application curry f returns fn x => fn y => f(x,y), so that
curry f x y = f(x,y)
Failure
A call curry f never fails; however, curry f x y fails if f (x,y)
fails.
Example
> val increment = curry op+ 1;
val increment = fn: int -> int
> increment 6;
val it = 7: int
See also
delta
delta
Lib.type 'a delta
A type used for telling when a function has changed its argument.
The delta type is declared as follows:
datatype 'a delta = SAME | DIFF of 'a
The delta type may be used in applications where it is important to
tell if a function has changed its argument or not. As an example of
this, consider mapping a function over a large collection of elements.
If only a few elements are changed, it makes sense to re-use all those
that were not changed. This can of course be handled on an ad hoc basis;
the delta type provides a mechanism for doing this systematically.
Comments
The delta type is an example of polytypism.
See also
Lib.delta_apply,
Lib.delta_map, Lib.delta_pair
delta_apply
delta_apply
Lib.delta_apply : ('a -> 'a delta) -> 'a -> 'a
Apply a function to an argument, re-using the argument if possible.
An application delta_apply f x applies f to x and, if the result
is SAME, returns x. If the result is DIFF y, then y is returned.
Failure
If f x raises exception e, then delta_apply f x raises e.
Example
Suppose we want to write a function that replaces every even integer in a list of pairs of integers with an odd one. The most basic replacement function is therefore
- fun ireplace i = if i mod 2 = 0 then DIFF (i+1) else SAME
Applying ireplace to an arbitrary integer would yield an element of
the int delta type. It's not seemingly useful, but it becomes useful
when used with similar functions for type operators. Then a delta
function for pairs of integers is built by
delta_pair ireplace ireplace, and a delta function for a list of pairs
of integers is built by applying delta_map.
- delta_map (delta_pair ireplace ireplace)
[(1,2), (3,5), (5,7), (4,8)];
> val it = DIFF [(1,3), (3,5), (5,7), (5,9)] : (int * int) list delta
- delta_map (delta_pair ireplace ireplace)
[(1,3), (3,5), (5,7), (7,9)];
> val it = SAME : (int * int) list delta
Finally, we can move the result from the delta type to the actual type
we are interested in.
- delta_apply (delta_map (delta_pair ireplace ireplace))
[(1,2), (3,5), (5,7), (4,8)];
> val it = [(1,3), (3,5), (5,7), (5,9)] : (int * int) list
Comments
Used to change a function from one that returns an 'a delta element to
one that returns an 'a element.
See also
Lib.delta, Lib.delta_map,
Lib.delta_pair
delta_map
delta_map
Lib.delta_map : ('a -> 'a delta) -> 'a list -> 'a list delta
Apply a function to a list, sharing as much structure as possible.
An application delta_map f list applies f to each member
[x1,...,xn] of list. If all applications of f return SAME, then
delta_map f list returns SAME. Otherwise, DIFF [y1,...,yn] is
returned. If f xi yielded SAME, then yi is xi. Otherwise, f xi
equals DIFF yi.
Failure
If some application of f xi raises e, then delta_map f list raises
e.
Example
See the example in the documentation for delta_apply.
See also
Lib.delta, Lib.delta_apply,
Lib.delta_pair
delta_pair
delta_pair
Lib.delta_pair : ('a -> 'a delta) ->
('b -> 'b delta) ->
'a * 'b -> ('a * 'b) delta
Apply two functions to the projections of a pair, sharing as much structure as possible.
An application delta_pair f g (x,y) applies f to x and g to y.
If f x equals g y equals SAME, then SAME is returned. Otherwise
DIFF (p1,p2) is returned, where p1 is x if f x equals SAME;
otherwise p1 is f x. Similarly, p2 is y if g y equals SAME;
otherwise p2 is g y.
Failure
If f x raises e, then delta_pair f g (x,y) raises e.
If g y raises e, then delta_pair f g (x,y) raises e.
Example
See the example in the documentation for delta_apply.
See also
Lib.delta, Lib.delta_apply,
Lib.delta_pair
el
el
Lib.el : int -> 'a list -> 'a
Extracts a specified element from a list.
el i [x1,...,xn] returns xi. Note that the elements are numbered
starting from 1, not 0.
Failure
Fails with el if the integer argument is less than 1 or greater than
the length of the list.
Example
> el 3 [1,2,7,1];
val it = 7: int
See also
end_itlist
end_itlist
Lib.end_itlist : ('a -> 'a -> 'a) -> 'a list -> 'a
List iteration function. Applies a binary function between adjacent elements of a list.
end_itlist f [x1,...,xn] returns f x1 ( ... (f x(n-1) xn)...).
Returns x for a one-element list [x].
Failure
Fails if list is empty, or if an application of f raises an exception.
Example
> end_itlist (curry op+) [1,2,3,4];
val it = 10: int
See also
Lib.itlist, Lib.rev_itlist,
Lib.itlist2, Lib.rev_itlist2
end_time
end_time
Lib.end_time : Timer.cpu_timer -> unit
Check a running timer, and print out how long it has been running.
An application end_time timer looks to see how long timer has been
running, and prints out the elapsed runtime, garbage collection time,
and system time.
Failure
Never fails.
Example
> val clock = start_time();
val clock = ?: Timer.cpu_timer
> use "foo.sml";
Exception- Io
{cause = SysErr ("No such file or directory", SOME ENOENT), function =
"TextIO.openIn", name = "foo.sml"} raised
> end_time clock;
runtime: 0.00028s, gctime: 0.00000s, systime: 0.00013s.
val it = (): unit
Comments
A start_time ... end_time pair is for use when calling time would
be clumsy, e.g., when multiple function applications are to be timed.
See also
enumerate
enumerate
Lib.enumerate : int -> 'a list -> (int * 'a) list
Number each element of a list, in ascending order.
An invocation of enumerate i [x1, ..., xn] returns the list
[(i,x1), (i+1,x2), ..., (i+n-1,xn)].
Failure
Never fails.
Example
> enumerate 0 ["komodo", "iguana", "gecko", "gila"];
val it = [(0, "komodo"), (1, "iguana"), (2, "gecko"), (3, "gila")]:
(int * string) list
equal
equal
Lib.equal : ''a -> ''a -> bool
Curried form of ML equality.
In some programming situations it is useful to use equality in a curried
form. Although it is easy to code up on demand, the equal function is
provided for convenience.
Failure
Never fails.
Example
> filter (equal 1) [1,2,1,4,5];
val it = [1, 1]: int list
exists
exists
Lib.exists : ('a -> bool) -> 'a list -> bool
Check if a predicate holds somewhere in a list.
An invocation exists P l returns true if P holds of some element of
l. Since there are no elements of [], exists P [] always returns
false.
Failure
When searching for an element of l that P holds of, it may happen
that an application of P to an element of l raises an exception. In
that case, exists P l raises an exception.
Example
> exists (fn i => i mod 2 = 0) [1,3,4];
val it = true: bool
> exists (fn _ => raise Fail "") [];
val it = false: bool
> exists (fn _ => raise Fail "") [1];
Exception- Fail "" raised
See also
Lib.all, Lib.first,
Lib.tryfind
filter
filter
Lib.filter : ('a -> bool) -> 'a list -> 'a list
Filters a list to the sublist of elements satisfying a predicate.
filter P l applies P to every element of l, returning a list of
those that satisfy P, in the order they appeared in the original list.
Failure
If P x fails for some element x of l.
Comments
Identical to List.filter from the Standard ML Basis Library.
See also
first
first
Lib.first : ('a -> bool) -> 'a list -> 'a
Return first element in list that predicate holds of.
An invocation first P [x1,...,xk,...xn] returns xk if P xk returns
true and P xi (1 <= i < k) equals false.
Failure
If P xi is false for every element in list, then first P list
raises an exception. When searching for an element of list that P
holds of, it may happen that an application of P to an element of
list raises an exception e. In that case, first P list also raises
e.
Example
> first (fn i => i mod 2 = 0) [1,3,4,5];
val it = 4: int
> first (fn i => i mod 2 = 0) [1,3,5,7];
Exception- HOL_ERR (at Lib.first: unsatisfied predicate) raised
> first (fn _ => raise Fail "") [1];
Exception- Fail "" raised
See also
Lib.exists, Lib.tryfind,
Lib.all
flatten
flatten
Lib.flatten : 'a list list -> 'a list
Removes one level of bracketing from a list.
An invocation flatten [[x11,...,x1k1],...,[xn1,...,xnkn]] yields the
list [x1,...,x1k1,...,xn1,...,xnkn].
Failure
Never fails.
Example
> flatten [[1,2,3],[],[4,5]];
val it = [1, 2, 3, 4, 5]: int list
> flatten ([[[]]] : int list list list);
val it = [[]]: int list list
for
for
Lib.for : int -> int -> (int -> 'a) -> 'a list
Functional 'for' loops.
An application for b t f is equal to [f b, f (b+1), ..., f t]. If
b is greater than t, the empty list is returned.
Failure
If f i fails for b <= i <= t.
Example
> for 97 122 Char.chr;
val it =
[#"a", #"b", #"c", #"d", #"e", #"f", #"g", #"h", #"i", #"j", #"k", #"l",
#"m", #"n", #"o", #"p", #"q", #"r", #"s", #"t", #"u", #"v", #"w", #"x",
#"y", #"z"]: char list
See also
for_se
for_se
Lib.for_se : int -> int -> (int -> unit) -> unit
Side-effecting 'for' loops.
An application for_se b t f is equal to (f b; f (b+1); ...; f t). If
b is greater than t, then for_se b t f does no evaluation, in
particular f b is not evaluated.
Failure
If f i fails for b <= i <= t.
Example
> let val A = Array.array(26,#" ")
in
for_se 0 25 (fn i => Array.update(A,i, Char.chr (i+97)))
; for_se 0 25 (Feedback.HOL_INFO o Char.toString o curry Array.sub A)
; Feedback.HOL_INFO "\n"
end;
abcdefghijklmnopqrstuvwxyz
val it = (): unit
See also
front_last
front_last
Lib.front_last : 'a list -> 'a list * 'a
Takes a non-empty list L and returns a pair (front,last) such that
front @ [last] = L.
Failure
Fails if the list is empty.
Example
> front_last [1];
val it = ([], 1): int list * int
> front_last [1,2,3];
val it = ([1, 2], 3): int list * int
See also
fst
fst
Lib.fst : ('a * 'b) -> 'a
Extracts the first component of a pair.
fst (x,y) returns x.
Failure
Never fails. However, notice that fst (x,y,z) fails to typecheck,
since (x,y,z) is not a pair.
Example
> fst (1, "foo");
val it = 1: int
> fst (1, "foo", []);
Exception- Type error in function application.
Function: fst : 'a * 'b -> 'a
Argument: (1, "foo", []) : int * string * 'a list
Reason:
Can't unify 'a * 'b to int * string * 'a list
(Different number of fields)
Fail "Static Errors" raised
> fst (1, ("foo", []));
val it = 1: int
See also
funpow
funpow
Lib.funpow : int -> ('a -> 'a) -> 'a -> 'a
Iterates a function a fixed number of times.
funpow n f x applies f to x, n times, giving the result
f (f ... (f x)...) where the number of f's is n. If n is not
positive, the result is x.
Failure
funpow n f x fails if any of the n applications of f fail.
Example
Apply tl three times to a list:
- funpow 3 tl [1,2,3,4,5];
> [4, 5] : int list
Apply tl zero times:
- funpow 0 tl [1,2,3,4,5];
> [1; 2; 3; 4; 5] : int list
Apply tl six times to a list of only five elements:
- funpow 6 tl [1,2,3,4,5];
! Uncaught exception:
! List.Empty
See also
hash
hash
Lib.hash : int -> string -> int * int -> int
Hash function for strings.
An invocation hash i s (j,k) takes an integer i and uses that to
construct a function that, given a string s, will produce values
approximately equally distributed among the numbers less than i. The
argument j gives an index in the string to start from. The k
argument is an accumulator, which is useful when hashing a collection of
strings.
Failure
Never fails.
Example
> hash 13 "ishkabibble" (0,0);
Exception- Type error in function application.
Function: hash : string -> string
Argument: 13 : int
Reason:
Can't unify int (*In Basis*) with string (*In Basis*)
(Different type constructors)
Type error in function application.
Function: hash 13 : string
Argument: "ishkabibble" : string
Reason: Value being applied does not have a function type
Fail "Static Errors" raised
Comments
For better results, the i parameter should be a prime.
This is probably not an industrial strength hash function.
hash2
##
op Lib.## : ('a -> 'b) * ('c -> 'd) -> 'a * 'c -> 'b * 'd
Infix combinator for applying two functions to the two projections of a pair.
An application (f ## g) (x,y) is equal to (f x, g y).
Failure
If f x or g y fails.
Example
> (I ## dest_imp) (strip_forall (Term `!x y z. x /\ y ==> z /\ p`));
val it = ([“x”, “y”, “z”], (“x ∧ y”, “z ∧ p”)): term list * (term * term)
Comments
The ## combinator can be thought of as a map operation for pairs. It
is declared as a right associative infix.
See also
I
I
Lib.I : 'a -> 'a
Performs identity operation: I x = x.
Failure
Never fails.
See also
Lib, Lib.##, Lib.C,
Lib.K, Lib.S, Lib.W
index
index
Lib.index : ('a -> bool) -> 'a list -> int
Finds index of first list element for which predicate holds.
An application index P l returns the index (0-based) to the first
element (in a left-to-right scan) of l that P holds of.
Failure
If P doesn't hold of any element of l, then index P l fails. If
P x fails for any x encountered in the scan, then index P l fails.
Example
> index (equal 3) [1,2,3];
val it = 2: int
> let fun even i = (i mod 2 = 0)
in try (index even) [1,3,5,7,9]
end;
Exception- Type error in function application.
Function: try (index even) :
(int -> int list option) list -> int -> int
Argument: [1, 3, 5, 7, 9] : int list
Reason:
Can't unify int to int -> int list option (Incompatible types)
Fail "Static Errors" raised
> index (equal 3 o hd) [[1],[],[2,3]];
Exception- Empty raised
See also
insert
insert
Lib.insert ''a -> ''a list -> ''a list
Add an element to a list if it is not already there.
If x is already in list, then insert x list equals list.
Otherwise, x becomes an element of list.
Failure
Never fails.
Example
> insert 1 [3,2];
val it = [1, 3, 2]: int list
> insert 1 it;
val it = [1, 3, 2]: int list
Comments
In some programming situations, it is convenient to implement sets by
lists, in which case insert may be helpful. However, such an
implementation is only suitable for small sets.
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of insert and its
kin. This limits its applicability to types that allow equality. For
other types, typically abstract ones, use the 'op_' variants.
One should not write code that depends on where the 'list-as-set' algorithms place elements in the list which is being considered as a set.
See also
Lib.op_insert, Lib.mem,
Lib.mk_set, Lib.union,
Lib.U, Lib.set_diff,
Lib.subtract, Lib.intersect,
Lib.null_intersection,
Lib.set_eq
int_sort
int_sort
Lib.int_sort : int list -> int list
Sorts a list of integers using the <= relation.
The call int_sort list is equal to sort (curry (op <=)). That is, it
is the specialization of sort to the usual notion of
less-than-or-equal on ML integers.
Failure
Never fails.
Example
A simple example is:
> int_sort [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9];
val it = [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 9, 9]: int list
Comments
The Standard ML Basis Library also provides implementations of sorting.
See also
int_to_string
int_to_string
Lib.int_to_string : int -> string
Translates an integer into a string.
An application int_to_string i returns the printable form of i.
Failure
Never fails.
Example
> int_to_string 12323;
val it = "12323": string
> int_to_string ~1;
val it = "~1": string
Comments
Equivalent functionality can be found in the Standard ML Basis Library
function Int.toString.
See also
intersect
intersect
Lib.intersect : ''a list -> ''a list -> ''a list
Computes the intersection of two 'sets'.
intersect l1 l2 returns a list consisting of those elements of l1
that also appear in l2.
Failure
Never fails.
Example
> intersect [1,2,3] [3,5,4,1];
val it = [1, 3]: int list
Comments
Do not make the assumption that the order of items in the list returned
by intersect is fixed. Later implementations may use different
algorithms, and return a different concrete result while still meeting
the specification.
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of intersect and its
kin. This limits its applicability to types that allow equality. For
other types, typically abstract ones, use the 'op_' variants.
See also
Lib.op_intersect, Lib.union,
Lib.U, Lib.mk_set, Lib.mem,
Lib.insert, Lib.set_eq,
Lib.set_diff
istream
istream
Lib.type ('a,'b) istream
Type of imperative streams.
The type ('a,'b) istream is an abstract type of imperative streams.
These may be created with mk_istream, advanced by next, accessed by
state, and reset with reset.
Comments
Purely functional streams are well-known in functional programming, and more elegant. However, this type proved useful in implementing some imperative 'gensym'-like algorithms used in HOL.
See also
Lib.mk_istream, Lib.next,
Lib.state, Lib.reset
itlist
itlist
Lib.itlist : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
List iteration function. Applies a binary function between adjacent elements of a list.
itlist f [x1,...,xn] b returns
f x1 (f x2 ... (f xn b)...)
An invocation itlist f list b returns b if list is empty.
Failure
Fails if some application of f fails.
Example
> itlist (curry op+) [1,2,3,4] 0;
val it = 10: int
See also
Lib.itlist2, Lib.rev_itlist,
Lib.rev_itlist2,
Lib.end_itlist
itlist2
itlist2
Lib.itlist2 : ('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c
Applies a function to corresponding elements of 2 lists.
itlist2 f [x1,...,xn] [y1,...,yn] z returns
f x1 y1 (f x2 y2 ... (f xn yn z)...)
An invocation itlist2 f list1 list2 b returns b if list1 and
list2 are empty.
Failure
Fails if the two lists are of different lengths, or if one of the
applications of f fails.
Example
> itlist2 (fn x => fn y => fn z => (x,y)::z) [1,2] [3,4] [];
val it = [(1, 3), (2, 4)]: (int * int) list
See also
Lib.itlist, Lib.rev_itlist,
Lib.rev_itlist2,
Lib.end_itlist
K
K
Lib.K : 'a -> 'b -> 'a
Forms a constant function: K x y = x.
Failure
Never fails.
See also
Lib.##, Lib.C, Lib.I,
Lib.S, Lib.W
last
last
Lib.last : 'a list -> 'a
Computes the last element of a list.
last [x1,...,xn] returns xn.
Failure
Fails if the list is empty.
See also
Lib.butlast, Lib.el,
Lib.front_last
list_compare
list_compare
Lib.list_compare : 'a cmp -> 'a list cmp
Lifts a comparison function to a lexicographic ordering on lists.
An application list_compare comp (L1,L2) uses comp as a basis for
comparing the lists L1 and L2 lexicographically, in left-to-right
order. The returned value is one of {LESS, EQUAL, GREATER}.
Failure
If comp fails when applied to corresponding elements of L1 and L2.
Example
> list_compare Int.compare ([1,2,3,4], [1,2,3,4]);
val it = EQUAL: order
> list_compare Int.compare ([1,2,3,4], [1,2,3,4,5]);
val it = LESS: order
> list_compare Int.compare ([1,2,3,4], [1,2,3,2]);
val it = GREATER: order
map2
map2
Lib.map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list
Maps a function over two lists to create one new list.
map2 f [x1,...,xn] [y1,...,yn] returns [f x1 y1,...,f xn yn].
Failure
Fails if the two lists are of different lengths. Also fails if any
f xi yi fails.
Example
> map2 (curry op+) [1,2,3] [3,2,1];
val it = [4, 4, 4]: int list
See also
Lib.itlist, Lib.rev_itlist,
Lib.itlist2, Lib.rev_itlist2
mapfilter
mapfilter
Lib.mapfilter : ('a -> 'b) -> 'a list -> 'b list
Like map, but drops elements that raise exceptions.
Applies a function to every element of a list, returning a list of results for those elements for which application succeeds. The function is applied to the elements of the list from left to right (which is significant if its action includes side effects).
Failure
If f x raises Interrupt for some element x of l, then
mapfilter f l fails (with an Interrupt exception).
Example
> mapfilter hd [[1,2,3],[4,5],[],[6,7,8],[]];
val it = [1, 4, 6]: int list
See also
maplet
|->
op Lib.|-> : 'a * 'b -> {redex : 'a, residue : 'b}
Infix operator for building a component of a substitution.
An application x |-> y is equal to {redex = x, residue = y}. Since
HOL substitutions are lists of {redex,residue} records, the |->
operator is merely sugar used to create substitutions.
Failure
Never fails.
Example
> type_subst [alpha |-> beta, beta |-> gamma]
(alpha --> beta);
val it = “:β -> γ”: hol_type
See also
Lib.subst, Type.type_subst,
Term.subst, Term.inst,
Thm.SUBST
mem
mem
Lib.mem : ''a -> ''a list -> bool
Tests whether a list contains a certain member.
An invocation mem x [x1,...,xn] returns true if some xi in the
list is equal to x. Otherwise it returns false.
Failure
Never fails.
Comments
Note that the type of the members of the list must be an SML equality type. If set operations on a non-equality type are desired, use the 'op_' variants, which take an equality predicate as an extra argument.
A high-performance implementation of finite sets may be found in
structure HOLset.
See also
Lib.op_mem, Lib.insert,
Lib.tryfind, Lib.exists,
Lib.all, Lib.assoc,
Lib.rev_assoc
mk_istream
mk_istream
Lib.mk_istream : ('a -> 'a) -> 'a -> ('a -> 'b) -> ('a,'b) istream
Create a stream.
An application mk_istream trans init proj creates an imperative stream
of elements. The stream is generated by applying trans to the state.
The first element in the stream state is init. The value of the state
is obtained by applying proj.
Failure
If an application of trans or proj fails when applied to the state.
Example
The following creates a stream of distinct strings.
- mk_istream (fn x => x+1) 0 (concat "gsym" o int_to_string);
> val it = <istream> : (int, string) istream
Comments
It is aesthetically unpleasant that the underlying implementation type is visible.
See any book on ML programming to see how functional streams are built.
See also
Lib.next, Lib.state,
Lib.reset
mk_set
mk_set
Lib.mk_set : ''a list -> ''a list
Transforms a list into one with distinct elements.
An invocation mk_set list returns a list consisting of the distinct
members of list. In particular, the result list has no repeated
elements.
Failure
Never fails.
Example
> mk_set [1,1,1,2,2,2,3,3,4];
val it = [1, 2, 3, 4]: int list
Comments
In some programming situations, it is convenient to implement sets by
lists, in which case mk_set may be helpful. However, such an
implementation is only suitable for small sets.
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of mk_set and its
kin. This limits its applicability to types that allow equality. For
other types, typically abstract ones, use the 'op_' variants.
See also
Lib.op_mk_set, Lib.mem,
Lib.insert, Lib.union,
Lib.U, Lib.set_diff,
Lib.subtract, Lib.intersect,
Lib.null_intersection,
Lib.set_eq
mlquote
mlquote
Lib.mlquote : string -> string
Put quotation marks around a string.
Like quote, mlquote s puts quotation marks around a string. However,
it also transforms the characters in a string so that, when printed, it
would be a valid ML lexeme.
Failure
Never fails
Example
> quote "foo\nbar";
val it = "val it = foo \nbar ; \n": string
> mlquote "foo\nbar";
val it = "\"foo\\nbar\"": string
See also
next
next
Lib.next : ('a,'b) istream -> ('a,'b) istream
Move to the next element in the stream.
An application next istrm moves to the next element in the stream.
Failure
If the transition function supplied when building the stream fails on the current state.
Example
> val istrm = mk_istream (fn x => x+1) 0 (strcat "gsym" o int_to_string);
val istrm = ?: (int, string) istream
> next istrm;
val it = ?: (int, string) istream
Comments
Perhaps the type of next should be ('a,'b) istream -> unit.
See also
Lib.mk_istream, Lib.state,
Lib.reset
null_intersection
null_intersection
Lib.null_intersection : ''a list -> ''a list -> bool
Tells if two lists have no common elements.
An invocation null_intersection l1 l2 is equivalent to
null(intersect l1 l2), but is more efficient in the case where the
intersection is not empty.
Failure
Never fails.
Example
> null_intersection [1,2,3,4] [5,6,7,8];
val it = true: bool
> null_intersection [1,2,3,4] [8,5,3];
val it = false: bool
Comments
A high-performance implementation of finite sets may be found in
structure HOLset.
See also
Lib.intersect, Lib.union,
Lib.U, Lib.mk_set, Lib.mem,
Lib.insert, Lib.set_eq,
Lib.set_diff
op_insert
op_insert
Lib.op_insert ('a -> 'a -> bool) -> 'a -> 'a list -> 'a list
Add an element to a list if it is not already there.
If there exists an element y in list, such that eq x y, then
insert eq x list equals list. Otherwise, x is added to list.
Failure
Never fails.
Example
> op_insert (fn x => fn y => x = y mod 2) 1 [3,2];
val it = [3, 2]: int list
> op_insert aconv (Term `\x. x /\ y`)
[T, Term `\z. z /\ y`, F];
val it = [“T”, “λz. z ∧ y”, “F”]: term list
> op_insert aconv (Term `\x. x /\ y`)
[T, Term `\z. z /\ a`, F];
val it = [“λx. x ∧ y”, “T”, “λz. z ∧ a”, “F”]: term list
Comments
There is no requirement that eq be recognizable as a kind of equality
(it could be implemented by an order relation, for example).
One should not write code that depends on the arrangement of elements in the result.
A high-performance implementation of finite sets may be found in
structure HOLset.
See also
Lib.insert, Lib.op_mem,
Lib.op_union, Lib.op_mk_set,
Lib.op_U, Lib.op_intersect,
Lib.op_set_diff
op_intersect
op_intersect
Lib.op_intersect : ('a -> 'a -> bool) -> 'a list -> 'a list -> 'a list
Computes the intersection of two 'sets'.
op_intersect eq l1 l2 returns a list consisting of those elements of
l1 that are eq to some element in l2.
Failure
Fails if an application of eq fails.
Example
> op_intersect aconv [Term `\x:bool.x`, Term `\x y. x /\ y`]
[Term `\y:bool.y`, Term `\x y. x /\ z`];
val it = [“λx. x”]: term list
Comments
The order of items in the list returned by op_intersect is not
dependable.
A high-performance implementation of finite sets may be found in
structure HOLset.
There is no requirement that eq be recognizable as a kind of equality
(it could be implemented by an order relation, for example).
See also
Lib.intersect, Lib.op_mem,
Lib.op_insert, Lib.op_mk_set,
Lib.op_union, Lib.op_U,
Lib.op_set_diff
op_mem
op_mem
Lib.op_mem : ('a -> 'a -> bool) -> 'a -> 'a list -> bool
Tests whether a list contains a certain element.
An invocation op_mem eq x [x1,...,xn] returns true if, for some xi
in the list, eq xi x evaluates to true. Otherwise it returns
false.
Failure
Only fails if an application of eq fails.
Example
> op_mem aconv (Term `\x. x /\ y`) [T, Term `\z. z /\ y`, F];
val it = true: bool
Comments
A high-performance implementation of finite sets may be found in
structure HOLset.
See also
Lib.mem, Lib.op_insert,
Lib.tryfind, Lib.exists,
Lib.all, Lib.assoc,
Lib.rev_assoc, Lib.assoc1,
Lib.assoc2, Lib.op_union,
Lib.op_mk_set, Lib.op_U,
Lib.op_intersect,
Lib.op_set_diff
op_mk_set
op_mk_set
Lib.op_mk_set : ('a -> 'a -> bool) -> 'a list -> 'a list
Transforms a list into one with elements that are distinct modulo the supplied relation.
An invocation op_mk_set eq list returns a list consisting of the
eq-distinct members of list. In particular, the result list will not
contain elements x and y at different positions such that eq x y
evaluates to true.
Failure
If an application of eq fails when applied to two elements of list.
Example
> op_mk_set aconv [Term `\x y. x /\ y`,
Term `\y x. y /\ x`,
Term `\z a. z /\ a`];
val it = [“λz a. z ∧ a”]: term list
Comments
The order of items in the list returned by op_mk_set is not
dependable.
A high-performance implementation of finite sets may be found in
structure HOLset.
There is no requirement that eq be recognizable as a kind of equality
(it could be implemented by an order relation, for example).
See also
Lib.mk_set, Lib.op_mem,
Lib.op_insert, Lib.op_union,
Lib.op_U, Lib.op_intersect,
Lib.op_set_diff
op_set_diff
op_set_diff
Lib.op_set_diff : ('a -> 'a -> bool) -> 'a list -> 'a list -> 'a list
Computes the set-theoretic difference of two 'sets', modulo a supplied relation.
op_set_diff eq l1 l2 returns a list consisting of those elements of
l1 that are not eq to some element of l2.
Failure
Fails if an application of eq fails.
Example
> op_set_diff (fn x => fn y => x mod 2 = y mod 2) [1,2,3] [4,5,6];
val it = []: int list
> op_set_diff (fn x => fn y => x mod 2 = y mod 2) [1,2,3] [2,4,6,8];
val it = [1, 3]: int list
Comments
The order in which the elements occur in the resulting list should not be depended upon.
A high-performance implementation of finite sets may be found in
structure HOLset.
See also
Lib.set_diff, Lib.op_mem,
Lib.op_insert, Lib.op_union,
Lib.op_U, Lib.op_mk_set,
Lib.op_intersect
op_U
op_U
Lib.op_U : ('a -> 'a -> bool) -> 'a list list -> 'a list
Takes the union of a list of sets, modulo the supplied relation.
An application op_U eq [l1, ..., ln] is equivalent to
op_union eq l1 (... (op_union eq ln-1, ln)...). Thus, every element
that occurs in one of the lists will appear in the result. However, if
there are two elements x and y from different lists such that
eq x y, then only one of x and y will appear in the result.
Failure
If an application of eq fails when applied to two elements from the
lists.
Example
> op_U (fn x => fn y => x mod 2 = y mod 2)
[[1,2,3], [4,5,6], [2,4,6,8,10]];
val it = [5, 2, 4, 6, 8, 10]: int list
Comments
The order in which the elements occur in the resulting list should not be depended upon.
A high-performance implementation of finite sets may be found in
structure HOLset.
There is no requirement that eq be recognizable as a kind of equality
(it could be implemented by an order relation, for example).
See also
Lib.U, Lib.op_mem,
Lib.op_insert, Lib.op_union,
Lib.op_mk_set,
Lib.op_intersect,
Lib.op_set_diff
op_union
op_union
Lib.op_union : ('a -> 'a -> bool) -> 'a list -> 'a list -> 'a list
Computes the union of two 'sets'.
If l1 and l2 are both 'sets' (lists with no repeated members),
union eq l1 l2 returns the set union of l1 and l2, using eq as
the implementation of element equality. If one or both of l1 and l2
have repeated elements, there may be repeated elements in the result.
Failure
If some application of eq fails.
Example
> op_union (fn x => fn y => x mod 2 = y mod 2) [1,2,3] [5,4,7];
val it = [5, 4, 7]: int list
Comments
Do not make the assumption that the order of items in the list returned
by op_union is fixed. Later implementations may use different
algorithms, and return a different concrete result while still meeting
the specification.
There is no requirement that eq be recognizable as a kind of equality
(it could be implemented by an order relation, for example).
A high-performance implementation of finite sets may be found in
structure HOLset.
See also
Lib.union, Lib.op_mem,
Lib.op_insert, Lib.op_mk_set,
Lib.op_U, Lib.op_intersect,
Lib.op_set_diff
pair
pair
Lib.pair : 'a -> 'b -> 'a * 'b
Makes two values into a pair.
pair x y returns (x, y).
Failure
Never fails.
See also
Lib.rpair, Lib.swap,
Lib.fst, Lib.snd,
Lib.pair_of_list, Lib.triple,
Lib.quadruple, Lib.curry,
Lib.uncurry
pair_of_list
pair_of_list
Lib.pair_of_list : 'a list -> 'a * 'a
Turns a two-element list into a pair.
pair_of_list [x, y] returns (x, y).
Failure
Fails if applied to a list that is not of length 2.
See also
Lib.singleton_of_list,
Lib.triple_of_list,
Lib.quadruple_of_list
partial
partial
Lib.partial : exn -> ('a -> 'b option) -> 'a -> 'b
Converts a total function to a partial function.
In ML, there are two main ways for a function to signal that it has been
called on an element outside of its intended domain of application:
exceptions and options. The function partial maps a function returning
an element in an option type to one that may raise an exception. Thus,
if f x returns NONE, then partial e f x results in the exception
e being raised. If f x returns SOME y, then partial e f x
returns y.
The function partial has an inverse total. Generally speaking,
(partial err o total) f equals f, provided that err is the only
exception that f raises. Similarly, (total o partial err) f is equal
to f.
Failure
When application of the second argument to the third argument returns
NONE.
Example
> Int.fromString "foo";
val it = NONE: int option
> partial (Fail "not convertable") Int.fromString "foo";
Exception- Fail "not convertable" raised
> (total o partial (Fail "not convertable")) Int.fromString "foo";
val it = NONE: int option
See also
partition
partition
Lib.partition : ('a -> bool) -> 'a list -> 'a list * 'a list
Split a list by a predicate.
An invocation partition P l divides l into a pair of lists
(l1,l2). P holds of each element of l1, and P does not hold of
any element of l2.
Failure
If applying P to any element of l results in failure.
Example
> partition (fn i => i mod 2 = 0) [1,2,3,4,5,6,7,8,9];
val it = ([2, 4, 6, 8], [1, 3, 5, 7, 9]): int list * int list
> partition (fn _ => true) [1,2,3];
val it = ([1, 2, 3], []): int list * int list
> partition (fn _ => raise Fail "") ([]:int list);
val it = ([], []): int list * int list
> partition (fn _ => raise Fail "") [1];
Exception- Fail "" raised
See also
pipegt
|>
op Lib.|> : 'a -> ('a -> 'b) -> 'b
Infix operator for writing function application.
The expression x |> f is equal to f x. This way of writing
application has two advantages, both apparent when multiple functions
are being applied. Without using |>, one might write f (g (h x)).
With it, one writes x |> h |> g |> f. The latter form needs fewer
parentheses, and also makes the order in which functions will operate
correspond to a left-to-right reading.
Failure
Never fails.
pluck
pluck
Lib.pluck : ('a -> bool) -> 'a list -> 'a * 'a list
Pull an element out of a list.
An invocation pluck P [x1,...,xk,...,xn] returns a pair
(xk,[x1,...,xk-1,xk+1,...xn]), where xk has been lifted out of the
list without disturbing the relative positions of the other elements.
For this to happen, P xk must hold, and P xi must not have held for
x1,...,xk-1.
Failure
If the input list is empty. Also fails if P holds of no member of the
list. Also fails if an application of P fails.
Example
> val (x,rst) = pluck (fn x => x mod 2 = 0) [1,2,3];
val rst = [1, 3]: int list
val x = 2: int
See also
Lib.first, Lib.filter,
Lib.mapfilter, Lib.assoc1,
Lib.assoc2, Lib.assoc,
Lib.rev_assoc
ppstring
ppstring
Lib.ppstring : 'a PP.pprinter -> 'a -> string
Pretty-prints a value into a string.
A call to ppstring ppf x will call the pretty-printing function ppf
on value x, with the pretty-printing output stored in the string that
is eventually returned to the user. The linewidth used for determining
when to wrap with newline characters is given by the reference
Globals.linewidth (typically 72).
Failure
Fails if the pretty-printing function fails on the particular input value.
Example
> ppstring PP.add_string "hello"
val it = "hello": string
Comments
The returned string may contain unwanted terminal-specific escape codes,
see rawterm_pp.
See also
Portable.pprint,
Parse.term_to_string,
Parse.rawterm_pp
prime
prime
Lib.prime : string -> string
Attach a prime mark to a string.
A call prime s is equal to s ^ "'".
Failure
Never fails.
See also
quadruple
quadruple
Lib.quadruple : 'a -> 'b -> 'c -> 'd -> 'a * 'b * 'c * 'd
Makes four values into a quadruple.
quadruple x1 x2 x3 x4 returns (x1, x2, x3, x4).
Failure
Never fails.
See also
Lib.quadruple_of_list,
Lib.pair, Lib.triple
quadruple_of_list
quadruple_of_list
Lib.quadruple_of_list : 'a list -> 'a * 'a * 'a * 'a
Turns a four-element list into a quadruple.
quadruple_of_list [x1, x2, x3, x4] returns (x1, x2, x3, x4).
Failure
Fails if applied to a list that is not of length 4.
See also
Lib.singleton_of_list,
Lib.pair_of_list,
Lib.triple_of_list
quote
quote
Lib.quote : string -> string
Put quotation marks around a string.
An application quote s is equal to "\"" ^ s ^ "\"". This is often
useful when printing messages.
Failure
Never fails
Example
> "foo";
val it = "foo": string
> quote "foo";
val it = "val it = foo ; \n": string
See also
repeat
repeat
Lib.repeat : ('a -> 'a) -> 'a -> 'a
Iteratively apply a function until it fails.
An invocation repeat f x expands to repeat f (f x). Thus it unrolls
to f(...(f x)...), returning the most recent argument to f before
application fails.
Failure
The evaluation of repeat f x fails only if interrupted, or machine
resources are exhausted.
Example
The following gives a simple-minded way of calculating the largest integer on the machine.
> fun incr x = x+1;
val incr = fn: int -> int
(Caution: in some ML implementations, the type int is not implemented
by machine words, but by 'bignum' techniques that allow numbers of
arbitrary size, in which case the example above will not return for a
very long time.)
See also
reset
reset
Lib.reset : ('a,'b) istream -> ('a,'b) istream
Restart an istream.
An application reset istrm replaces the current state of istrm with
the value supplied when istrm was constructed.
Failure
Never fails.
Example
> reset(next(next
(mk_istream (fn x => x+1) 0 (concat "gsym" o int_to_string))));
Exception- Type error in function application.
Function: concat : string list -> string
Argument: "gsym" : string
Reason:
Can't unify string list (*In Basis*) with string (*In Basis*)
(Different type constructors)
Type error in function application.
Function: o : ('a -> 'b) * ('c -> 'a) -> 'c -> 'b
Argument: (concat "gsym", int_to_string) : string * (int -> string)
Reason: Can't unify string to 'a -> 'b (Incompatible types)
Fail "Static Errors" raised
> state it;
Exception- Type error in function application.
Function: state : ('a, 'b) istream -> 'b
Argument: it : unit
Reason: Can't unify ('a, 'b) istream to {} (Incompatible types)
Fail "Static Errors" raised
Comments
Perhaps the type of reset should be ('a,'b) istream -> unit.
See also
Lib.mk_istream, Lib.next,
Lib.state
rev_assoc
rev_assoc
Lib.rev_assoc : ''a -> ('b * ''a) list -> 'b
Searches a list of pairs for a pair whose second component equals a specified value.
An invocation rev_assoc y [(x1,y1),...,(xn,yn)] locates the first
(xi,yi) in a left-to-right scan of the list such that yi equals y.
Then xi is returned. The lookup is done on an eqtype, i.e., the SML
implementation must be able to decide equality for the type of y.
Failure
Fails if no matching pair is found. This will always be the case if the list is empty.
Example
> rev_assoc 2 [(1,4),(3,2),(2,5),(2,6)];
val it = 3: int
See also
Lib.assoc, Lib.assoc1,
Lib.assoc2, Lib.mem,
Lib.tryfind, Lib.exists,
Lib.all
rev_itlist
rev_itlist
Lib.rev_itlist : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
Applies a binary function between adjacent elements of the reverse of a list.
rev_itlist f [x1,...,xn] b returns f xn ( ... (f x2 (f x1 b))...).
It returns b if the second argument is an empty list.
Failure
Fails if some application of f fails.
Example
> rev_itlist (curry op * ) [1,2,3,4] 1;
val it = 24: int
See also
Lib.itlist, Lib.itlist2,
Lib.rev_itlist2,
Lib.end_itlist
rev_itlist2
rev_itlist2
Lib.rev_itlist2 : ('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c
Applies a function to corresponding elements of 2 lists.
rev_itlist2 f [x1,...,xn] [y1,...,yn] z returns
f xn yn (f xn-1 yn-1 ... (f x1 y1 z)...)
It returns z if both lists are empty.
Failure
Fails if the two lists are of different lengths, or if an application of
f raises an exception.
Example
> rev_itlist2 (fn x => fn y => cons (x,y)) [1,2] [3,4] [];
val it = [(2, 4), (1, 3)]: (int * int) list
See also
Lib.itlist, Lib.rev_itlist,
Lib.itlist2, Lib.end_itlist
rpair
rpair
Lib.rpair : 'a -> 'b -> 'b * 'a
Makes two values into a pair, in reverse order.
rpair x y returns (y,x).
Failure
Never fails.
See also
Lib.pair, Lib.swap, Lib.fst,
Lib.snd, Lib.curry,
Lib.uncurry
S
S
Lib.S : ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c
Generalized function composition: S f g x equals f x (g x).
Failure
S f never fails and S f g never fails, but S f g x fails if g x
fails or f x (g x) fails.
See also
Lib, Lib.##, Lib.C,
Lib.I, Lib.K, Lib.W
say
say
Lib.say : string -> unit
Print a string.
An application say s prints the string s on the standard output.
Failure
Never fails.
Comments
The Standard ML Basis Library structure TextIO offers related
functions.
set_diff
set_diff
Lib.set_diff : ''a list -> ''a list -> ''a list
Computes the set-theoretic difference of two 'sets'.
set_diff l1 l2 returns a list consisting of those elements of l1
that do not appear in l2. It is identical to Lib.subtract.
Failure
Never fails.
Example
> set_diff [] [1,2];
val it = []: int list
> set_diff [1,2,3] [2,1];
val it = [3]: int list
Comments
The order in which the elements occur in the resulting list should not be depended upon.
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of union and its kin.
This limits its applicability to types that allow equality. For other
types, typically abstract ones, use the 'op_' variants.
See also
Lib.op_set_diff, Lib.subtract,
Lib.mk_set, Lib.set_eq,
Lib.union, Lib.intersect
set_eq
set_eq
Lib.set_eq : ''a list -> ''a list -> bool
Tells whether two lists have the same elements.
An application set_eq l1 l2 returns true just in case l1 and l2
are permutations of each other when duplicate elements within each list
are ignored.
Failure
Never fails.
Example
> set_eq [1,2,1] [1,2,2,1];
val it = true: bool
> set_eq [1,2,1] [2,1];
val it = true: bool
Comments
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of set_eq and its
kin. This limits its applicability to types that allow equality. For
other types, typically abstract ones, use the 'op_' variants.
See also
Lib.intersect, Lib.union,
Lib.U, Lib.mk_set, Lib.mem,
Lib.insert, Lib.set_diff
singleton_of_list
singleton_of_list
Lib.singleton_of_list : 'a list -> 'a
Turns a single-element list into a singleton.
singleton_of_list [x] returns x.
Failure
Fails if applied to a list that is not of length 1.
See also
Lib.pair_of_list,
Lib.triple_of_list,
Lib.quadruple_of_list
snd
snd
Lib.snd : ('a * 'b) -> 'b
Extracts the second component of a pair.
snd (x,y) returns y.
Failure
Never fails. However, notice that snd (x,y,z) fails to typecheck,
since (x,y,z) is not a pair.
Example
- snd (1, "foo");
> val it = "foo" : string
- snd (1, "foo", []);
! Toplevel input:
! snd (1, "foo", []);
! ^^^^^^^^^^^^^^
! Type clash: expression of type
! 'g * 'h * 'i
! cannot have type
! 'j * 'k
! because the tuple has the wrong number of components
- snd (1, ("foo", ()));
> val it = ("foo", ()) : string * unit
See also
sort
sort
Lib.sort : ('a -> 'a -> bool) -> 'a list -> 'a list
Sorts a list using a given transitive 'ordering' relation.
The call sort opr list where opr is a curried transitive relation on
the elements of list, will sort the list, i.e., will permute list
such that if x opr y but not y opr x then x will occur to the left
of y in the sorted list. In particular if opr is a total order, the
result list will be sorted in the usual sense of the word.
Failure
Never fails.
Example
A simple example is:
- sort (curry (op<)) [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9];
> val it = [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 9, 9] : int list
The following example is a little more complicated. Note that the 'ordering' is not antisymmetric.
- sort (curry (op< o (fst ## fst)))
[(1,3), (7,11), (3,2), (3,4), (7,2), (5,1)];
> val it = [(1,3), (3,4), (3,2), (5,1), (7,2), (7,11)] : (int * int) list
Comments
The Standard ML Basis Library also provides implementations of sorting.
See also
split
split
Lib.split : ('a * 'b) list -> ('a list * 'b list)
Converts a list of pairs into a pair of lists.
split [(x1,y1),...,(xn,yn)] returns ([x1,...,xn],[y1,...,yn]).
Failure
Never fails.
Comments
Identical to the Basis function ListPair.unzip and the function
Lib.unzip.
See also
Lib.unzip, Lib.zip,
Lib.combine
split_after
split_after
Lib.split_after : int -> 'a list -> 'a list * 'a list
Breaks a list in two at a specified index.
An invocation split_after k [x1,...,xk,...xn] returns the pair
([x1,...,xk], [xk+1,...,xn]). If k is 0, then split_after k l
returns ([],l). Similarly, split_after (length l) l returns
(l,[]).
Failure
If k is negative, or longer than the length of the list.
Example
> split_after 2 [1,2,3,4,5]
val it = ([1, 2], [3, 4, 5]): int list * int list
> split_after 0 [1,2,3,4,5];
val it = ([], [1, 2, 3, 4, 5]): int list * int list
> split_after 5 [1,2,3,4,5];
val it = ([1, 2, 3, 4, 5], []): int list * int list
> split_after 6 [1,2,3,4,5];
Exception- HOL_ERR (at Lib.split_after: index too big) raised
> split_after 0 ([]:int list);
val it = ([], []): int list * int list
See also
start_time
start_time
Lib.start_time : unit -> Timer.cpu_timer
Set a timer running.
An application start_time () creates a timer and starts it. A later
invocation end_time t, where t is a timer, will need to be called to
get the elapsed time between the two function calls.
Failure
Never fails.
Example
> val clock = start_time ();
val clock = ?: Timer.cpu_timer
Comments
Multiple timers may be started without any interfering with the others.
Further operations associated with the type cpu_timer may be found in
the Standard ML Basis Library structures Timer and Time.
See also
state
state
Lib.state : ('a,'b) istream -> 'b
Project the state of an istream.
An application state istrm yields the value of the current state of
istrm.
Failure
If the projection function supplied when building the stream fails on the current element of the state.
Example
> val istrm = mk_istream (fn x => x+1) 0 (strcat "gsym" o int_to_string);
val istrm = ?: (int, string) istream
> state istrm;
val it = "gsym0": string
> next (next istrm);
val it = ?: (int, string) istream
> state istrm;
val it = "gsym2": string
See also
Lib.mk_istream, Lib.next,
Lib.reset
strcat
strcat
Lib.strcat : string -> string -> string
Concatenates two ML strings.
Failure
Never fails.
Example
> strcat "1" "";
val it = "1": string
> strcat "hello" "world";
val it = "helloworld": string
> strcat "hello" (strcat " " "world");
val it = "hello world": string
string_to_int
string_to_int
Lib.string_to_int : string -> int
Translates from a string to an integer.
An application string_to_int s returns the integer denoted by s, if
such exists.
Failure
If the string cannot be translated to an integer.
Example
> string_to_int "123";
val it = 123: int
> string_to_int "~123";
val it = ~123: int
> string_to_int "foo";
Exception- HOL_ERR (at Lib.string_to_int: not convertable) raised
Comments
Similar functionality can be obtained from the Standard ML Basis Library
function Int.fromString.
See also
subst
subst
Lib.type ('a,'b) subst
Type abbreviation for substitutions.
The type ('a,'b) subst abbreviates the type {redex,residue} list, in
which redex has type 'a and residue has type 'b. Usually, a
{redex,residue} pair in a substition is interpreted as 'replace
occurrences of redex by residue'.
Comments
The different types of redex and residue components allows
flexibility, as in the rule of inference SUBST, which takes a
(term,thm) subst argument.
See also
Lib.|->, Term.subst,
Term.inst, Thm.SUBST
subst_assoc
subst_assoc
Lib.subst_assoc : ('a -> bool) -> ('a,'b)subst -> 'b option
Treats a substitution as an association list.
An application
subst_assoc P [{redex_1,residue_1},...,{redex_n,residue_n}] returns
SOME residue_i if P holds of redex_i, and did not hold (or fail)
for {redex_j | 1 <= j < i}. If P holds for none of the redexes in
the substitution, NONE is returned.
Failure
If P redex_i fails for some redex encountered in the left-to-right
traversal of the substitution.
Example
> subst_assoc is_abs [T |-> F, Term `\x.x` |-> Term `combin$I`];
val it = SOME (“I”): term option
See also
Lib.assoc, Lib.rev_assoc,
Lib.assoc1, Lib.assoc2,
Lib.|->
subtract
subtract
Lib.subtract : ''a list -> ''a list -> ''a list
Computes the set-theoretic difference of two 'sets'.
Behaves exactly like set_diff.
See also
swap
swap
Lib.swap : 'a * 'b -> 'b * 'a
Swaps the two components of a pair.
swap (x,y) returns (y,x).
Failure
Never fails.
See also
Lib.fst, Lib.snd, Lib.pair,
Lib.rpair
time
time
Lib.time : ('a -> 'b) -> 'a -> 'b
Measure how long a function application takes.
An application time f x starts a clock, applies f to x, and then
checks the clock to see how long that took. It prints out the elapsed
runtime, garbage collection time, and system time before returning the
value of f x.
Failure
If f x raises e, then time f x raises e, but still reports
elapsed time.
Example
> time (int_sort) (for 0 999 I);
runtime: 0.00503s, gctime: 0.00000s, systime: 0.00146s.
val it =
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
93, 94, 95, 96, 97, 98, 99, ...]: int list
> fun f x = f (x + 1);
val f = fn: int -> 'a
> time f 0; (* would need interrupting *)
See also
Lib.end_time, Lib.start_time,
Count.thm_count
topsort
topsort
Lib.topsort : ('a -> 'a -> bool) -> 'a list -> 'a list
Topologically sorts a list using a given partial order relation.
The call topsort opr list where opr is a curried partial order on
the elements of list, will topologically sort the list, i.e., will
permute it such that if x opr y then x will occur to the left of y
in the resulting list.
Failure
If opr fails when applied to x and y in list. Also, topsort
will fail if there is a chain of elements x1,...,xn, all in list,
such that opr x_1 x_2, ..., opr xn x1. This displays a cyclic
dependency.
Example
The following call arranges a list of terms in subterm order:
- fun is_subterm x y = Lib.can (find_term (aconv x)) y;
> val is_subterm = fn : term -> term -> bool
- topsort is_subterm
[``x+1``, ``x:num``, ``y + (x + 1)``, ``y + x``, ``y + x + z``, ``y:num``];
> val it = [``y``, ``x``, ``x + 1``, ``y + x``, ``y + x + z``, ``y + (x + 1)``] : term list
See also
total
total
Lib.total : ('a -> 'b) -> 'a -> 'b option
Converts a partial function to a total function.
In ML, there are two main ways for a function to signal that it has been
called on an element outside of its intended domain of application:
exceptions and options. The function total maps a function that may
raise an exception to one that returns an element in the option type.
Thus, if f x results in any exception other than Interrupt being
raised, then total f x returns NONE. If f x raises Interrupt,
then total f x likewise raises Interrupt. If f x returns y, then
total f x returns SOME y.
The function total has an inverse partial. Generally speaking,
(partial err o total) f equals f, provided that err is the only
exception that f raises. Similarly, (total o partial err) f is equal
to f.
Failure
When application of the first argument to the second argument raises
Interrupt.
Example
> 3 div 0;
Exception- Div raised
> total (op div) (3,0);
val it = NONE: int option
> (partial Div o total) (op div) (3,0);
Exception- Div raised
See also
triple
triple
Lib.triple : 'a -> 'b -> 'c -> 'a * 'b * 'c
Makes three values into a triple.
triple x y z returns (x, y, z).
Failure
Never fails.
See also
Lib.triple_of_list, Lib.pair,
Lib.quadruple
triple_of_list
triple_of_list
Lib.triple_of_list : 'a list -> 'a * 'a * 'a
Turns a three-element list into a triple.
triple_of_list [x, y, z] returns (x, y, z).
Failure
Fails if applied to a list that is not of length 3.
See also
Lib.singleton_of_list,
Lib.pair_of_list,
Lib.quadruple_of_list
try
try
Lib.try : ('a -> 'b) -> 'a -> 'b
Apply a function and print any exceptions.
The application try f x evaluates f x; if this evaluation raises an
exception e, then e is examined and some information about it is
printed before e is re-raised. If f x evaluates to y, then y is
returned.
Often, a HOL_ERR exception can propagate all the way to the top level.
Unfortunately, the information held in the exception is not then
printed. try can often display this information.
Failure
When application of the first argument to the second raises an exception.
Example
> mk_comb (T,F);
Exception- HOL_ERR (at Term.mk_comb: incompatible types) raised
> try mk_comb (T,F);
Exception- Type error in function application.
Function: try mk_comb :
(term -> (term * term) option) list -> term -> term
Argument: (T, F) : term * term
Reason:
Can't unify (term -> (term * term) option) list to term * term
(Incompatible types)
Fail "Static Errors" raised
Evaluation order can be significant. ML evaluates try M N by
evaluating M (yielding f say) and N (yielding x say), and then
f is applied to x. Any exceptions raised in the course of evaluating
M or N will not be detected by try. In such cases it is better to
use Raise. In the following example, the erroneous construction of an
abstraction is not detected by try and the exception propagates all
the way to the top level; however, Raise does handle the exception.
- try mk_comb (T, mk_abs(T,T));
! Uncaught exception:
! HOL_ERR
- mk_comb (T, mk_abs(T,T)) handle e => Raise e;
Exception raised at Term.mk_abs:
Bvar not a variable
! Uncaught exception:
! HOL_ERR
See also
trye
trye
Lib.trye : ('a -> 'b) -> 'a -> 'b
Maps exceptions into HOL_ERR
The standard exception for HOL applications to raise is HOL_ERR. The
use of a single exception simplifies the writing of exception handlers
and facilities for decoding and printing error messages. However, ML
functions that raise exceptions, such as hd and many others, are often
used to implement HOL programs. In such cases, trye may be used to
coerce exceptions into applications of HOL_ERR. Note however, that the
Interrupt exception is not coerced by trye.
The application trye f x evaluates f x; if this evaluates to y,
then y is returned. However, if evaluation raises an exception e,
there are three cases: if e is Interrupt, then it is raised; if e
is HOL_ERR, then it is raised; otherwise, e is mapped to an
application of HOL_ERR and then raised.
Failure
Fails if the function application fails.
Example
> hd [];
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
Empty raised
> trye hd [];
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
HOL_ERR (at Lib.trye: original exn. not a HOL_ERR) raised
> trye (fn _ => raise Interrupt) 1;
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
Interrupt raised
See also
tryfind
tryfind
Lib.tryfind : ('a -> 'b) -> 'a list -> 'b
Returns the result of the first successful application of a function to the elements of a list.
tryfind f [x1,...,xn] returns (f xi) for the first xi in the list
for which application of f does not raise an exception. However, if
Interrupt is raised in the course of some application of f xi, then
tryfind f [x1,...,xn] raises Interrupt.
Failure
Fails if the application of f fails for all elements in the list. This
will always be the case if the list is empty.
See also
Lib.first, Lib.mem,
Lib.exists, Lib.all,
Lib.assoc, Lib.rev_assoc,
Lib.assoc1, Lib.assoc2
trypluck
trypluck
Lib.trypluck : ('a -> 'b) -> 'a list -> 'b * 'a list
Pull an element out of a list.
An invocation trypluck f [x1,...,xk,...,xn] returns a pair
(f(xk),[x1,...,xk-1,xk+1,...xn])
where xk has been lifted out of the list without disturbing the
relative positions of the other elements. For this to happen, f(xk)
must hold, and f(xi) must fail for x1,...,xk-1.
Failure
If the input list is empty. Also fails if f fails on every member of
the list.
Example
> val (x,rst) = trypluck BETA_CONV [``1``,``(\x. x+2) 3``, ``p + q``];
val rst = [“1”, “p + q”]: term list
val x = ⊢ (λx. x + 2) 3 = 3 + 2: thm
See also
Lib.first, Lib.filter,
Lib.mapfilter, Lib.tryfind
trypluckprime
trypluck'
Lib.trypluck' : ('a -> 'b option) -> 'a list -> ('b option * 'a list)
Pull an element out of a list.
An invocation trypluck' f [x1,...,xk,...,xn] returns either the pair
(f(xk),[x1,...,xk-1,xk+1,...xn])
where xk has been lifted out of the list without disturbing the
relative positions of the other elements, where f(xk) is SOME(v),
and where f(xi) returns NONE for x1,...,xk-1; or it returns
(NONE,[x1,...xn] when f applied to every element of the list returns
NONE.
This is an 'option' version of the other library function trypluck.
Failure
Never fails.
See also
Lib.first, Lib.filter,
Lib.mapfilter, Lib.tryfind,
Lib.trypluck
U
U
Lib.U : ''a list list -> ''a list
Takes the union of a list of sets.
An application U [l1, ..., ln] is equivalent to
union l1 (... (union ln-1, ln)...). Thus, every element that occurs in
one of the lists will appear in the result.
Failure
Never fails.
Example
> U [[1,2,3], [4,5,6], [1,2,5]];
val it = [3, 6, 4, 1, 2, 5]: int list
Comments
The order in which the elements occur in the resulting list should not be depended upon.
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of U and its kin.
This limits its applicability to types that allow equality. For other
types, typically abstract ones, use the 'op_' variants.
See also
Lib.op_U, Lib.union,
Lib.mk_set, Lib.mem,
Lib.insert, Lib.set_eq,
Lib.intersect, Lib.set_diff
uncurry
uncurry
Lib.uncurry : ('a -> 'b -> 'c) -> ('a * 'b) -> 'c
Converts a function taking two arguments into a function taking a single paired argument.
The application uncurry f returns fn (x,y) => f x y, so that
uncurry f (x,y) = f x y
Failure
Never fails.
Example
> fun add x y = x + y
val add = fn: int -> int -> int
> uncurry add (3,4);
val it = 7: int
See also
union
union
Lib.union : ''a list -> ''a list -> ''a list
Computes the union of two 'sets'.
If l1 and l2 are both 'sets' (lists with no repeated members),
union l1 l2 returns the set union of l1 and l2. In the case that
l1 or l2 is not a set, all the user can depend on is that
union l1 l2 returns a list l3 such that every unique element of l1
and l2 is in l3 and each element of l3 is found in either l1 or
l2.
Failure
Never fails.
Example
> union [1,2,3] [1,5,4,3];
val it = [2, 1, 5, 4, 3]: int list
> union [1,1,1] [1,2,3,2];
val it = [1, 2, 3, 2]: int list
> union [1,2,3,2] [1,1,1] ;
val it = [3, 2, 1, 1, 1]: int list
Comments
Do not make the assumption that the order of items in the list returned
by union is fixed. Later implementations may use different algorithms,
and return a different concrete result while still meeting the
specification.
A high-performance implementation of finite sets may be found in
structure HOLset.
ML equality types are used in the implementation of union and its kin.
This limits its applicability to types that allow equality. For other
types, typically abstract ones, use the 'op_' variants.
See also
Lib.op_union, Lib.U,
Lib.mk_set, Lib.mem,
Lib.insert, Lib.set_eq,
Lib.intersect, Lib.set_diff,
Lib.subtract
unzip
unzip
Lib.unzip : ('a * 'b) list -> ('a list * 'b list)
Converts a list of pairs into a pair of lists.
unzip [(x1,y1),...,(xn,yn)] returns ([x1,...,xn],[y1,...,yn]).
Failure
Never fails.
Comments
Identical to Lib.split.
See also
Lib.split, Lib.zip,
Lib.combine
upto
upto
Lib.upto : int -> int -> int list
Builds a list of integers.
An invocation upto b t returns the list [b, b+1, ..., t], if
b <= t. Otherwise, the empty list is returned.
Failure
Never fails.
Example
> upto 2 10;
val it = [2, 3, 4, 5, 6, 7, 8, 9, 10]: int list
W
W
Lib.W : ('a -> 'a -> 'b) -> 'a -> 'b
Duplicates function argument : W f x equals f x x.
The W combinator can be understood as a planner: in the application
f x x, the function f can scrutinize x and generate a function
that then gets applied to x.
Failure
W f never fails. W f x fails if f x fails or if f x x fails.
Example
> load "tautLib";
val it = (): unit
> tautLib.TAUT_PROVE (Term `(a:bool = b) = (~a = ~b)`);
val it = ⊢ (a ⇔ b) ⇔ (¬a ⇔ ¬b): thm
> W (GENL o free_vars o concl) it;
val it = ⊢ ∀b a. (a ⇔ b) ⇔ (¬a ⇔ ¬b): thm
See also
Lib.##, Lib.C, Lib.I,
Lib.K, Lib.S
with_exn
with_exn
Lib.with_exn : ('a -> 'b) -> 'a -> exn -> 'b
Apply a function to an argument, raising supplied exception on failure.
An evaluation of with_exn f x e applies function f to argument x.
If that computation finishes with y, then y is the result.
Otherwise, f x raised an exception, and the exception e is raised
instead. However, if f x raises the Interrupt exception, then
with_exn f x e results in the Interrupt exception being raised.
Failure
When f x fails or is interrupted.
Example
> with_exn dest_comb (Term`\x. x /\ y`) (Fail "My kingdom for a horse");
Exception- Fail "My kingdom for a horse" raised
> with_exn (fn _ => raise Interrupt) 1 (Fail "My kingdom for a horse");
Exception- The type of (it) contains a free type variable. Setting it to a unique
monotype.
Interrupt raised
Comments
Often with_exn can be used to clean up programming where lots of
exceptions may be handled. For example, taking apart a compound term of
a certain desired form may fail at several places, but a uniform error
message is desired.
local val expected = mk_HOL_ERR "" "dest_quant" "expected !v.M or ?v.M"
in
fun dest_quant tm =
let val (q,body) = with_exn dest_comb tm expected
val (p as (v,M)) = with_exn dest_abs body expected
in
if q = universal orelse q = existential
then p
else raise expected
end
end
See also
Feedback.wrap_exn,
Lib.assert_exn, Lib.assert
with_flag
with_flag
Lib.with_flag : 'a ref * 'a -> ('b -> 'c) -> 'b -> 'c
Apply a function under a particular flag setting.
An invocation with_flag (r,v) f x sets the reference variable r to
the value v, then evaluates f x, then resets r to its original
value, and returns the value of f x.
Failure
Fails if f x fails. In that case, r is reset to its original value
before raising the exception from f x.
Example
> fun print_term_nl tm = (print_term tm; Feedback.HOL_INFO "\n");
val print_term_nl = fn: term -> unit
> with_flag (show_types, true) print_term_nl (concl T_DEF);
T ⇔ (λ(x :bool). x) = (λ(x :bool). x)
val it = (): unit
> print_term_nl (concl T_DEF);
T ⇔ (λx. x) = (λx. x)
val it = (): unit
See also
Feedback.traces,
Feedback.register_btrace,
Feedback.trace, Lib.time
words2
words2
Lib.words2 : string -> string -> string list
Splits a string into a list of substrings, breaking at occurrences of a specified character.
words2 char s splits the string s into a list of substrings.
Splitting occurs at each occurrence of a sequence of the character
char. The char characters do not appear in the list of substrings.
Leading and trailing occurrences of char are also thrown away. If
char is not a single-character string (its length is not 1), then s
will not be split and so the result will be the list [s].
Failure
Never fails.
Example
> words2 "/" "/the/cat//sat/on//the/mat/";
val it = ["the", "cat", "sat", "on", "the", "mat"]: string list
> words2 "//" "/the/cat//sat/on//the/mat/";
val it = ["/the/cat//sat/on//the/mat/"]: string list
Comments
The SML Library functions String.tokens and String.fields offer
similar functionality.
zip
zip
Lib.zip : 'a list -> 'b list -> ('a * 'b) list
Transforms a pair of lists into a list of pairs.
zip [x1,...,xn] [y1,...,yn] returns [(x1,y1),...,(xn,yn)].
Failure
Fails if the two lists are of different lengths.
Comments
Has much the same effect as the SML Basis function ListPair.zip except
that it fails if the arguments are not of equal length. zip is a
curried version of combine
See also
Lib.combine, Lib.unzip,
Lib.split
ALL_EL_CONV
ALL_EL_CONV
listLib.ALL_EL_CONV : conv -> conv
Computes by inference the result of applying a predicate to elements of a list.
ALL_EL_CONV takes a conversion conv and a term tm in the following
form:
ALL_EL P [x0;...xn]
It returns the theorem
|- ALL_EL P [x0;...xn] = T
if for every xi occurring in the list, conv “P xi” returns a theorem
|- P xi = T, otherwise, if for at least one xi, evaluating
conv “P xi” returns the theorem |- P xi = F, then it returns the
theorem
|- ALL_EL P [x0;...xn] = F
Failure
ALL_EL_CONV conv tm fails if tm is not of the form described above,
or failure occurs when evaluating conv “P xi” for some xi.
Example
Evaluating
ALL_EL_CONV bool_EQ_CONV “ALL_EL ($= T) [T;F;T]”;
returns the following theorem:
|- ALL_EL($= T)[T;F;T] = F
In general, if the predicate P is an explicit lambda abstraction
(\x. P x), the conversion should be in the form
(BETA_CONV THENC conv')
See also
listLib.SOME_EL_CONV,
listLib.IS_EL_CONV,
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
AND_EL_CONV
AND_EL_CONV
listLib.AND_EL_CONV : conv
Computes by inference the result of taking the conjunction of the elements of a boolean list.
For any object language list of the form “[x1;x2;...;xn]”, where x1,
x2, ..., xn are boolean expressions, the result of evaluating
AND_EL_CONV “AND_EL [x1;x2;...;xn]”
is the theorem
|- AND_EL [x1;x2;...;xn] = b
where b is either the boolean constant that denotes the conjunction of
the elements of the list, or a conjunction of those xi that are not
boolean constants.
Example
> listLib.AND_EL_CONV “AND_EL [T;F;F;T]”;
val it = ⊢ AND_EL [T; F; F; T] ⇔ F: thm
> listLib.AND_EL_CONV “AND_EL [T;T;T]”;
val it = ⊢ AND_EL [T; T; T] ⇔ T: thm
> listLib.AND_EL_CONV “AND_EL [T;x;y]”;
val it = ⊢ AND_EL [T; x; y] ⇔ x ∧ y: thm
> listLib.AND_EL_CONV “AND_EL [x;F;y]”;
val it = ⊢ AND_EL [x; F; y] ⇔ F: thm
Failure
AND_EL_CONV tm fails if tm is not of the form described above.
APPEND_CONV
APPEND_CONV
listLib.APPEND_CONV : conv
Computes by inference the result of appending two object-language lists.
For any pair of object language lists of the form “[x1;...;xn]” and
“[y1;...;ym]”, the result of evaluating
APPEND_CONV “APPEND [x1;...;xn] [y1;...;ym]”
is the theorem
|- APPEND [x1;...;xn] [y1;...;ym] = [x1;...;xn;y1;...;ym]
The length of either list (or both) may be 0.
Failure
APPEND_CONV tm fails if tm is not of the form “APPEND l1 l2”,
where l1 and l2 are (possibly empty) object-language lists of the
forms “[x1;...;xn]” and “[y1;...;ym]”.
BUTFIRSTN_CONV
BUTFIRSTN_CONV
listLib.BUTFIRSTN_CONV : conv
Computes by inference the result of dropping the initial n elements of a list.
For any object language list of the form “[x0;...x(n-k);...;x(n-1)]” ,
the result of evaluating
BUTFIRSTN_CONV “BUTFIRSTN k [x0;...x(n-k);...;x(n-1)]”
is the theorem
|- BUTFIRSTN k [x0;...;x(n-k);...;x(n-1)] = [x(n-k);...;x(n-1)]
Failure
BUTFIRSTN_CONV tm fails if tm is not of the form described above, or
k is greater than the length of the list.
BUTLAST_CONV
BUTLAST_CONV
listLib.BUTLAST_CONV : conv
Computes by inference the result of stripping the last element of a list.
For any object language list of the form “[x0;...x(n-1)]” , the result
of evaluating
BUTLAST_CONV “BUTLAST [x0;...;x(n-1)]”
is the theorem
|- BUTLAST [x0;...;x(n-1)] = [x0;...; x(n-2)]
Failure
BUTLAST_CONV tm fails if tm is an empty list.
BUTLASTN_CONV
BUTLASTN_CONV
listLib.BUTLASTN_CONV : conv
Computes by inference the result of dropping the last n elements of a list.
For any object language list of the form “[x0;...x(n-k);...;x(n-1)]” ,
the result of evaluating
BUTLASTN_CONV “BUTLASTN k [x0;...x(n-k);...;x(n-1)]”
is the theorem
|- BUTLASTN k [x0;...;x(n-k);...;x(n-1)] = [x0;...;x(n-k-1)]
Failure
BUTLASTN_CONV tm fails if tm is not of the form described above, or
k is greater than the length of the list.
EL_CONV
EL_CONV
listLib.EL_CONV : conv
Computes by inference the result of indexing an element from a list.
For any object language list of the form “[x0;...xk;...;xn]” , the
result of evaluating
EL_CONV “EL k [x0;...xk;...;xn]”
is the theorem
|- EL k [x0;...;xk;...;xn] = xk
Failure
EL_CONV tm fails if tm is not of the form described above, or k is
not less than the length of the list.
See also
ELL_CONV
ELL_CONV
listLib.ELL_CONV : conv
Computes by inference the result of indexing an element of a list from the tail end.
For any object language list of the form “[xn-1;...;xk;...x0]” , the
result of evaluating
ELL_CONV “ELL k [xn-1;...;xk;...;x0]”
is the theorem
|- ELL k [xn-1;...;xk;...;x0] = xk
where k must not be greater then the length of the list. Note that
ELL indexes the list elements from the tail end.
Failure
ELL_CONV tm fails if tm is not of the form described above, or k
is not less than the length of the list.
See also
EQ_LENGTH_INDUCT_TAC
EQ_LENGTH_INDUCT_TAC
listLib.EQ_LENGTH_INDUCT_TAC : tactic
Performs tactical proof by structural induction on two equal length lists.
EQ_LENGTH_INDUCT_TAC reduces a goal
!x y . (LENGTH x = LENGTH y) ==> t[x,y], where x and y range over
lists, to two subgoals corresponding to the base and step cases in a
proof by induction on the length of x and y. The induction
hypothesis appears among the assumptions of the subgoal for the step
case. The specification of EQ_LENGTH_INDUCT_TAC is:
A ?- !x y . (LENGTH x = LENGTH y) ==> t[x,y]
==================================================== EQ_LENGTH_INDUCT_TAC
A ?- t[NIL/x][NIL/y]
A u {{LENGTH x = LENGTH y, t[x'/x, y'/y]}} ?-
!h h'. t[(CONS h x)/x, (CONS h' y)/y]
Failure
EQ_LENGTH_INDUCT_TAC g fails unless the conclusion of the goal g has
the form
!x y . (LENGTH x = LENGTH y) ==> t[x,y]
where the variables x and y have types (xty)list and (yty)list
for some types xty and yty. It also fails if either of the variables
x or y appear free in the assumptions.
Use this tactic to perform structural induction over two lists that have identical length.
See also
listLib.LIST_INDUCT_TAC,
listLib.SNOC_INDUCT_TAC,
listLib.EQ_LENGTH_SNOC_INDUCT_TAC
EQ_LENGTH_SNOC_INDUCT_TAC
EQ_LENGTH_SNOC_INDUCT_TAC
listLib.EQ_LENGTH_SNOC_INDUCT_TAC : tactic
Performs tactical proof by structural induction on two equal length lists from the tail end.
EQ_LENGTH_SNOC_INDUCT_TAC reduces a goal
!x y . (LENGTH x = LENGTH y) ==> t[x,y], where x and y range over
lists, to two subgoals corresponding to the base and step cases in a
proof by induction on the length of x and y. The induction
hypothesis appears among the assumptions of the subgoal for the step
case. The specification of EQ_LENGTH_SNOC_INDUCT_TAC is:
A ?- !x y . (LENGTH x = LENGTH y) ==> t[x,y]
================================================ EQ_LENGTH_SNOC_INDUCT_TAC
A ?- t[NIL/x][NIL/y]
A u {{LENGTH x = LENGTH y, t[x'/x, y'/y]}} ?-
!h h'. t[(SNOC h x)/x, (SNOC h' y)/y]
Failure
EQ_LENGTH_SNOC_INDUCT_TAC g fails unless the conclusion of the goal
g has the form
!x y . (LENGTH x = LENGTH y) ==> t[x,y]
where the variables x and y have types (xty)list and (yty)list
for some types xty and yty. It also fails if either of the variables
x or y appear free in the assumptions.
Use this tactic to perform structural induction on two lists that have identical length.
See also
listLib.EQ_LENGTH_INDUCT_TAC,
listLib.LIST_INDUCT_TAC,
listLib.SNOC_INDUCT_TAC
FILTER_CONV
FILTER_CONV
listLib.FILTER_CONV : conv -> conv
Computes by inference the result of applying a predicate to the elements of a list.
FILTER_CONV takes a conversion conv and a term tm in the following
form:
FILTER P [x0;...xn]
It returns the theorem
|- FILTER P [x0;...xn] = [...xi...]
where for every xi occurring in the right-hand side of the resulting
theorem, conv “P xi” returns a theorem |- P xi = T.
Failure
FILTER_CONV conv tm fails if tm is not of the form described above.
Example
Evaluating
FILTER_CONV bool_EQ_CONV “FILTER ($= T) [T;F;T]”;
returns the following theorem:
|- FILTER($= T)[T;F;T] = [T;T]
In general, if the predicate P is an explicit lambda abstraction
(\x. P x), the conversion should be in the form
(BETA_CONV THENC conv')
See also
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
FIRSTN_CONV
FIRSTN_CONV
listLib.FIRSTN_CONV : conv
Computes by inference the result of taking the initial n elements of a list.
For any object language list of the form “[x0;...x(n-k);...;x(n-1)]” ,
the result of evaluating
FIRSTN_CONV “FIRSTN k [x0;...x(n-k);...;x(n-1)]”
is the theorem
|- FIRSTN k [x0;...;x(n-k);...;x(n-1)] = [x0;...;x(n-k)]
Failure
FIRSTN_CONV tm fails if tm is not of the form described above, or
k is greater than the length of the list.
FLAT_CONV
FLAT_CONV
listLib.FLAT_CONV : conv
Computes by inference the result of flattening a list of lists.
FLAT_CONV takes a term tm in the following form:
FLAT [[x00;...x0n]; ...; [xm0;...xmn]]
It returns the theorem
|- FLAT [[x00;...x0n];...;[xm0;...xmn]] = [x00;...x0n;...;xm0;...xmn]
Failure
FLAT_CONV tm fails if tm is not of the form described above.
Example
Evaluating
FLAT_CONV “FLAT [[0;2;4];[0;1;2;3;4]]”;
returns the following theorem:
|- FLAT[[0;2;4];[0;1;2;3;4]] = [0;2;4;0;1;2;3;4]
See also
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
FOLDL_CONV
FOLDL_CONV
listLib.FOLDL_CONV : conv -> conv
Computes by inference the result of applying a function to the elements of a list.
FOLDL_CONV takes a conversion conv and a term tm in the following
form:
FOLDL f e [x0;...xn]
It returns the theorem
|- FOLDL f e [x0;...xn] = tm'
where tm' is the result of applying the function f iteratively to
the successive elements of the list and the result of the previous
application starting from the tail end of the list. During each
iteration, an expression f ei xi is evaluated. The user supplied
conversion conv is used to derive a theorem
|- f ei xi = e(i+1)
which is used in the next iteration.
Failure
FOLDL_CONV conv tm fails if tm is not of the form described above.
Example
To sum the elements of a list, one can use FOLDL_CONV with
REDUCE_CONV from the library numLib.
- FOLDL_CONV numLib.REDUCE_CONV ``FOLDL $+ 0 [0;1;2;3]``;
val it = |- FOLDL $+ 0 [0;1;2;3] = 6 : thm
In general, if the function f is an explicit lambda abstraction
(\x x'. t[x,x']), the conversion should be in the form
((RATOR_CONV BETA_CONV) THENC BETA_CONV THENC conv'))
where conv' applied to t[x,x'] returns the theorem
|-t[x,x'] = e''.
See also
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
FOLDR_CONV
FOLDR_CONV
listLib.FOLDR_CONV : conv -> conv
Computes by inference the result of applying a function to the elements of a list.
FOLDR_CONV takes a conversion conv and a term tm in the following
form:
FOLDR f e [x0;...xn]
It returns the theorem
|- FOLDR f e [x0;...xn] = tm'
where tm' is the result of applying the function f iteratively to
the successive elements of the list and the result of the previous
application starting from the tail end of the list. During each
iteration, an expression f xi ei is evaluated. The user supplied
conversion conv is used to derive a theorem
|- f xi ei = e(i+1)
which is used in the next iteration.
Failure
FOLDR_CONV conv tm fails if tm is not of the form described above.
Example
To sum the elements of a list, one can use FOLDR_CONV with
REDUCE_CONV from the library numLib.
- FOLDR_CONV numLib.REDUCE_CONV ``FOLDR $+ 0 [0;1;2;3]``;
val it = |- FOLDR $+ 0[0;1;2;3] = 6 : thm
In general, if the function f is an explicit lambda abstraction
(\x x'. t[x,x']), the conversion should be in the form
((RATOR_CONV BETA_CONV) THENC BETA_CONV THENC conv'))
where conv' applied to t[x,x'] returns the theorem
|-t[x,x'] = e''.
See also
listLib.FOLDL_CONV,
listLib.list_FOLD_CONV
GENLIST_CONV
GENLIST_CONV
listLib.GENLIST_CONV : conv -> conv
Computes by inference the result of generating a list from a function.
For an arbitrary function f, numeral constant n and conversion to
evaluate f conv, the result of evaluating
GENLIST_CONV conv “GENLIST f n”
is the theorem
|- GENLIST f x = [x0;x1...xi...x(n-1)]
where each xi is the result of evaluating conv “f i”
Example
Evaluating GENLIST_CONV BETA_CONV “GENLIST (\n . n) 4” will return the
following theorem:
|- GENLIST (\n. n) 4 = [0; 1; 2; 3]
Failure
GENLIST_CONV tm fails if tm is not of the form described above, or
if any call conv “f i” fails.
IS_EL_CONV
IS_EL_CONV
listLib.IS_EL_CONV : conv -> conv
Computes by inference the result of testing whether a list contains a certain element.
IS_EL_CONV takes a conversion conv and a term tm in the following
form:
IS_EL x [x0;...xn]
It returns the theorem
|- IS_EL x [x0;...xn] = F
if for every xi occurred in the list, conv “x = xi” returns a
theorem |- P xi = F, otherwise, if for at least one xi, evaluating
conv “P xi” returns the theorem |- P xi = T, then it returns the
theorem
|- IS_EL P [x0;...xn] = T
Failure
IS_EL_CONV conv tm fails if tm is not of the form described above,
or failure occurs when evaluating conv “x = xi” for some xi.
Example
Evaluating
IS_EL_CONV bool_EQ_CONV “IS_EL T [T;F;T]”;
returns the following theorem:
|- IS_EL($= T)[F;F] = F
See also
listLib.SOME_EL_CONV,
listLib.ALL_EL_CONV,
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
LAST_CONV
LAST_CONV
listLib.LAST_CONV : conv
Computes by inference the result of taking the last element of a list.
For any object language list of the form “[x0;...x(n-1)]” , the result
of evaluating
LAST_CONV “LAST [x0;...;x(n-1)]”
is the theorem
|- LAST [x0;...;x(n-1)] = x(n-1)
Failure
LAST_CONV tm fails if tm is an empty list.
LASTN_CONV
LASTN_CONV
listLib.LASTN_CONV : conv
Computes by inference the result of taking the last n elements of a list.
For any object language list of the form “[x0;...x(n-k);...;x(n-1)]” ,
the result of evaluating
LASTN_CONV “LASTN k [x0;...x(n-k);...;x(n-1)]”
is the theorem
|- LASTN k [x0;...;x(n-k);...;x(n-1)] = [x(n-k);...;x(n-1)]
Failure
LASTN_CONV tm fails if tm is not of the form described above, or k
is greater than the length of the list.
LENGTH_CONV
LENGTH_CONV
listLib.LENGTH_CONV : conv
Computes by inference the length of an object-language list.
For any object language list of the form “[x1;x2;...;xn]”, where x1,
x2, ..., xn are arbitrary terms of the same type, the result of
evaluating
LENGTH_CONV “LENGTH [x1;x2;...;xn]”
is the theorem
|- LENGTH [x1;x2;...;xn] = n
where n is the numeral constant that denotes the length of the list.
Failure
LENGTH_CONV tm fails if tm is not of the form
“LENGTH [x1;x2;...;xn]” or “LENGTH []”.
list_FOLD_CONV
list_FOLD_CONV
listLib.list_FOLD_CONV : thm -> conv -> conv
Computes by inference the result of applying a function to the elements of a list.
Evaluating list_FOLD_CONV fthm conv tm returns a theorem
|- CONST x0' ... xi' ... xn' = tm'
The first argument fthm should be a theorem of the form
|- !x0 ... xi ... xn. CONST x0 ... xi ... xn = FOLD[LR] f e xi
where FOLD[LR] means either FOLDL or FOLDR. The last argument tm
is a term of the following form:
CONST x0' ... xi' ... xn'
where xi' is a concrete list. list_FOLD_CONV first instantiates the
input theorem using tm. It then calls either FOLDL_CONV or
FOLDR_CONV with the user supplied conversion conv on the right-hand
side.
Failure
list_FOLD_CONV fthm conv tm fails if fthm or tm is not of the form
described above, or if they do not agree, or the call to FOLDL_CONV OR
FOLDR_CONV fails.
This function is used to implement conversions for logical constants
which can be expressed in terms of the fold operators. For example, the
constant SUM can be expressed in terms of FOLDR as in the following
theorem:
|- !l. SUM l = FOLDR $+ 0 l
The conversion for SUM, SUM_CONV can be implemented as
load_library_in_place num_lib;
val SUM_CONV =
list_FOLD_CONV (theorem "list" "SUM_FOLDR") Num_lib.ADD_CONV;
Then, evaluating SUM_CONV “SUM [0;1;2;3]” will return the following
theorem:
|- SUM [0;1;2;3] = 6
See also
listLib.FOLDL_CONV,
listLib.FOLDR_CONV
LIST_INDUCT_TAC
LIST_INDUCT_TAC
listLib.LIST_INDUCT_TAC : tactic
Performs tactical proof by structural induction on lists.
LIST_INDUCT_TAC reduces a goal !l.P[l], where l ranges over lists,
to two subgoals corresponding to the base and step cases in a proof by
structural induction on l. The induction hypothesis appears among the
assumptions of the subgoal for the step case. The specification of
LIST_INDUCT_TAC is:
A ?- !l. P
===================================================== LIST_INDUCT_TAC
A |- P[NIL/l] A u {{P[l'/l]}} ?- !h. P[CONS h l'/l]
where l' is a primed variant of l that does not appear free in the
assumptions A (usually, l' is just l). When LIST_INDUCT_TAC is
applied to a goal of the form !l.P, where l does not appear free in
P, the subgoals are just A ?- P and A u {{P}} ?- !h.P.
Failure
LIST_INDUCT_TAC g fails unless the conclusion of the goal g has the
form !l.t, where the variable l has type (ty)list for some type
ty.
See also
listLib.EQ_LENGTH_INDUCT_TAC,
listLib.EQ_LENGTH_SNOC_INDUCT_TAC,
listLib.SNOC_INDUCT_TAC
MAP2_CONV
MAP2_CONV
listLib.MAP2_CONV : conv -> conv
Compute the result of mapping a binary function down two lists.
The function MAP2_CONV is a conversion for computing the result of
mapping a binary function f:ty1->ty2->ty3 down two lists
“[l11;...;l1n]” whose elements are of type ty1 and “[l21;...;l2n]”
whose elements are of type ty2. The lengths of the two lists must be
identical. The first argument to MAP2_CONV is expected to be a
conversion that computes the result of applying the function f to a
pair of corresponding elements of these lists. When applied to a term
“f l1i l2i”, this conversion should return a theorem of the form
|- (f l1i l2i) = ri, where ri is the result of applying the function
f to the elements l1i and l2i.
Given an appropriate conv, the conversion MAP2_CONV conv takes a
term of the form “MAP2 f [l11;...;dl2tn] [l21;...;l2n]” and returns
the theorem
|- MAP2 f [l11;...;l1n] [l21;...;l2n] = [r1;...;rn]
where conv “f l1i l2i” returns |- (f l1i l2i) = ri for i from 1
to n.
Example
The following is a very simple example in which the corresponding elements from the two lists are summed to form the resulting list:
- load_library_in_place num_lib;
- MAP2_CONV Num_lib.ADD_CONV “MAP2 $+ [1;2;3] [1;2;3]”;
|- MAP2 $+ [1;2;3] [1;2;3] = [2;4;6]
Failure
MAP2_CONV conv fails if applied to a term not of the form described
above. An application of MAP2_CONV conv to a term
“MAP2 f [l11;...;l1n] [l21;...;l2n]” fails unless for all i where
1<=i<=n evaluating conv “f l1i l2i” returns |- (f l1i l2i) = ri
for some ri.
See also
MAP_CONV
MAP_CONV
listLib.MAP_CONV : conv -> conv
Compute the result of mapping a function down a list.
The function MAP_CONV is a parameterized conversion for computing the
result of mapping a function f:ty1->ty2 down a list “[t1;...;tn]” of
elements of type ty1. The first argument to MAP_CONV is expected to
be a conversion that computes the result of applying the function f to
an element of this list. When applied to a term “f ti”, this
conversion should return a theorem of the form |- (f ti) = ri, where
ri is the result of applying the function f to the element ti.
Given an appropriate conv, the conversion MAP_CONV conv takes a term
of the form “MAP f [t1;...;tn]” to the theorem
|- MAP f [t1;...;tn] = [r1;...;rn]
where conv “f ti” returns |- (f ti) = ri for i from 1 to n.
Example
The following is a very simple example in which no computation is done for applications of the function being mapped down a list:
- MAP_CONV ALL_CONV “MAP SUC [1;2;1;4]”;
|- MAP SUC[1;2;1;4] = [SUC 1;SUC 2;SUC 1;SUC 4]
The result just contains applications of SUC, since the supplied
conversion ALL_CONV does no evaulation.
We now construct a conversion that maps SUC n for any numeral n to
the numeral standing for the successor of n:
- fun SUC_CONV tm =
let val n = string_to_int(#Name(dest_const(rand tm)))
val sucn = mk_const{{Name =int_to_string(n+1), Ty=(==`:num`==)}}
in
SYM (num_CONV sucn)
end;
SUC_CONV = - : conv
The result is a conversion that inverts num_CONV:
- num_CONV “4”;
|- 4 = SUC 3
- SUC_CONV “SUC 3”;
|- SUC 3 = 4
The conversion SUC_CONV can then be used to compute the result of
mapping the successor function down a list of numerals:
- MAP_CONV SUC_CONV “MAP SUC [1;2;1;4]”;
|- MAP SUC[1;2;1;4] = [2;3;2;5]
Failure
MAP_CONV conv fails if applied to a term not of the form
“MAP f [t1;...;tn]”. An application of MAP_CONV conv to a term
“MAP f [t1;...;tn]” fails unless for all ti in the list
[t1;...;tn], evaluating conv “f ti” returns |- (f ti) = ri for
some ri.
OR_EL_CONV
OR_EL_CONV
listLib.OR_EL_CONV : conv
Computes by inference the result of taking the disjunction of the elements of a boolean list.
For any object language list of the form “[x1;x2;...;xn]”, where x1,
x2, ..., xn are boolean expressions, the result of evaluating
OR_EL_CONV “OR_EL [x1;x2;...;xn]”
is the theorem
|- OR_EL [x1;x2;...;xn] = b
where b is either the boolean constant that denotes the disjunction of
the elements of the list, or a disjunction of those xi that are not
boolean constants.
Example
> listLib.OR_EL_CONV “OR_EL [T;F;F;T]”;
val it = ⊢ OR_EL [T; F; F; T] ⇔ T: thm
> listLib.OR_EL_CONV “OR_EL [F;F;F]”;
val it = ⊢ OR_EL [F; F; F] ⇔ F: thm
> listLib.OR_EL_CONV “OR_EL [F;x;y]”;
val it = ⊢ OR_EL [F; x; y] ⇔ x ∨ y: thm
> listLib.OR_EL_CONV “OR_EL [x;T;y]”;
val it = ⊢ OR_EL [x; T; y] ⇔ T: thm
Failure
OR_EL_CONV tm fails if tm is not of the form described above.
REPLICATE_CONV
REPLICATE_CONV
listLib.REPLICATE_CONV : conv
Computes by inference the result of replicating an element a given number of times to form a list.
For an arbitrary expression x and numeral constant n, the result of
evaluating
REPLICATE_CONV “REPLICATE n x”
is the theorem
|- REPLICATE n x = [x;x;...;x]
where the list[x;x;...;x] is of length n.
Example
Evaluating REPLICATE_CONV “REPLICATE 3 [0;1;2;3]” will return the
following theorem:
|- REPLICATE 3 [0;1;2;3] = [[0;1;2;3]; [0;1;2;3]; [0;1;2;3]]
Failure
REPLICATE_CONV tm fails if tm is not of the form described above.
REVERSE_CONV
REVERSE_CONV
listLib.REVERSE_CONV : conv
Computes by inference the result of reversing a list.
REVERSE_CONV takes a term tm in the following form:
REVERSE [x0;...xn]
It returns the theorem
|- REVERSE [x0;...xn] = [xn;...x0]
where the right-hand side is the list in the reverse order.
Failure
REVERSE_CONV tm fails if tm is not of the form described above.
Example
Evaluating
REVERSE_CONV “REVERSE [0;1;2;3;4]”;
returns the following theorem:
|- REVERSE [0;1;2;3;4] = [4;3;2;1;0]
See also
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
SCANL_CONV
SCANL_CONV
listLib.SCANL_CONV : conv -> conv
Computes by inference the result of applying a function to the elements of a list.
SCANL_CONV takes a conversion conv and a term tm in the following
form:
SCANL f e0 [x1;...xn]
It returns the theorem
|- SCANL f e0 [x1;...xn] = [e0; e1; ...;en]
where ei is the result of applying the function f to the result of
the previous iteration and the current element, i.e.,
ei = f e(i-1) xi. The iteration starts from the left-hand side (the
head) of the list. The user supplied conversion conv is used to derive
a theorem
|- f e(i-1) xi = ei
which is used in the next iteration.
Failure
SCANL_CONV conv tm fails if tm is not of the form described above,
or failure occurs when evaluating conv “f e(i-1) xi”.
Example
To sum the elements of a list and save the result at each step, one can
use SCANL_CONV with ADD_CONV from the library num_lib.
- load_library_in_place num_lib;
- SCANL_CONV Num_lib.ADD_CONV “SCANL $+ 0 [1;2;3]”;
|- SCANL $+ 0[1;2;3] = [0;1;3;6]
In general, if the function f is an explicit lambda abstraction
(\x x'. t[x,x']), the conversion should be in the form
((RATOR_CONV BETA_CONV) THENC BETA_CONV THENC conv'))
where conv' applied to t[x,x'] returns the theorem
|-t[x,x'] = e''.
See also
listLib.SCANR_CONV,
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
SCANR_CONV
SCANR_CONV
listLib.SCANR_CONV : conv -> conv
Computes by inference the result of applying a function to the elements of a list.
SCANR_CONV takes a conversion conv and a term tm in the following
form:
SCANR f e0 [xn;...;x1]
It returns the theorem
|- SCANR f e0 [xn;...;x1] = [en; ...;e1;e0]
where ei is the result of applying the function f to the result of
the previous iteration and the current element, i.e.,
ei = f e(i-1) xi. The iteration starts from the right-hand side (the
tail) of the list. The user supplied conversion conv is used to derive
a theorem
|- f e(i-1) xi = ei
which is used in the next iteration.
Failure
SCANR_CONV conv tm fails if tm is not of the form described above,
or failure occurs when evaluating conv “f e(i-1) xi”.
Example
To sum the elements of a list and save the result at each step, one can
use SCANR_CONV with ADD_CONV from the library num_lib.
- load_library_in_place num_lib;
- SCANR_CONV Num_lib.ADD_CONV “SCANR $+ 0 [1;2;3]”;
|- SCANR $+ 0[1;2;3] = [6;5;3;0]
In general, if the function f is an explicit lambda abstraction
(\x x'. t[x,x']), the conversion should be in the form
((RATOR_CONV BETA_CONV) THENC BETA_CONV THENC conv'))
where conv' applied to t[x,x'] returns the theorem
|-t[x,x'] = e''.
See also
listLib.SCANL_CONV,
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
SEG_CONV
SEG_CONV
listLib.SEG_CONV : conv
Computes by inference the result of taking a segment of a list.
For any object language list of the form “[x0;...x(n-1)]” , the result
of evaluating
SEG_CONV “SEG m k [x0;...;x(n-1)]”
is the theorem
|- SEG m k [x0;...;x(n-1)] = [xk;...;x(m+k-1)]
Failure
SEG_CONV tm fails if tm is not in the form described above or the
indexes m and k are not in the correct range, i.e., m + k <= n.
Example
Evaluating the expression
SEG_CONV “SEG 2 3[0;1;2;3;4;5]”;
returns the following theorem
|- SEG 2 3[0;1;2;3;4;5] = [3;4]
See also
listLib.FIRSTN_CONV,
listLib.LASTN_CONV,
listLib.BUTFIRSTN_CONV,
listLib.BUTLASTN_CONV,
listLib.LAST_CONV,
listLib.BUTLAST_CONV
SNOC_CONV
SNOC_CONV
listLib.SNOC_CONV : conv
Computes by inference the result of adding an element to the tail end of a list.
SNOC_CONV takes a term tm in the following form:
SNOC x [x0;...xn]
It returns the theorem
|- SNOC x [x0;...xn] = [x0;...xn;x]
where the right-hand side is the list in the canonical form, i.e.,
constructed with only the constructor CONS.
Failure
SNOC_CONV tm fails if tm is not of the form described above.
Example
Evaluating
SNOC_CONV “SNOC 5[0;1;2;3;4]”;
returns the following theorem:
|- SNOC 5[0;1;2;3;4] = [0;1;2;3;4;5]
See also
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
SNOC_INDUCT_TAC
SNOC_INDUCT_TAC
listLib.SNOC_INDUCT_TAC : tactic
Performs tactical proof by structural induction on lists.
SNOC_INDUCT_TAC reduces a goal !l.P[l], where l ranges over lists,
to two subgoals corresponding to the base and step cases in a proof by
structural induction on l from the tail end. The induction hypothesis
appears among the assumptions of the subgoal for the step case. The
specification of SNOC_INDUCT_TAC is:
A ?- !l. P
===================================================== SNOC_INDUCT_TAC
A |- P[NIL/l] A u {{P[l'/l]}} ?- !x. P[SNOC x l'/l]
where l' is a primed variant of l that does not appear free in the
assumptions A (usually, l' is just l). When SNOC_INDUCT_TAC is
applied to a goal of the form !l.P, where l does not appear free in
P, the subgoals are just A ?- P and A u {{P}} ?- !h.P.
Failure
SNOC_INDUCT_TAC g fails unless the conclusion of the goal g has the
form !l.t, where the variable l has type (ty)list for some type
ty.
See also
listLib.EQ_LENGTH_INDUCT_TAC,
listLib.EQ_LENGTH_SNOC_INDUCT_TAC,
listLib.LIST_INDUCT_TAC
SOME_EL_CONV
SOME_EL_CONV
listLib.SOME_EL_CONV : conv -> conv
Computes by inference the result of applying a predicate to the elements of a list.
SOME_EL_CONV takes a conversion conv and a term tm of the
following form:
SOME_EL P [x0;...xn]
It returns the theorem
|- SOME_EL P [x0;...xn] = F
if for every xi occurred in the list, conv “P xi” returns a theorem
|- P xi = F, otherwise, if for at least one xi, evaluating
conv “P xi” returns the theorem |- P xi = T, then it returns the
theorem
|- SOME_EL P [x0;...xn] = T
Failure
SOME_EL_CONV conv tm fails if tm is not of the form described above,
or failure occurs when evaluating conv “P xi” for some xi.
Example
Evaluating
SOME_EL_CONV bool_EQ_CONV “SOME_EL ($= T) [T;F;T]”;
returns the following theorem:
|- SOME_EL($= T)[T;F;T] = T
In general, if the predicate P is an explicit lambda abstraction
(\x. P x), the conversion should be in the form
(BETA_CONV THENC conv')
See also
listLib.ALL_EL_CONV,
listLib.IS_EL_CONV,
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
SUM_CONV
SUM_CONV
listLib.SUM_CONV : conv
Computes by inference the result of summing the elements of a list.
For any object language list of the form “[x1;x2;...;xn]”, where x1,
x2, ..., xn are numeral constants, the result of evaluating
SUM_CONV “SUM [x1;x2;...;xn]”
is the theorem
|- SUM [x1;x2;...;xn] = n
where n is the numeral constant that denotes the sum of the elements
of the list.
Example
Evaluating SUM_CONV “SUM [0;1;2;3]” will return the following theorem:
|- SUM [0;1;2;3] = 6
Failure
SUM_CONV tm fails if tm is not of the form described above.
See also
listLib.FOLDL_CONV,
listLib.FOLDR_CONV,
listLib.list_FOLD_CONV
dest_cons
dest_cons
listSyntax.dest_cons : term -> term * term
Breaks apart a 'CONS pair' into head and tail.
dest_cons is a term destructor for 'CONS pairs'. When applied to a
term representing a nonempty list [t;t1;...;tn] (which is equivalent
to CONS t [t1;...;tn]), it returns the pair of terms
(t, [t1;...;tn]).
Failure
Fails if the term is an empty list.
See also
listSyntax.mk_cons,
listSyntax.is_cons,
listSyntax.mk_list,
listSyntax.dest_list,
listSyntax.is_list
dest_list
dest_list
listSyntax.dest_list : term -> term list * hol_type
Iteratively breaks apart a list term.
dest_list is a term destructor for lists:
dest_list ``[t1;...;tn]:ty list`` returns ([t1,...,tn], ty).
Failure
Fails if the term is not a list.
See also
listSyntax.mk_list,
listSyntax.is_list,
listSyntax.mk_cons,
listSyntax.dest_cons,
listSyntax.is_cons
is_cons
is_cons
listSyntax.is_cons : (term -> bool)
Tests a term to see if it is an application of CONS.
is_cons returns true of a term representing a non-empty list.
Otherwise it returns false.
Failure
Never fails.
See also
listSyntax.mk_cons,
listSyntax.dest_cons,
listSyntax.mk_list,
listSyntax.dest_list,
listSyntax.is_list
is_list
is_list
listSyntax.is_list : (term -> bool)
Tests a term to see if it is a list.
is_list returns true of a term representing a list. Otherwise it
returns false.
Failure
Never fails.
See also
listSyntax.mk_list,
listSyntax.dest_list,
listSyntax.mk_cons,
listSyntax.dest_cons,
listSyntax.is_cons
mk_cons
mk_cons
listSyntax.mk_cons : term * term -> term
Constructs a CONS pair.
mk_cons (``t``, ``[t1;...;tn]``) returns
``[t;t1;...;tn]``.
Failure
Fails if the second element is not a list or if the first element is not of the same type as the elements of the list.
See also
listSyntax.dest_cons,
listSyntax.is_cons,
listSyntax.mk_list,
listSyntax.dest_list,
listSyntax.is_list
mk_list
mk_list
listSyntax.mk_list : term list * hol_type -> term
Constructs an object-level (HOL) list from an ML list of terms.
mk_list ([t1, ..., tn], ty) returns [t1;...;tn]:ty list. The type
argument is required so that empty lists can be constructed.
Failure
Fails if any term in the list is not of the type specified as the second argument.
See also
listSyntax.dest_list,
listSyntax.is_list,
listSyntax.mk_cons,
listSyntax.dest_cons,
listSyntax.is_cons
MK_USING
MK_USING
markerSyntax.MK_USING : thm -> thm
Encodes a theorem so it can be ASSUME_TAC-ed into a goal.
A call to MK_USING th encodes th in such a way that it can safely be
the argument to ASSUME_TAC, and detectable by other tactics operating
on the resulting goal as a theorem that might be worthy of notice.
Failure
Fails if the theorem has no hypotheses, is polymorphic, and cannot be
found by reverse lookup in the theorem database (using DB.revlookup).
See also
ASM_MESON_TAC
ASM_MESON_TAC
mesonLib.ASM_MESON_TAC : thm list -> tactic
Performs first order proof search to prove the goal, using the assumptions and the theorems given.
ASM_MESON_TAC is identical in behaviour to MESON_TAC except that it
uses the assumptions of a goal as well as the provided theorems.
Failure
ASM_MESON_TAC fails if it can not find a proof of the goal with depth
less than or equal to the mesonLib.max_depth value.
See also
mesonLib.GEN_MESON_TAC,
mesonLib.MESON_TAC
GEN_MESON_TAC
GEN_MESON_TAC
mesonLib.GEN_MESON_TAC : int -> int -> int -> thm list -> tactic
Performs first order proof search to prove the goal, using both the given theorems and the assumptions in the search.
GEN_MESON_TAC is the function which provides the underlying
implementation of the model elimination solver used by both MESON_TAC
and ASM_MESON_TAC. The three integer parameters correspond to various
ways in which the search can be tuned.
The first is the minimum depth at which to search. Setting this to a
number greater than zero can save time if its clear that there will not
be a proof of such a small depth. ASM_MESON_TAC and MESON_TAC always
use a value of 0 for this parameter.
The second is the maximum depth to which to search. Setting this low
will stop the search taking too long, but may cause the engine to miss
proofs it would otherwise find. The setting of this variable for
ASM_MESON_TAC and MESON_TAC is done through the reference variable
mesonLib.max_depth. This is set to 30 by default, but most proofs do
not need anything like this depth.
The third parameter is the increment used to increase the depth of search done by the proof search procedure.
The approach used is iterative deepening, so with a call to
GEN_MESON_TAC mn mx inc
the algorithm looks for a proof of depth mn, then for one of depth
mn + inc, then at depth mn + 2 * inc etc. Once the depth gets
greater than mx, the proof search stops.
Failure
GEN_MESON_TAC fails if it searches to a depth equal to the second
integer parameter without finding a proof. Shouldn't fail otherwise.
The construction of tailored versions of MESON_TAC and
ASM_MESON_TAC.
See also
mesonLib.ASM_MESON_TAC,
mesonLib.MESON_TAC
MESON_TAC
MESON_TAC
mesonLib.MESON_TAC : thm list -> tactic
Performs first order proof search to prove the goal, using the given theorems as additional assumptions in the search.
MESON_TAC performs first order proof using the model elimination
algorithm. This algorithm is semi-complete for pure first order logic.
It makes special provision for handling polymorphic and higher-order
values, and often this is sufficient. It does not handle conditional
expressions at all, and these should be eliminated before MESON_TAC is
applied.
MESON_TAC works by first converting the problem instance it is given
into an internal format where it can do proof search efficiently,
without having to do proof search at the level of HOL inference. If a
proof is found, this is translated back into applications of HOL
inference rules, proving the goal.
The feedback given by MESON_TAC is controlled by the level of the
integer reference variable mesonLib.chatting. At level zero, nothing
is printed. At the default level of one, a line of dots is printed out
as the proof progresses. At all other values for this variable,
MESON_TAC is most verbose. If the proof is progressing quickly then it
is often worth waiting for it to go quite deep into its search. Once a
proof slows down, it is not usually worth waiting for it after it has
gone through a few (no more than five or six) levels. (At level one, a
"level" is represented by the printing of a single dot.)
Failure
MESON_TAC fails if it searches to a depth equal to the contents of the
reference variable mesonLib.max_depth (set to 30 by default, but
changeable by the user) without finding a proof. Shouldn't fail
otherwise.
MESON_TAC can only progress the goal to a successful proof of the
(whole) goal or not at all. In this respect it differs from tactics such
as simplification and rewriting. Its ability to solve existential goals
and to make effective use of transitivity theorems make it a
particularly powerful tactic.
Comments
The assumptions of a goal are ignored when MESON_TAC is applied. To
include assumptions use ASM_MESON_TAC.
See also
mesonLib.ASM_MESON_TAC,
mesonLib.GEN_MESON_TAC
random_tnn
random_tnn
mlTreeNeuralNetwork.random_tnn : (term * int list) list -> tnn
Creates a random tree neural network (TNN) with the precised dimensions for each neural network operators.
To create an initial TNN, the user first needs to gather all operators
(constants or variables) appearing in the examples. Then, given an
embedding dimension d, for each operator f with arity a the list
of dimensions of is to be defined as [a x d,u1,...,uk,d]. The natural
numbers u1,...,uk are sizes of the intermediate layers that can be
freely chosen by the user. In the case of a head operator h, the input
dimension is to be d and the output dimension is to be the length of
the objective l.
Failure
Fails if the list of dimensions is empty.
Example
> val tnn =
mlTreeNeuralNetwork.random_tnn [(``h: bool -> bool``,[4,10,1]),(``$~``,[4,8,4]),(F,[0,4])];
val tnn = <Redblackmap(3)>: mlTreeNeuralNetwork.tnn
Comments
Precising a list of dimensions of length 1 results in an unusable empty neural network for this operator.
See also
train_tnn
train_tnn
mlTreeNeuralNetwork.train_tnn : schedule -> tnn -> tnnex * tnnex -> tnn
Train a tree neural network (TNN) on a set of examples via backpropagation to minimize mean square error.
Hyperparameters such as batch size, learning rate and number of epochs
can be set in the schedule arguments. The initial TNN can be constructed
by calling mlTreeNeuralNetwork.random_tnn. Examples consists of a term
t and a list l. The term t is expected to be lambda-free with each
operator appearing with a unique arity. The list l is expected to be a
list of real numbers between 0 and 1. In the case of a simple objective
each example (t,l) is to be written as [(h(t),l)] where h is a
variable representing the head network. For multiple objectives, one can
write [(h1(t),l1),...,(hn(t),ln)] for a single example. The created
list of examples is to be split into a training set and a test set
(possibly empty).
Failure
Fails when dimension constraints are not respected (see
mlTreeNeuralNetwork.random_tnn) or a variable/constant from the
examples is not defined in the TNN.
Comments
See the end of the file
src/AI/machine_learning/mlTreeNeuralNetwork.sml for a toy example.
See also
mlTreeNeuralNetwork.random_tnn
all_monads
all_monads
monadsyntax.all_monads :
unit ->
(string *
{bind : term, unit : term, ignorebind : term option,
choice : term option, fail : term option, guard : term option}) list
Lists all declared monads
Returns a list of all declared monad types. These can be enabled with
calls to enable_monad.
Failure
Never fails.
Example
> monadsyntax.all_monads();
val it =
[("list",
{bind = “LIST_BIND”, choice = SOME (“$++”), fail = SOME (“[]”), guard =
SOME (“LIST_GUARD”), ignorebind = SOME (“LIST_IGNORE_BIND”), unit =
“λx. [x]”}),
("option",
{bind = “OPTION_BIND”, choice = SOME (“OPTION_CHOICE”), fail =
SOME (“NONE”), guard = SOME (“OPTION_GUARD”), ignorebind =
SOME (“OPTION_IGNORE_BIND”), unit = “SOME”})]:
(string * monadsyntax.monadinfo) list
See also
monadsyntax.declare_monad,
monadsyntax.enable_monad
declare_monad
declare_monad
monadsyntax.declare_monad :
string * { bind : term, unit : term, ignorebind : term option,
choice : term option, fail : term option, guard : term option }
->
unit
Declares a monad type for which the do/od syntax can be used.
A call to declare_monad(mname, minfo) alters the internal "monad
database" so that a subsequent call to enable_monad mname will cause
do/od syntax to try to use the terms in minfo as interpretations of
that syntax. The only compulsory values are the unit and bind
values, which should have types conforming to the pattern :α M and
:α -> β M respectively. For example, the list monad would have M
instantiated by the pattern :_ list, while the reader monad would have
M instantiated by the pattern :'env -> _.
The ignorebind field allows the user to provide a specific constant to
interpret a bind where the second argument ignores the value. If this
is not provided, then syntax such as do M1; M2; od will be interpreted
as bind M1 (K M2), where K is the constant combinator.
The remaining fields are used when the monad has a notion of failure.
For example, the option monad uses NONE as the appropriate value for
fail. The choice term should be of type :α M -> α M -> α M, and
should return the first value if it is not a failure, or otherwise use
the second argument. The supported syntax for choice is ++.
Finally, the guard field should be a term of type :bool -> unit M.
It is rendered as assert b with b a boolean value. If b is true,
the monad "returns" the unit value; if b is false the monad fails.
The information declared with a call to declare_monad is exported with
the current theory and is thus available to descendent theories.
Failure
Never fails. However, the terms present in the monad-information record must have appropriate types if strange type-checking errors on subsequent uses of the do/od syntax are to be avoided.
Example
A set monad could be declared:
> monadsyntax.declare_monad("set", {
unit = “λa. {a}”, bind = “λs f. BIGUNION (IMAGE f s)”,
ignorebind = NONE,
fail = SOME “{}”, guard = SOME “λb. if b then {()} else {}”,
choice = SOME “$UNION”
});
val it = (): unit
Comments
This function does not even care if the constants have the right respective types; it certainly doesn't care if the constants satisfy the monadic axioms.
See also
monadsyntax.all_monads,
monadsyntax.enable_monad
enable_monad
enable_monad
monadsyntax.enable_monad : string -> unit
Enables a particular monadic type for use with do/od syntax.
A call to enable_monad mname, where mname is an SML value of type
string, enables the stored information about monad mname to govern
the interpretation of the do/od syntax. If multiple monads are enabled,
normal overloading resolution will decide between them.
Failure
Fails if mname is not the name of a stored monad in the internal
database (which can be examined with a call to
monadsyntax.all_monads(). Will have little effect if monad syntax has
not been generally enabled with a prior call to enable_monadsyntax.
Example
In what follows, oHD is the function which maps a non-empty list to
SOME applied to that list's first element, and the empty list to
NONE. The ++ is the monad choice function (the option monad has a
notion of failure). Thus, the function below that is bound to SML
variable f is one that either increments the first element of a list
and returns that value, or returns 0.
> monadsyntax.enable_monadsyntax(); monadsyntax.enable_monad "option";
val it = (): unit
val it = (): unit
> val f = “λl. do x <- oHD l; return (x + 1); od ++ return 0”
val f = “λl. do x <- oHD l; SOME (x + 1) od ⧺ SOME 0”: term
> EVAL “^f [3; 10]”;
val it = ⊢ (λl. do x <- oHD l; SOME (x + 1) od ⧺ SOME 0) [3; 10] = SOME 4:
thm
> EVAL “^f []”;
val it = ⊢ (λl. do x <- oHD l; SOME (x + 1) od ⧺ SOME 0) [] = SOME 0: thm
Note how the return keyword is not printed as such by the parser; it
would be too confusing if all occurrences of common functions such as
SOME were printed as return.
Comments
As with other parsing and printing functions, there is a
temp_enable_monad function whose changes to the parser and printer do
not persist to descendent theories.
See also
monadsyntax.all_monads,
monadsyntax.declare_monad,
monadsyntax.enable_monadsyntax
enable_monadsyntax
enable_monadsyntax
monadsyntax.enable_monadsyntax : unit -> unit
Enables parsing and printing of monadic do/od syntax.
A call to enable_monadsyntax() alters the parser and pretty-printer to
support the do/od syntax for writing monadic values. This call should be
followed by calls to enable_monad (or weak_enable_monad) so that the
do/od syntax can be linked to actual monadic types.
Failure
Never fails.
Example
This first example gives a clear demonstration of the nature of the syntactic translation that the monad syntax implements because there is no specific enabled monad for the syntax to map to:
> monadsyntax.enable_monadsyntax();
val it = () : unit
> “do M1 ; M2; od”;
val it = “monad_unitbind M1 M2” : term;
> “do v <- M1; w <- M2 v 3; return (v + w); od”;
val it = “monad_bind M1 (λv. monad_bind (M2 v 3) (λw. return (v + w)))”
: term
The monad_bind, monad_unitbind and return terms above are
variables that would be instantiated with the appropriate terms given
the available choices of enabled monads.
See also
monadsyntax.all_monads,
monadsyntax.enable_monad
CNF_CONV
CNF_CONV
normalForms.CNF_CONV : conv
Converts a formula into Conjunctive Normal Form (CNF).
Given a formula consisting of truths, falsities, conjunctions,
disjunctions, negations, equivalences, conditionals, and universal and
existential quantifiers, CNF_CONV will convert it to the canonical
form:
?a_1 ... a_k.
(!v_1 ... v_m1. P_1 \/ ... \/ P_n1) /\
... /\
(!v_1 ... v_mp. P_1 \/ ... \/ P_np)
The P_ij are literals: possibly-negated atoms. In first-order logic an
atom is a formula consisting of a top-level relation symbol applied to
first-order terms: function symbols and variables. In higher-order logic
there is no distinction between formulas and terms, so the concept of
atom is not well-formed. Note also that the a_i existentially bound
variables may be functions, as a result of Skolemization.
Failure
CNF_CONV should never fail.
Example
> normalForms.CNF_CONV ``!x. P x ==> ?y z. Q y \/ ~?z. P z /\ Q z``;
val it =
⊢ (∀x. P x ⇒ ∃y z. Q y ∨ ¬∃z. P z ∧ Q z) ⇔
∃y. ∀x z. ¬Q z ∨ ¬P z ∨ Q (y x) ∨ ¬P x: thm
Example
> normalForms.CNF_CONV ``~(~(x = y) = z) = ~(x = ~(y = z))``;
val it = ⊢ (((x ⇎ y) ⇎ z) ⇔ (x ⇎ (y ⇎ z))) ⇔ T: thm
ARITH_CONV
ARITH_CONV
numLib.ARITH_CONV : conv
Partial decision procedure for a subset of linear natural number arithmetic.
ARITH_CONV is a partial decision procedure for Presburger natural
arithmetic. Presburger natural arithmetic is the subset of arithmetic
formulae made up from natural number constants, numeric variables,
addition, multiplication by a constant, the relations <, <=, =,
>=, > and the logical connectives ~, /\, \/, ==>, =
(if-and-only-if), ! ('forall') and ? ('there exists'). Products of
two expressions which both contain variables are not included in the
subset, but the functions SUC and PRE which are not normally
included in a specification of Presburger arithmetic are allowed in this
HOL implementation.
ARITH_CONV further restricts the subset as follows: when the formula
has been put in prenex normal form it must contain only one kind of
quantifier, that is the quantifiers must either all be universal
('forall') or all existential. Variables may appear free (unquantified)
provided any quantifiers that do appear in the prenex normal form are
universal; free variables are taken as being implicitly universally
quantified so mixing them with existential quantifiers would violate the
above restriction.
Given a formula in the permitted subset, ARITH_CONV attempts to prove
that it is equal to T (true). For universally quantified formulae the
procedure only works if the formula would also be true of the
non-negative rationals; it cannot prove formulae whose truth depends on
the integral properties of the natural numbers. The procedure is also
incomplete for existentially quantified formulae, but in this case there
is no rule-of-thumb for determining whether the procedure will work.
The function features a number of preprocessors which extend the coverage beyond the subset specified above. In particular, natural number subtraction and conditional statements are allowed. Another permits substitution instances of universally quantified formulae to be accepted. Note that Boolean-valued variables are not allowed.
Failure
The function can fail in two ways. It fails if the argument term is not a formula in the specified subset, and it also fails if it is unable to prove the formula. The failure strings are different in each case. However, the function may announce that it is unable to prove a formula that one would expect it to reject as being outside the subset. This is due to it looking for substitution instances; it has generalised the formula so that the new formula is in the subset but is not valid.
Example
A simple example containing a free variable:
- ARITH_CONV ``m < SUC m``;
> val it = |- m < (SUC m) = T : thm
A more complex example with subtraction and universal quantifiers, and which is not initially in prenex normal form:
- ARITH_CONV
``!m p. p < m ==> !q r. (m < (p + q) + r) ==> ((m - p) < q + r)``;
> val it = |- (!m p. p < m ==> (!q r. m < ((p + q) + r) ==> (m - p) < (q + r))) = T
Two examples with existential quantifiers:
- ARITH_CONV ``?m n. m < n``;
> val it = |- (?m n. m < n) = T
- ARITH_CONV ``?m n. (2 * m) + (3 * n) = 10``;
> val it = |- (?m n. (2 * m) + (3 * n) = 10) = T
An instance of a universally quantified formula involving a conditional statement and subtraction:
- ARITH_CONV
``((p + 3) <= n) ==> (!m. ((m EXP 2 = 0) => (n - 1) | (n - 2)) > p)``;
> val it = |- (p + 3) <= n ==> (!m. ((m EXP 2 = 0) => n - 1 | n - 2) > p) = T
Failure due to mixing quantifiers:
- ARITH_CONV ``!m. ?n. m < n``;
evaluation failed ARITH_CONV -- formula not in the allowed subset
Failure because the truth of the formula relies on the fact that the variables cannot have fractional values:
- ARITH_CONV ``!m n. ~(SUC (2 * m) = 2 * n)``;
evaluation failed ARITH_CONV -- cannot prove formula
See also
Arith.NEGATE_CONV,
Arith.EXISTS_ARITH_CONV,
Arith.FORALL_ARITH_CONV,
Arith.INSTANCE_T_CONV,
Arith.PRENEX_CONV,
Arith.SUB_AND_COND_ELIM_CONV
INDUCT_TAC
INDUCT_TAC
numLib.INDUCT_TAC : tactic
Performs tactical proof by mathematical induction on the natural numbers.
INDUCT_TAC reduces a goal !n.P[n], where n has type num, to two
subgoals corresponding to the base and step cases in a proof by
mathematical induction on n. The induction hypothesis appears among
the assumptions of the subgoal for the step case. The specification of
INDUCT_TAC is:
A ?- !n. P
======================================== INDUCT_TAC
A ?- P[0/n] A u {P} ?- P[SUC n'/n]
where n' is a primed variant of n that does not appear free in the
assumptions A (usually, n' just equals n). When INDUCT_TAC is
applied to a goal of the form !n.P, where n does not appear free in
P, the subgoals are just A ?- P and A u {P} ?- P.
Failure
INDUCT_TAC g fails unless the conclusion of the goal g has the form
!n.t, where the variable n has type num.
LEAST_ELIM_TAC
LEAST_ELIM_TAC
numLib.LEAST_ELIM_TAC : tactic
Eliminates a LEAST term from the current goal.
LEAST_ELIM_TAC searches the goal it is applied to for free sub-terms
involving the LEAST operator, of the form $LEAST P (P will usually
be an abstraction). If such a term is found, the tactic produces a new
goal where instances of the LEAST-term have disappeared. The resulting
goal will require the proof that there exists a value satisfying P,
and that a minimal value satisfies the original goal.
Thus, LEAST_ELIM_TAC can be seen as a higher-order match against the
theorem
|- !P Q.
(?n. P x) /\ (!n. (!m. m < n ==> ~P m) /\ P n ==> Q n) ==>
Q ($LEAST P)
where the new goal is the antecdent of the implication. (This theorem is
LEAST_ELIM, from theory while.)
Failure
The tactic fails if there is no free LEAST-term in the goal.
Example
When applied to the goal
?- (LEAST n. 4 < n) = 5
the tactic LEAST_ELIM_TAC produces
?- (?n. 4 < n) /\ !n. (!m. m < n ==> ~(4 < m)) /\ 4 < n ==> (n = 5)
Comments
This tactic assumes that there is indeed a least number satisfying the
given predicate. If there is not, then the LEAST-term will have an
arbitrary value, and the proof should proceed by showing that the
enclosing predicate Q holds for all possible numbers.
If there are multiple different LEAST-terms in the goal, then
LEAST_ELIM_TAC will pick the first free LEAST-term returned by the
standard find_terms function.
See also
Tactic.DEEP_INTRO_TAC,
Tactic.SELECT_ELIM_TAC
num_CONV
num_CONV
numLib.num_CONV : conv
Equates a non-zero numeral with the form SUC x for some x.
Example
> numLib.num_CONV ``1203``;
val it = ⊢ 1203 = SUC 1202: thm
Failure
Fails if the argument term is not a numeral of type ``:num``, or
if the argument is ``0``.
See also
numLib.SUC_TO_NUMERAL_DEFN_CONV
SUC_TO_NUMERAL_DEFN_CONV
SUC_TO_NUMERAL_DEFN_CONV
numLib.SUC_TO_NUMERAL_DEFN_CONV : conv
Translates equations using SUC n to use numeral constructors instead.
This conversion modifies conjunctions of universally quantified
equations so that any argument terms of the form SUC x on the LHS of
the equations (with x one of the equation's universally quantified
variables), are translated to a form appropriate for rewriting when the
argument term is a numeral.
This procedure uses the following theorem:
|- !f g. (!n. f (SUC n) = g n (SUC n)) =
(!n. f (NUMERAL (BIT1 n)) =
g (NUMERAL (BIT1 n)) (NUMERAL (BIT1 n) - 1)) /\
(!n. f (NUMERAL (BIT2 n)) =
g (NUMERAL (BIT2 n)) (NUMERAL (BIT1 n)))
Example
> CONV_RULE numLib.SUC_TO_NUMERAL_DEFN_CONV arithmeticTheory.FACT;
val it =
⊢ FACT 0 = 1 ∧
(∀n. FACT (NUMERAL (BIT1 n)) =
NUMERAL (BIT1 n) * FACT (NUMERAL (BIT1 n) − 1)) ∧
∀n. FACT (NUMERAL (BIT2 n)) = NUMERAL (BIT2 n) * FACT (NUMERAL (BIT1 n)):
thm
Failure
Fails if the input term is not the conjunction of universally quantified
equations, where there may be just one conjunct, and where equations may
have no quantification at all. Those conjuncts which don't involve terms
of the form SUC x are returned unchanged.
Comments
Useful for translating definitions over numbers (which often involve
SUC terms), into a form that can be used to work with numerals easily.
See also
dest_numeral
dest_numeral
numSyntax.dest_numeral : term -> Arbnum.num
Convert HOL numeral to ML bignum value.
An invocation dest_numeral tm, where tm is a HOL numeral (a literal
of type num), returns the corrresponding ML value of type
Arbnum.num. A numeral is a dyadic positional notation described by the
following BNF:
<numeral> ::= 0 | NUMERAL <bits>
<bits> ::= ZERO | BIT1 (<bits>) | BIT2 (<bits>)
The NUMERAL constant is used as a tag signalling that its argument is
indeed a numeric literal. The ZERO constant is equal to 0, and
BIT1(n) = 2*n + 1 while BIT2(n) = 2*n + 2. This representation
allows asymptotically efficient operations on numeric values.
The system prettyprinter will print a numeral as a string of digits.
Example
> numSyntax.dest_numeral ``1234``;
val it = 1234: num
Failure
Fails if tm is not in the specified format.
See also
numSyntax.mk_numeral,
numSyntax.is_numeral
is_numeral
is_numeral
numSyntax.is_numeral : term -> bool
Check if HOL term is a numeral.
An invocation is_numeral tm, where tm is a HOL term with the
following form
<numeral> ::= 0 | NUMERAL <bits>
<bits> ::= ZERO | BIT1 (<bits>) | BIT2 (<bits>)
returns true; otherwise, false is returned. The NUMERAL constant
is used as a tag signalling that its argument is indeed a numeric
literal. The ZERO constant is equal to 0, and BIT1(n) = 2*n + 1
while BIT2(n) = 2*n + 2. This representation allows asymptotically
efficient operations on numeric values.
The system prettyprinter will print a numeral as a string of digits.
Example
> numSyntax.is_numeral ``1234``;
val it = true: bool
Failure
Fails if tm is not in the specified format.
See also
numSyntax.dest_numeral,
numSyntax.mk_numeral
mk_numeral
mk_numeral
numSyntax.mk_numeral : Arbnum.num -> term
Convert ML bignum value to HOL numeral.
An invocation mk_numeral n, where n is an ML value of type
Arbnum.num returns the corrresponding HOL term.
Example
> Arbnum.fromString "1234";
val it = 1234: num
> numSyntax.mk_numeral it;
val it = “1234”: term
Failure
Never fails.
See also
numSyntax.dest_numeral,
numSyntax.is_numeral
GEN_BETA_CONV
GEN_BETA_CONV
PairedLambda.GEN_BETA_CONV : conv
Beta-reduces single or paired beta-redexes, creating a paired argument if needed.
The conversion GEN_BETA_CONV will perform beta-reduction of simple
beta-redexes in the manner of BETA_CONV, or of tupled beta-redexes in
the manner of PAIRED_BETA_CONV. Unlike the latter, it will force
through a beta-reduction by introducing arbitrarily nested pair
destructors if necessary. The following shows the action for one level
of pairing; others are similar.
GEN_BETA_CONV "(\(x,y). t) p" = t[(FST p)/x, (SND p)/y]
Failure
GEN_BETA_CONV tm fails if tm is neither a simple nor a tupled
beta-redex.
Example
The following examples show the action of GEN_BETA_CONV on tupled
redexes. In the following, it acts in the same way as
PAIRED_BETA_CONV:
- pairLib.GEN_BETA_CONV (Term `(\(x,y). x + y) (1,2)`);
val it = |- (\(x,y). x + y)(1,2) = 1 + 2 : thm
whereas in the following, the operand of the beta-redex is not a pair,
so FST and SND are introduced:
- pairLib.GEN_BETA_CONV (Term `(\(x,y). x + y) numpair`);
> val it = |- (\(x,y). x + y) numpair = FST numpair + SND numpair : thm
The introduction of FST and SND will be done more than once as
necessary:
- pairLib.GEN_BETA_CONV (Term `(\(w,x,y,z). w + x + y + z) (1,triple)`);
> val it =
|- (\(w,x,y,z). w + x + y + z) (1,triple) =
1 + FST triple + FST (SND triple) + SND (SND triple) : thm
See also
Thm.BETA_CONV,
PairedLambda.PAIRED_BETA_CONV
PAIRED_BETA_CONV
PAIRED_BETA_CONV
PairedLambda.PAIRED_BETA_CONV : conv
Performs generalized beta conversion for tupled beta-redexes.
The conversion PAIRED_BETA_CONV implements beta-reduction for certain
applications of tupled lambda abstractions called 'tupled beta-redexes'.
Tupled lambda abstractions have the form \<vs>.tm, where <vs> is an
arbitrarily-nested tuple of variables called a 'varstruct'. For the
purposes of PAIRED_BETA_CONV, the syntax of varstructs is given by:
<vs> ::= (v1,v2) | (<vs>,v) | (v,<vs>) | (<vs>,<vs>)
where v, v1, and v2 range over variables. A tupled beta-redex is
an application of the form (\<vs>.tm) t, where the term t is a
nested tuple of values having the same structure as the varstruct
<vs>. For example, the term:
(\((a,b),(c,d)). a + b + c + d) ((1,2),(3,4))
is a tupled beta-redex, but the term:
(\((a,b),(c,d)). a + b + c + d) ((1,2),p)
is not, since p is not a pair of terms.
Given a tupled beta-redex (\<vs>.tm) t, the conversion
PAIRED_BETA_CONV performs generalized beta-reduction and returns the
theorem
|- (\<vs>.tm) t = t[t1,...,tn/v1,...,vn]
where ti is the subterm of the tuple t that corresponds to the
variable vi in the varstruct <vs>. In the simplest case, the
varstruct <vs> is flat, as in the term:
(\(v1,...,vn).t) (t1,...,tn)
When applied to a term of this form, PAIRED_BETA_CONV returns:
|- (\(v1, ... ,vn).t) (t1, ... ,tn) = t[t1,...,tn/v1,...,vn]
As with ordinary beta-conversion, bound variables may be renamed to
prevent free variable capture. That is, the term
t[t1,...,tn/v1,...,vn] in this theorem is the result of substituting
ti for vi in parallel in t, with suitable renaming of variables to
prevent free variables in t1, ..., tn becoming bound in the result.
Failure
PAIRED_BETA_CONV tm fails if tm is not a tupled beta-redex, as
described above. Note that ordinary beta-redexes are specifically
excluded: PAIRED_BETA_CONV fails when applied to (\v.t)u. For these
beta-redexes, use BETA_CONV, or GEN_BETA_CONV.
Example
The following is a typical use of the conversion:
- PairedLambda.PAIRED_BETA_CONV
(Term `(\((a,b),(c,d)). a + b + c + d) ((1,2),(3,4))`);
> val it = |- (\((a,b),c,d). a+b+c+d) ((1,2),3,4) = 1+2+3+4 : thm
Note that the term to which the tupled lambda abstraction is applied must have the same structure as the varstruct. For example, the following succeeds:
- PairedLambda.PAIRED_BETA_CONV
(Term `(\((a,b),p). a + b) ((1,2),(3+5,4))`);
> val it = |- (\((a,b),p). a + b)((1,2),3 + 5,4) = 1 + 2 : thm
but the following call fails:
- PairedLambda.PAIRED_BETA_CONV
(Term `(\((a,b),(c,d)). a + b + c + d) ((1,2),p)`);
! Uncaught exception:
! HOL_ERR
because p is not a pair.
See also
Thm.BETA_CONV, Conv.BETA_RULE,
Tactic.BETA_TAC,
Drule.LIST_BETA_CONV,
Drule.RIGHT_BETA,
Drule.RIGHT_LIST_BETA
PAIRED_ETA_CONV
PAIRED_ETA_CONV
PairedLambda.PAIRED_ETA_CONV : conv
Performs generalized eta conversion for tupled eta-redexes.
The conversion PAIRED_ETA_CONV generalizes ETA_CONV to eta-redexes
with tupled abstractions.
PAIRED_ETA_CONV \(v1..(..)..vn). f (v1..(..)..vn)
= |- \(v1..(..)..vn). f (v1..(..)..vn) = f
Failure
Fails unless the given term is a paired eta-redex as illustrated above.
Comments
Note that this result cannot be achieved by ordinary eta-reduction because the tupled abstraction is a surface syntax for a term which does not correspond to a normal pattern for eta reduction. Taking the term apart reveals the true form of a paired eta redex:
- dest_comb (Term `\(x:num,y:num). FST (x,y)`)
> val it = (`UNCURRY`, `\x y. FST (x,y)`) : term * term
Example
The following is a typical use of the conversion:
val SELECT_PAIR_EQ = Q.prove
(`(@(x:'a,y:'b). (a,b) = (x,y)) = (a,b)`,
CONV_TAC (ONCE_DEPTH_CONV PairedLambda.PAIRED_ETA_CONV) THEN
ACCEPT_TAC (SYM (MATCH_MP SELECT_AX (REFL (Term `(a:'a,b:'b)`)))));
See also
PairCases_on
PairCases_on
pairLib.PairCases_on : term quotation -> tactic
Recursively split variables of product type.
An application PairCases_on q first parses q in the context of the
goal to obtain v, which should be a variable of product type. Then, it
introduces new variables of the form vn, where n is a number,
representing the atomic components of v after all nested pair
structure is expanded away. Finally, all occurrences of v in the goal
(including in the assumptions) are replaced by the explicit pair
structure (with the new variables at its leaves).
The new variables are numbered from zero according to a depth-first
traversal. (Therefore, they should appear in increasing order from left
to right when the tree is pretty-printed.) Primed variants of the new
numbered variables are used if necessary (i.e. vn already occurs free
in the goal).
Failure
Fails if v is not a variable of product type.
Example
val PairCases_on = pairLib.PairCases_on; g('(x = y) ==> ((x:((bool#bool)#bool#(bool#((bool#bool)#bool))))=z)');
Initial goal:
(x = y) ==> (x = z)
e(DISCH_TAC); OK.. 1 subgoal:
x = z
x = y
e(PairCases_on 'y'); OK.. 1 subgoal:
x = z
x = ((y0,y1),y2,y3,(y4,y5),y6)
e(PairCases_on'x'); OK.. 1 subgoal:
((x0,x1),x2,x3,(x4,x5),x6) = z
((x0,x1),x2,x3,(x4,x5),x6) = ((y0,y1),y2,y3,(y4,y5),y6)
See also
Tactic.FULL_STRUCT_CASES_TAC,
Conv.RENAME_VARS_CONV
AND_PEXISTS_CONV
AND_PEXISTS_CONV
PairRules.AND_PEXISTS_CONV : conv
Moves a paired existential quantification outwards through a conjunction.
When applied to a term of the form (?p. t) /\ (?p. u), where no
variables in p are free in either t or u, AND_PEXISTS_CONV
returns the theorem:
|- (?p. t) /\ (?p. u) = (?p. t /\ u)
Failure
AND_PEXISTS_CONV fails if it is applied to a term not of the form
(?p. t) /\ (?p. u), or if it is applied to a term (?p. t) /\ (?p. u)
in which variables from p are free in either t or u.
See also
Conv.AND_EXISTS_CONV,
PairRules.PEXISTS_AND_CONV,
PairRules.LEFT_AND_PEXISTS_CONV,
PairRules.RIGHT_AND_PEXISTS_CONV
AND_PFORALL_CONV
AND_PFORALL_CONV
PairRules.AND_PFORALL_CONV : conv
Moves a paired universal quantification outwards through a conjunction.
When applied to a term of the form (!p. t) /\ (!p. t), the conversion
AND_PFORALL_CONV returns the theorem:
|- (!p. t) /\ (!p. u) = (!p. t /\ u)
Failure
Fails if applied to a term not of the form (!p. t) /\ (!p. t).
See also
Conv.AND_FORALL_CONV,
PairRules.PFORALL_AND_CONV,
PairRules.LEFT_AND_PFORALL_CONV,
PairRules.RIGHT_AND_PFORALL_CONV
CURRY_CONV
CURRY_CONV
PairRules.CURRY_CONV : conv
Currys an application of a paired abstraction.
Example
> PairRules.CURRY_CONV (Term `(\(x,y). x + y) (1,2)`);
val it = ⊢ (λ(x,y). x + y) (1,2) = (λx y. x + y) 1 2: thm
> PairRules.CURRY_CONV (Term `(\(x,y). x + y) z`);
val it = ⊢ (λ(x,y). x + y) z = (λx y. x + y) (FST z) (SND z): thm
Failure
CURRY_CONV tm fails if tm is not an application of a paired
abstraction.
See also
CURRY_EXISTS_CONV
CURRY_EXISTS_CONV
PairRules.CURRY_EXISTS_CONV : conv
Currys paired existential quantifications into consecutive existential quantifications.
Example
> PairRules.CURRY_EXISTS_CONV (Term `?(x,y). x + y = y + x`);
val it = ⊢ (∃(x,y). x + y = y + x) ⇔ ∃x y. x + y = y + x: thm
> PairRules.CURRY_EXISTS_CONV (Term `?((w,x),(y,z)). w+x+y+z = z+y+x+w`);
val it =
⊢ (∃((w,x),y,z). w + x + y + z = z + y + x + w) ⇔
∃(w,x) (y,z). w + x + y + z = z + y + x + w: thm
Failure
CURRY_EXISTS_CONV tm fails if tm is not a paired existential
quantification.
See also
PairRules.CURRY_CONV,
PairRules.UNCURRY_CONV,
PairRules.UNCURRY_EXISTS_CONV,
PairRules.CURRY_FORALL_CONV,
PairRules.UNCURRY_FORALL_CONV
CURRY_FORALL_CONV
CURRY_FORALL_CONV
PairRules.CURRY_FORALL_CONV : conv
Currys paired universal quantifications into consecutive universal quantifications.
Example
> PairRules.CURRY_FORALL_CONV (Term `!(x,y). x + y = y + x`);
val it = ⊢ (∀(x,y). x + y = y + x) ⇔ ∀x y. x + y = y + x: thm
> PairRules.CURRY_FORALL_CONV (Term `!((w,x),(y,z)). w+x+y+z = z+y+x+w`);
val it =
⊢ (∀((w,x),y,z). w + x + y + z = z + y + x + w) ⇔
∀(w,x) (y,z). w + x + y + z = z + y + x + w: thm
Failure
CURRY_FORALL_CONV tm fails if tm is not a paired universal
quantification.
See also
PairRules.CURRY_CONV,
PairRules.UNCURRY_CONV,
PairRules.UNCURRY_FORALL_CONV,
PairRules.CURRY_EXISTS_CONV,
PairRules.UNCURRY_EXISTS_CONV
FILTER_PGEN_TAC
FILTER_PGEN_TAC
PairRules.FILTER_PGEN_TAC : (term -> tactic)
Strips off a paired universal quantifier, but fails for a given quantified pair.
When applied to a term q and a goal A ?- !p. t, the tactic
FILTER_PGEN_TAC fails if the quantified pair p is the same as p,
but otherwise advances the goal in the same way as PGEN_TAC,
i.e. returns the goal A ?- t[p'/p] where p' is a variant of p
chosen to avoid clashing with any variables free in the goal's
assumption list. Normally p' is just p.
A ?- !p. t
============== FILTER_PGEN_TAC "q"
A ?- t[p'/p]
Failure
Fails if the goal's conclusion is not a paired universal quantifier or the quantified pair is equal to the given term.
See also
Tactic.FILTER_GEN_TAC,
PairRules.PGEN,
PairRules.PGEN_TAC,
PairRules.PGENL,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC,
PairRules.PSTRIP_TAC
FILTER_PSTRIP_TAC
FILTER_PSTRIP_TAC
PairRules.FILTER_PSTRIP_TAC : (term -> tactic)
Conditionally strips apart a goal by eliminating the outermost connective.
Stripping apart a goal in a more careful way than is done by
PSTRIP_TAC may be necessary when dealing with quantified terms and
implications. FILTER_PSTRIP_TAC behaves like PSTRIP_TAC, but it does
not strip apart a goal if it contains a given term.
If u is a term, then FILTER_PSTRIP_TAC u is a tactic that removes
one outermost occurrence of one of the connectives !, ==>, ~ or
/\ from the conclusion of the goal t, provided the term being
stripped does not contain u. FILTER_PSTRIP_TAC will strip paired
universal quantifications. A negation ~t is treated as the implication
t ==> F. FILTER_PSTRIP_TAC also breaks apart conjunctions without
applying any filtering.
If t is a universally quantified term, FILTER_PSTRIP_TAC u strips
off the quantifier:
A ?- !p. v
================ FILTER_PSTRIP_TAC "u" [where p is not u]
A ?- v[p'/p]
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the assumptions A. If t is a
conjunction, no filtering is done and FILTER_PSTRIP_TAC simply splits
the conjunction:
A ?- v /\ w
================= FILTER_PSTRIP_TAC "u"
A ?- v A ?- w
If t is an implication and the antecedent does not contain a free
instance of u, then FILTER_PSTRIP_TAC u moves the antecedent into
the assumptions and recursively splits the antecedent according to the
following rules (see PSTRIP_ASSUME_TAC):
A ?- v1 /\ ... /\ vn ==> v A ?- v1 \/ ... \/ vn ==> v
============================ =================================
A u {v1,...,vn} ?- v A u {v1} ?- v ... A u {vn} ?- v
A ?- (?p. w) ==> v
====================
A u {w[p'/p]} ?- v
where p' is a variant of the pair p.
Failure
FILTER_PSTRIP_TAC u (A,t) fails if t is not a universally quantified
term, an implication, a negation or a conjunction; or if the term being
stripped contains u in the sense described above (conjunction
excluded).
FILTER_PSTRIP_TAC is used when stripping outer connectives from a goal
in a more delicate way than PSTRIP_TAC. A typical application is to
keep stripping by using the tactic REPEAT (FILTER_PSTRIP_TAC u) until
one hits the term u at which stripping is to stop.
See also
PairRules.PGEN_TAC,
PairRules.PSTRIP_GOAL_THEN,
PairRules.FILTER_PSTRIP_THEN,
PairRules.PSTRIP_TAC,
Tactic.FILTER_STRIP_TAC
FILTER_PSTRIP_THEN
FILTER_PSTRIP_THEN
PairRules.FILTER_PSTRIP_THEN : (thm_tactic -> term -> tactic)
Conditionally strips a goal, handing an antecedent to the theorem-tactic.
Given a theorem-tactic ttac, a term u and a goal (A,t),
FILTER_STRIP_THEN ttac u removes one outer connective (!, ==>, or
~) from t, if the term being stripped does not contain a free
instance of u. Note that FILTER_PSTRIP_THEN will strip paired
universal quantifiers. A negation ~t is treated as the implication
t ==> F. The theorem-tactic ttac is applied only when stripping an
implication, by using the antecedent stripped off. FILTER_PSTRIP_THEN
also breaks conjunctions.
FILTER_PSTRIP_THEN behaves like PSTRIP_GOAL_THEN, if the term being
stripped does not contain a free instance of u. In particular,
FILTER_PSTRIP_THEN PSTRIP_ASSUME_TAC behaves like FILTER_PSTRIP_TAC.
Failure
FILTER_PSTRIP_THEN ttac u (A,t) fails if t is not a paired
universally quantified term, an implication, a negation or a
conjunction; or if the term being stripped contains the term u
(conjunction excluded); or if the application of ttac fails, after
stripping the goal.
FILTER_PSTRIP_THEN is used to manipulate intermediate results using
theorem-tactics, after stripping outer connectives from a goal in a more
delicate way than PSTRIP_GOAL_THEN.
See also
PairRules.PGEN_TAC,
PairRules.PSTRIP_GOAL_THEN,
Tactic.FILTER_STRIP_THEN,
PairRules.PSTRIP_TAC,
PairRules.FILTER_PSTRIP_TAC
GEN_PALPHA_CONV
GEN_PALPHA_CONV
PairRules.GEN_PALPHA_CONV : term -> conv
Renames the bound pair of a paired abstraction, quantified term, or other binder.
The conversion GEN_PALPHA_CONV provides alpha conversion for lambda
abstractions of the form \p.t, quantified terms of the forms !p.t,
?p.t or ?!p.t, and epsilon terms of the form @p.t.
The renaming of pairs is as described for PALPHA_CONV.
Failure
GEN_PALPHA_CONV q tm fails if q is not a variable, or if tm does
not have one of the required forms. GEN_ALPHA_CONV q tm also fails if
tm does have one of these forms, but types of the variables p and
q differ.
See also
Drule.GEN_ALPHA_CONV,
PairRules.PALPHA,
PairRules.PALPHA_CONV
GPSPEC
GPSPEC
PairRules.GPSPEC : (thm -> thm)
Specializes the conclusion of a theorem with unique pairs.
When applied to a theorem A |- !p1...pn. t, where the number of
universally quantified variables may be zero, GPSPEC returns
A |- t[g1/p1]...[gn/pn], where the gi is paired structures of the
same structure as pi and made up of distinct variables , chosen by
genvar.
A |- !p1...pn. t
------------------------- GPSPEC
A |- t[g1/p1]...[gn/pn]
Failure
Never fails.
GPSPEC is useful in writing derived inference rules which need to
specialize theorems while avoiding using any variables that may be
present elsewhere.
See also
Drule.GSPEC, PairRules.PGEN,
PairRules.PGENL, Term.genvar,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC,
PairRules.PSPEC_PAIR
HALF_MK_PABS
HALF_MK_PABS
PairRules.HALF_MK_PABS : (thm -> thm)
Converts a function definition to lambda-form.
When applied to a theorem A |- !p. t1 p = t2, whose conclusion is a
universally quantified equation, HALF_MK_PABS returns the theorem
A |- t1 = (\p. t2).
A |- !p. t1 p = t2
-------------------- HALF_MK_PABS [where p is not free in t1]
A |- t1 = (\p. t2)
Failure
Fails unless the theorem is a singly paired universally quantified equation whose left-hand side is a function applied to the quantified pair, or if any of the variables in the quantified pair is free in that function.
See also
jrhUtils.HALF_MK_ABS,
PairRules.PETA_CONV,
PairRules.MK_PABS,
PairRules.MK_PEXISTS
IPSPEC
IPSPEC
PairRules.IPSPEC : (term -> thm -> thm)
Specializes a theorem, with type instantiation if necessary.
This rule specializes a paired quantification as does PSPEC; it
differs from it in also instantiating the type if needed:
A |- !p:ty.tm
----------------------- IPSPEC "q:ty'"
A |- tm[q/p]
(where q is free for p in tm, and ty' is an instance of ty).
Failure
IPSPEC fails if the input theorem is not universally quantified, if
the type of the given term is not an instance of the type of the
quantified variable, or if the type variable is free in the assumptions.
See also
Drule.ISPEC,
Drule.INST_TY_TERM,
Thm.INST_TYPE,
PairRules.IPSPECL,
PairRules.PSPEC, DB.match
IPSPECL
IPSPECL
PairRules.IPSPECL : (term list -> thm -> thm)
Specializes a theorem zero or more times, with type instantiation if necessary.
IPSPECL is an iterative version of IPSPEC
A |- !p1...pn.tm
---------------------------- IPSPECL ["q1",...,"qn"]
A |- t[q1,...qn/p1,...,pn]
(where qi is free for pi in tm).
Failure
IPSPECL fails if the list of terms is longer than the number of
quantified variables in the term, if the type instantiation fails, or if
the type variable being instantiated is free in the assumptions.
See also
Drule.ISPECL, Thm.INST_TYPE,
Drule.INST_TY_TERM,
PairRules.IPSPEC, Thm.SPEC,
PairRules.PSPECL
LEFT_AND_PEXISTS_CONV
LEFT_AND_PEXISTS_CONV
PairRules.LEFT_AND_PEXISTS_CONV : conv
Moves a paired existential quantification of the left conjunct outwards through a conjunction.
When applied to a term of the form (?p. t) /\ u, the conversion
LEFT_AND_PEXISTS_CONV returns the theorem:
|- (?p. t) /\ u = (?p'. t[p'/p] /\ u)
where p' is a primed variant of the pair p that does not contains
variables free in the input term.
Failure
Fails if applied to a term not of the form (?p. t) /\ u.
See also
Conv.LEFT_AND_EXISTS_CONV,
PairRules.AND_PEXISTS_CONV,
PairRules.PEXISTS_AND_CONV,
PairRules.RIGHT_AND_PEXISTS_CONV
LEFT_AND_PFORALL_CONV
LEFT_AND_PFORALL_CONV
PairRules.LEFT_AND_PFORALL_CONV : conv
Moves a paired universal quantification of the left conjunct outwards through a conjunction.
When applied to a term of the form (!p. t) /\ u, the conversion
LEFT_AND_PFORALL_CONV returns the theorem:
|- (!p. t) /\ u = (!p'. t[p'/p] /\ u)
where p' is a primed variant of p that does not appear free in the
input term.
Failure
Fails if applied to a term not of the form (!p. t) /\ u.
See also
Conv.LEFT_AND_FORALL_CONV,
PairRules.AND_PFORALL_CONV,
PairRules.PFORALL_AND_CONV,
PairRules.RIGHT_AND_PFORALL_CONV
LEFT_IMP_PEXISTS_CONV
LEFT_IMP_PEXISTS_CONV
PairRules.LEFT_IMP_PEXISTS_CONV : conv
Moves a paired existential quantification of the antecedent outwards through an implication.
When applied to a term of the form (?p. t) ==> u, the conversion
LEFT_IMP_PEXISTS_CONV returns the theorem:
|- (?p. t) ==> u = (!p'. t[p'/p] ==> u)
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the input term.
Failure
Fails if applied to a term not of the form (?p. t) ==> u.
See also
Conv.LEFT_IMP_EXISTS_CONV,
PairRules.PFORALL_IMP_CONV,
PairRules.RIGHT_IMP_PFORALL_CONV
LEFT_IMP_PFORALL_CONV
LEFT_IMP_PFORALL_CONV
PairRules.LEFT_IMP_PFORALL_CONV : conv
Moves a paired universal quantification of the antecedent outwards through an implication.
When applied to a term of the form (!p. t) ==> u, the conversion
LEFT_IMP_PFORALL_CONV returns the theorem:
|- (!p. t) ==> u = (?p'. t[p'/p] ==> u)
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the input term.
Failure
Fails if applied to a term not of the form (!p. t) ==> u.
See also
Conv.LEFT_IMP_FORALL_CONV,
PairRules.PEXISTS_IMP_CONV,
PairRules.RIGHT_IMP_PFORALL_CONV
LEFT_LIST_PBETA
LEFT_LIST_PBETA
PairRules.LEFT_LIST_PBETA : (thm -> thm)
Iteratively beta-reduces a top-level paired beta-redex on the left-hand side of an equation.
When applied to an equational theorem, LEFT_LIST_PBETA applies paired
beta-reduction over a top-level chain of beta-redexes to the left-hand
side (only). Variables are renamed if necessary to avoid free variable
capture.
A |- (\p1...pn. t) q1 ... qn = s
---------------------------------- LEFT_LIST_BETA
A |- t[q1/p1]...[qn/pn] = s
Failure
Fails unless the theorem is equational, with its left-hand side being a top-level paired beta-redex.
See also
Drule.RIGHT_LIST_BETA,
PairRules.PBETA_CONV,
PairRules.PBETA_RULE,
PairRules.PBETA_TAC,
PairRules.LIST_PBETA_CONV,
PairRules.LEFT_PBETA,
PairRules.RIGHT_PBETA,
PairRules.RIGHT_LIST_PBETA
LEFT_OR_PEXISTS_CONV
LEFT_OR_PEXISTS_CONV
PairRules.LEFT_OR_PEXISTS_CONV : conv
Moves a paired existential quantification of the left disjunct outwards through a disjunction.
When applied to a term of the form (?p. t) \/ u, the conversion
LEFT_OR_PEXISTS_CONV returns the theorem:
|- (?p. t) \/ u = (?p'. t[p'/p] \/ u)
where p' is a primed variant of the pair p that does not contain any
variables free in the input term.
Failure
Fails if applied to a term not of the form (?p. t) \/ u.
See also
Conv.LEFT_OR_EXISTS_CONV,
PairRules.PEXISTS_OR_CONV,
PairRules.OR_PEXISTS_CONV,
PairRules.RIGHT_OR_PEXISTS_CONV
LEFT_OR_PFORALL_CONV
LEFT_OR_PFORALL_CONV
PairRules.LEFT_OR_PFORALL_CONV : conv
Moves a paired universal quantification of the left disjunct outwards through a disjunction.
When applied to a term of the form (!p. t) \/ u, the conversion
LEFT_OR_FORALL_CONV returns the theorem:
|- (!p. t) \/ u = (!p'. t[p'/p] \/ u)
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the input term.
Failure
Fails if applied to a term not of the form (!p. t) \/ u.
See also
Conv.LEFT_OR_FORALL_CONV,
PairRules.OR_PFORALL_CONV,
PairRules.PFORALL_OR_CONV,
PairRules.RIGHT_OR_PFORALL_CONV
LEFT_PBETA
LEFT_PBETA
PairRules.LEFT_PBETA : (thm -> thm)
Beta-reduces a top-level paired beta-redex on the left-hand side of an equation.
When applied to an equational theorem, LEFT_PBETA applies paired
beta-reduction at top level to the left-hand side (only). Variables are
renamed if necessary to avoid free variable capture.
A |- (\x. t1) t2 = s
---------------------- LEFT_PBETA
A |- t1[t2/x] = s
Failure
Fails unless the theorem is equational, with its left-hand side being a top-level paired beta-redex.
See also
Drule.RIGHT_BETA,
PairRules.PBETA_CONV,
PairRules.PBETA_RULE,
PairRules.PBETA_TAC,
PairRules.RIGHT_PBETA,
PairRules.RIGHT_LIST_PBETA,
PairRules.LEFT_LIST_PBETA
LIST_MK_PEXISTS
LIST_MK_PEXISTS
PairRules.LIST_MK_PEXISTS : (term list -> thm -> thm)
Multiply existentially quantifies both sides of an equation using the given pairs.
When applied to a list of terms [p1;...;pn], where the pi are all
paired structures of variables, and a theorem A |- t1 = t2, the
inference rule LIST_MK_PEXISTS existentially quantifies both sides of
the equation using the pairs given, none of the variables in the pairs
should be free in the assumption list.
A |- t1 = t2
-------------------------------------- LIST_MK_PEXISTS ["x1";...;"xn"]
A |- (?x1...xn. t1) = (?x1...xn. t2)
Failure
Fails if any term in the list is not a paired structure of variables, or if any variable is free in the assumption list, or if the theorem is not equational.
See also
Drule.LIST_MK_EXISTS,
PairRules.PEXISTS_EQ,
PairRules.MK_PEXISTS
LIST_MK_PFORALL
LIST_MK_PFORALL
PairRules.LIST_MK_PFORALL : (term list -> thm -> thm)
Multiply universally quantifies both sides of an equation using the given pairs.
When applied to a list of terms [p1;...;pn], where the pi are all
paired structures of variables, and a theorem A |- t1 = t2, the
inference rule LIST_MK_PFORALL universally quantifies both sides of
the equation using the pairs given, none of the variables in the pairs
should be free in the assumption list.
A |- t1 = t2
-------------------------------------- LIST_MK_PFORALL ["x1";...;"xn"]
A |- (!x1...xn. t1) = (!x1...xn. t2)
Failure
Fails if any term in the list is not a paired structure of variables, or if any variable is free in the assumption list, or if the theorem is not equational.
See also
Drule.LIST_MK_EXISTS,
PairRules.PFORALL_EQ,
PairRules.MK_PFORALL
LIST_PBETA_CONV
LIST_PBETA_CONV
PairRules.LIST_PBETA_CONV : conv
Performs an iterated paired beta-conversion.
The conversion LIST_PBETA_CONV maps terms of the form
(\p1 p2 ... pn. t) q1 q2 ... qn
to the theorems of the form
|- (\p1 p2 ... pn. t) q1 q2 ... qn = t[q1/p1][q2/p2] ... [qn/pn]
where t[qi/pi] denotes the result of substituting qi for all free
occurrences of pi in t, after renaming sufficient bound variables to
avoid variable capture.
Failure
LIST_PBETA_CONV tm fails if tm does not have the form
(\p1 ... pn. t) q1 ... qn for n greater than 0.
Example
> PairRules.LIST_PBETA_CONV (Term `(\(a,b) (c,d) . a + b + c + d) (1,2) (3,4)`);
val it = ⊢ (λ(a,b) (c,d). a + b + c + d) (1,2) (3,4) = 1 + 2 + 3 + 4: thm
See also
Drule.LIST_BETA_CONV,
PairRules.PBETA_CONV,
Conv.BETA_RULE,
Tactic.BETA_TAC,
PairRules.RIGHT_PBETA,
PairRules.RIGHT_LIST_PBETA,
PairRules.LEFT_PBETA,
PairRules.LEFT_LIST_PBETA
MK_PABS
MK_PABS
PairRules.MK_PABS : (thm -> thm)
Abstracts both sides of an equation.
When applied to a theorem A |- !p. t1 = t2, whose conclusion is a
paired universally quantified equation, MK_PABS returns the theorem
A |- (\p. t1) = (\p. t2).
A |- !p. t1 = t2
-------------------------- MK_PABS
A |- (\p. t1) = (\p. t2)
Failure
Fails unless the theorem is a (singly) paired universally quantified equation.
See also
Drule.MK_ABS, PairRules.PABS,
PairRules.HALF_MK_PABS,
PairRules.MK_PEXISTS
MK_PAIR
MK_PAIR
PairRules.MK_PAIR : thm * thm -> thm
Proves equality of pairs constructed from equal components.
When applied to theorems A1 |- a = x and A2 |- b = y, the inference
rule MK_PAIR returns the theorem A1 u A2 |- (a,b) = (x,y).
A1 |- a = x A2 |- b = y
--------------------------- MK_PAIR
A1 u A2 |- (a,b) = (x,y)
Failure
Fails unless both theorems are equational.
MK_PEXISTS
MK_PEXISTS
PairRules.MK_PEXISTS : (thm -> thm)
Existentially quantifies both sides of a universally quantified equational theorem.
When applied to a theorem A |- !p. t1 = t2, the inference rule
MK_PEXISTS returns the theorem A |- (?x. t1) = (?x. t2).
A |- !p. t1 = t2
-------------------------- MK_PEXISTS
A |- (?p. t1) = (?p. t2)
Failure
Fails unless the theorem is a singly paired universally quantified equation.
See also
PairRules.PEXISTS_EQ,
PairRules.PGEN,
PairRules.LIST_MK_PEXISTS,
PairRules.MK_PABS
MK_PFORALL
MK_PFORALL
PairRules.MK_PFORALL : (thm -> thm)
Universally quantifies both sides of a universally quantified equational theorem.
When applied to a theorem A |- !p. t1 = t2, the inference rule
MK_PFORALL returns the theorem A |- (!x. t1) = (!x. t2).
A |- !p. t1 = t2
-------------------------- MK_PFORALL
A |- (!p. t1) = (!p. t2)
Failure
Fails unless the theorem is a singly paired universally quantified equation.
See also
PairRules.PFORALL_EQ,
PairRules.LIST_MK_PFORALL,
PairRules.MK_PABS
MK_PSELECT
MK_PSELECT
PairRules.MK_PSELECT : (thm -> thm)
Quantifies both sides of a universally quantified equational theorem with the choice quantifier.
When applied to a theorem A |- !p. t1 = t2, the inference rule
MK_PSELECT returns the theorem A |- (@x. t1) = (@x. t2).
A |- !p. t1 = t2
-------------------------- MK_PSELECT
A |- (@p. t1) = (@p. t2)
Failure
Fails unless the theorem is a singly paired universally quantified equation.
See also
PairRules.PSELECT_EQ,
PairRules.MK_PABS
NOT_PEXISTS_CONV
NOT_PEXISTS_CONV
PairRules.NOT_PEXISTS_CONV : conv
Moves negation inwards through a paired existential quantification.
When applied to a term of the form ~(?p. t), the conversion
NOT_PEXISTS_CONV returns the theorem:
|- ~(?p. t) = (!p. ~t)
Failure
Fails if applied to a term not of the form ~(?p. t).
See also
Conv.NOT_EXISTS_CONV,
PairRules.PEXISTS_NOT_CONV,
PairRules.PFORALL_NOT_CONV,
PairRules.NOT_PFORALL_CONV
NOT_PFORALL_CONV
NOT_PFORALL_CONV
PairRules.NOT_PFORALL_CONV : conv
Moves negation inwards through a paired universal quantification.
When applied to a term of the form ~(!p. t), the conversion
NOT_PFORALL_CONV returns the theorem:
|- ~(!p. t) = (?p. ~t)
It is irrelevant whether any variables in p occur free in t.
Failure
Fails if applied to a term not of the form ~(!p. t).
See also
Conv.NOT_FORALL_CONV,
PairRules.PEXISTS_NOT_CONV,
PairRules.PFORALL_NOT_CONV,
PairRules.NOT_PEXISTS_CONV
OR_PEXISTS_CONV
OR_PEXISTS_CONV
PairRules.OR_PEXISTS_CONV : conv
Moves a paired existential quantification outwards through a disjunction.
When applied to a term of the form (?p. t) \/ (?p. u), the conversion
OR_PEXISTS_CONV returns the theorem:
|- (?p. t) \/ (?p. u) = (?p. t \/ u)
Failure
Fails if applied to a term not of the form (?p. t) \/ (?p. u).
See also
Conv.OR_EXISTS_CONV,
PairRules.PEXISTS_OR_CONV,
PairRules.LEFT_OR_PEXISTS_CONV,
PairRules.RIGHT_OR_PEXISTS_CONV
OR_PFORALL_CONV
OR_PFORALL_CONV
PairRules.OR_PFORALL_CONV : conv
Moves a paired universal quantification outwards through a disjunction.
When applied to a term of the form (!p. t) \/ (!p. u), where no
variables from p are free in either t nor u, OR_PFORALL_CONV
returns the theorem:
|- (!p. t) \/ (!p. u) = (!p. t \/ u)
Failure
OR_PFORALL_CONV fails if it is applied to a term not of the form
(!p. t) \/ (!p. u), or if it is applied to a term (!p. t) \/ (!p. u)
in which the variables from p are free in either t or u.
See also
Conv.OR_FORALL_CONV,
PairRules.PFORALL_OR_CONV,
PairRules.LEFT_OR_PFORALL_CONV,
PairRules.RIGHT_OR_PFORALL_CONV
P_FUN_EQ_CONV
P_FUN_EQ_CONV
PairRules.P_FUN_EQ_CONV : (term -> conv)
Performs extensionality conversion for functions (function equality).
The conversion P_FUN_EQ_CONV embodies the fact that two functions are
equal precisely when they give the same results for all values to which
they can be applied. For any paired variable structure "p" and
equation "f = g", where p is of type ty1 and f and g are
functions of type ty1->ty2, a call to P_FUN_EQ_CONV "p" "f = g"
returns the theorem:
|- (f = g) = (!p. f p = g p)
Failure
P_FUN_EQ_CONV p tm fails if p is not a paired structure of variables
or if tm is not an equation f = g where f and g are functions.
Furthermore, if f and g are functions of type ty1->ty2, then the
pair x must have type ty1; otherwise the conversion fails. Finally,
failure also occurs if any of the variables in p is free in either f
or g.
See also
Conv.FUN_EQ_CONV,
PairRules.PEXT
P_PCHOOSE_TAC
P_PCHOOSE_TAC
PairRules.P_PCHOOSE_TAC : (term -> thm_tactic)
Assumes a theorem, with existentially quantified pair replaced by a given witness.
P_PCHOOSE_TAC expects a pair q and theorem with a paired
existentially quantified conclusion. When applied to a goal, it adds a
new assumption obtained by introducing the pair q as a witness for the
pair p whose existence is asserted in the theorem.
A ?- t
=================== P_CHOOSE_TAC "q" (A1 |- ?p. u)
A u {u[q/p]} ?- t ("y" not free anywhere)
Failure
Fails if the theorem's conclusion is not a paired existential
quantification, or if the first argument is not a paired structure of
variables. Failures may arise in the tactic-generating function. An
invalid tactic is produced if the introduced variable is free in u or
t, or if the theorem has any hypothesis which is not alpha-convertible
to an assumption of the goal.
See also
Tactic.X_CHOOSE_TAC,
PairRules.PCHOOSE,
PairRules.PCHOOSE_THEN,
PairRules.P_PCHOOSE_THEN
P_PCHOOSE_THEN
P_PCHOOSE_THEN
PairRules.P_PCHOOSE_THEN : (term -> thm_tactical)
Replaces existentially quantified pair with given witness, and passes it to a theorem-tactic.
P_PCHOOSE_THEN expects a pair q, a tactic-generating function
f:thm->tactic, and a theorem of the form (A1 |- ?p. u) as arguments.
A new theorem is created by introducing the given pair q as a witness
for the pair p whose existence is asserted in the original theorem,
(u[q/p] |- u[q/p]). If the tactic-generating function f applied to
this theorem produces results as follows when applied to a goal
(A ?- u):
A ?- t
========= f ({u[q/p]} |- u[q/p])
A ?- t1
then applying (P_PCHOOSE_THEN "q" f (A1 |- ?p. u)) to the goal
(A ?- t) produces the subgoal:
A ?- t
========= P_PCHOOSE_THEN "q" f (A1 |- ?p. u)
A ?- t1 ("q" not free anywhere)
Failure
Fails if the theorem's conclusion is not existentially quantified, or if
the first argument is not a paired structure of variables. Failures may
arise in the tactic-generating function. An invalid tactic is produced
if the introduced variable is free in u or t, or if the theorem has
any hypothesis which is not alpha-convertible to an assumption of the
goal.
See also
Thm_cont.X_CHOOSE_THEN,
PairRules.PCHOOSE,
PairRules.PCHOOSE_THEN,
PairRules.P_PCHOOSE_TAC
P_PGEN_TAC
P_PGEN_TAC
PairRules.P_PGEN_TAC : (term -> tactic)
Specializes a goal with the given paired structure of variables.
When applied to a paired structure of variables p', and a goal
A ?- !p. t, the tactic P_PGEN_TAC returns the goal A ?- t[p'/p].
A ?- !p. t
============== P_PGEN_TAC "p'"
A ?- t[p'/x]
Failure
Fails unless the goal's conclusion is a paired universal quantification and the term a paired structure of variables of the appropriate type. It also fails if any of the variables of the supplied structure occurs free in either the assumptions or (initial) conclusion of the goal.
See also
Tactic.X_GEN_TAC,
PairRules.FILTER_PGEN_TAC,
PairRules.PGEN,
PairRules.PGENL,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC
P_PSKOLEM_CONV
P_PSKOLEM_CONV
PairRules.P_PSKOLEM_CONV : (term -> conv)
Introduces a user-supplied Skolem function.
P_PSKOLEM_CONV takes two arguments. The first is a variable f, which
must range over functions of the appropriate type, and the second is a
term of the form !p1...pn. ?q. t (where pi and q may be pairs).
Given these arguments, P_PSKOLEM_CONV returns the theorem:
|- (!p1...pn. ?q. t) = (?f. !p1...pn. tm[f p1 ... pn/q])
which expresses the fact that a skolem function f of the universally
quantified variables p1...pn may be introduced in place of the the
existentially quantified pair p.
Failure
P_PSKOLEM_CONV f tm fails if f is not a variable, or if the input
term tm is not a term of the form !p1...pn. ?q. t, or if the
variable f is free in tm, or if the type of f does not match its
intended use as an n-place curried function from the pairs p1...pn
to a value having the same type as p.
See also
Conv.X_SKOLEM_CONV,
PairRules.PSKOLEM_CONV
PABS
PABS
PairRules.PABS : (term -> thm -> thm)
Paired abstraction of both sides of an equation.
A |- t1 = t2
------------------------ ABS "p" [Where p is not free in A]
A |- (\p.t1) = (\p.t2)
Failure
If the theorem is not an equation, or if any variable in the paired
structure of variables p occurs free in the assumptions A.
EXAMPLE
> PairRules.PABS (Term `(x:'a,y:'b)`) (REFL (Term `(x:'a,y:'b)`));
val it = ⊢ (λ(x,y). (x,y)) = (λ(x,y). (x,y)): thm
See also
Thm.ABS, PairRules.PABS_CONV,
PairRules.PETA_CONV,
PairRules.PEXT,
PairRules.MK_PABS
PABS_CONV
PABS_CONV
PairRules.PABS_CONV : conv -> conv
Applies a conversion to the body of a paired abstraction.
If c is a conversion that maps a term t to the theorem |- t = t',
then the conversion PABS_CONV c maps abstractions of the form \p.t
to theorems of the form:
|- (\p.t) = (\p.t')
That is, ABS_CONV c "\p.t" applies p to the body of the paired
abstraction "\p.t".
Failure
PABS_CONV c tm fails if tm is not a paired abstraction or if tm
has the form "\p.t" but the conversion c fails when applied to the
term t. The function returned by ABS_CONV p may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
Example
> PairRules.PABS_CONV SYM_CONV (Term `\(x,y). (1,2) = (x,y)`);
val it = ⊢ (λ(x,y). (1,2) = (x,y)) = (λ(x,y). (x,y) = (1,2)): thm
See also
Conv.ABS_CONV,
PairRules.PSUB_CONV
PAIR_CONV
PAIR_CONV
PairRules.PAIR_CONV : (conv -> conv)
Applies a conversion to all the components of a pair structure.
For any conversion c, the function returned by PAIR_CONV c is a
conversion that applies c to all the components of a pair. If the term
t is not a pair, them PAIR_CONV c t applies c to t. If the term
t is the pair (t1,t2) then PAIR c t recursively applies
PAIR_CONV c to t1 and t2.
Failure
The conversion returned by PAIR_CONV c will fail for the pair
structure t if the conversion c would fail for any of the components
of t.
See also
Conv.RAND_CONV,
Conv.RATOR_CONV
PALPHA
PALPHA
PairRules.PALPHA : term -> term -> thm
Proves equality of paired alpha-equivalent terms.
When applied to a pair of terms t1 and t1' which are
alpha-equivalent, ALPHA returns the theorem |- t1 = t1'.
------------- PALPHA "t1" "t1'"
|- t1 = t1'
The difference between PALPHA and ALPHA is that PALPHA is prepared
to consider pair structures of different structure to be
alpha-equivalent. In its most trivial case this means that PALPHA can
consider a variable and a pair to alpha-equivalent.
Failure
Fails unless the terms provided are alpha-equivalent.
Example
> PairRules.PALPHA (Term `\(x:'a,y:'a). (x,y)`) (Term`\xy:'a#'a. xy`);
val it = ⊢ (λ(x,y). (x,y)) = (λxy. xy): thm
Comments
Alpha-converting a paired abstraction to a nonpaired abstraction can
introduce instances of the terms FST and SND. A paired abstraction
and a nonpaired abstraction will be considered equivalent by PALPHA if
the nonpaired abstraction contains all those instances of FST and
SND present in the paired abstraction, plus the minimum additional
instances of FST and SND. For example:
- PALPHA
(Term `\(x:'a,y:'b). (f x y (x,y)):'c`)
(Term `\xy:'a#'b. (f (FST xy) (SND xy) xy):'c`);
> val it = |- (\(x,y). f x y (x,y)) = (\xy. f (FST xy) (SND xy) xy) : thm
- PALPHA
(Term `\(x:'a,y:'b). (f x y (x,y)):'c`)
(Term `\xy:'a#'b. (f (FST xy) (SND xy) (FST xy, SND xy)):'c`)
handle e => Raise e;
Exception raised at ??.failwith:
PALPHA
! Uncaught exception:
! HOL_ERR
See also
Thm.ALPHA, Term.aconv,
PairRules.PALPHA_CONV,
PairRules.GEN_PALPHA_CONV
PALPHA_CONV
PALPHA_CONV
PairRules.PALPHA_CONV : term -> conv
Renames the bound variables of a paired lambda-abstraction.
If q is a variable of type ty and \p.t is a paired abstraction in
which the bound pair p also has type ty, then ALPHA_CONV q "\p.t"
returns the theorem:
|- (\p.t) = (\q'. t[q'/p])
where the pair q':ty is a primed variant of q chosen so that none of
its components are free in \p.t. The pairs p and q need not have
the same structure, but they must be of the same type.
Example
PALPHA_CONV renames the variables in a bound pair:
- PALPHA_CONV
(Term `((w:'a,x:'a),(y:'a,z:'a))`)
(Term `\((a:'a,b:'a),(c:'a,d:'a)). (f a b c d):'a`);
> val it = |- (\((a,b),c,d). f a b c d) = (\((w,x),y,z). f w x y z) : thm
The new bound pair and the old bound pair need not have the same structure.
- PALPHA_CONV
(Term `((wx:'a#'a),(y:'a,z:'a))`)
(Term `\((a:'a,b:'a),(c:'a,d:'a)). (f a b c d):'a`);
> val it = |- (\((a,b),c,d). f a b c d) =
(\(wx,y,z). f (FST wx) (SND wx) y z) : thm
PALPHA_CONV recognises subpairs of a pair as variables and preserves
structure accordingly.
- PALPHA_CONV
(Term `((wx:'a#'a),(y:'a,z:'a))`)
(Term `\((a:'a,b:'a),(c:'a,d:'a)). (f (a,b) c d):'a`);
> val it = |- (\((a,b),c,d). f (a,b) c d) = (\(wx,y,z). f wx y z) : thm
Comments
PALPHA_CONV will only ever add the terms FST and SND, i.e., it
will never remove them. This means that while \(x,y). x + y can be
converted to \xy. (FST xy) + (SND xy), it can not be converted back
again.
Failure
PALPHA_CONV q tm fails if q is not a variable, if tm is not an
abstraction, or if q is a variable and tm is the lambda abstraction
\p.t but the types of p and q differ.
See also
Drule.ALPHA_CONV,
PairRules.PALPHA,
PairRules.GEN_PALPHA_CONV
PART_PMATCH
PART_PMATCH
PairRules.PART_PMATCH : ((term -> term) -> thm -> term -> thm)
Instantiates a theorem by matching part of it to a term.
When applied to a 'selector' function of type term -> term, a theorem
and a term:
PART_MATCH fn (A |- !p1...pn. t) tm
the function PART_PMATCH applies fn to t' (the result of
specializing universally quantified pairs in the conclusion of the
theorem), and attempts to match the resulting term to the argument term
tm. If it succeeds, the appropriately instantiated version of the
theorem is returned.
Failure
Fails if the selector function fn fails when applied to the
instantiated theorem, or if the match fails with the term it has
provided.
See also
PBETA_CONV
PBETA_CONV
PairRules.PBETA_CONV : conv
Performs a general beta-conversion.
The conversion PBETA_CONV maps a paired beta-redex "(\p.t)q" to the
theorem
|- (\p.t)q = t[q/p]
where u[q/p] denotes the result of substituting q for all free
occurrences of p in t, after renaming sufficient bound variables to
avoid variable capture. Unlike PAIRED_BETA_CONV, PBETA_CONV does not
require that the structure of the argument match the structure of the
pair bound by the abstraction. However, if the structure of the argument
does match the structure of the pair bound by the abstraction, then
PAIRED_BETA_CONV will do the job much faster.
Failure
PBETA_CONV tm fails if tm is not a paired beta-redex.
Example
PBETA_CONV will reduce applications with arbitrary structure.
- PBETA_CONV
(Term `((\((a:'a,b:'a),(c:'a,d:'a)). f a b c d) ((w,x),(y,z))):'a`);
> val it = |- (\((a,b),c,d). f a b c d) ((w,x),y,z) = f w x y z : thm
PBETA_CONV does not require the structure of the argument and the
bound pair to match.
- PBETA_CONV
(Term `((\((a:'a,b:'a),(c:'a,d:'a)). f a b c d) ((w,x),yz)):'a`);
> val it = |- (\((a,b),c,d). f a b c d) ((w,x),yz) =
f w x (FST yz) (SND yz) : thm
PBETA_CONV regards component pairs of the bound pair as variables in
their own right and preserves structure accordingly:
- PBETA_CONV
(Term `((\((a:'a,b:'a),(c:'a,d:'a)). f (a,b) (c,d)) (wx,(y,z))):'a`);
> val it = |- (\((a,b),c,d). f (a,b) (c,d)) (wx,y,z) = f wx (y,z) : thm
See also
Thm.BETA_CONV,
PairedLambda.PAIRED_BETA_CONV,
PairRules.PBETA_RULE,
PairRules.PBETA_TAC,
PairRules.LIST_PBETA_CONV,
PairRules.RIGHT_PBETA,
PairRules.RIGHT_LIST_PBETA,
PairRules.LEFT_PBETA,
PairRules.LEFT_LIST_PBETA
PBETA_RULE
PBETA_RULE
PairRules.PBETA_RULE : (thm -> thm)
Beta-reduces all the paired beta-redexes in the conclusion of a theorem.
When applied to a theorem A |- t, the inference rule PBETA_RULE
beta-reduces all beta-redexes, at any depth, in the conclusion t.
Variables are renamed where necessary to avoid free variable capture.
A |- ....((\p. s1) s2)....
---------------------------- BETA_RULE
A |- ....(s1[s2/p])....
Failure
Never fails, but will have no effect if there are no paired beta-redexes.
See also
Conv.BETA_RULE,
PairRules.PBETA_CONV,
PairRules.PBETA_TAC,
PairRules.RIGHT_PBETA,
PairRules.LEFT_PBETA
PBETA_TAC
PBETA_TAC
PairRules.PBETA_TAC : tactic
Beta-reduces all the paired beta-redexes in the conclusion of a goal.
When applied to a goal A ?- t, the tactic PBETA_TAC produces a new
goal which results from beta-reducing all paired beta-redexes, at any
depth, in t. Variables are renamed where necessary to avoid free
variable capture.
A ?- ...((\p. s1) s2)...
========================== PBETA_TAC
A ?- ...(s1[s2/p])...
Failure
Never fails, but will have no effect if there are no paired beta-redexes.
See also
Tactic.BETA_TAC,
PairRules.PBETA_CONV,
PairRules.PBETA_RULE
PCHOOSE
PCHOOSE
PairRules.PCHOOSE : term * thm -> thm -> thm
Eliminates paired existential quantification using deduction from a particular witness.
When applied to a term-theorem pair (q,A1 |- ?p. s) and a second
theorem of the form A2 u {s[q/p]} |- t, the inference rule PCHOOSE
produces the theorem A1 u A2 |- t.
A1 |- ?p. s A2 u {s[q/p]} |- t
------------------------------------ PCHOOSE ("q",(A1 |- ?q. s))
A1 u A2 |- t
Where no variable in the paired variable structure q is free in A1,
A2 or t.
Failure
Fails unless the terms and theorems correspond as indicated above; in
particular q must have the same type as the pair existentially
quantified over, and must not contain any variable free in A1, A2 or
t.
See also
Thm.CHOOSE,
PairRules.PCHOOSE_TAC,
PairRules.PEXISTS,
PairRules.PEXISTS_TAC,
PairRules.PSELECT_ELIM
PCHOOSE_TAC
PCHOOSE_TAC
PairRules.PCHOOSE_TAC : thm_tactic
Adds the body of a paired existentially quantified theorem to the assumptions of a goal.
When applied to a theorem A' |- ?p. t and a goal, CHOOSE_TAC adds
t[p'/p] to the assumptions of the goal, where p' is a variant of the
pair p which has no components free in the assumption list; normally
p' is just p.
A ?- u
==================== CHOOSE_TAC (A' |- ?q. t)
A u {t[p'/p]} ?- u
Unless A' is a subset of A, this is not a valid tactic.
Failure
Fails unless the given theorem is a paired existential quantification.
See also
Tactic.CHOOSE_TAC,
PairRules.PCHOOSE_THEN,
PairRules.P_PCHOOSE_TAC
PCHOOSE_THEN
PCHOOSE_THEN
PairRules.PCHOOSE_THEN : thm_tactical
Applies a tactic generated from the body of paired existentially quantified theorem.
When applied to a theorem-tactic ttac, a paired existentially
quantified theorem:
A' |- ?p. t
and a goal, CHOOSE_THEN applies the tactic ttac (t[p'/p] |- t[p'/p])
to the goal, where p' is a variant of the pair p chosen to have no
components free in the assumption list of the goal. Thus if:
A ?- s1
========= ttac (t[q'/q] |- t[q'/q])
B ?- s2
then
A ?- s1
========== CHOOSE_THEN ttac (A' |- ?q. t)
B ?- s2
This is invalid unless A' is a subset of A.
Failure
Fails unless the given theorem is a paired existential quantification, or if the resulting tactic fails when applied to the goal.
See also
Thm_cont.CHOOSE_THEN,
PairRules.PCHOOSE_TAC,
PairRules.P_PCHOOSE_THEN
PETA_CONV
PETA_CONV
PairRules.PETA_CONV : conv
Performs a top-level paired eta-conversion.
PETA_CONV maps an eta-redex \p. t p, where none of variables in the
paired structure of variables p occurs free in t, to the theorem
|- (\p. t p) = t.
Failure
Fails if the input term is not a paired eta-redex.
PEXISTENCE
PEXISTENCE
PairRules.PEXISTENCE : (thm -> thm)
Deduces paired existence from paired unique existence.
When applied to a theorem with a paired unique-existentially quantified
conclusion, EXISTENCE returns the same theorem with normal paired
existential quantification over the same pair.
A |- ?!p. t
------------- PEXISTENCE
A |- ?p. t
Failure
Fails unless the conclusion of the theorem is a paired unique-existential quantification.
See also
Conv.EXISTENCE,
PairRules.PEXISTS_UNIQUE_CONV
PEXISTS
PEXISTS
PairRules.PEXISTS : term * term -> thm -> thm
Introduces paired existential quantification given a particular witness.
When applied to a pair of terms and a theorem, where the first term a
paired existentially quantified pattern indicating the desired form of
the result, and the second a witness whose substitution for the
quantified pair gives a term which is the same as the conclusion of the
theorem, PEXISTS gives the desired theorem.
A |- t[q/p]
------------- EXISTS ("?p. t","q")
A |- ?p. t
Failure
Fails unless the substituted pattern is the same as the conclusion of the theorem.
Example
The following examples illustrate the various uses of PEXISTS:
- PEXISTS (Term`?x. x + 2 = x + 2`, Term`1`) (REFL (Term`1 + 2`));
> val it = |- ?x. x + 2 = x + 2 : thm
- PEXISTS (Term`?y. 1 + y = 1 + y`, Term`2`) (REFL (Term`1 + 2`));
> val it = |- ?y. 1 + y = 1 + y : thm
- PEXISTS (Term`?(x,y). x + y = x + y`, Term`(1,2)`) (REFL (Term`1 + 2`));
> val it = |- ?(x,y). x + y = x + y : thm
- PEXISTS (Term`?(a:'a,b:'a). (a,b) = (a,b)`, Term`ab:'a#'a`)
(REFL (Term `ab:'a#'a`));
> val it = |- ?(a,b). (a,b) = (a,b) : thm
See also
Thm.EXISTS, PairRules.PCHOOSE,
PairRules.PEXISTS_TAC
PEXISTS_AND_CONV
PEXISTS_AND_CONV
PairRules.PEXISTS_AND_CONV : conv
Moves a paired existential quantification inwards through a conjunction.
When applied to a term of the form ?p. t /\ u, where variables in p
are not free in both t and u, PEXISTS_AND_CONV returns a theorem
of one of three forms, depending on occurrences of variables from p in
t and u. If p contains variables free in t but none in u, then
the theorem:
|- (?p. t /\ u) = (?p. t) /\ u
is returned. If p contains variables free in u but none in t, then
the result is:
|- (?p. t /\ u) = t /\ (?x. u)
And if p does not contain any variable free in either t nor u,
then the result is:
|- (?p. t /\ u) = (?x. t) /\ (?x. u)
Failure
PEXISTS_AND_CONV fails if it is applied to a term not of the form
?p. t /\ u, or if it is applied to a term ?p. t /\ u in which
variables in p are free in both t and u.
See also
Conv.EXISTS_AND_CONV,
PairRules.AND_PEXISTS_CONV,
PairRules.LEFT_AND_PEXISTS_CONV,
PairRules.RIGHT_AND_PEXISTS_CONV
PEXISTS_CONV
PEXISTS_CONV
PairRules.PEXISTS_CONV : conv
Eliminates paired existential quantifier by introducing a paired choice-term.
The conversion PEXISTS_CONV expects a boolean term of the form
(?p. t[p]), where p may be a paired structure or variables, and
converts it to the form (t [@p. t[p]]).
--------------------------------- PEXISTS_CONV "(?p. t[p])"
(|- (?p. t[p]) = (t [@p. t[p]])
Failure
Fails if applied to a term that is not a paired existential quantification.
See also
PairRules.PSELECT_RULE,
PairRules.PSELECT_CONV,
PairRules.PEXISTS_RULE,
PairRules.PSELECT_INTRO,
PairRules.PSELECT_ELIM
PEXISTS_EQ
PEXISTS_EQ
PairRules.PEXISTS_EQ : (term -> thm -> thm)
Existentially quantifies both sides of an equational theorem.
When applied to a paired structure of variables p and a theorem whose
conclusion is equational:
A |- t1 = t2
the inference rule PEXISTS_EQ returns the theorem:
A |- (?p. t1) = (?p. t2)
provided the none of the variables in p is not free in any of the
assumptions.
A |- t1 = t2
-------------------------- PEXISTS_EQ "p" [where p is not free in A]
A |- (?p. t1) = (?p. t2)
Failure
Fails unless the theorem is equational with both sides having type
bool, or if the term is not a paired structure of variables, or if any
variable in the pair to be quantified over is free in any of the
assumptions.
See also
Drule.EXISTS_EQ,
PairRules.PEXISTS_IMP,
PairRules.PFORALL_EQ,
PairRules.MK_PEXISTS,
PairRules.PSELECT_EQ
PEXISTS_IMP
PEXISTS_IMP
PairRules.PEXISTS_IMP : (term -> thm -> thm)
Existentially quantifies both the antecedent and consequent of an implication.
When applied to a paired structure of variables p and a theorem
A |- t1 ==> t2, the inference rule PEXISTS_IMP returns the theorem
A |- (?p. t1) ==> (?p. t2), provided no variable in p is free in the
assumptions.
A |- t1 ==> t2
-------------------------- EXISTS_IMP "x" [where x is not free in A]
A |- (?x.t1) ==> (?x.t2)
Failure
Fails if the theorem is not implicative, or if the term is not a paired structure of variables, of if any variable in the pair is free in the assumption list.
See also
Drule.EXISTS_IMP,
PairRules.PEXISTS_EQ
PEXISTS_IMP_CONV
PEXISTS_IMP_CONV
PairRules.PEXISTS_IMP_CONV : conv
Moves a paired existential quantification inwards through an implication.
When applied to a term of the form ?p. t ==> u, where variables from
p are not free in both t and u, PEXISTS_IMP_CONV returns a
theorem of one of three forms, depending on occurrences of variable from
p in t and u. If variables from p are free in t but none are
in u, then the theorem:
|- (?p. t ==> u) = (!p. t) ==> u
is returned. If variables from p are free in u but none are in t,
then the result is:
|- (?p. t ==> u) = t ==> (?p. u)
And if no variable from p is free in either t nor u, then the
result is:
|- (?p. t ==> u) = (!p. t) ==> (?p. u)
Failure
PEXISTS_IMP_CONV fails if it is applied to a term not of the form
?p. t ==> u, or if it is applied to a term ?p. t ==> u in which the
variables from p are free in both t and u.
See also
Conv.EXISTS_IMP_CONV,
PairRules.LEFT_IMP_PFORALL_CONV,
PairRules.RIGHT_IMP_PEXISTS_CONV
PEXISTS_NOT_CONV
PEXISTS_NOT_CONV
PairRules.PEXISTS_NOT_CONV : conv
Moves a paired existential quantification inwards through a negation.
When applied to a term of the form ?p. ~t, the conversion
PEXISTS_NOT_CONV returns the theorem:
|- (?p. ~t) = ~(!p. t)
Failure
Fails if applied to a term not of the form ?p. ~t.
See also
Conv.EXISTS_NOT_CONV,
PairRules.PFORALL_NOT_CONV,
PairRules.NOT_PEXISTS_CONV,
PairRules.NOT_PFORALL_CONV
PEXISTS_OR_CONV
PEXISTS_OR_CONV
PairRules.PEXISTS_OR_CONV : conv
Moves a paired existential quantification inwards through a disjunction.
When applied to a term of the form ?p. t \/ u, the conversion
PEXISTS_OR_CONV returns the theorem:
|- (?p. t \/ u) = (?p. t) \/ (?p. u)
Failure
Fails if applied to a term not of the form ?p. t \/ u.
See also
Conv.EXISTS_OR_CONV,
PairRules.OR_PEXISTS_CONV,
PairRules.LEFT_OR_PEXISTS_CONV,
PairRules.RIGHT_OR_PEXISTS_CONV
PEXISTS_RULE
PEXISTS_RULE
PairRules.PEXISTS_RULE : (thm -> thm)
Introduces a paired existential quantification in place of a paired choice.
The inference rule PEXISTS_RULE expects a theorem asserting that
(@p. t) denotes a pair for which t holds. The equivalent assertion
that there exists a p for which t holds is returned.
A |- t[(@p. t)/p]
------------------ PEXISTS_RULE
A |- ?p. t
Failure
Fails if applied to a theorem the conclusion of which is not of the form
(t[(@p.t)/p]).
See also
PairRules.PEXISTS_CONV,
PairRules.PSELECT_RULE,
PairRules.PSELECT_CONV,
PairRules.PSELECT_INTRO,
PairRules.PSELECT_ELIM
PEXISTS_TAC
PEXISTS_TAC
PairRules.PEXISTS_TAC : (term -> tactic)
Reduces paired existentially quantified goal to one involving a specific witness.
When applied to a term q and a goal ?p. t, the tactic PEXISTS_TAC
reduces the goal to t[q/p].
A ?- ?p. t
============= EXISTS_TAC "q"
A ?- t[q/p]
Failure
Fails unless the goal's conclusion is a paired existential quantification and the term supplied has the same type as the quantified pair in the goal.
Example
The goal:
?- ?(x,y). (x,y)=(1,2)
can be solved by:
PEXISTS_TAC "(1,2)" THEN REFL_TAC
See also
Tactic.EXISTS_TAC,
PairRules.PEXISTS
PEXISTS_UNIQUE_CONV
PEXISTS_UNIQUE_CONV
PairRules.PEXISTS_UNIQUE_CONV : conv
Expands with the definition of paired unique existence.
Given a term of the form "?!p. t[p]", the conversion
PEXISTS_UNIQUE_CONV proves that this assertion is equivalent to the
conjunction of two statements, namely that there exists at least one
pair p such that t[p], and that there is at most one value p for
which t[p] holds. The theorem returned is:
|- (?!p. t[p]) = (?p. t[p]) /\ (!p p'. t[p] /\ t[p'] ==> (p = p'))
where p' is a primed variant of the pair p none of the components of
which appear free in the input term. Note that the quantified pair p
need not in fact appear free in the body of the input term. For example,
PEXISTS_UNIQUE_CONV "?!(x,y). T" returns the theorem:
|- (?!(x,y). T) =
(?(x,y). T) /\ (!(x,y) (x',y'). T /\ T ==> ((x,y) = (x',y')))
Failure
PEXISTS_UNIQUE_CONV tm fails if tm does not have the form "?!p.t".
See also
Conv.EXISTS_UNIQUE_CONV,
PairRules.PEXISTENCE
PEXT
PEXT
PairRules.PEXT : (thm -> thm)
Derives equality of functions from extensional equivalence.
When applied to a theorem A |- !p. t1 p = t2 p, the inference rule
PEXT returns the theorem A |- t1 = t2.
A |- !p. t1 p = t2 p
---------------------- PEXT [where p is not free in t1 or t2]
A |- t1 = t2
Failure
Fails if the theorem does not have the form indicated above, or if any
of the component variables in the paired variable structure p is free
either of the functions t1 or t2.
Example
> PairRules.PEXT (ASSUME (Term `!(x,y). ((f:('a#'a)->'a) (x,y)) = (g (x,y))`));
val it = [.] ⊢ f = g: thm
See also
Drule.EXT, Thm.AP_THM,
PairRules.PETA_CONV,
Conv.FUN_EQ_CONV,
PairRules.P_FUN_EQ_CONV
PFORALL_AND_CONV
PFORALL_AND_CONV
PairRules.PFORALL_AND_CONV : conv
Moves a paired universal quantification inwards through a conjunction.
When applied to a term of the form !p. t /\ u, the conversion
PFORALL_AND_CONV returns the theorem:
|- (!p. t /\ u) = (!p. t) /\ (!p. u)
Failure
Fails if applied to a term not of the form !p. t /\ u.
See also
Conv.FORALL_AND_CONV,
PairRules.AND_PFORALL_CONV,
PairRules.LEFT_AND_PFORALL_CONV,
PairRules.RIGHT_AND_PFORALL_CONV
PFORALL_EQ
PFORALL_EQ
PairRules.PFORALL_EQ : (term -> thm -> thm)
Universally quantifies both sides of an equational theorem.
When applied to a paired structure of variables p and a theorem
A |- t1 = t2
whose conclusion is an equation between boolean terms:
PFORALL_EQ
returns the theorem:
A |- (!p. t1) = (!p. t2)
unless any of the variables in p is free in any of the assumptions.
A |- t1 = t2
-------------------------- PFORALL_EQ "p" [where p is not free in A]
A |- (!p. t1) = (!p. t2)
Failure
Fails if the theorem is not an equation between boolean terms, or if the supplied term is not a paired structure of variables, or if any of the variables in the supplied pair is free in any of the assumptions.
See also
Drule.FORALL_EQ,
PairRules.PEXISTS_EQ,
PairRules.PSELECT_EQ
PFORALL_IMP_CONV
PFORALL_IMP_CONV
PairRules.PFORALL_IMP_CONV : conv
Moves a paired universal quantification inwards through an implication.
When applied to a term of the form !p. t ==> u, where variables from
p are not free in both t and u, PFORALL_IMP_CONV returns a
theorem of one of three forms, depending on occurrences of the variables
from p in t and u. If variables from p are free in t but none
are in u, then the theorem:
|- (!p. t ==> u) = (?p. t) ==> u
is returned. If variables from p are free in u but none are in t,
then the result is:
|- (!p. t ==> u) = t ==> (!p. u)
And if no variable from p is free in either t nor u, then the
result is:
|- (!p. t ==> u) = (?p. t) ==> (!p. u)
Failure
PFORALL_IMP_CONV fails if it is applied to a term not of the form
!p. t ==> u, or if it is applied to a term !p. t ==> u in which
variables from p are free in both t and u.
See also
Conv.FORALL_IMP_CONV,
PairRules.LEFT_IMP_PEXISTS_CONV,
PairRules.RIGHT_IMP_PFORALL_CONV
PFORALL_NOT_CONV
PFORALL_NOT_CONV
PairRules.PFORALL_NOT_CONV : conv
Moves a paired universal quantification inwards through a negation.
When applied to a term of the form !p. ~t, the conversion
PFORALL_NOT_CONV returns the theorem:
|- (!p. ~t) = ~(?p. t)
Failure
Fails if applied to a term not of the form !p. ~t.
See also
Conv.FORALL_NOT_CONV,
PairRules.PEXISTS_NOT_CONV,
PairRules.NOT_PEXISTS_CONV,
PairRules.NOT_PFORALL_CONV
PFORALL_OR_CONV
PFORALL_OR_CONV
PairRules.PFORALL_OR_CONV : conv
Moves a paired universal quantification inwards through a disjunction.
When applied to a term of the form !p. t \/ u, where no variable in
p is free in both t and u, PFORALL_OR_CONV returns a theorem of
one of three forms, depending on occurrences of the variables from p
in t and u. If variables from p are free in t but not in u,
then the theorem:
|- (!p. t \/ u) = (!p. t) \/ u
is returned. If variables from p are free in u but none are free in
t, then the result is:
|- (!p. t \/ u) = t \/ (!t. u)
And if no variable from p is free in either t nor u, then the
result is:
|- (!p. t \/ u) = (!p. t) \/ (!p. u)
Failure
PFORALL_OR_CONV fails if it is applied to a term not of the form
!p. t \/ u, or if it is applied to a term !p. t \/ u in which
variables from p are free in both t and u.
See also
Conv.FORALL_OR_CONV,
PairRules.OR_PFORALL_CONV,
PairRules.LEFT_OR_PFORALL_CONV,
PairRules.RIGHT_OR_PFORALL_CONV
PGEN
PGEN
PairRules.PGEN : (term -> thm -> thm)
Generalizes the conclusion of a theorem.
When applied to a paired structure of variables p and a theorem
A |- t, the inference rule PGEN returns the theorem A |- !p. t,
provided that no variable in p occurs free in the assumptions A.
There is no compulsion that the variables of p should be free in t.
A |- t
------------ PGEN "p" [where p does not occur free in A]
A |- !p. t
Failure
Fails if p is not a paired structure of variables, of if any variable
in p is free in the assumptions.
See also
Thm.GEN, PairRules.PGENL,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC
PGEN_TAC
PGEN_TAC
PairRules.PGEN_TAC : tactic
Strips the outermost paired universal quantifier from the conclusion of a goal.
When applied to a goal A ?- !p. t, the tactic PGEN_TAC reduces it to
A ?- t[p'/p] where p' is a variant of the paired variable structure
p chosen to avoid clashing with any variables free in the goal's
assumption list. Normally p' is just p.
A ?- !p. t
============== PGEN_TAC
A ?- t[p'/p]
Failure
Fails unless the goal's conclusion is a paired universally quantification.
See also
Tactic.GEN_TAC,
PairRules.FILTER_PGEN_TAC,
PairRules.PGEN,
PairRules.PGENL,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC,
PairRules.PSTRIP_TAC,
PairRules.P_PGEN_TAC
PGENL
PGENL
PairRules.PGENL : (term list -> thm -> thm)
Generalizes zero or more pairs in the conclusion of a theorem.
When applied to a list of paired variable structures [p1;...;pn] and a
theorem A |- t, the inference rule PGENL returns the theorem
A |- !p1...pn. t, provided none of the constituent variables from any
of the pairs pi occur free in the assumptions.
A |- t
------------------ PGENL "[p1;...;pn]" [where no pi is free in A]
A |- !p1...pn. t
Failure
Fails unless all the terms in the list are paired structures of variables, none of the variables from which are free in the assumption list.
See also
Thm.GENL, PairRules.PGEN,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC
PMATCH_MP
PMATCH_MP
PairRules.PMATCH_MP : (thm -> thm -> thm)
Modus Ponens inference rule with automatic matching.
When applied to theorems A1 |- !p1...pn. t1 ==> t2 and A2 |- t1',
the inference rule PMATCH_MP matches t1 to t1' by instantiating
free or paired universally quantified variables in the first theorem
(only), and returns a theorem A1 u A2 |- !pa..pk. t2', where t2' is
a correspondingly instantiated version of t2. Polymorphic types are
also instantiated if necessary.
Variables free in the consequent but not the antecedent of the first argument theorem will be replaced by variants if this is necessary to maintain the full generality of the theorem, and any pairs which were universally quantified over in the first argument theorem will be universally quantified over in the result, and in the same order.
A1 |- !p1..pn. t1 ==> t2 A2 |- t1'
-------------------------------------- MATCH_MP
A1 u A2 |- !pa..pk. t2'
Failure
Fails unless the first theorem is a (possibly repeatedly paired
universally quantified) implication whose antecedent can be instantiated
to match the conclusion of the second theorem, without instantiating any
variables which are free in A1, the first theorem's assumption list.
See also
PMATCH_MP_TAC
PMATCH_MP_TAC
PairRules.PMATCH_MP_TAC : thm_tactic
Reduces the goal using a supplied implication, with matching.
When applied to a theorem of the form
A' |- !p1...pn. s ==> !q1...qm. t
PMATCH_MP_TAC produces a tactic that reduces a goal whose conclusion
t' is a substitution and/or type instance of t to the corresponding
instance of s. Any variables free in s but not in t will be
existentially quantified in the resulting subgoal:
A ?- !u1...ui. t'
====================== PMATCH_MP_TAC (A' |- !p1...pn. s ==> !q1...qm. t)
A ?- ?w1...wp. s'
where w1, ..., wp are (type instances of) those pairs among p1,
..., pn having variables that do not occur free in t. Note that this
is not a valid tactic unless A' is a subset of A.
Failure
Fails unless the theorem is an (optionally paired universally
quantified) implication whose consequent can be instantiated to match
the goal. The generalized pairs u1, ..., ui must occur in s' in
order for the conclusion t of the supplied theorem to match t'.
See also
PSELECT_CONV
PSELECT_CONV
PairRules.PSELECT_CONV : conv
Eliminates a paired epsilon term by introducing an existential quantifier.
The conversion PSELECT_CONV expects a boolean term of the form
"t[@p.t[p]/p]", which asserts that the epsilon term @p.t[p] denotes
a pair, p say, for which t[p] holds. This assertion is equivalent to
saying that there exists such a pair, and PSELECT_CONV applied to a
term of this form returns the theorem |- t[@p.t[p]/p] = ?p. t[p].
Failure
Fails if applied to a term that is not of the form "p[@p.t[p]/p]".
See also
Conv.SELECT_CONV,
PairRules.PSELECT_ELIM,
PairRules.PSELECT_INTRO,
PairRules.PSELECT_RULE
PSELECT_ELIM
PSELECT_ELIM
PairRules.PSELECT_ELIM : thm -> term * thm -> thm
Eliminates a paired epsilon term, using deduction from a particular instance.
PSELECT_ELIM expects two arguments, a theorem th1, and a pair
(p,th2): term * thm. The conclusion of th1 must have the form
P($@ P), which asserts that the epsilon term $@ P denotes some value
at which P holds. The paired variable structure p appears only in
the assumption P p of the theorem th2. The conclusion of the
resulting theorem matches that of th2, and the hypotheses include the
union of all hypotheses of the premises excepting P p.
A1 |- P($@ P) A2 u {P p} |- t
------------------------------------- PSELECT_ELIM th1 (p ,th2)
A1 u A2 |- t
where p is not free in A2. If p appears in the conclusion of
th2, the epsilon term will NOT be eliminated, and the conclusion will
be t[$@ P/p].
Failure
Fails if the first theorem is not of the form A1 |- P($@ P), or if any
of the variables from the variable structure p occur free in any other
assumption of th2.
See also
Drule.SELECT_ELIM,
PairRules.PCHOOSE,
PairRules.PSELECT_CONV,
PairRules.PSELECT_INTRO,
PairRules.PSELECT_RULE
PSELECT_EQ
PSELECT_EQ
PairRules.PSELECT_EQ : (term -> thm -> thm)
Applies epsilon abstraction to both terms of an equation.
When applied to a paired structure of variables p and a theorem whose
conclusion is equational:
A |- t1 = t2
the inference rule PSELECT_EQ returns the theorem:
A |- (@p. t1) = (@p. t2)
provided no variable in p is free in the assumptions.
A |- t1 = t2
-------------------------- SELECT_EQ "p" [where p is not free in A]
A |- (@p. t1) = (@p. t2)
Failure
Fails if the conclusion of the theorem is not an equation, of if p is
not a paired structure of variables, or if any variable in p is free
in A.
See also
Drule.SELECT_EQ,
PairRules.PFORALL_EQ,
PairRules.PEXISTS_EQ
PSELECT_INTRO
PSELECT_INTRO
PairRules.PSELECT_INTRO : (thm -> thm)
Introduces an epsilon term.
PSELECT_INTRO takes a theorem with an applicative conclusion, say
P x, and returns a theorem with the epsilon term $@ P in place of
the original operand x.
A |- P x
-------------- PSELECT_INTRO
A |- P($@ P)
The returned theorem asserts that $@ P denotes some value at which P
holds.
Failure
Fails if the conclusion of the theorem is not an application.
Comments
This function is exactly the same as SELECT_INTRO, it is duplicated in
the pair library for completeness.
See also
Drule.SELECT_INTRO,
PairRules.PEXISTS,
PairRules.PSELECT_CONV,
PairRules.PSELECT_ELIM,
PairRules.PSELECT_RULE
PSELECT_RULE
PSELECT_RULE
PairRules.PSELECT_RULE : (thm -> thm)
Introduces a paired epsilon term in place of a paired existential quantifier.
The inference rule PSELECT_RULE expects a theorem asserting the
existence of a pair p such that t holds. The equivalent assertion
that the epsilon term @p.t denotes a pair p for which t holds is
returned as a theorem.
A |- ?p. t
------------------ PSELECT_RULE
A |- t[(@p.t)/p]
Failure
Fails if applied to a theorem the conclusion of which is not a paired existential quantifier.
See also
Drule.SELECT_RULE,
PairRules.PCHOOSE,
PairRules.PSELECT_CONV,
PairRules.PEXISTS_CONV,
PairRules.PSELECT_ELIM,
PairRules.PSELECT_INTRO
PSKOLEM_CONV
PSKOLEM_CONV
PairRules.PSKOLEM_CONV : conv
Proves the existence of a pair of Skolem functions.
When applied to an argument of the form !p1...pn. ?q. tm, the
conversion PSKOLEM_CONV returns the theorem:
|- (!p1...pn. ?q. tm) = (?q'. !p1...pn. tm[q' p1 ... pn/yq)
where q' is a primed variant of the pair q not free in the input
term.
Failure
PSKOLEM_CONV tm fails if tm is not a term of the form
!p1...pn. ?q. tm.
Example
Both q and any pi may be a paired structure of variables:
- PSKOLEM_CONV
(Term `!(x11:'a,x12:'a) (x21:'a,x22:'a).
?(y1:'a,y2:'a). tm x11 x12 x21 x21 y1 y2`);
> val it =
|- (!(x11,x12) (x21,x22). ?(y1,y2). tm x11 x12 x21 x21 y1 y2) =
?(y1,y2).
!(x11,x12) (x21,x22).
tm x11 x12 x21 x21 (y1 (x11,x12) (x21,x22)) (y2 (x11,x12) (x21,x22))
: thm
See also
Conv.SKOLEM_CONV,
PairRules.P_PSKOLEM_CONV
PSPEC
PSPEC
PairRules.PSPEC : (term -> thm -> thm)
Specializes the conclusion of a theorem.
When applied to a term q and a theorem A |- !p. t, then PSPEC
returns the theorem A |- t[q/p]. If necessary, variables will be
renamed prior to the specialization to ensure that q is free for p
in t, that is, no variables free in q become bound after
substitution.
A |- !p. t
-------------- PSPEC "q"
A |- t[q/p]
Failure
Fails if the theorem's conclusion is not a paired universal
quantification, or if p and q have different types.
Example
PSPEC specialised paired quantifications.
- PSPEC (Term `(1,2)`) (ASSUME (Term`!(x,y). (x + y) = (y + x)`));
> val it = [.] |- 1 + 2 = 2 + 1 : thm
PSPEC treats paired structures of variables as variables and preserves
structure accordingly.
- PSPEC (Term `x:'a#'a`) (ASSUME (Term `!(x:'a,y:'a). (x,y) = (x,y)`));
> val it = [.] |- x = x : thm
See also
Thm.SPEC, PairRules.IPSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PGEN,
PairRules.PGENL
PSPEC_ALL
PSPEC_ALL
PairRules.PSPEC_ALL : (thm -> thm)
Specializes the conclusion of a theorem with its own quantified pairs.
When applied to a theorem A |- !p1...pn. t, the inference rule
PSPEC_ALL returns the theorem A |- t[p1'/p1]...[pn'/pn] where the
pi' are distinct variants of the corresponding pi, chosen to avoid
clashes with any variables free in the assumption list and with the
names of constants. Normally pi' is just pi, in which case
PSPEC_ALL simply removes all universal quantifiers.
A |- !p1...pn. t
--------------------------- PSPEC_ALL
A |- t[p1'/x1]...[pn'/xn]
Failure
Never fails.
See also
Drule.SPEC_ALL,
PairRules.PGEN,
PairRules.PGENL,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_TAC
PSPEC_PAIR
PSPEC_PAIR
PairRules.PSPEC_PAIR : thm -> term * thm
Specializes the conclusion of a theorem, returning the chosen variant.
When applied to a theorem A |- !p. t, the inference rule PSPEC_PAIR
returns the term q' and the theorem A |- t[q'/p], where q' is a
variant of p chosen to avoid free variable capture.
A |- !p. t
-------------- PSPEC_PAIR
A |- t[q'/q]
Failure
Fails unless the theorem's conclusion is a paired universal quantification.
Comments
This rule is very similar to plain PSPEC, except that it returns the
variant chosen, which may be useful information under some
circumstances.
See also
Drule.SPEC_VAR,
PairRules.PGEN,
PairRules.PGENL,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL
PSPEC_TAC
PSPEC_TAC
PairRules.PSPEC_TAC : term * term -> tactic
Generalizes a goal.
When applied to a pair of terms (q,p), where p is a paired structure
of variables and a goal A ?- t, the tactic PSPEC_TAC generalizes the
goal to A ?- !p. t[p/q], that is, all components of q are turned
into the corresponding components of p.
A ?- t
================= PSPEC_TAC (q,p)
A ?- !x. t[p/q]
Failure
Fails unless p is a paired structure of variables with the same type
as q.
Example
> g `1 + 2 = 2 + 1`;
val it =
Proof manager status: 2 proofs.
2. Incomplete goalstack:
Initial goal:
∃R. WF R ∧ (∀rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)) ∧
∀rst x ord. R (ord,FILTER ($¬ ∘ ord x) rst) (ord,x::rst)
1. Incomplete goalstack:
Initial goal:
1 + 2 = 2 + 1
> e (PairRules.PSPEC_TAC (Term`(1,2)`, Term`(x:num,y:num)`));
OK..
1 subgoal:
val it =
∀(x,y). x + y = y + x
Removing unnecessary speciality in a goal, particularly as a prelude to an inductive proof.
See also
PairRules.PGEN,
PairRules.PGENL,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPECL,
PairRules.PSPEC_ALL,
PairRules.PSTRIP_TAC
PSPECL
PSPECL
PairRules.PSPECL : (term list -> thm -> thm)
Specializes zero or more pairs in the conclusion of a theorem.
When applied to a term list [q1;...;qn] and a theorem
A |- !p1...pn. t, the inference rule SPECL returns the theorem
A |- t[q1/p1]...[qn/pn], where the substitutions are made sequentially
left-to-right in the same way as for PSPEC.
A |- !p1...pn. t
-------------------------- SPECL "[q1;...;qn]"
A |- t[q1/p1]...[qn/pn]
It is permissible for the term-list to be empty, in which case the
application of PSPECL has no effect.
Failure
Fails unless each of the terms is of the same type as that of the appropriate quantified variable in the original theorem. Fails if the list of terms is longer than the number of quantified pairs in the theorem.
See also
Drule.SPECL, PairRules.PGEN,
PairRules.PGENL,
PairRules.PGEN_TAC,
PairRules.PSPEC,
PairRules.PSPEC_ALL,
PairRules.PSPEC_TAC
PSTRIP_ASSUME_TAC
PSTRIP_ASSUME_TAC
PairRules.PSTRIP_ASSUME_TAC : thm_tactic
Splits a theorem into a list of theorems and then adds them to the assumptions.
Given a theorem th and a goal (A,t), PSTRIP_ASSUME_TAC th splits
th into a list of theorems. This is done by recursively breaking
conjunctions into separate conjuncts, cases-splitting disjunctions, and
eliminating paired existential quantifiers by choosing arbitrary
variables. Schematically, the following rules are applied:
A ?- t
====================== PSTRIP_ASSUME_TAC (A' |- v1 /\ ... /\ vn)
A u {v1,...,vn} ?- t
A ?- t
================================= PSTRIP_ASSUME_TAC (A' |- v1 \/ ... \/ vn)
A u {v1} ?- t ... A u {vn} ?- t
A ?- t
==================== PSTRIP_ASSUME_TAC (A' |- ?p. v)
A u {v[p'/p]} ?- t
where p' is a variant of the pair p.
If the conclusion of th is not a conjunction, a disjunction or a
paired existentially quantified term, the whole theorem th is added to
the assumptions.
As assumptions are generated, they are examined to see if they solve the goal (either by being alpha-equivalent to the conclusion of the goal or by deriving a contradiction).
The assumptions of the theorem being split are not added to the
assumptions of the goal(s), but they are recorded in the proof. This
means that if A' is not a subset of the assumptions A of the goal
(up to alpha-conversion), PSTRIP_ASSUME_TAC (A'|-v) results in an
invalid tactic.
Failure
Never fails.
PSTRIP_ASSUME_TAC is used when applying a previously proved theorem to
solve a goal, or when enriching its assumptions so that resolution,
rewriting with assumptions and other operations involving assumptions
have more to work with.
See also
PairRules.PSTRIP_THM_THEN,
PairRules.PSTRIP_ASSUME_TAC,
PairRules.PSTRIP_GOAL_THEN,
PairRules.PSTRIP_TAC
PSTRIP_GOAL_THEN
PSTRIP_GOAL_THEN
PairRules.PSTRIP_GOAL_THEN : (thm_tactic -> tactic)
Splits a goal by eliminating one outermost connective, applying the given theorem-tactic to the antecedents of implications.
Given a theorem-tactic ttac and a goal (A,t), PSTRIP_GOAL_THEN
removes one outermost occurrence of one of the connectives !, ==>,
~ or /\ from the conclusion of the goal t. If t is a universally
quantified term, then STRIP_GOAL_THEN strips off the quantifier. Note
that PSTRIP_GOAL_THEN will strip off paired universal quantifications.
A ?- !p. u
============== PSTRIP_GOAL_THEN ttac
A ?- u[p'/p]
where p' is a primed variant that contains no variables that appear
free in the assumptions A. If t is a conjunction, then
PSTRIP_GOAL_THEN simply splits the conjunction into two subgoals:
A ?- v /\ w
================= PSTRIP_GOAL_THEN ttac
A ?- v A ?- w
If t is an implication "u ==> v" and if:
A ?- v
=============== ttac (u |- u)
A' ?- v'
then:
A ?- u ==> v
==================== PSTRIP_GOAL_THEN ttac
A' ?- v'
Finally, a negation ~t is treated as the implication t ==> F.
Failure
PSTRIP_GOAL_THEN ttac (A,t) fails if t is not a paired universally
quantified term, an implication, a negation or a conjunction. Failure
also occurs if the application of ttac fails, after stripping the
goal.
PSTRIP_GOAL_THEN is used when manipulating intermediate results
(obtained by stripping outer connectives from a goal) directly, rather
than as assumptions.
See also
PairRules.PGEN_TAC,
Tactic.STRIP_GOAL_THEN,
PairRules.FILTER_PSTRIP_THEN,
PairRules.PSTRIP_TAC,
PairRules.FILTER_PSTRIP_TAC
PSTRIP_TAC
PSTRIP_TAC
PairRules.PSTRIP_TAC : tactic
Splits a goal by eliminating one outermost connective.
Given a goal (A,t), PSTRIP_TAC removes one outermost occurrence of
one of the connectives !, ==>, ~ or /\ from the conclusion of
the goal t. If t is a universally quantified term, then STRIP_TAC
strips off the quantifier. Note that PSTRIP_TAC will strip off paired
quantifications.
A ?- !p. u
============== PSTRIP_TAC
A ?- u[p'/p]
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the assumptions A. If t is a
conjunction, then PSTRIP_TAC simply splits the conjunction into two
subgoals:
A ?- v /\ w
================= PSTRIP_TAC
A ?- v A ?- w
If t is an implication, PSTRIP_TAC moves the antecedent into the
assumptions, stripping conjunctions, disjunctions and existential
quantifiers according to the following rules:
A ?- v1 /\ ... /\ vn ==> v A ?- v1 \/ ... \/ vn ==> v
============================ =================================
A u {v1,...,vn} ?- v A u {v1} ?- v ... A u {vn} ?- v
A ?- (?p. w) ==> v
=====================
A u {w[p'/p]} ?- v
where p' is a primed variant of the pair p that does not appear free
in A. Finally, a negation ~t is treated as the implication
t ==> F.
Failure
PSTRIP_TAC (A,t) fails if t is not a paired universally quantified
term, an implication, a negation or a conjunction.
When trying to solve a goal, often the best thing to do first is
REPEAT PSTRIP_TAC to split the goal up into manageable pieces.
See also
PairRules.PGEN_TAC,
PairRules.PSTRIP_GOAL_THEN,
PairRules.FILTER_PSTRIP_THEN,
Tactic.STRIP_TAC,
PairRules.FILTER_PSTRIP_TAC
PSTRIP_THM_THEN
PSTRIP_THM_THEN
PairRules.PSTRIP_THM_THEN : thm_tactical
PSTRIP_THM_THEN applies the given theorem-tactic using the result of
stripping off one outer connective from the given theorem.
Given a theorem-tactic ttac, a theorem th whose conclusion is a
conjunction, a disjunction or a paired existentially quantified term,
and a goal (A,t), STRIP_THM_THEN ttac th first strips apart the
conclusion of th, next applies ttac to the theorem(s) resulting from
the stripping and then applies the resulting tactic to the goal.
In particular, when stripping a conjunctive theorem A'|- u /\ v, the
tactic
ttac(u|-u) THEN ttac(v|-v)
resulting from applying ttac to the conjuncts, is applied to the goal.
When stripping a disjunctive theorem A'|- u \/ v, the tactics
resulting from applying ttac to the disjuncts, are applied to split
the goal into two cases. That is, if
A ?- t A ?- t
========= ttac (u|-u) and ========= ttac (v|-v)
A ?- t1 A ?- t2
then:
A ?- t
================== PSTRIP_THM_THEN ttac (A'|- u \/ v)
A ?- t1 A ?- t2
When stripping a paired existentially quantified theorem A'|- ?p. u,
the tactic resulting from applying ttac to the body of the paired
existential quantification, ttac(u|-u), is applied to the goal. That
is, if:
A ?- t
========= ttac (u|-u)
A ?- t1
then:
A ?- t
============= PSTRIP_THM_THEN ttac (A'|- ?p. u)
A ?- t1
The assumptions of the theorem being split are not added to the
assumptions of the goal(s) but are recorded in the proof. If A' is not
a subset of the assumptions A of the goal (up to alpha-conversion),
PSTRIP_THM_THEN ttac th results in an invalid tactic.
Failure
PSTRIP_THM_THEN ttac th fails if the conclusion of th is not a
conjunction, a disjunction or a paired existentially quantification.
Failure also occurs if the application of ttac fails, after stripping
the outer connective from the conclusion of th.
PSTRIP_THM_THEN is used enrich the assumptions of a goal with a
stripped version of a previously-proved theorem.
See also
Thm_cont.STRIP_THM_THEN,
PairRules.PSTRIP_ASSUME_TAC,
PairRules.PSTRIP_GOAL_THEN,
PairRules.PSTRIP_TAC
PSTRUCT_CASES_TAC
PSTRUCT_CASES_TAC
PairRules.PSTRUCT_CASES_TAC : thm_tactic
Performs very general structural case analysis.
When it is applied to a theorem of the form:
th = A' |- ?p11...p1m. (x=t1) /\ (B11 /\ ... /\ B1k) \/ ... \/
?pn1...pnp. (x=tn) /\ (Bn1 /\ ... /\ Bnp)
in which there may be no paired existential quantifiers where a 'vector'
of them is shown above, PSTRUCT_CASES_TAC th splits a goal A ?- s
into n subgoals as follows:
A ?- s
===============================================================
A u {B11,...,B1k} ?- s[t1/x] ... A u {Bn1,...,Bnp} ?- s[tn/x]
that is, performs a case split over the possible constructions (the
ti) of a term, providing as assumptions the given constraints, having
split conjoined constraints into separate assumptions. Note that unless
A' is a subset of A, this is an invalid tactic.
Failure
Fails unless the theorem has the above form, namely a conjunction of
(possibly multiply paired existentially quantified) terms which assert
the equality of the same variable x and the given terms.
Generating a case split from the axioms specifying a structure.
See also
PSUB_CONV
PSUB_CONV
PairRules.PSUB_CONV : (conv -> conv)
Applies a conversion to the top-level subterms of a term.
For any conversion c, the function returned by PSUB_CONV c is a
conversion that applies c to all the top-level subterms of a term. If
the conversion c maps t to |- t = t', then SUB_CONV c maps a
paired abstraction "\p.t" to the theorem:
|- (\p.t) = (\p.t')
That is, PSUB_CONV c "\p.t" applies c to the body of the paired
abstraction "\p.t". If c is a conversion that maps "t1" to the
theorem |- t1 = t1' and "t2" to the theorem |- t2 = t2', then the
conversion PSUB_CONV c maps an application "t1 t2" to the theorem:
|- (t1 t2) = (t1' t2')
That is, PSUB_CONV c "t1 t2" applies c to the both the operator t1
and the operand t2 of the application "t1 t2". Finally, for any
conversion c, the function returned by PSUB_CONV c acts as the
identity conversion on variables and constants. That is, if "t" is a
variable or constant, then PSUB_CONV c "t" returns |- t = t.
Failure
PSUB_CONV c tm fails if tm is a paired abstraction "\p.t" and the
conversion c fails when applied to t, or if tm is an application
"t1 t2" and the conversion c fails when applied to either t1 or
t2. The function returned by PSUB_CONV c may also fail if the ML
function c:term->thm is not, in fact, a conversion (i.e. a function
that maps a term t to a theorem |- t = t').
See also
Conv.SUB_CONV,
PairRules.PABS_CONV,
Conv.RAND_CONV,
Conv.RATOR_CONV
pvariant
pvariant
PairRules.pvariant : (term list -> term -> term)
Modifies variable and constant names in a paired structure to avoid clashes.
When applied to a list of (possibly paired structures of) variables to
avoid clashing with, and a pair to modify, pvariant returns a variant
of the pair. That is, it changes the names of variables and constants in
the pair as intuitively as possible to make them distinct from any
variables in the list, or any (non-hidden) constants. This is normally
done by adding primes to the names.
The exact form of the altered names should not be relied on, except that the original variables will be unmodified unless they are in the list to avoid clashing with. Also note that if the same variable occurs more that one in the pair, then each instance of the variable will be modified in the same way.
Failure
pvariant l p fails if any term in the list l is not a paired
structure of variables, or if p is not a paired structure of variables
and constants.
Example
The following shows a case that exhibits most possible behaviours:
- pvariant [Term `b:'a`, Term `(c:'a,c':'a)`]
(Term `((a:'a,b:'a),(c:'a,b':'a,T,b:'a))`);
val it = `(a,b''),c'',b',T',b''` : term
The function pvariant is extremely useful for complicated derived
rules which need to rename pairs variable to avoid free variable capture
while still making the role of the pair obvious to the user.
See also
RIGHT_AND_PEXISTS_CONV
RIGHT_AND_PEXISTS_CONV
PairRules.RIGHT_AND_PEXISTS_CONV : conv
Moves a paired existential quantification of the right conjunct outwards through a conjunction.
When applied to a term of the form t /\ (?p. t), the conversion
RIGHT_AND_PEXISTS_CONV returns the theorem:
|- t /\ (?p. u) = (?p'. t /\ (u[p'/p]))
where p' is a primed variant of the pair p that does not contain any
variables free in the input term.
Failure
Fails if applied to a term not of the form t /\ (?p. u).
See also
Conv.RIGHT_AND_EXISTS_CONV,
PairRules.AND_PEXISTS_CONV,
PairRules.PEXISTS_AND_CONV,
PairRules.LEFT_AND_PEXISTS_CONV
RIGHT_AND_PFORALL_CONV
RIGHT_AND_PFORALL_CONV
PairRules.RIGHT_AND_PFORALL_CONV : conv
Moves a paired universal quantification of the right conjunct outwards through a conjunction.
When applied to a term of the form t /\ (!p. u), the conversion
RIGHT_AND_PFORALL_CONV returns the theorem:
|- t /\ (!p. u) = (!p'. t /\ (u[p'/p]))
where p' is a primed variant of the pair p that does not contain any
variables free in the input term.
Failure
Fails if applied to a term not of the form t /\ (!p. u).
See also
Conv.RIGHT_AND_FORALL_CONV,
PairRules.AND_PFORALL_CONV,
PairRules.PFORALL_AND_CONV,
PairRules.LEFT_AND_PFORALL_CONV
RIGHT_IMP_PEXISTS_CONV
RIGHT_IMP_PEXISTS_CONV
PairRules.RIGHT_IMP_PEXISTS_CONV : conv
Moves a paired existential quantification of the consequent outwards through an implication.
When applied to a term of the form t ==> (?p. u),
RIGHT_IMP_PEXISTS_CONV returns the theorem:
|- t ==> (?p. u) = (?p'. t ==> (u[p'/p]))
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the input term.
Failure
Fails if applied to a term not of the form t ==> (?p. u).
See also
Conv.RIGHT_IMP_EXISTS_CONV,
PairRules.PEXISTS_IMP_CONV,
PairRules.LEFT_IMP_PFORALL_CONV
RIGHT_IMP_PFORALL_CONV
RIGHT_IMP_PFORALL_CONV
PairRules.RIGHT_IMP_PFORALL_CONV : conv
Moves a paired universal quantification of the consequent outwards through an implication.
When applied to a term of the form t ==> (!p. u), the conversion
RIGHT_IMP_FORALL_CONV returns the theorem:
|- t ==> (!p. u) = (!p'. t ==> (u[p'/p]))
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the input term.
Failure
Fails if applied to a term not of the form t ==> (!p. u).
See also
Conv.RIGHT_IMP_FORALL_CONV,
PairRules.PFORALL_IMP_CONV,
PairRules.LEFT_IMP_PEXISTS_CONV
RIGHT_LIST_PBETA
RIGHT_LIST_PBETA
PairRules.RIGHT_LIST_PBETA : (thm -> thm)
Iteratively beta-reduces a top-level paired beta-redex on the right-hand side of an equation.
When applied to an equational theorem, RIGHT_LIST_PBETA applies paired
beta-reduction over a top-level chain of beta-redexes to the right-hand
side (only). Variables are renamed if necessary to avoid free variable
capture.
A |- s = (\p1...pn. t) q1 ... qn
---------------------------------- RIGHT_LIST_BETA
A |- s = t[q1/p1]...[qn/pn]
Failure
Fails unless the theorem is equational, with its right-hand side being a top-level paired beta-redex.
See also
Drule.RIGHT_LIST_BETA,
PairRules.PBETA_CONV,
PairRules.PBETA_RULE,
PairRules.PBETA_TAC,
PairRules.LIST_PBETA_CONV,
PairRules.RIGHT_PBETA,
PairRules.LEFT_PBETA,
PairRules.LEFT_LIST_PBETA
RIGHT_OR_PEXISTS_CONV
RIGHT_OR_PEXISTS_CONV
PairRules.RIGHT_OR_PEXISTS_CONV : conv
Moves a paired existential quantification of the right disjunct outwards through a disjunction.
When applied to a term of the form t \/ (?p. u), the conversion
RIGHT_OR_PEXISTS_CONV returns the theorem:
|- t \/ (?p. u) = (?p'. t \/ (u[p'/p]))
where p' is a primed variant of the pair p that does not contain any
variables free in the input term.
Failure
Fails if applied to a term not of the form t \/ (?p. u).
See also
Conv.RIGHT_OR_EXISTS_CONV,
PairRules.OR_PEXISTS_CONV,
PairRules.PEXISTS_OR_CONV,
PairRules.LEFT_OR_PEXISTS_CONV
RIGHT_OR_PFORALL_CONV
RIGHT_OR_PFORALL_CONV
PairRules.RIGHT_OR_PFORALL_CONV : conv
Moves a paired universal quantification of the right disjunct outwards through a disjunction.
When applied to a term of the form t \/ (!p. u), the conversion
RIGHT_OR_FORALL_CONV returns the theorem:
|- t \/ (!p. u) = (!p'. t \/ (u[p'/p]))
where p' is a primed variant of the pair p that does not contain any
variables that appear free in the input term.
Failure
Fails if applied to a term not of the form t \/ (!p. u).
See also
Conv.RIGHT_OR_FORALL_CONV,
PairRules.OR_PFORALL_CONV,
PairRules.PFORALL_OR_CONV,
PairRules.LEFT_OR_PFORALL_CONV
RIGHT_PBETA
RIGHT_PBETA
PairRules.RIGHT_PBETA : (thm -> thm)
Beta-reduces a top-level paired beta-redex on the right-hand side of an equation.
When applied to an equational theorem, RIGHT_PBETA applies paired
beta-reduction at top level to the right-hand side (only). Variables are
renamed if necessary to avoid free variable capture.
A |- s = (\p. t1) t2
---------------------- RIGHT_PBETA
A |- s = t1[t2/p]
Failure
Fails unless the theorem is equational, with its right-hand side being a top-level paired beta-redex.
See also
Drule.RIGHT_BETA,
PairRules.PBETA_CONV,
PairRules.PBETA_RULE,
PairRules.PBETA_TAC,
PairRules.RIGHT_LIST_PBETA,
PairRules.LEFT_PBETA,
PairRules.LEFT_LIST_PBETA
SWAP_PEXISTS_CONV
SWAP_PEXISTS_CONV
PairRules.SWAP_PEXISTS_CONV : conv
Interchanges the order of two existentially quantified pairs.
When applied to a term argument of the form ?p q. t, the conversion
SWAP_PEXISTS_CONV returns the theorem:
|- (?p q. t) = (?q t. t)
Failure
SWAP_PEXISTS_CONV fails if applied to a term that is not of the form
?p q. t.
See also
Conv.SWAP_EXISTS_CONV,
PairRules.SWAP_PFORALL_CONV
SWAP_PFORALL_CONV
SWAP_PFORALL_CONV
PairRules.SWAP_PFORALL_CONV : conv
Interchanges the order of two universally quantified pairs.
When applied to a term argument of the form !p q. t, the conversion
SWAP_PFORALL_CONV returns the theorem:
|- (!p q. t) = (!q p. t)
Failure
SWAP_PFORALL_CONV fails if applied to a term that is not of the form
!p q. t.
See also
UNCURRY_CONV
UNCURRY_CONV
PairRules.UNCURRY_CONV : conv
Uncurrys an application of an abstraction.
Example
> PairRules.UNCURRY_CONV (Term `(\x y. x + y) 1 2`);
val it = ⊢ (λx y. x + y) 1 2 = (λ(x,y). x + y) (1,2): thm
Failure
UNCURRY_CONV tm fails if tm is not double abstraction applied to two
arguments
See also
UNCURRY_EXISTS_CONV
UNCURRY_EXISTS_CONV
PairRules.UNCURRY_EXISTS_CONV : conv
Uncurrys consecutive existential quantifications into a paired existential quantification.
Example
> PairRules.UNCURRY_EXISTS_CONV (Term `?x y. x + y = y + x`);
val it = ⊢ (∃x y. x + y = y + x) ⇔ ∃(x,y). x + y = y + x: thm
> PairRules.UNCURRY_EXISTS_CONV (Term `?(w,x) (y,z). w+x+y+z = z+y+x+w`);
val it =
⊢ (∃(w,x) (y,z). w + x + y + z = z + y + x + w) ⇔
∃((w,x),y,z). w + x + y + z = z + y + x + w: thm
Failure
UNCURRY_EXISTS_CONV tm fails if tm is not a consecutive existential
quantification.
See also
PairRules.CURRY_CONV,
PairRules.UNCURRY_CONV,
PairRules.CURRY_EXISTS_CONV,
PairRules.CURRY_FORALL_CONV,
PairRules.UNCURRY_FORALL_CONV
UNCURRY_FORALL_CONV
UNCURRY_FORALL_CONV
PairRules.UNCURRY_FORALL_CONV : conv
Uncurrys consecutive universal quantifications into a paired universal quantification.
Example
> PairRules.UNCURRY_FORALL_CONV (Term `!x y. x + y = y + x`);
val it = ⊢ (∀x y. x + y = y + x) ⇔ ∀(x,y). x + y = y + x: thm
> PairRules.UNCURRY_FORALL_CONV (Term `!(w,x) (y,z). w+x+y+z = z+y+x+w`);
val it =
⊢ (∀(w,x) (y,z). w + x + y + z = z + y + x + w) ⇔
∀((w,x),y,z). w + x + y + z = z + y + x + w: thm
Failure
UNCURRY_FORALL_CONV tm fails if tm is not a consecutive universal
quantification.
See also
PairRules.CURRY_CONV,
PairRules.UNCURRY_CONV,
PairRules.CURRY_FORALL_CONV,
PairRules.CURRY_EXISTS_CONV,
PairRules.UNCURRY_EXISTS_CONV
UNPBETA_CONV
UNPBETA_CONV
PairRules.UNPBETA_CONV : (term -> conv)
Creates an application of a paired abstraction from a term.
The user nominates some pair structure of variables p and a term t,
and UNPBETA_CONV turns t into an abstraction on p applied to p.
------------------ UNPBETA_CONV "p" "t"
|- t = (\p. t) p
Failure
Fails if p is not a paired structure of variables.
See also
PairRules.PBETA_CONV,
PairedLambda.PAIRED_BETA_CONV
dest_anylet
dest_anylet
pairSyntax.dest_anylet : term -> (term * term) list * term
Destructs arbitrary let terms.
The invocation dest_anylet M where M has the form of a
let-abstraction, i.e., LET P Q, returns a pair
([(a1,b1),...,(an,bn)],body), where the first argument is a list of
bindings, and the second is the body of the let. The list of bindings is
required since let terms can, in general, be of the form (using surface
syntax) let a1 = b1 and ... and an = bn in body.
Each ai can be a varstruct (a single variable or a tuple of
variables), or a function variable applied to a sequence of varstructs.
Failure
Fails if M is not a let abstraction.
Example
> pairSyntax.dest_anylet ``let f (x,y) = M and g z = N in g (f (a,b))``;
val it = ([(“f (x,y)”, “M”), (“g z”, “N”)], “g (f (a,b))”):
(term * term) list * term
> pairSyntax.dest_anylet ``let f (x,y) = M in
let g z = N
in g (f (a,b))``;
val it = ([(“f (x,y)”, “M”)], “let g z = N in g (f (a,b))”):
(term * term) list * term
Programming that involves manipulation of term syntax.
See also
boolSyntax.dest_let,
pairSyntax.mk_anylet,
pairSyntax.list_mk_anylet,
pairSyntax.strip_anylet
dest_pabs
dest_pabs
pairSyntax.dest_pabs : term -> term * term
Breaks apart a paired abstraction into abstracted pair and body.
dest_pabs is a term destructor for paired abstractions:
dest_abs "\pair. t" returns ("pair","t").
Failure
Fails with dest_pabs if term is not a paired abstraction.
See also
Term.dest_abs,
pairSyntax.mk_pabs,
pairSyntax.is_pabs,
pairSyntax.strip_pabs
dest_pair
dest_pair
pairSyntax.dest_pair : term -> term * term
Breaks apart a pair into two separate terms.
dest_pair is a term destructor for pairs: if M is a term of the form
(t1,t2), then dest_pair M returns (t1,t2).
Failure
Fails if M is not a pair.
See also
pairSyntax.mk_pair,
pairSyntax.is_pair,
pairSyntax.strip_pair
dest_pexists
dest_pexists
pairSyntax.dest_pexists : term -> term * term
Breaks apart paired existential quantifiers into the bound pair and the body.
dest_pexists is a term destructor for paired existential
quantification. The application of dest_pexists to ?pair. t returns
(pair,t).
Failure
Fails with dest_pexists if term is not a paired existential
quantification.
See also
boolSyntax.dest_exists,
pairSyntax.is_pexists,
pairSyntax.strip_pexists
dest_pforall
dest_pforall
pairSyntax.dest_pforall : term -> term * term
Breaks apart paired universal quantifiers into the bound pair and the body.
dest_pforall is a term destructor for paired universal quantification.
The application of dest_pforall to "!pair. t" returns
("pair","t").
Failure
Fails with dest_pforall if term is not a paired universal
quantification.
See also
boolSyntax.dest_forall,
pairSyntax.is_pforall,
pairSyntax.strip_pforall
dest_prod
dest_prod
pairSyntax.dest_prod : hol_type -> hol_type * hol_type
Breaks a product type into its two component types.
dest_prod is a type destructor for products: dest_pair ":t1#t2"
returns (":t1",":t2").
Failure
Fails with dest_prod if the argument is not a product type.
See also
pairSyntax.is_prod,
pairSyntax.mk_prod
dest_pselect
dest_pselect
pairSyntax.dest_pselect : term -> term * term
Breaks apart a paired choice-term into the selected pair and the body.
dest_pselect is a term destructor for paired choice terms. The
application of dest_select to @pair. t returns (pair,t).
Failure
Fails with dest_pselect if term is not a paired choice-term.
See also
boolSyntax.dest_select,
pairSyntax.is_pselect
genvarstruct
genvarstruct
pairSyntax.genvarstruct : hol_type -> term
Returns a pair structure of variables whose names have not been previously used.
When given a product type, genvarstruct returns a paired structure of
variables whose names have not been used for variables or constants in
the HOL session so far. The structure of the term returned will be
identical to the structure of the argument.
Failure
Never fails.
Example
The following example illustrates the behaviour of genvarstruct:
- genvarstruct (type_of (Term `((1,2),(x:'a,x:'a))`));
> val it = `((%%genvar%%1535,%%genvar%%1536),%%genvar%%1537,%%genvar%%1538)`
: term
Unique variables are useful in writing derived rules, for specializing
terms without having to worry about such things as free variable
capture. It is often important in such rules to keep the same structure.
If not, genvar will be adequate. If the names are to be visible to a
typical user, the function pvariant can provide rather more meaningful
names.
See also
Term.genvar, PairRules.GPSPEC,
pairSyntax.pvariant
is_pabs
is_pabs
pairSyntax.is_pabs : term -> bool
Tests a term to see if it is a paired abstraction.
is_pabs "\pair. t" returns true. If the term is not a paired
abstraction the result is false.
Failure
Never fails.
See also
Term.is_abs,
pairSyntax.mk_pabs,
pairSyntax.dest_pabs
is_pair
is_pair
pairSyntax.is_pair : (term -> bool)
Tests a term to see if it is a pair.
is_pair "(t1,t2)" returns true. If the term is not a pair the result
is false.
Failure
Never fails.
See also
pairSyntax.mk_pair,
pairSyntax.dest_pair
is_pexists
is_pexists
pairSyntax.is_pexists : (term -> bool)
Tests a term to see if it as a paired existential quantification.
is_pexists "?pair. t" returns true. If the term is not a paired
existential quantification the result is false.
Failure
Never fails.
See also
boolSyntax.is_exists,
pairSyntax.dest_pexists
is_pforall
is_pforall
pairSyntax.is_pforall : (term -> bool)
Tests a term to see if it is a paired universal quantification.
is_pforall "!pair. t" returns true. If the term is not a paired
universal quantification the result is false.
Failure
Never fails.
See also
boolSyntax.is_forall,
pairSyntax.dest_pforall
is_prod
is_prod
pairSyntax.is_prod : hol_type -> bool
Tests a type to see if it is a product type.
If ty is a type of the form ty1 # ty2, then is_prod ty returns
true.
Failure
Never fails.
See also
pairSyntax.dest_prod,
pairSyntax.mk_prod
is_pselect
is_pselect
pairSyntax.is_pselect : (term -> bool)
Tests a term to see if it is a paired choice-term.
is_select "@pair. t" returns true. If the term is not a paired
choice-term the result is false.
Failure
Never fails.
See also
boolSyntax.is_select,
pairSyntax.dest_pselect
list_mk_anylet
list_mk_anylet
pairSyntax.list_mk_anylet : (term * term) list list * term -> term
Construct arbitrary let terms.
The invocation
list_mk_anylet ([[(a1,b1),...,(an,bn)], ... [(u1,v1),...,(uk,vk)]],body)
returns a term with surface syntax
let a1 = b1 and ... an = bn in
... in
let u1 = v1 and ... and uk = vk
in body
Failure
If any binding pair (x,y) is such that x and y have different
types.
Example
list_mk_anylet
([[(``x:'a``, ``P:'a``)],
[(``(y:'a, z:ind)``, ``M:'a#ind``)],
[(``f (x:'a):bool``, ``N:bool``),
(``g:bool->'a``, ``K (v:'a):bool->'a``)]], ``g (f (x:'a):bool):'a``);
> val it = `let x = P in
let (y,z) = M in
let f x = N
and g = K v
in g (f x)`
val it =
[QUOTE
" (*#loc 1 11*)let x = P in\n let (y,z) = M in\n let f x = N\n and g = K v\n in g (f x)"]:
'a frag list
Programming that involves manipulation of term syntax.
See also
boolSyntax.dest_let,
pairSyntax.mk_anylet,
pairSyntax.strip_anylet,
pairSyntax.dest_anylet
list_mk_pabs
list_mk_pabs
pairSyntax.list_mk_pabs : term list * term -> term
Iteratively constructs paired abstractions.
list_mk_pabs([p1,...,pn], t) returns \p1 ... pn. t.
Failure
Fails with list_mk_pabs if the terms in the list are not paired
structures of variables.
See also
boolSyntax.list_mk_abs,
pairSyntax.strip_pabs,
pairSyntax.mk_pabs
list_mk_pair
list_mk_pair
pairSyntax.list_mk_pair : term list -> term
Constructs a tuple from a list of terms.
list_mk_pair([t1,...,tn]) returns the term (t1,...,tn).
Failure
Fails if the list is empty.
Example
> pairSyntax.list_mk_pair [Term `1`, T, Term `2`];
val it = “(1,T,2)”: term
> pairSyntax.list_mk_pair [Term `1`];
val it = “1”: term
See also
pairSyntax.strip_pair,
pairSyntax.mk_pair
mk_anylet
mk_anylet
pairSyntax.mk_anylet : (term * term) list * term -> term
Constructs arbitrary let terms.
The invocation mk_anylet ([(a1,b1),...,(an,bn)],N) returns a term of
the form `LET P Q`, which will prettyprint as
let a1 = b1 and ... and an = bn in N. The internal representation is
equal to
LET (...(LET (\an ...\a1. N) bn) ...) b1
Each ai can be a varstruct (a single variable or a tuple of
variables), or a function variable applied to a sequence of varstructs.
In the usual case, only a single binding is made, i.e.,
mk_anylet ([(a,b)],N), and the result is equal to LET (\a. N) b.
Failure
Fails if the type of any ai is not equal to the type of the
corresponding bi.
Example
> strip_comb (pairSyntax.mk_anylet ([(Term`x`, Term`M`)], Term`N x`));
val it = (“LET”, [“λx. N x”, “M”]): term * term list
> pairSyntax.mk_anylet ([(``f (x:'a,y:'b):'c``, ``M:'c``), (``g (z:'c) :'d``, ``N:'d``)],
``g (f (a:'a,b:'b):'c):'d``);
val it = “let f (x,y) = M and g z = N in g (f (a,b))”: term
Programming that involves manipulation of term syntax.
See also
boolSyntax.mk_let,
boolSyntax.dest_let,
boolSyntax.is_let,
pairSyntax.list_mk_anylet,
pairSyntax.dest_anylet
mk_pabs
mk_pabs
pairSyntax.mk_pabs : term * term -> term
Constructs a paired abstraction.
If M is the tuple (v1,..(..)..,vn), and N is an arbitrary term,
then mk_pabs (M,N) returns the paired abstraction
`\(v1,..(..)..,vn).N`.
Failure
Fails unless M is an arbitrarily nested pair composed from variables,
with no repetitions of variables.
See also
pairSyntax.dest_pabs,
pairSyntax.is_pabs,
Term.mk_abs
mk_pair
mk_pair
pairSyntax.mk_pair : term * term -> term
Constructs object-level pair from a pair of terms.
mk_pair (t1,t2) returns (t1,t2).
Failure
Never fails.
See also
pairSyntax.dest_pair,
pairSyntax.is_pair,
pairSyntax.list_mk_pair
mk_prod
mk_prod
pairSyntax.mk_prod : hol_type * hol_type -> hol_type
Constructs a product type from two constituent types.
mk_prod(ty1, ty2) returns ty1 # t2.
Failure
Never fails.
See also
pairSyntax.is_prod,
pairSyntax.dest_prod
pbody
pbody
pairSyntax.pbody : (term -> term)
Returns the body of a paired abstraction.
pbody "\pair. t" returns "t".
Failure
Fails unless the term is a paired abstraction.
See also
Term.body,
pairSyntax.dest_pabs
spine_pair
spine_pair
pairSyntax.spine_pair : term -> term list
Breaks a paired structure into its constituent pieces.
Example
> pairSyntax.spine_pair (Term `((1,2),(3,4))`);
val it = [“(1,2)”, “3”, “4”]: term list
Comments
Note that spine_pair is similar, but not identical, to strip_pair
which works recursively.
Failure
Never fails.
See also
strip_anylet
strip_anylet
pairSyntax.strip_anylet : term -> (term * term) list list * term
Repeatedly destructs arbitrary let terms.
The invocation strip_anylet M where M has the form of a
let-abstraction, i.e., LET P Q, returns a pair
([[(a1,b1),...,(an,bn)], ... [(u1,v1),...,(uk,vk)]],body), where the
first element of the pair is a list of lists of bindings, and the second
is the body of the let. The binding lists are required since let terms
can, in general, be of the form (using surface syntax)
let a1 = b1 and ... and an = bn in body.
Failure
Never fails.
Example
> pairSyntax.strip_anylet ``let g x = A in
let v = g x y in
let f x y (a,b) = g a
and foo = M
in
f x foo v``;
val it =
([[(“g x”, “A”)], [(“v”, “g x y”)],
[(“f x y (a,b)”, “g a”), (“foo”, “M”)]], “f x foo v”):
(term * term) list list * term
Programming that involves manipulation of term syntax.
See also
boolSyntax.dest_let,
pairSyntax.mk_anylet,
pairSyntax.list_mk_anylet,
pairSyntax.dest_anylet
strip_pabs
strip_pabs
pairSyntax.strip_pabs : term -> term list * term
Iteratively breaks apart paired abstractions.
strip_pabs "\p1 ... pn. t" returns ([p1,...,pn],t). Note that
strip_pabs(list_mk_abs([p1,...,pn],t))
will not return ([p1,...,pn],t) if t is a paired abstraction.
Failure
Never fails.
See also
boolSyntax.strip_abs,
pairSyntax.list_mk_pabs,
pairSyntax.dest_pabs
strip_pair
strip_pair
pairSyntax.strip_pair : term -> term list
Recursively breaks a paired structure into its constituent pieces.
Example
> pairSyntax.strip_pair (Term `((1,2),(3,4))`);
val it = [“1”, “2”, “3”, “4”]: term list
Comments
Note that strip_pair is similar, but not identical, to spine_pair
which does not work recursively.
Failure
Never fails.
See also
strip_pexists
strip_pexists
pairSyntax.strip_pexists : term -> term list * term
Iteratively breaks apart paired existential quantifications.
strip_pexists "?p1 ... pn. t" returns ([p1,...,pn],t). Note that
strip_pexists(list_mk_pexists([[p1,...,pn],t))
will not return ([p1,...,pn],t) if t is a paired existential
quantification.
Failure
Never fails.
See also
boolSyntax.strip_exists,
pairSyntax.dest_pexists
strip_pforall
strip_pforall
pairSyntax.strip_pforall : term -> term list * term
Iteratively breaks apart paired universal quantifications.
strip_pforall "!p1 ... pn. t" returns ([p1,...,pn],t). Note that
strip_pforall(list_mk_pforall([p1,...,pn],t))
will not return ([p1,...,pn],t) if t is a paired universal
quantification.
Failure
Never fails.
See also
boolSyntax.strip_forall,
pairSyntax.dest_pforall
==
==
Parse.== : hol_type quotation -> 'a -> hol_type
Parses a quotation into a HOL type.
An invocation ==` ... `== is identical to Type ` ... `.
Failure
As for Parse.Type.
Turns strings into types.
See also
Absyn
Absyn
Parse.Absyn : term quotation -> Absyn.absyn
Implements the first phase of term parsing; the removal of special syntax.
Absyn takes a quotation and parses it into an abstract syntax tree of
type absyn, using the current term and type grammars. This phase of
parsing is unconcerned with types, and will happily parse meaningless
expressions that are syntactically valid.
Example
Absyn will parse the expression `let x = e1 in e2` into
APP(APP(IDENT "LET", LAM(VIDENT "x", IDENT "e2")), IDENT "e1")
The record syntax `rec.fld1` is converted into something of the
form
APP(IDENT "....fld1", IDENT "rec")
where the dots will actually be equal to the value of
GrammarSpecials.recsel_special (a string).
Failure
Fails if the quotation has a syntax error.
Absyn is not often used, but may be handy for implementing some weird
and wonderful concrete syntax that surpasses the functionality of the
HOL parser.
See also
Parse.Term, Parse.term_grammar
add_bare_numeral_form
add_bare_numeral_form
Parse.add_bare_numeral_form : (char * string option) -> unit
Adds support for annotated numerals to the parser/pretty-printer.
The function add_bare_numeral_form allows the user to give special
meaning to strings of digits that are suffixed with single characters. A
call to this function with pair argument (c, s) adds c as a possible
suffix. Subsequently, if a sequence of digits is parsed, and it has the
character c directly after the digits, then the natural number
corresponding to these digits is made the argument of the "map function"
corresponding to s.
This map function is computed as follows: if the s option value is
NONE, then the function is considered to be the identity and never
really appears; the digits denote a natural number. If the value of s
is SOME s', then the parser translates the string to an application of
s' to the natural number denoted by the digits.
Failure
Fails if the suffix character is not a letter.
Example
The following function, binary_of, defined with equations:
val bthm =
|- binary_of n = if n = 0 then 0
else n MOD 10 + 2 * binary_of (n DIV 10) : thm
can be used to convert numbers whose decimal notation is x, to numbers
whose binary notation is x (as long as x only involves zeroes and
ones).
The following call to add_bare_numeral_form then sets up a numeral
form that could be used by users wanting to deal with binary numbers:
- add_bare_numeral_form(#"b", SOME "binary_of");
> val it = () : unit
- Term`1011b`;
> val it = `1011b` : term
- dest_comb it;
> val it = (`binary_of`, `1011`) : term * term
Comments
It is highly recommended that users avoid using suffixes that might be interpreted as hexadecimal digits A to F, in either upper or lower case. Further, HOL convention has it that suffix character should be lower case.
If one has a range of values that are usefully indexed by natural
numbers, the function add_bare_numeral_form provides a syntactically
convenient way of reading and writing these values. If there are other
functions in the range type such that the mapping function is a
homomorphism from the natural numbers, then add_numeral_form could be
used, and the appropriate operators (+, * etc) overloaded.
See also
add_infix
add_infix
Parse.add_infix : string * int * HOLgrammars.associativity -> unit
Adds a string as an infix with the given precedence and associativity to the term grammar.
This function adds the given string to the global term grammar such that the string
<str1> s <str2>
will be parsed as
s <t1> <t2>
where <str1> and <str2> have been parsed to two terms <t1> and
<t2>. The parsing process does not pay any attention to whether or not
s corresponds to a constant or not. This resolution happens later in
the parse, and will result in either a constant or a variable with name
s. In fact, if this name is overloaded, the eventual term generated
may have a constant of quite a different name again; the resolution of
overloading comes as a separate phase (see the entry for overload_on).
Failure
add_infix fails if the precedence level chosen for the new infix is
the same as a different type of grammar rule (e.g., suffix or binder),
or if the specified precedence level has infixes already but of a
different associativity.
It is also possible that the choice of string s will result in an
ambiguous grammar. This will be marked with a warning. The parser may
behave in strange ways if it encounters ambiguous phrases, but will work
normally otherwise.
Example
Though we may not have + defined as a constant, we can still define it
as an infix for the purposes of printing and parsing:
- add_infix ("+", 500, HOLgrammars.LEFT);
> val it = () : unit
- val t = Term`x + y`;
<<HOL message: inventing new type variable names: 'a, 'b, 'c.>>
> val t = `x + y` : term
We can confirm that this new infix has indeed been parsed that way by taking the resulting term apart:
- dest_comb t;
> val it = (`$+ x`, `y`) : term * term
With its new status, + has to be "quoted" with a dollar-sign if we
wish to use it in a position where it is not an infix, as in the binding
list of an abstraction:
- Term`\$+. x + y`;
<<HOL message: inventing new type variable names: 'a, 'b, 'c.>>
> val it = `\$+. x + y` : term
- dest_abs it;
> val it = (`$+`,`x + y`) : term * term
The generation of three new type variables in the examples above
emphasises the fact that the terms in the first example and the body of
the second are really no different from f x y (where f is a
variable), and don't have anything to do with the constant for addition
from arithmeticTheory. The new + infix is left associative:
- Term`x + y + z`;
<<HOL message: inventing new type variable names: 'a, 'b.>>
> val it = `x + y + z` : term
- dest_comb it;
> val it = (`$+ (x + y)`, `z`) : term * term
It is also more tightly binding than /\ (which has precedence 400 by
default):
- Term`p /\ q + r`;
<<HOL message: inventing new type variable names: 'a, 'b.>>
> val it = `p /\ q + r` : term
- dest_comb it;
> val it = (`$/\ p`, `q + r`) : term * term
An attempt to define a right associative operator at the same level fails:
Lib.try add_infix("-", 500, HOLgrammars.RIGHT);
Exception raised at Parse.add_infix:
Grammar Error: Attempt to have differently associated infixes
(RIGHT and LEFT) at same level
Similarly we can't define an infix at level 900, because this is where
the (true prefix) rule for logical negation (~) is.
- Lib.try add_infix("-", 900, HOLgrammars.RIGHT);
Exception raised at Parse.add_infix:
Grammar Error: Attempt to have different forms at same level
Finally, an attempt to have a second + infix at a different precedence
level causes grief when we later attempt to use the parser:
- add_infix("+", 400, HOLgrammars.RIGHT);
> val it = () : unit
- Term`p + q`;
<<HOL warning: Parse.Term: Grammar ambiguous on token pair + and +,
and probably others too>>
<<HOL message: inventing new type variable names: 'a, 'b, 'c>>
> val it = ``p + q`` : term
In this situation, the behaviour of the parser will become quite
unpredictable whenever the + token is encountered. In particular, +
may parse with either fixity.
Most use of infixes will want to have them associated with a particular
constant in which case the definitional principles
(new_infixl_definition etc) are more likely to be appropriate.
However, a development of a theory of abstract algebra may well want to
have infix variables such as + above.
Comments
As with other functions in the Parse structure, there is a companion
temp_add_infix function, which has the same effect on the global
grammar, but which does not cause this effect to persist when the
current theory is exported.
See also
Parse.add_rule,
Parse.add_listform, Parse.Term
add_infix_type
add_infix_type
Parse.add_infix_type : {Assoc : associativity,
Name : string,
ParseName : string option,
Prec : int} ->
unit
Adds a type infix.
A call to add_infix_type adds an infix type symbol to the type
grammar. The argument is a record of four values providing information
about the infix.
The Assoc field specifies the associativity of the symbol (possible
values: LEFT, RIGHT and NONASSOC). The standard HOL type infixes
(+, #, -> and |->) are all right-associative. The Name field
specifies the name of the binary type operator that is being mapped to.
If the name of the type is not the same as the concrete syntax (as in
all the standard HOL examples above), the concrete syntax can be
provided in the ParseName field. The Prec field specifies the
binding precedence of the infix. This should be a number less than 100,
and probably greater than or equal to 50, where the function -> symbol
lies. The greater the number, the more tightly the symbol attempts to
"grab" its arguments.
Failure
Fails if the desired precedence level contains an existing infix with a different associativity.
Example
> Hol_datatype `atree = Nd of 'v => ('k # atree) list`;
val it = (): unit
> add_infix_type { Assoc = LEFT, Name = "atree",
ParseName = SOME ">->", Prec = 65 };
val it = (): unit
> type_of ``Nd``;
val it = “:α -> (β # (β >-> α)) list -> β >-> α”: hol_type
add_listform
add_listform
Parse.add_listform :
{separator : pp_element list, leftdelim : pp_element list,
rightdelim : pp_element list, cons : string, nilstr : string,
block_info : term_grammar.block_info } ->
unit
Adds a "list-form" to the built-in grammar, allowing the parsing of
strings such as [a; b; c] and {}.
The add_listform function allows the user to augment the HOL parser
with rules so that it can turn a string of the form
<ld> str1 <sep> str2 <sep> ... strn <rd>
into the term
<cons> t1 (<cons> t2 ... (<cons> tn <nilstr>))
where <ld> is the left delimiter string, <rd> the right delimiter,
and <sep> is the separator string from the fields of the record
argument to the function. The various stri are strings representing
the ti terms. Further, the grammar will also parse <ld> <rd> into
<nilstr>.
The pp_element lists passed to this function for the separator,
leftdelim and rightdelim fields are interpreted as by the add_rule
function. These lists must have exactly one TOK element (this provides
the string that will be printed), and other formatting elements such as
BreakSpace.
The block_info field is a pair consisting of a "consistency"
(PP.CONSISTENT, or PP.INCONSISTENT), and an indentation depth (an
integer). The standard value for this field is (PP.INCONSISTENT,0),
which will cause lists too long to fit in a single line to print with as
many elements on the first line as will fit, and for subsequent elements
to appear unindented on subsequent lines. Changing the "consistency" to
PP.CONSISTENT would cause lists too long for a single line to print
with one element per line. The indentation level number specifies the
number of extra spaces to be inserted when a line-break occurs.
In common with the add_rule function, there is no requirement that the
cons and nilstr fields be the names of constants; the parser/grammar
combination will generate variables with these names if there are no
corresponding constants.
The HOL pretty-printer is simultaneously aware of the new rule, and terms of the forms above will print appropriately.
Failure
Fails if any of the pp_element lists are ill-formed: if they include
TM, BeginFinalBlock, or EndInitialBlock elements, or if do not
include exactly one TOK element. Subsequent calls to the term parser
may also fail or behave unpredictably if the strings chosen for the
various fields above introduce precedence conflicts. For example, it
will almost always be impossible to use left and right delimiters that
are already present in the grammar, unless they are there as the left
and right parts of a closefix.
Example
The definition of the "list-form" for lists in the HOL distribution is:
add_listform {separator = [TOK ";", BreakSpace(1,0)],
leftdelim = [TOK "["], rightdelim = [TOK "]"],
cons = "CONS", nilstr = "NIL",
block_info = (PP.INCONSISTENT, 0)};
while the set syntax is defined similarly:
add_listform {leftdelim = [TOK "{"], rightdelim = TOK ["}"],
separator = [";", BreakSpace(1,0)],
cons = "INSERT", nilstr = "EMPTY",
block_info = (PP.INCONSISTENT, 0)};
Used to make sequential term structures print and parse more pleasingly.
Comments
As with other parsing functions, there is a temp_add_listform version
of this function, which has the same effect on the global grammar, but
which does not cause this effect to persist when the current theory is
exported.
See also
add_numeral_form
add_numeral_form
Parse.add_numeral_form : (char * string option) -> unit
Adds support for numerals of differing types to the parser/pretty-printer.
This function allows the user to extend HOL's parser and pretty-printer
so that they recognise and print numerals. A numeral in this context is
a string of digits. Each such string corresponds to a natural number
(i.e., the HOL type num) but add_numeral_form allows for numerals to
stand for values in other types as well.
A call to add_numeral_form(c,s) augments the global term grammar in
two ways. Firstly, in common with the function add_bare_numeral_form
(q.v.), it allows the user to write a single letter suffix after a
numeral (the argument c). The presence of this character specifies s
as the "injection function" which is to be applied to the natural number
denoted by the preceding digits.
Secondly, the constant denoted by the s argument is overloaded to be
one of the possible resolutions of an internal, overloaded operator,
which is invisibly wrapped around all numerals that appear without a
character suffix. After applying add_numeral_form, the function
denoted by the argument s is now a possible resolution of this
overloading, so numerals can now be seen as members of the range of the
type of s.
Finally, if s is not NONE, the constant denoted by s is overloaded
to be one of the possible resolutions of the string &. This operator
is thus the standard way of writing the injection function from :num
into other numeric types.
The injection function specifed by argument s is either the constant
with name s0, if s is of the form SOME s0, or the identity
function if s is NONE. Using add_numeral_form with NONE for this
parameter is done in the development of arithmeticTheory, and should
not be done subsequently.
Failure
Fails if arithmeticTheory is not loaded, as this is where the basic
constants implementing natural number numerals are defined. Also fails
if there is no constant with the given name, or if it doesn't have type
:num -> 'a for some 'a. Fails if add_bare_numeral_form would also
fail on this input.
Example
The natural numbers are given numeral forms as follows:
val _ = add_numeral_form (#"n", NONE);
This is done in arithmeticTheory so that after it is loaded, one can
write numerals and have them parse (and print) as natural numbers.
However, later in the development, in integerTheory, numeral forms for
integers are also introduced:
val _ = add_numeral_form(#"i", SOME "int_of_num");
Here int_of_num is the name of the function which injects natural
numbers into integers. After this call is made, numeral strings can be
treated as integers or natural numbers, depending on the context.
- load "integerTheory";
> val it = () : unit
- Term`3`;
<<HOL message: more than one resolution of overloading was possible.>>
> val it = `3` : term
- type_of it;
> val it = `:int` : hol_type
The parser has chosen to give the string "3" integer type (it will prefer the most recently specified possibility, in common with overloading in general). However, numerals can appear with natural number type in appropriate contexts:
- Term`(SUC 3, 4 + ~x)`;
> val it = `(SUC 3,4 + ~x)` : term
- type_of it;
> val it = `:num # int` : hol_type
Moreover, one can always use the character suffixes to absolutely specify the type of the numeral form:
- Term`f 3 /\ p`;
<<HOL message: more than one resolution of overloading was possible.>>
> val it = `f 3 /\ p` : term
- Term`f 3n /\ p`;
> val it = `f 3 /\ p` : term
Comments
Overloading on too many numeral forms is a sure recipe for confusion.
See also
Parse.add_bare_numeral_form,
Parse.overload_on,
Parse.show_numeral_types
add_rule
add_rule
Parse.add_rule :
{term_name : string, fixity : fixity,
pp_elements: term_grammar.pp_element list,
paren_style : term_grammar.ParenStyle,
block_style : term_grammar.PhraseBlockStyle *
term_grammar.block_info} -> unit
Adds a parsing/printing rule to the global grammar.
The function add_rule is a fundamental method for adding parsing (and
thus printing) rules to the global term grammar that sits behind the
term-parsing function Parse.Term, and the pretty-printer installed for
terms. It is used for everything except the addition of list-forms, for
which refer to the entry for add_listform.
There are five components in the record argument to add_rule. The
term_name component is the name of the term (whether a constant or a
variable) that will be generated at the head of the function
application. Thus, the term_name component when specifying parsing for
conditional expressions is COND.
The following values (all in structure Parse) are useful for
constructing fixity values:
val LEFT : HOLgrammars.associativity
val RIGHT : HOLgrammars.associativity
val NONASSOC : HOLgrammars.associativity
val Binder : fixity
val Closefix : fixity
val Infixl : int -> fixity
val Infixr : int -> fixity
val Infix : HOLgrammars.associativity * int -> fixity
val Prefix : int -> fixity
val Suffix : int -> fixity
The Binder fixity is for binders such as universal and existential
quantifiers (! and ?). Binders can actually be seen as (true)
prefixes (should `!x. p /\ q` be parsed as `(!x. p) /\ q` or
as `!x. (p /\ q)`?), but the add_rule interface only allows
binders to be added at the one level (the weakest in the grammar).
Further, when binders are added using this interface, all elements of
the record apart from the term_name are ignored, so the name of the
binder must be the same as the string that is parsed and printed (but
see also restricted quantifiers: associate_restriction).
The remaining fixities all cause add_rule to pay due heed to the
pp_elements ("parsing/printing elements") component of the record. As
far as parsing is concerned, the only important elements are TOK and
TM values, of the following types:
val TM : term_grammar.pp_element
val TOK : string -> term_grammar.pp_element
The TM value corresponds to a "hole" where a sub-term is possible. The
TOK value corresponds to a piece of concrete syntax, a string that is
required when parsing, and which will appear when printing. The sequence
of pp_elements specified in the record passed to add_rule specifies
the "kernel" syntax of an operator in the grammar. The "kernel" of a
rule is extended (or not) by additional sub-terms depending on the
fixity type, thus:
Closefix : [Kernel] (* no external arguments *)
Prefix : [Kernel] _ (* an argument to the right *)
Suffix : _ [Kernel] (* an argument to the left *)
Infix : _ [Kernel] _ (* arguments on both sides *)
Thus simple infixes, suffixes and prefixes would have singleton
pp_element lists, consisting of just the symbol desired. More
complicated mix-fix syntax can be constructed by identifying whether or
not sub-term arguments exist beyond the kernel of concrete syntax. For
example, syntax for the evaluation relation of an operational semantics
(_ |- _ --> _) is an infix with a kernel delimited by |- and -->
tokens. Syntax for denotation brackets [| _ |] is a closefix with one
internal argument in the kernel.
The remaining sorts of possible pp_element values are concerned with
pretty-printing. (The basic scheme is implemented on top of a standard
Oppen-style pretty-printing package.) They are
(* where
type term_grammar.block_info = PP.break_style * int
*)
val BreakSpace : (int * int) -> term_grammar.pp_element
val HardSpace : int -> term_grammar.pp_element
val BeginFinalBlock : term_grammar.block_info -> term_grammar.pp_element
val EndInitialBlock : term_grammar.block_info -> term_grammar.pp_element
val PPBlock : term_grammar.pp_element list * term_grammar.block_info
-> term_grammar.pp_element
val OnlyIfNecessary : term_grammar.ParenStyle
val ParoundName : term_grammar.ParenStyle
val ParoundPrec : term_grammar.ParenStyle
val Always : term_grammar.ParenStyle
val IfNotTop : {realonly:bool} -> term_grammar.ParenStyle
val AroundEachPhrase : term_grammar.PhraseBlockStyle
val AroundSamePrec : term_grammar.PhraseBlockStyle
val AroundSameName : term_grammar.PhraseBlockStyle
val NoPhrasing : term_grammar.PhraseBlockStyle
The two spacing values provide ways of specifying white-space should be
added when terms are printed. Use of HardSpace n results in n spaces
being added to the term whatever the context. On the other hand,
BreakSpace(m,n) results in a break of width m spaces unless this
makes the current line too wide, in which case a line-break will occur,
and the next line will be indented an extra n spaces.
For example, the add_infix function (q.v.) is implemented in terms of
add_rule in such a way that a single token infix s, has a
pp_element list of
[HardSpace 1, TOK s, BreakSpace(1,0)]
This results in chains of infixes (such as those that occur with
conjunctions) that break so as to leave the infix on the right hand side
of the line. Under this constraint, printing can't break so as to put
the infix symbol on the start of a line, because that would imply that
the HardSpace had in fact been broken. (Consequently, if a change to
this behaviour is desired, there is no global way of effecting it, but
one can do it on an infix-by-infix basis by deleting the given rule
(see, for example, remove_termtok) and then "putting it back" with
different pretty-printing constraints.)
The PPBlock function allows the specification of nested blocks (blocks
in the Oppen pretty-printing sense) within the list of pp_elements.
Because there are sub-terms in all but the Closefix fixities that
occur beyond the scope of the pp_element list, the BeginFinalBlock
and EndInitialBlock functions can also be used to indicate the
boundary of blocks whose outer extent is the term beyond the kernel
represented by the pp_element list. There is an example of this below.
The possible ParenStyle values describe when parentheses should be
added to terms. The OnlyIfNecessary value will cause parentheses to be
added only when required to disambiguate syntax. The ParoundName will
cause parentheses to be added if necessary, or where the head symbol has
the given term_name and where this term is not the argument of a
function with the same head name. This style of parenthesisation is used
with tuples, for example. The ParoundPrec value is similar, but causes
parentheses to be added when the term is the argument to a function with
the same precedence level. This is useful for forcing the
parenthesisation of stacked suffixes that share a precedence level, so
that, for example, the transpose of a transitive closure prints as
(R⁺)ᵀ rather than R⁺ ᵀ, and inv (inv 2) prints as (2⁻¹)⁻¹. The
IfNotTop value will cause
parentheses to appear whenever the term is not being printed as the
"top" term. A term is considered to be "top" if it is the whole term
being printed (and this is known as the "real top"), or if it occurs
between two tokens that always delimit complete terms. For example, the
semi-colons in a list-like form are such delimiters, as are the
list-form's left and right brackets, as are the "if" and "then" tokens
in an if-then-else form. Having the realonly parameter set to true
will cause parentheses whenever the context is anything not the real
top, while having it set to false will cause parentheses if in neither
sort of "top". Finally, the Always value causes parentheses always to
be added.
The PhraseBlockStyle values describe when pretty-printing blocks
involving this term should be entered. The AroundEachPhrase style
causes a pretty-printing block to be created around each term. This is
not appropriate for operators such as conjunction however, where all of
the arguments to the conjunctions in a list are more pleasingly thought
of as being at the same level. This effect is gained by specifying
either AroundSamePrec or AroundSameName. The former will cause the
creation of a new block for the phrase if it is at a different
precedence level from its parent, while the latter creates the block if
the parent name is not the same. The former is appropriate for + and
- which are at the same precedence level, while the latter is
appropriate for /\. Finally, the NoPhrasing style causes there to be
no block at all around terms controlled by this rule. The intention in
using such a style is to have block structure controlled by the level
above.
Failure
This function will fail if the pp_element list does not have TOK
values at the beginning and the end of the list, or if there are two
adjacent TM values in the list. It will fail if the rule specifies a
fixity with a precedence, and if that precedence level in the grammar is
already taken by rules with a different sort of fixity.
Example
The traditional (now discontinued) HOL88/90 syntax for conditionals is
b => t | e. With "dangling" terms (the b and the e) to the left
and right, it is an infix (and one of very weak precedence at that).
val _ = add_rule{term_name = "COND",
fixity = Infix (HOLgrammars.RIGHT, 3),
pp_elements = [HardSpace 1, TOK "=>",
BreakSpace(1,0), TM,
BreakSpace(1,0), TOK "|",
HardSpace 1],
paren_style = OnlyIfNecessary,
block_style = (AroundEachPhrase,
(PP.INCONSISTENT, 0))};
The more familiar if-then-else syntax has a "dangling" term only to
the right of the construction, so this rule's fixity is of type
Prefix. (If the rule was made a Closefix, strings such as
`if P then Q else R` would still parse, but so too would
`if P then Q else`.) This example also illustrates the use of
blocks within rules to improve pretty-printing.
val _ = add_rule{term_name = "COND", fixity = Prefix 70,
pp_elements = [PPBlock([TOK "if", BreakSpace(1,2),
TM, BreakSpace(1,0),
TOK "then"], (PP.CONSISTENT, 0)),
BreakSpace(1,2), TM, BreakSpace(1,0),
BeginFinalBlock(PP.CONSISTENT, 2),
TOK "else", BreakSpace(1,0)],
paren_style = OnlyIfNecessary,
block_style = (AroundEachPhrase,
(PP.INCONSISTENT, 0))};
Note that the above form is not that actually used in the system. As written, it allows for pretty-printing some expressions as:
if P then
<very long term> else Q
because the block_style is INCONSISTENT. The actual pretty-printer
for if-then-else is a custom piece of code installed with
add_user_printer. This handles nice printing of chained conditionals.
The pretty-printer prefers later rules over earlier rules by default
(though this choice can be changed with prefer_form_with_tok (q.v.)),
so if both of these calls were made, conditional expressions would print
using the if-then-else syntax rather than the _ => _ | _ syntax.
For making pretty concrete syntax possible.
Comments
Because adding new rules to the grammar may result in precedence
conflicts in the operator-precedence matrix, it is as well with
interactive use to test the Term parser immediately after adding a new
rule, as it is only with this call that the precedence matrix is built.
As with other functions in the Parse structure, there is a companion
temp_add_rule function, which has the same effect on the global
grammar, but which does not cause this effect to persist when the
current theory is exported.
An Isabelle-style concrete syntax for specifying rules would probably be desirable as it would conceal the complexity of the above from most users.
See also
Parse.add_listform,
Parse.add_infix,
Parse.prefer_form_with_tok,
Parse.remove_rules_for_term
add_strliteral_form
add_strliteral_form
Parse.add_strliteral_form : {inj:term, ldelim:string} -> unit
Adds interpretation for string literal syntaxes
If ld is a valid left delimiter, with corresponding right delimiter
rd, then a call to add_strliteral_form{inj=t,ldelim=ld} causes the
parser and pretty-printer to treat string literals delimited by ld and
rd as occurrences of the term inj applied to the given HOL value
(which will be of string type).
If the given ld-rd pair is already associated with an injector, then
the parsing process will resolve the ambiguity with the standard
overloading resolution method. In particular, note that the standard
double quotation mark (ASCII character 34, ") is associated with the
"null" injector, which takes string literals into the string type.
Other injectors can be associated with this delimiter pair.
The other valid delimiter pairs are double guillemets («...», U+00AB
and U+00BB) and single guillemets (‹...›, U+2039 and U+203A).
Failure
Fails if the ldelim field does not correspond to a valid left
delimiter, or if the HOL type of the inj field is not :string->X for
some type X.
Example
If we have established a new type of deeply embedded terms with variables, constants and binary applications:
Datatype`tm = V string | Cst string | App tm tm`;
then we can overload the usual double-quoted string literals to also be
applications of the V constructor:
> add_strliteral_form {inj=``V``, ldelim="\""};
> ``App (V "foo") (App "bar" "baz")``;
val it = “App "foo" (App "bar" "baz")”: term
where all the string literals in the output are actually applications of
V to a real literal.
We can further choose to have constants printed with enclosing «...»
by:
> add_strliteral_form {inj=``Cst``, ldelim="«"};
> ``App "foo" (Cst "bar")``;
val it = “App "foo" «bar»”: term
Note that in this situation, use of the double guillemets is unambiguous, but a bare string literal is strictly ambiguous (the default is to prefer the core string type):
> type_of “«foo»”;
val it = “:tm”: hol_type
> type_of “"foo"”;
<<HOL message: more than one resolution of overloading was possible>>
val it = “:string”: hol_type
Comments
This facility is analogous to the way in which numerals can be seen to
inhabit types other than just :num. As with other parsing facilities
there is a temporary form temp_add_strliteral_form, which does not
cause the change to the grammar to persist to descendant theories.
The effect of adding a new string literal form can be reversed by
parallel remove_string_literal_form and
temp_remove_string_literal_form functions.
See also
add_user_printer
add_user_printer
Parse.add_user_printer : (string * term) -> unit
Adds a user specified pretty-printer for a specified type.
The function add_user_printer is used to add a special purpose term
pretty-printer to the interactive system. The pretty-printer is called
whenever the term to be printed matches (with match_term) the term
provided as the second parameter. If multiple calls to
add_user_printer are made with the same string parameter, the older
functions are replaced entirely. If multiple printers match, the more
specific match will be chosen. If two matches are equally specific, the
match chosen is unspecified.
The function that performs the printing is not given directly, but is
instead referred to by name (the first parameter to add_user_printer).
This name must be linked to the desired code with a call to
term_grammar.userSyntaxFns.register_userPP, which function should be
called within another ML file (i.e., not the "Script'' file of the
theory). The name passed to the register_userPP function is then the
name that must also be passed to add_user_printer. The term argument
is the desired pattern.
Alternatively, if the name specified is the empty string (""), the
behaviour is to ensure that terms matching this pattern are not handled
by the user-printing machinery. The expectation is that a more general
pattern has already been registered, but that in this specified scenario
the general term-printing machinery should be used.
The user-supplied function may choose not to print anything for the
given term and hand back control to the standard printer by raising the
exception term_pp_types.UserPP_Failed. All other exceptions will
propagate to the top-level. If the system printer receives the
UserPP_Failed exception, it prints out the term using its standard
algorithm, but will again attempt to call the user function on any
sub-terms that match the pattern.
The type userprinter is an abbreviation defined in term_grammar to
be
type userprinter =
type_grammar.grammar * term_grammar.grammar ->
PPBackend.t ->
sysprinter ->
term_pp_types.ppstream_funs ->
(grav * grav * grav) -> int ->
term -> uprinter
where the type grav (from term_pp_types) is
datatype grav = Top | RealTop | Prec of (int * string)
The type uprinter (standing for "unit printer'') is a special monadic
printing type based on the smpp module (explained further in the
example below). The type sysprinter is another abbreviation
type sysprinter =
{ gravs : (grav * grav * grav), binderp : bool,
depth : int } -> term -> uprinter
Thus, when the user's printing function is called, it is passed ten
parameters, including three "gravity'' values in a triple, and two
grammars. The fourth parameter is the system's own printer. The fifth
parameter is a record of functions to call for adding a string to the
output, adding a break, adding new lines, defining some styles for
printing like the color, etc. The availability of the system's printer
allows the user function to use the default printer on sub-terms that it
is not interested in. The user function must not call the sysprinter
on the term that it is handed initially as the sysprinter will
immediately call the user printing function all over again. If the user
printer wants to give the whole term back to the system printer, then it
must use the UserPP_Failed exception described above.
Though there are existing functions add_string, add_break etc. that
can be used to create pretty-printing values, users should prefer
instead to use the functions that are provided in the triple with the
sysprinter. This then gives them access to functions that can prevent
inadvertent symbol merges.
The grav type is used to let pretty-printers know a little about the
context in which a term is to be printed out. The triple of gravities is
given in the order "parent", "left" and "right". The left and right
gravities specify the precedence of any operator that might be
attempting to "grab" arguments from the left and right. For example, the
term
(p /\ (if q then r else s)) ==> t
should be pretty-printed as
p /\ (if q then r else s) ==> t
The system figures this out when it comes to print the conditional expression because it knows both that the operator to the left has the appropriate precedence for conjunction but also that there is an operator with implication's precedence to the right. The issue arises because conjunction is tighter than implication in precedence, leading the printer to decide that parentheses aren't necessary around the conjunction. Similarly, considered on its own, the conjunction doesn't require parentheses around the conditional expression because there is no competition between them for arguments.
The grav constructors Top and RealTop indicate a context analogous
to the top of the term, where there is no binding competition. The
constructor RealTop is reserved for situations where the term really
is the top of the tree; Top is used for analogous situations such when
the term is enclosed in parentheses. (In the conditional expression
above, the printing of q will have Top gravities to the left and
right.)
The Prec constructor for gravity values takes both a number indicating
precedence level and a string corresponding to the token that has this
precedence level. This string parameter is of most importance in the
parent gravity (the first component of the triple) where it can be
useful in deciding whether or not to print parentheses and whether or
not to begin fresh pretty-printing blocks. For example, tuples in the
logic look better if they have parentheses around the topmost instance
of the comma-operator, regardless of whether or not this is required
according to precedence considerations. By examining the parent gravity,
a printer can determine more about the term's context. (Note that the
parent gravity will also be one or other of the left and right
gravities; but it is not possible to tell which.)
The integer parameter to both the system printing function and the user
printing function is the depth of the term. The system printer will stop
printing a term if the depth ever reaches exactly zero. Each time it
calls itself recursively, the depth parameter is reduced by one. It
starts out at the value stored in Globals.max_print_depth. Setting the
latter to ~1 will ensure that all of a term is always printed.
The binderp parameter to the system-printer is true when the term to
be printed should be considered as a binder. This makes a difference
when the printer comes to print type annotations: annotations will occur
with variables if the variable is in a binding position, and not
elsewhere. This logic ensures that a term like \x. x prints as
\x:'a. x. The first, binding occurrence of the variable gets an
annotation; subsequent occurrences do not.
Failure
Fails if the string parameter does not correspond to a name used to
register a function with term_grammar.userSyntaxFns.register_userPP.
In addition, if the function parameter fails to print all terms of the
registered type in any other way than raising the UserPP_Failed
exception, then the pretty-printer will also fail.
Example
In the examples that follow, the companion temp_add_userprinter
function is used: this function takes a value of type userprinter
directly, and so is a more direct demonstration of how user-printers can
behave. The boilerplate required for preserved-across-export_theory
functionality starts with the external module. For a theory
fooScript.sml, one might write the file fooPP.sml:
structure fooPP =
struct
fun term_printer_code ... = ...
val _ = term_grammar.userSyntaxFns.register_userPP {
name = "foo.term_printer", code = term_printer_code
}
end
where term_printer_code has type userprinter. Note that the code for
the printer has to be written so that it can be compiled before the
theory foo is in context. In particular, top-level calls to
mk_thy_const and the like will fail if they attempt to bind constants
declared in theory foo.
In fooScript.sml, the following is the idiom required:
local open fooPP in end;
val _ = add_ML_dependency "fooPP"
val _ = add_user_printer ("foo.term_printer", ``term pattern``)
As discussed, the remaining examples use temp_add_user_printer. The
first example uses the system printer to print sub-terms, and concerns
itself only with printing conjunctions. Note how the actions that make
up the pretty-printer (combinations of add_string and add_break are
combined with the infix >> operator (from the smpp module).
> fun myprint Gs B sys (ppfns:term_pp_types.ppstream_funs) gravs d t =
let
open Portable term_pp_types smpp
val (str,brk) = (#add_string ppfns, #add_break ppfns);
val (l,r) = dest_conj t
fun syspr gravs =
sys {gravs = gravs, depth = d - 1, binderp = false}
in
str "CONJ:" >>
brk (1,0) >>
syspr (Top, Top, Top) l >>
brk (1,0) >> str "and then" >> brk(1,0) >>
sys (Top, Top, Top) r >>
str "ENDCONJ"
end handle HOL_ERR _ => raise term_pp_types.UserPP_Failed;
val myprint = fn :
'a -> 'b ->
(grav * grav * grav -> int -> term ->
(term_pp_types.printing_info,'c)smpp.t) ->
term_pp_types.ppstream_funs -> 'd -> int -> term ->
(term_pp_types.printing_info,unit)smpp.t
> temp_add_user_printer ("myprint", ``p /\ q``, myprint);
val it = () : unit
> ``p ==> q /\ r``;
val it = ``p ==> CONJ: q and then r ENDCONJ`` : term
The variables p, q and r as well as the implication are all of
boolean type, but are handled by the system printer. The user printer
handles just the special form of the conjunction. Note that this example
actually falls within the scope of the add_rule functionality.
The next approach to printing conjunctions is not possible with
add_rule. This example uses the styling and blocking functions to
create part of its effect. These functions (ustyle and ublock
respectively) are higher-order functions that take printers as arguments
and cause the arguments to be printed with a particular governing style
(ustyle), or indented to reveal block structure (ublock).
- fun myprint2 Gs B sys (ppfns:term_pp_types.ppstream_funs) (pg,lg,rg) d t =
let
open Portable term_pp_types PPBackEnd smpp
val {add_string,add_break,ublock,ustyle,...} = ppfns
val (l,r) = dest_conj t
fun delim wrap body =
case pg of
Prec(_, "CONJ") => body
| _ => wrap body
fun syspr t =
sys {gravs = (Prec(0,"CONJ"), Top, Top), depth = d - 1,
binderp = false} t
in
delim (fn bod => ublock CONSISTENT 0
(ustyle [Bold] (add_string "CONJ") >>
add_break (1,2) >>
ublock INCONSISTENT 0 bod >>
add_break (1,0) >>
ustyle [Bold] (add_string "ENDCONJ")))
(syspr l >> add_string "," >> add_break (1,0) >> syspr r)
end handle HOL_ERR _ => raise term_pp_types.UserPP_Failed;
- temp_add_user_printer ("myprint2", ``p /\ q``, myprint2);
- ``p /\ q /\ r /\ s /\ t /\ u /\ p /\ p /\ p /\ p /\ p /\ p /\
p /\ p /\ p /\ p/\ p /\ p /\ q /\ r /\ s /\ t /\ u /\ v /\
(w /\ x) /\ (p \/ q) /\ r``;
> val it =
``CONJ
p, q, r, s, t, u, p, p, p, p, p, p, p, p, p, p, p, p, q,
r, s, t, u, v, w, x, p \/ q, r
ENDCONJ`` : term
This example also demonstrates using parent gravities to print out a big
term. The function passed as an argument to delim is only called when
the parent gravity is not "CONJ". This ensures that the special
delimiters only get printed when the first conjunction is encountered.
Subsequent, internal conjunctions get passed the "CONJ" gravity in the
calls to sys.
A better approach (and certainly a more direct one) would probably be to
call strip_conj and print all of the conjuncts in one fell swoop.
Additionally, this example demonstrates how easy it is to conceal
genuine syntactic structure with a pretty-printer. Finally, it shows how
styles can be used.
For extending the pretty-printer in ways not possible to encompass with the built-in grammar rules for concrete syntax.
See also
Parse.add_rule,
Term.match_term,
Parse.remove_user_printer
associate_restriction
associate_restriction
Parse.associate_restriction : (string * string) -> unit
Associates a restriction semantics with a binder.
If B is a binder and RES_B a constant then
associate_restriction("B", "RES_B")
will cause the parser and pretty-printer to support:
---- parse ---->
Bv::P. B RES_B P (\v. B)
<---- print ----
Anything can be written between the binder and "::" that could be
written between the binder and "." in the old notation. See the
examples below.
The following associations are predefined:
\v::P. B <----> RES_ABSTRACT P (\v. B)
!v::P. B <----> RES_FORALL P (\v. B)
?v::P. B <----> RES_EXISTS P (\v. B)
@v::P. B <----> RES_SELECT P (\v. B)
Where the constants RES_FORALL, RES_EXISTS and RES_SELECT are
defined in the theory bool, such that :
|- RES_FORALL P B = !x:'a. P x ==> B x
|- RES_EXISTS P B = ?x:'a. P x /\ B x
|- RES_SELECT P B = @x:'a. P x /\ B x
The constant RES_ABSTRACT has the following characterisation
|- (!p m x. x IN p ==> (RES_ABSTRACT p m x = m x)) /\
!p m1 m2.
(!x. x IN p ==> (m1 x = m2 x)) ==>
(RES_ABSTRACT p m1 = RES_ABSTRACT p m2)
Failure
Never fails.
Example
> new_binder_definition("DURING", ``DURING(p:num#num->bool) = $!p``);
val it = ⊢ ∀p. $DURING p ⇔ $! p: thm
> ``DURING x::(m,n). p x``;
Exception- HOL_ERR
(at Absyn.Absyn: on line 1, characters 2-21:
parse_term: No restricted quantifier associated with DURING) raised
> new_definition("RES_DURING",
``RES_DURING(m,n)p = !x. m<=x /\ x<=n ==> p x``);
val it = ⊢ ∀m n p. RES_DURING (m,n) p ⇔ ∀x. m ≤ x ∧ x ≤ n ⇒ p x: thm
> associate_restriction("DURING","RES_DURING");
val it = (): unit
> ``DURING x::(m,n). p x``;
val it = “DURING x::(m,n). p x”: term
> dest_comb it;
val it = (“RES_DURING (m,n)”, “λx. p x”): term * term
clear_overloads_on
clear_overloads_on
Parse.clear_overloads_on : string -> unit
Clears all overloading on the specified operator.
This function removes all overloading associated with the given string,
except those "overloads" that map the string to constants of the same
name. These additional overloads (there may be more than one constant of
the same name, as long as each such is part of a different theory) may
be removed with remove_ovl_mapping, or by using hide.
Failure
Never fails. If a string is not overloaded, this function simply has no effect.
Example
> realTheory.REAL_INV_LT1;
val it =
⊢ ∀x. realax$real_lt (realax$real_of_num 0) x ∧
realax$real_lt x (realax$real_of_num 1) ⇒
realax$real_lt (realax$real_of_num 1) (realax$inv x): thm
> clear_overloads_on "<";
val it = (): unit
> realTheory.REAL_INV_LT1;
val it =
⊢ ∀x. realax$real_lt (realax$real_of_num 0) x ∧
realax$real_lt x (realax$real_of_num 1) ⇒
realax$real_lt (realax$real_of_num 1) (realax$inv x): thm
> clear_overloads_on "&";
val it = (): unit
> realTheory.REAL_INV_LT1;
val it =
⊢ ∀x. realax$real_lt (realax$real_of_num 0) x ∧
realax$real_lt x (realax$real_of_num 1) ⇒
realax$real_lt (realax$real_of_num 1) (realax$inv x): thm
If overloading gets too confusing, this function should help to clear away one layer of supposedly helpful obfuscation.
Comments
As with other parsing functions, there is a sister function,
temp_clear_overloads_on that does the same thing, but whose effect is
not saved to a theory file.
See also
Parse.overload_on,
Parse.remove_ovl_mapping
current_grammars
current_grammars
Parse.current_grammars : unit -> type_grammar.grammar * term_grammar.grammar
Obtains the global type and term grammars.
HOL uses two global grammars to control the parsing and printing of term
and type values. These can be adjusted in a controlled way with
functions such as add_rule and overload_on.Parse.current_grammars () returns the current values of these
grammars.
Failure
Never fails.
See also
Parse.temp_set_grammars,
Parse.term_grammar,
Parse.type_grammar
disable_tyabbrev_printing
disable_tyabbrev_printing
Parse.disable_tyabbrev_printing : string -> unit
Disables the printing of a type abbreviation.
A call to disable_tyabbrev_printing s causes type abbreviations
mapping the string s to some type expansion not to be printed when an
instance of the type expansion is seen.
If the string s is not a qualified name (of the form "thy$name"),
then all type abbreviations with base name s are disabled. If s does
have a qualified name, then only a type abbreviation of that name and
theory will be disabled (if such exists).
Failure
Fails if the given string is a malformed qualified identifier (e.g.,
foo$$). If the given name is syntactically valid, but there are no
abbreviations keyed to the given name, a call to
disable_tyabbrev_printing will silently do nothing.
Example
> type_abbrev("LIST", ``:'a list``)
val it = (): unit
> ``:num list``;
val it = “:num list”: hol_type
> disable_tyabbrev_printing "LIST";
val it = (): unit
> ``:num LIST``;
val it = “:num list”: hol_type
Comments
When a type-abbreviation is established with the function type_abbrev,
this alters both parsing and printing: when the new abbreviation appears
in input the type parser will translate away the abbreviation.
Similarly, when an instance of the abbreviation appears in a type that
the printer is to output, it will replace the instance with the
abbreviation.
This is generally the appropriate behaviour. However, there is are a
number of useful abbreviations where reversing parsing when printing is
not so useful. For example, the abbreviation mapping 'a set to
'a -> bool is convenient, but it would be a mistake having it print
because types such as that of conjunction would print as
(/\) : bool -> bool set
which is rather confusing.
As with other printing and parsing functions, there is a version of this
function, temp_disable_tyabbrev_printing that does not cause its
effect to persist with an exported theory.
See also
Parse.remove_type_abbrev,
Parse.type_abbrev
hidden
hidden
Parse.hidden : string -> bool
Checks to see if a given name has been hidden.
A call hidden c where c is the name of a constant, will check to see
if the given name had been hidden by a previous call to Parse.hide.
Failure
Never fails.
Comments
The hiding of a constant only affects the quotation parser; the constant is still there in a theory.
See also
hide
hide
Parse.hide : string -> ({Name : string, Thy : string} list *
{Name : string, Thy : string} list)
Stops the quotation parser from recognizing a constant.
A call hide c where c is a string that maps to one or more
constants, will prevent the quotation parser from parsing it as such; it
will just be parsed as a variable. (A string maps to a set of possible
constants because of the possibility of overloading.) The function
returns two lists. Both specify constants by way of pairs of strings.
The first list is of constants that the string might have mapped to in
parsing (specifically, in the absyn_to_term stage of parsing), and the
second is the list of constants that would have tried to be printed as
the string. It is important to note that the two lists need not be the
same.
The effect can be reversed by Parse.update_overload_maps. The function
reveal is only the inverse of hide if the only constants mapped to
by the string all have that string as their names. (These constants will
all be in different theories.)
Failure
Never fails.
Comments
The hiding of a constant only affects the quotation parser; the constant
is still there in a theory. Further, (re-)defining a string hidden with
hide will reveal it once more. The hide function's effect is
temporary; it is not exported with a theory. A more permanent hiding
effect is possible with use of the remove_ovl_mapping function.
See also
Parse.hidden,
Parse.known_constants,
Parse.remove_ovl_mapping,
Parse.reveal,
Parse.set_known_constants,
Parse.update_overload_maps
known_constants
known_constants
Parse.known_constants : unit -> string list
Returns the list of constants known to the parser.
A call to this functions returns the list of constants that will be treated as such by the parser. Those constants with names not on the list will be parsed as if they were variables.
Failure
Never fails.
See also
Parse.hide, Parse.reveal,
Parse.set_known_constants
overload_info_for
overload_info_for
Parse.overload_info_for: string -> unit
Prints overload information for a string.
A call to overload_info_for s will cause the system to print (to
standard out) some information about the way in which the string s may
be overloaded in the current global grammar. The system will print first
the terms that s may parse to, and then the terms that might prompt
the printing of s. Typically, both sets of terms will be the same, but
they don't have to be.
Failure
Never fails.
Example
> overload_info_for "<=>";
<=> parses to:
($= :bool -> bool -> bool)
<=> might be printed from:
($= :bool -> bool -> bool)
val it = (): unit
Comments
Pretty-printed grammar values (such as returned by term_grammar())
include some of this information for all the constants that the grammar
parses.
See also
Parse.overload_on,
Parse.term_grammar
overload_on
overload_on
Parse.overload_on : string * term -> unit
Establishes a term as one of the overloading possibilities for a string.
Calling overload_on(name,tm) establishes tm as a possible resolution
of the overloaded name. The call to overload_on also ensures that
tm is the first in the list of possible resolutions chosen when a
string might be parsed into a term in more than one way, and this is the
only effect if this combination is already recorded as a possible
overloading.
When printing, this call causes tm to be seen as the operator name.
The string name may prompt further pretty-printing if it is involved
in any of the relevant grammar's rules for concrete syntax.
If tm is an abstraction, then the parser will perform beta-reductions
if the term is the function part of a redex position.
Failure
Never fails.
Example
We define the equivalent of intersection over predicates:
- val inter = new_definition("inter", Term`inter p q x = p x /\ q x`);
<<HOL message: inventing new type variable names: 'a.>>
> val inter = |- !p q x. inter p q x = p x /\ q x : thm
We overload on our new intersection constant, and can be sure that in ambiguous situations, it will be preferred:
- overload_on ("/\\", Term`inter`);
<<HOL message: inventing new type variable names: 'a.>>
> val it = () : unit
- Term`p /\ q`;
<<HOL message: more than one resolution of overloading was possible.>>
<<HOL message: inventing new type variable names: 'a.>>
> val it = `p /\ q` : term
- type_of it;
> val it = `:'a -> bool` : hol_type
Note that the original constant is considered overloaded to itself, so
that our one call to overload_on now allows for two possibilities
whenever the identifier /\ is seen. In order to make normal
conjunction the preferred choice, we can call overload_on with the
original constant:
- overload_on ("/\\", Term`bool$/\`);
> val it = () : unit
- Term`p /\ q`;
<<HOL message: more than one resolution of overloading was possible.>>
> val it = `p /\ q` : term
- type_of it;
> val it = `:bool` : hol_type
Note that in order to specify the original conjunction constant, we used
the qualified identifier syntax, with the $. If we'd used just /\,
the overloading would have ensured that this was parsed as inter.
Instead of the qualified identifier syntax, we could have also
constrained the type of conjunction explicitly so that the original
constant would be the only possibility. Thus:
- overload_on ("/\\", Term`/\ :bool->bool->bool`);
> val it = () : unit
The ability to overload to abstractions allows the use of simple symbols for "complicated" effects, without needing to actually define new constants.
- overload_on ("|<", Term`\x y. ~(x < y)`);
> val it = () : unit
- set_fixity "|<" (Infix(NONASSOC, 450));
> val it = () : unit
- val t = Term`p |< q`;
> val t = `p |< q` : term
- dest_neg t;
> Val it = `p < q` : term
This facility is used to provide symbols for "is-not-equal" (<>), and
"is-not-a-member" (NOTIN).
Comments
Overloading with abandon can lead to input that is very hard to make
sense of, and so should be used with caution. There is a temporary
version of this function: temp_overload_on.
See also
Parse.clear_overloads_on,
Parse.set_fixity
parse_from_grammars
parse_from_grammars
Parse.parse_from_grammars :
(type_grammar.grammar * term_grammar.grammar) ->
((hol_type frag list -> hol_type) * (term frag list -> term))
Returns parsing functions based on the supplied grammars.
When given a pair consisting of a type and a term grammar, this function returns parsing functions that use those grammars to turn strings (strictly, quotations) into types and terms respectively.
Failure
Can't fail immediately. However, when the precedence matrix for the term parser is built on first application of the term parser, this may generate precedence conflict errors depending on the rules in the grammar.
Example
First the user loads arithmeticTheory to augment the built-in grammar
with the ability to lex numerals and deal with symbols such as + and
-:
- load "arithmeticTheory";
> val it = () : unit
- val t = Term`2 + 3`;
> val t = `2 + 3` : term
Then the parse_from_grammars function is used to make the values
Type and Term use the grammar present in the simpler theory of
booleans. Using this function fails to parse numerals or even the +
infix:
- val (Type,Term) = parse_from_grammars boolTheory.bool_grammars;
> val Type = fn : hol_type frag list -> hol_type
val Term = fn : term frag list -> term
- Term`2 + 3`;
<<HOL message: No numerals currently allowed.>>
! Uncaught exception:
! HOL_ERR <poly>
- Term`x + y`;
<<HOL message: inventing new type variable names: 'a, 'b.>>
> val it = `x $+ y` : term
But, as the last example above also demonstrates, the installed
pretty-printer is still dependent on the global grammar, and the global
value of Term can still be accessed through the Parse structure:
- t;
> val it = `2 + 3` : term
- Parse.Term`2 + 3`;
> val it = `2 + 3` : term
This function is used to ensure that library code has access to a term
parser that is a known quantity. In particular, it is not good form to
have library code that depends on the default parsers Term and Type.
When the library is loaded, which may happen at any stage, these global
values may be such that the parsing causes quite unexpected results or
failures.
See also
Parse.add_rule,
Parse.print_from_grammars,
Parse.Term
parse_in_context
parse_in_context
Parse.parse_in_context : term list -> term quotation -> term
Parses a quotation into a term, using the terms as typing context.
Where the Term function parses a quotation in isolation of all
possible contexts (except inasmuch as the global grammar provides a form
of context), this function uses the additional parameter, a list of
terms, to help in giving variables in the quotation types.
Thus, Term`x` will either guess the type ``:'a`` for this
quotation, or refuse to parse it at all, depending on the value of the
guessing_tyvars flag. The parse_in_context function, in contrast,
will attempt to find a type for x from the list of free variables.
If the quotation already provides enough context in itself to determine a type for a variable, then the context is not consulted, and a conflicting type there for a given variable is ignored.
Failure
Fails if the quotation doesn't make syntactic sense, or if the
assignment of context types to otherwise unconstrained variables in the
quotation causes overloading resolution to fail. The latter would happen
if the variable x was given boolean type in the context, if + was
overloaded to be over either :num or :int, and if the quotation was
x + y.
Example
<< There should be an example here >>
Used in many of the Q module's variants of the standard tactics in
order to have a goal provide contextual information to the parsing of
arguments to tactics.
See also
permahide
permahide
Parse.permahide : term -> unit
Hide a constant so that its name doesn't overload to it.
A call to permahide c where c is a constant removes any mapping from
c's name to that string in the overloading map. This is done by
calling remove_ovl_mapping, which see.
Failure
Fails if the term argument is not a constant.
Comments
This is a convenience wrapper for remove_ovl_mapping. It is not the
same as a "permanent" form of the related hide function. A call to
hide s, with s a string, clears all overloads to the string s,
making that string parse to a variable when name resolution is
performed. By contrast, permahide c only adjusts the overloading maps
to and from c.
The intention is that permahide can be used in theory developments
where a constant is needed but contaminating the namespace with that
constant's name is not desired.
See also
Parse.hide,
Parse.remove_ovl_mapping
pp_term_without_overloads_on
pp_term_without_overloads_on
Parse.pp_term_without_overloads_on : string list -> term PP.pprinter
Printing function for terms without using overload mappings of certain tokens.
The call pp_term_without_overloads_on ls returns a printing function
to print terms without using any overload mappings of the tokens in
ls, using the system's standard pretty-printing stream type.
Example
> val termpp = pp_term_without_overloads_on ["+"];
val termpp = fn: term Parse.pprinter
> val _ = Portable.pprint termpp ``x + y`` ;
arithmetic$+ x y
val it = (): unit
Failure
Should never fail.
See also
Parse.pp_term_without_overloads,
Parse.print_term_without_overloads_on,
Parse.term_without_overloads_on_to_string,
Parse.print_from_grammars
prefer_form_with_tok
prefer_form_with_tok
Parse.prefer_form_with_tok : {term_name : string, tok : string} -> unit
Sets a grammar rule's preferred flag, causing it to be preferentially printed.
A call to prefer_form_with_tok causes the parsing/pretty-printing rule
specified by the term_name-tok combination to be the preferred rule
for pretty-printing purposes. This change affects the global grammar.
Failure
Never fails.
Example
Imagine that one wants to use an infix "U" to stand for the "UNION"
term. This could be done as follows:
> set_mapped_fixity {term_name = "UNION", fixity = Infixl 500,
tok = "U"};
val it = () : unit
> ``s U t``;
val it = ``s U t`` : term
> dest_term it;
val it = COMB(``$UNION s``, ``t``) : lambda
Having made this change, one might prefer to see the form with UNION
printed:
> prefer_form_with_tok {term_name = "UNION", tok = "UNION"};
val it = () : unit
> ``s U t``;
val it = ``s UNION t`` : term
Comments
As the example above demonstrates, using this function does not affect the parser at all.
There is a companion temp_prefer_form_with_tok function, which has the
same effect on the global grammar, but which does not cause this effect
to persist when the current theory is exported.
print_from_grammars
print_from_grammars
Parse.print_from_grammars :
(type_grammar.grammar * term_grammar.grammar) ->
(hol_type Parse.pprinter * term Parse.pprinter)
Returns printing functions based on the supplied grammars.
When given a pair consisting of a type and term grammar (such a pair is
exported with every theory, under the name <thy>_grammars), this
function returns printing functions that use those grammars to render
terms and types using the system's standard pretty-printing stream type.
Failure
Never fails.
Example
With arithmeticTheory loaded, arithmetic expressions and numerals
print pleasingly:
- load "arithmeticTheory";
> val it = () : unit
- ``3 + x * 4``;
> val it = ``3 + x * 4`` : term
The printing of these terms is controlled by the global grammar, which
is augmented when the theory of arithmetic is loaded. Printing functions
based on the grammar of the base theory bool can be defined:
> val (typepp, termpp) = print_from_grammars bool_grammars;
val termpp = fn : term Parse.pprinter
val typepp = fn : hol_type Parse.pprinter
These functions can then be used to print arithmetic terms (note that
neither the global parser nor printer are disturbed by this activity),
using the Portable.pprint function (or Lib.ppstring, which returns a
string):
> Portable.pprint termpp ``3 + x * 4``;
arithmetic$+
(arithmetic$NUMERAL
(arithmetic$BIT1 (arithmetic$BIT1 arithmetic$ZERO)))
(arithmetic$* x
(arithmetic$NUMERAL
(arithmetic$BIT2 (arithmetic$BIT1 arithmetic$ZERO))))
> val it = () : unit
Not only have the fixities of + and * been ignored, but the
constants in the term, belonging to arithmeticTheory, are all printed
in "long identifier" form because the grammars from boolTheory don't
know about them.
Printing terms with early grammars such as bool_grammars can remove
layers of potentially confusing pretty-printing, including complicated
concrete syntax and overloading, and even the underlying representation
of numerals.
See also
Parse.parse_from_grammars,
Parse.print_term_by_grammar,
Parse.Term, Portable.pprint,
Lib.ppstring
print_term
print_term
Parse.print_term : term -> unit
Prints a term to the screen (standard out).
The function print_term prints a term to the screen. It first converts
the term into a string, and then outputs that string to the standard
output stream.
The conversion to the string is done by term_to_string. The term is
printed using the pretty-printing information contained in the global
grammar.
Failure
Should never fail.
See also
print_term_by_grammar
print_term_by_grammar
Parse.print_term_by_grammar :
(type_grammar.grammar * term_grammar.grammar) -> term -> unit
Prints a term to standard out, using grammars to specify how.
Where print_term uses the (implicit) global grammars to control the
printing of its term argument, the print_term_by_grammar uses
user-supplied grammars. These can control the printing of concrete
syntax (operator fixities and precedency) and the degree of constant
overloading.
Failure
Never fails.
See also
print_without_macros
print_without_macros
Parse.print_without_macros : term -> unit
Prints a term to standard output, using the current grammars but without non-trivial overloading
Where print_term uses the (implicit) global grammars to control the
printing of its term argument, the print_without_macros uses these
grammars, modified to remove non-trivial overloading. (Each constant is
overloaded with itself, which avoids the printing of the theory name for
every constant).
Failure
Never fails.
Sometimes one wants to see how a term is built up, where the pretty-printing simplifies it to the point where this is not clear.
For example:
``MEM`` ;
val it = ``\x l. MEM x l`` ;
print_without_macros ``MEM`` ;
\x l. x IN LIST_TO_SET l
concl ratTheory.RATND_RAT_OF_NUM ;
val it = (RATN (&n) = &n) /\ (RATD (&n) = 1): term
Parse.print_without_macros (concl ratTheory.RATND_RAT_OF_NUM) ;
(RATN (rat_of_num n) = int_of_num n) /\ (RATD (rat_of_num n) = 1n)
Comments
To change the (implicit) global grammars to remove overloading, see
clear_overloads
See also
Parse.print_term_by_grammar,
term_grammar.clear_overloads
rawterm_pp
rawterm_pp
Parse.rawterm_pp : ('a -> 'b) -> 'a -> 'b
Causes a function to use the raw terminal backend when pretty-printing.
Functions that pretty-print HOL types, terms and theorems do so through an abstraction called a "backend". Using these backends allows output to be customised to the facilities provided by different display devices. For example, on terminals supporting DEC's vt100 colour coding, free variables are displayed in blue. There is also a "raw terminal" backend, that doesn't change the output in any way.
When an interactive session begins, HOL links all of the pretty-printing
functions to a backend value stored in a reference,
Parse.current_backend. Of course, this reference can be changed as a
user desires. A call to rawterm_pp f function wraps a call to
Lib.with_flag, setting the current backend to be the raw terminal
value for the duration of the f's application to its (first) argument.
Failure
A call to rawterm_pp f never fails. A call to rawterm_pp f x should
only fail if f x would fail, but this ultimately depends on f's
implementation.
Example
In a vt100-compatible terminal, capturing the output of pp_term
reveals a stream of horrible-looking escape codes:
> ppstring pp_term ``p /\ q``;
val it = "\^[[0;1;34mp\^[[0m /\\ \^[[0;1;34mq\^[[0m": string
If this string is to be print-ed to the vt100, it will colour the
p and q a pleasant blue colour. If, on the other hand, the string is
to be output to a file, the colouring is probably not desirable. Then
one can use rawterm_pp to get the unadorned characters of the output:
> rawterm_pp (ppstring pp_term) ``p /\ q``;
val it = "p /\\ q": string
This last usage is so common that it is already available in the library
as term_to_string.
Comments
If a function f is curried with multiple arguments, say f x y, then
care will probably be needed with modifying it with rawterm_pp. In
particular, rawterm_pp f x y is likely not to work, while
rawterm_pp (f x) y probably will.
See also
Lib.ppstring,
Parse.term_to_string,
Lib.with_flag
remove_ovl_mapping
remove_ovl_mapping
Parse.remove_ovl_mapping: string -> {Name:string,Thy:string} -> unit
Removes an overloading mapping between the string and constant specified.
Each grammar maintains two maps internally. One is from strings to non-empty lists of terms, and the other is from terms to strings. The first map is used to resolve overloading when parsing. A string will eventually be turned into one of the terms in the list that it maps to. When printing a constant, the map in the opposite direction is used to turn a term into a string.
A call to remove_ovl_mapping s {Name,Thy}, maps the Name-Thy
record to a constant c, and removes the c-s pair from both maps.
Failure
Never fails. If the given pair is not in either map, the function silently does nothing.
To prune the overloading maps of unwanted possibilities.
Comments
Note that removing a print-mapping for a constant will result in that
constant always printing fully qualified as thy$name. This situation
will persist until that constant is given a name to map to (either with
overload_on or update_overload_maps).
As with other parsing functions, there is a sister function,
temp_remove_ovl_mapping that does the same thing, but whose effect is
not saved to a theory file.
See also
Parse.clear_overloads_on,
Parse.overload_on,
Parse.update_overload_maps
remove_rules_for_term
remove_rules_for_term
Parse.remove_rules_for_term : string -> unit
Removes parsing/pretty-printing rules from the global grammar.
Calling remove_rules_for_term s removes all those rules (if any) in
the global grammar that are for the term s. The string specifies the
name of the term that the rule is for, not a token that may happen to be
used in concrete syntax for the term.
Failure
Never fails.
Example
The universal quantifier can have its special binder status removed using this function:
- val t = Term`!x. P x /\ ~Q x`;
<<HOL message: inventing new type variable names: 'a.>>
> val t = `!x. P x /\ ~Q x` : term
- remove_rules_for_term "!";
> val it = () : unit
- t;
> val it = `! (\x. P x /\ ~Q x)` : term
Similarly, one can remove the two rules for conditional expressions and see the raw syntax as follows:
- val t = Term`if p then q else r`;
<<HOL message: inventing new type variable names: 'a.>>
> val t = `if p then q else r` : term
- remove_rules_for_term "COND";
> val it = () : unit
- t;
> val it = `COND p q r` : term
Comments
There is a companion temp_remove_rules_for_term function, which has
the same effect on the global grammar, but which does not cause this
effect to persist when the current theory is exported.
See also
remove_termtok
remove_termtok
Parse.remove_termtok : {term_name : string, tok : string} -> unit
Removes a rule from the global grammar.
The remove_termtok removes parsing/printing rules from the global
grammar. Rules to be removed are those that are for the term with the
given name (term_name) and which include the string tok as part of
their concrete representation. If multiple rules satisfy this criterion,
they are all removed. If none match, the grammar is not changed.
Failure
Never fails.
Example
If one wished to revert to the traditional HOL syntax for conditional expressions, this would be achievable as follows:
- remove_termtok {term_name = "COND", tok = "if"};
> val it = () : unit
- Term`if p then q else r`;
<<HOL message: inventing new type variable names: 'a, 'b, 'c, 'd, 'e, 'f.>>
> val it = `if p then q else r` : term
- Term`p => q | r`;
<<HOL message: inventing new type variable names: 'a.>>
> val it = `COND p q r` : term
The first invocation of the parser above demonstrates that once the rule
for the if-then-else syntax has been removed, a string that used to
parse as a conditional expression then parses as a big function
application (the function if applied to five arguments).
The fact that the pretty-printer does not print the term using the
old-style syntax, even after the if-then-else rule has been removed,
is due to the fact that the corresponding rule in the grammar does not
have its preferred flag set. This can be accomplished with
prefer_form_with_tok as follows:
- prefer_form_with_tok {term_name = "COND", tok = "=>"};
> val it = () : unit
- Term`p => q | r`;
<<HOL message: inventing new type variable names: 'a.>>
> val it = `p => q | r` : term
Used to modify the global parsing/pretty-printing grammar by removing a rule, possibly as a prelude to adding another rule which would otherwise clash.
Comments
As with other functions in the Parse structure, there is a companion
temp_remove_termtok function, which has the same effect on the global
grammar, but which does not cause this effect to persist when the
current theory is exported.
The specification of a rule by term_name and one of its tokens is not
perfect, but seems adequate in practice.
See also
Parse.remove_rules_for_term,
Parse.prefer_form_with_tok
remove_type_abbrev
remove_type_abbrev
Parse.remove_type_abbrev : string -> unit
Remove a type abbreviation from the type grammar.
A call to remove_type_abbrev s removes any type abbreviations keyed on
string s. As with other functions affecting the global grammar, there
is a companion function, temp_remove_type_abbrev, which affects the
grammar but does not cause the effect to be replayed in descendant
theories.
If the string s is not a qualified name (of the form "thy$name"),
then all type abbreviations with base name s are removed. If s does
have a qualified name, then only a type abbreviation of that name and
theory will be removed (if such exists).
Failure
Fails if the given string is a malformed qualified identifier (e.g.,
foo$$). If the given name is syntactically valid, but there are no
abbreviations keyed to the given name, a call to remove_type_abbrev
will silently do nothing.
Example
The standard theory context (where pred_set is loaded), includes an
abbreviation mapping ``:'a set`` to ``:'a -> bool``. It
doesn't print the abbreviated form back to the user, because its
printing has been disabled with disable_tyabbrev_printing.
> ``:'a set``;
val it = ``:'a -> bool`` : hol_type
> remove_type_abbrev "set";
val it = (): unit
> ``:'a set``;
Exception- HOL_ERR ...
See also
Parse.disable_tyabbrev_printing,
Parse.type_abbrev
remove_user_printer
remove_user_printer
Parse.remove_user_printer : string * term -> unit
Removes a user-defined pretty-printing function associated with a particular name and term-pattern.
This removes the user-defined pretty-printing function that has been associated with a particular name (the name of the code for the function) and pattern (a term).
Failure
Never fails. If there is no user-printing function in the grammar associated with the provided key, the function has no effect.
Comments
As always, there is an accompanying function temp_remove_user_printer,
which does not affect the grammar exported to disk.
See also
reveal
reveal
Parse.reveal : string -> unit
Restores recognition of a constant by the quotation parser.
A call reveal c, where c the name of a (perhaps) hidden constant,
will 'unhide' the constant, that is, will make the quotation parser map
the identifier c to all current constants with the same name (there
may be more than one such as different theories may re-use the same
name).
Failure
Never fails, but prints a warning message if the string does not correspond to an actual constant.
Comments
The hiding of a constant only affects the quotation parser; the constant
is still there in a theory. If the parameter c is already overloaded
so as to map to other constants, these overloadings are not altered.
See also
Parse.hide, Parse.hidden,
Parse.remove_ovl_mapping,
Parse.update_overload_maps
set_fixity
set_fixity
Parse.set_fixity : string -> fixity -> unit
Allows the fixity of tokens to be updated.
The set_fixity function is used to change the fixity of single tokens.
It implements this functionality rather crudely. When called on to set
the fixity of t to f, it removes all rules mentioning t from the
global (term) grammar, and then adds a new rule to the grammar. The new
rule maps occurrences of t with the given fixity to terms of the same
name.
Failure
This function fails if the new fixity causes a clash with existing
rules, as happens if the precedence level of the specified fixity is
already taken by rules using a fixity of a different type. Even if the
application of set_fixity succeeds, it may cause the next subsequent
application of the Term parsing function to complain about precedence
conflicts in the operator precedence matrix. These problems may cause
the parser to behave oddly on terms involving the token whose fixity was
set. Excessive parentheses will usually cure even these problems.
Example
After a new constant is defined, set_fixity can be used to give it an
appropriate parse status:
- val thm = Psyntax.new_recursive_definition
prim_recTheory.num_Axiom "f"
(Term`(f 0 n = n) /\ (f (SUC n) m = SUC (SUC (f n m)))`);
> val thm =
|- (!n. f 0 n = n) /\ !n m. f (SUC n) m = SUC (SUC (f n m))
: thm
- set_fixity "f" (Infixl 500);
> val it = () : unit
- thm;
> val it =
|- (!n. 0 f n = n) /\ !n m. SUC n f m = SUC (SUC (n f m)) : thm
The same function can be used to alter the fixities of existing constants:
- val t = Term`2 + 3 + 4 - 6`;
> val t = `2 + 3 + 4 - 6` : term
- set_fixity "+" (Infixr 501);
> val it = () : unit
- t;
> val it = `(2 + 3) + 4 - 6` : term
- dest_comb (Term`3 - 1 + 2`);
> val it = (`$- 3`, `1 + 2`) : term * term
Comments
This function is of no use if multiple-token rules (such as those for
conditional expressions) are desired, or if the token does not
correspond to the name of the constant or variable that is to be
produced. (For the latter case, use set_mapped_fixity.)
As with other functions in the Parse structure, there is a companion
temp_set_fixity function, which has the same effect on the global
grammar, but which does not cause this effect to persist when the
current theory is exported.
See also
Parse.add_rule,
Parse.add_infix,
Parse.remove_rules_for_term,
Parse.remove_termtok,
Parse.set_mapped_fixity
set_known_constants
set_known_constants
Parse.set_known_constants : string list -> unit
Specifies the list of names that should be parsed as constants.
One of the final phases of parsing is the resolution of free names in putative terms as either variables, constants or overloaded constants. If such a free name is not overloaded, then the list of known constants is consulted to determine whether or not to treat it as a constant. If the name is not present in the list, then it will be treated as a free variable.
Failure
Never fails. If a name is specified in the list of constants that is not in fact a constant, a warning message is printed, and that name is ignored.
Example
> known_constants();
val it =
["", "!", "##", "%%", "&", "()", "*", "**", "*,", "+", "++", "+++", ",",
"-", "-->", "/\\", "0", ":-", ":>", "<", "<<=", "<=", "<=/=>", "<=>",
"<>", "=", "===>", "==>", ">", ">=", "?", "?!", "?!!", "@", "ABS_DIFF",
"ABS_num", "ABS_prod", "ABS_sum", "ALL_DISTINCT", "ALL_EL", "AND_EL",
"APPEND", "APPLICATIVE_FAPPLY", "APPLY_REDUNDANT_ROWS_INFO", "ARB",
"ASM_MARKER", "ASSOC", "Abbrev", "BIGINTER", "BIGUNION", "BIJ", "BIT1",
"BIT2", "BOUNDED", "BUTFIRSTN", "BUTLAST", "BUTLASTN", "CARD",
"CEILING_DIV", "CEILING_MOD", "CHOICE", "COMM", "COMPL", "COND", "CONS",
"COUNTABLE", "COUNT_LIST", "COUNT_LIST_AUX", "CR", "CROSS", "CURRY",
"Case", "Cong", "DATATYPE", "DELETE", "DELETE_ELEMENT", "DFUNSET",
"DIFF", "DISJOINT", "DIV", "DIV2", "DIVMOD", "DROP", "EL", "ELL",
"EMPTY", "EMPTY_REL", "EQC", "EQUIV", "EVEN", "EVERY", "EVERY2",
"EVERYi", "EXISTS", "EXP", "EXTENSIONAL", "EXT_POINT", "Exclude",
"ExcludeFrag", "F", ...]: string list
> Term`p /\ q`;
val it = “p ∧ q”: term
> set_known_constants (Lib.subtract (known_constants()) ["/\\"]);
val it = (): unit
> Term`p /\ q`;
val it = “p ∧ q”: term
> strip_comb it;
val it = (“$/\”, [“p”, “q”]): term * term list
> dest_var (#1 it);
val it = ("/\\", “:α -> β -> γ”): string * hol_type
When writing library code that calls the parser, it can be useful to know exactly what constants the parser will "recognise".
Comments
This function does not affect the contents of a theory. A constant made invisible using this call is still really present in the theory; it is just harder to find.
See also
Parse.hidden, Parse.hide,
Parse.known_constants,
Parse.reveal
set_mapped_fixity
set_mapped_fixity
Parse.set_mapped_fixity :
{tok : string, term_name : string, fixity : fixity} -> unit
Allows the fixity of tokens to be updated.
The set_mapped_fixity function is used to change the fixity of a
single token, simultaneously mapping forms using that token name to a
different name. Apart from the additional term_name field, the
behaviour is similar to that of set_fixity.
Failure
This function fails if the new fixity causes a clash with existing
rules, as happens if the precedence level of the specified fixity is
already taken by rules using a fixity of a different type. Even if the
application of set_mapped_fixity succeeds, it may cause the next
subsequent application of the Term parsing function to complain about
precedence conflicts in the operator precedence matrix. These problems
may cause the parser to behave oddly on terms involving the token whose
fixity was set. Excessive parentheses will usually cure even these
problems.
Comments
This function is of no use if multiple-token rules (such as those for conditional expressions) are desired.
As with other functions in the Parse structure, there is a companion
temp_set_mapped_fixity function, which has the same effect on the
global grammar, but which does not cause this effect to persist when the
current theory is exported.
See also
Parse.add_rule,
Parse.set_fixity
show_numeral_types
show_numeral_types
Globals.show_numeral_types : bool ref
A flag which causes numerals to be printed with suffix annotation when true.
This flag controls the pretty-printing of numeral forms that have been
added to the global grammar with the function add_numeral_form. If the
flag is true, then all numeric values are printed with the single-letter
suffixes that identify which type the value is.
Failure
Never fails, as it is just an SML value.
Example
> Term`~3`;
val it = “-3”: term
> show_numeral_types := true;
val it = (): unit
> Term`~3`;
val it = “-3i”: term
Can help to disambiguate terms involving numerals.
See also
Parse.add_numeral_form,
Globals.show_types
temp_set_grammars
temp_set_grammars
Parse.temp_set_grammars : type_grammar.grammar * term_grammar.grammar -> unit
Sets the global type and term grammars.
HOL uses two global grammars to control the parsing and printing of term
and type values. These can be adjusted in a controlled way with
functions such as add_rule and overload_on. By using just these
standard functions, the system is able to export theories in such a way
that changes to grammars persist from session to session.
Nonetheless it is occasionally useful to set grammar values directly. This change can't be made to persist, but will affect the current session.
Failure
Never fails.
See also
Parse.current_grammars,
Parse.add_rule,
Parse.overload_on,
Parse.parse_from_grammars,
Parse.print_from_grammars,
Parse.Term
Term
Term
Parse.Term : term quotation -> term
Parses a quotation into a term value.
The parsing process for terms divides into four distinct phases.
The first phase converts the quotation argument into abstract syntax, a
relatively simple parse tree datatype, with the following datatype
definition (from Absyn):
datatype vstruct
= VAQ of term
| VIDENT of string
| VPAIR of vstruct * vstruct
| VTYPED of vstruct * pretype
datatype absyn
= AQ of term
| IDENT of string
| APP of absyn * absyn
| LAM of vstruct * absyn
| TYPED of absyn * pretype
This phase of parsing is concerned with the treatment of the rawest
concrete syntax. It has no notion of whether or not a term corresponds
to a constant or a variable, so all preterm leaves are ultimately
either IDENTs or AQs (anti-quotations).
This first phase converts infixes, mixfixes and all the other categories
of syntactic rule from the global grammar into simple structures built
up using APP. For example, `x op y` (where op is an infix)
will turn into
APP(APP(IDENT "op", IDENT "x"), IDENT "y")
and `tok1 x tok2 y` (where tok1 _ tok2 has been declared as a
Prefix form for the term f) will turn into
APP(APP(IDENT "f", IDENT "x"), IDENT "y")
The special syntaxes for "let" and record expressions are also handled
at this stage. For more details on how this is done see the reference
entry for Absyn, which function can be used in isolation to see what
is done at this phase.
The second phase of parsing consists of the resolution of names,
identifying what were just VARs as constants or genuine variables
(whether free or bound). This phase also annotates all leaves of the
data structure (given in the entry for Preterm) with type information.
The third phase of parsing works over the Preterm datatype and does
type-checking, though ignoring overloaded values. The datatype being
operated over uses reference variables to allow for efficiency, and the
type-checking is done "in place". If type-checking is successful, the
resulting value has consistent type annotations.
The final phase of parsing resolves overloaded constants. The type-checking done to this point may completely determine which choice of overloaded constant is appropriate, but if not, the choice may still be completely determined by the interaction of the possible types for the overloaded possibilities.
Finally, depending on the value of the global flags guessing_tyvars
and guessing_overloads, the parser will make choices about how to
resolve any remaining ambiguities.
The parsing process is entirely driven by the global grammar. This value
can be inspected with the term_grammar function.
Failure
All over place, and for all sorts of reasons.
Turns strings into terms.
See also
Parse.Absyn,
Parse.overload_on,
Parse.term_grammar
term_grammar
term_grammar
Parse.term_grammar : unit -> term_grammar.grammar
Returns the current global term grammar.
Failure
Never fails.
Comments
There is a pretty-printer installed in the interactive system so that
term grammar values are presented nicely. The global term grammar is
passed as a parameter to the Term parsing function in the Parse
structure, and also drives the installed term and theorem
pretty-printers.
See also
Parse.parse_from_grammars,
Parse.print_from_grammars,
Parse.temp_set_grammars,
Parse.Term
term_to_string
term_to_string
Parse.term_to_string : term -> string
Converts a term to a string.
Uses the global term grammar and pretty-printing flags to turn a term
into a string. It assumes that the string should be broken up as if for
display on a screen that is as wide as the value stored in the
Globals.linewidth variable.
Failure
Should never fail.
See also
thytype_abbrev
thytype_abbrev
Parse.thytype_abbrev : {Name:string,Thy:string} * hol_type * bool -> unit
Abbreviates a type to a specific theory-qualified name.
A call to thytype_abbrev({Name=n,Thy=t}, ty, prp) establishes the
"kernel" name t$n as an abbreviation for the type ty, as happens
with type_abbrev. The boolean flag prp indicates whether or not this
abbreviation will also be used when the printer comes to print the given
type. In other words, after the call it becomes possible to write
“:args t$n” to stand for type ty. If there are type variables in
ty they become the parameters to the new abbreviated type operator.
These parameters need to be filled in in the args position above. If
there are no type variables in ty then abbreviation is of a whole
type, and args must be blank.
If there was an existing abbreviation for t$n, then this will be
replaced by the call.
In addition, after the given call, this abbreviation will become the
preferred binding for the bare name n. Other abbreviations in
different theories will need to use the form with fully-qualified names
(thy1$n, thy2$n etc).
If the boolean flag is false, this invocation is comparable to the
behaviour after intputonly_type_abbrev: the abbreviation can be used
to input types of the desired pattern, but such types will print as they
did previously.
Failure
Fails if ty is a variable type.
Comments
As with other parsing and pretty-printing functions, there is a
companion function, temp_thytype_abbrev, which has the same effect on
the global grammar but does not cause the change to persist when the
theory is exported.
It is legitimate to use a string for the theory component of the record that does not correspond to the current theory. Indeed, it is perfectly reasonable to do this, if one wants to give priority to a particular ancestral abbreviation.
See also
ty_antiq
ty_antiq
Parse.ty_antiq : hol_type -> term
Make a variable named ty_antiq.
Given a type ty, the ML invocation ty_antiq ty returns the HOL
variable ty_antiq : ty. This provides a way to antiquote types into
terms, which is necessary because the HOL term parser only allows terms
to be antiquoted. The use of ty_antiq promotes a type to a term
variable which can be antiquoted. The HOL parser detects occurrences of
ty_antiq ty and inserts ty as a constraint.
Example
Suppose we want to constrain a term to have type num list, which is
bound to ML value ty. Attempting to antiquote ty directly into the
term won't work:
> val ty = ``:num list``;
val ty = “:num list”: hol_type
> “x : ^ty”;
Exception- Type error in function application.
Function: Parse.Term : term frag list -> term
Argument: [QUOTE " (*#loc 1 4*)x : ", ANTIQUOTE ty] :
hol_type frag list
Reason:
Can't unify term (*Created from opaque signature*) with
hol_type (*Created from opaque signature*)
(Different type constructors)
Fail "Static Errors" raised
Use of ty_antiq solves the problem:
> ``x : ^(ty_antiq ty)``;
val it = “x”: term
> type_of it;
val it = “:num list”: hol_type
See also
type_abbrev
type_abbrev
Parse.type_abbrev : string * hol_type -> unit
Establishes a type abbreviation.
A call to type_abbrev(s,ty) sets up a type abbreviation that will
cause the parser to treat the string s as a synonym for the type ty.
Moreover, if ty includes any type variables, then the abbreviation is
treated as a type operator taking as many parameters as appear in ty.
The order of the parameters will be the alphabetic ordering of the type
variables' names.
Abbreviations work at the level of the names of type operators. It is thus possible to link a binary infix to an operator that is in turn an abbreviation.
Failure
Fails if the given type is just a type variable.
Example
This is a simple abbreviation.
> type_abbrev ("set", ``:'a -> bool``);
val it = () : unit
> ``:num set``;
val it = ``:num -> bool`` : hol_type
Here, the abbreviation is set up and provided with its own infix symbol.
- type_abbrev ("rfunc", ``:'b -> 'a``);
> val it = () : unit
- add_infix_type {Assoc = RIGHT, Name = "rfunc",
ParseName = SOME "<-", Prec = 50};
> val it = () : unit
- ``:'a <- bool``;
> val it = ``:bool -> 'a`` : hol_type
- dest_thy_type it;
> val it = {Args = [``:bool``, ``:'a``], Thy = "min", Tyop = "fun"} :
{Args : hol_type list, Thy : string, Tyop : string}
Comments
As is common with most of the parsing and printing functions, there is a
companion temp_type_abbrev function that does not cause the
abbreviation effect to persist when the theory is exported. As the
examples show, this entrypoint does not affect the pretty-printing of
types. If printing of abbreviations is desired as well as parsing, the
entrypoint type_abbrev_pp should be used.
See also
Parse.add_infix_type,
Parse.disable_tyabbrev_printing,
Parse.remove_type_abbrev,
Parse.thytype_abbrev,
Parse.type_abbrev_pp
type_abbrev_pp
type_abbrev_pp
Parse.type_abbrev_pp : string * hol_type -> unit
Installs type abbreviation affecting parsing and printing.
As with type_abbrev(s,ty), a call to type_abbrev_pp(s,ty) sets up
the string s to be an abbrevation for the type ty when types are
parsed. In addition, it causes the type pretty-printer to prefer the
abbreviation when it comes to print types that match the implicit
pattern specified by ty (which may include type variables).
Failure
Fails if the provided type is a single type variable.
Example
> type_abbrev_pp ("foo", ``:num -> 'a # num``);
val it = () : unit
> ``:bool foo``;
val it = ``:bool foo``: hol_type
> dest_thy_type it;
val it = {Args = [``:num``, ``:bool # num``],
Thy = "min", Tyop = "fun"}:
{Args: hol_type list, Thy: string, Tyop: string}
See also
update_overload_maps
update_overload_maps
Parse.update_overload_maps :
string -> ({Name : string, Thy : string} list *
{Name : string, Thy : string} list) -> unit
Adds to the parser's overloading maps.
The parser/pretty-printer for terms maintains two maps between constants and strings. From strings to terms, the map is from one string to a set of terms. Each term represents a possible overloading for the string. In the other direction, a term maps to just one string, its preferred representation.
The function update_overload_maps adds to (potentially overriding old
mappings in) both of these maps. Its first parameter, a string, is the
string involved in both directions. The two lists of Name-Thy
records specify terms for the two maps. The first component of the
tuple, specifies terms that the string will be overloaded to. (Note that
it is perfectly reasonable to "overload" to just one term, and that this
is the default situation for newly defined constants.)
The second component of the tuple sets the given string as the preferred identifier for the given terms.
Failure
Fails if any of the Name-Thy pairs doesn't correspond to an actual
constant.
See also
Parse.clear_overloads_on,
Parse.hide, Parse.overload_on,
Parse.remove_ovl_mapping,
Parse.reveal
Define_mk_ptree
Define_mk_ptree
patriciaLib.Define_mk_ptree : string -> term_ptree -> thm
Define a new Patricia tree constant.
A call to Define_mk_ptree c t builds a HOL Patricia tree from the ML
tree t and uses this to define a new constant c. This provides and
efficient mechanism to define large patricia trees in HOL: the trees can
be quickly built in ML and then imported into HOL via
patriciaLib.mk_ptree. Provided the tree is not too large, a
side-effect of Define_mk_ptree is to prove the theorem
|- IS_PTREE c. This is controlled by the reference
is_ptree_term_size_limit.
To avoid producing large terms, a call to EVAL will not expand out the
definition of the new constant c. However, it will efficiently
evaluate operations performed on c, e.g. PEEK c n for ground n.
Failure
Define_mk_ptree will fail when patriciaLib.mk_ptree fails.
Example
The following session shows the construction of Patricia trees in ML, which are then imported into HOL.
> open patriciaLib;
> val ptree = patriciaLib.Define_mk_ptree "ptree" (int_ptree_of_list [(1,``1``), (2, ``2``)]);
val ptree = ⊢ ptree = Branch 0 0 (Leaf 1 1) (Leaf 2 2): thm
> DB.fetch "-" "ptree_def";
val it = ⊢ ptree = Branch 0 0 (Leaf 1 1) (Leaf 2 2): thm
> val _ = Globals.max_print_depth := 7;
let
fun pp _ _ (_: term_ptree) = PolyML.PrettyString "<ptree>"
in
PolyML.addPrettyPrinter pp
end;
val it = (): unit
> val random_ptree =
real_time patriciaLib.ptree_of_ints
(Random.rangelist (0,100000) (10000,Random.newgenseed 1.0));
realtime: 0.013s
val random_ptree = <ptree>: term_ptree
> val random = real_time (patriciaLib.Define_mk_ptree "random") random_ptree;
realtime: 0.084s
val random =
⊢ random =
Branch 0 0
(... ... 1 (... ... (... ... ))
(... ... (... ... ) (... ... (... ... ))))
(Branch 0 1 (... ... (... ... ) (... ... (... ... )))
(... ... 2 (... ... (... ... ))
(... ... (... ... ) (... ... (... ... ))))): thm
> patriciaLib.size random_ptree;
val it = 9517: int
> real_time EVAL ``SIZE random``;
realtime: 0.118s
val it = ⊢ SIZE random = 9517: thm
> int_peek random_ptree 3;
val it = SOME (“()”): term option
> real_time PTREE_CONV ``random ' 3``;
realtime: 0.000s
val it = ⊢ random ' 3 = random ' 3: thm
> int_peek random_ptree 100;
val it = NONE: term option
> real_time EVAL ``random ' 100``;
realtime: 0.000s
val it = ⊢ random ' 100 = random ' 100: thm
See also
patriciaLib.mk_ptree,
patriciaLib.PTREE_CONV,
patriciaLib.PTREE_DEFN_CONV
dest_ptree
dest_ptree
patriciaLib.dest_ptree : term -> term_ptree
Term destructor for Patricia trees.
The destructor dest_ptree will return a Patricia tree in ML that
corresponds with the supplied HOL term. The ML abstract data type
term_ptree is defined in patriciaLib.
Failure
The conversion will fail if the supplied term is not well constructed Patricia tree.
Example
- dest_ptree ``(Branch 1 2 (Leaf 2 2) (Leaf 3 3))``;
Exception-
HOL_ERR
{message = "not a valid Patricia tree", origin_function = "dest_ptree",
origin_structure = "patricia"} raised
- dest_ptree ``(Branch 0 0 (Leaf 3 3) (Leaf 2 2))``;
val it = <ptree>: term_ptree
Comments
By default PolyML prints abstract data types in full. This can be turned off with:
let
fun pp _ _ (_: term_ptree) = PolyML.PrettyString "<ptree>"
in
PolyML.addPrettyPrinter pp
end;
See also
patriciaLib.mk_ptree,
patriciaLib.is_ptree
is_ptree
is_ptree
patriciaLib.is_ptree : term -> bool
Term recogniser for Patricia trees.
The destructor is_ptree will return true if, and only if, the supplied
term is a well-constructed, ground Patricia tree.
Example
> patriciaLib.is_ptree ``t:unit ptree``;
val it = false: bool
> patriciaLib.is_ptree ``Branch 1 2 (Leaf 2 2) (Leaf 3 3)``;
val it = false: bool
> patriciaLib.is_ptree ``Branch 0 0 (Leaf 1 1) (Leaf 2 2)``;
val it = true: bool
See also
patriciaLib.mk_ptree,
patriciaLib.dest_ptree
mk_ptree
mk_ptree
patriciaLib.mk_ptree : term_ptree -> term
Term constructor for Patricia trees.
The constructor mk_ptree will return a HOL term that corresponds with
the supplied ML Patricia tree. The ML abstract data type term_ptree is
defined in patriciaLib.
Failure
The conversion will fail if the terms stored in the supplied Patricia tree do not all have the same type.
Example
> patriciaLib.mk_ptree (patriciaLib.int_ptree_of_list [(1,``T``), (2, ``2``)]);
Exception- HOL_ERR at patriciaSyntax.mk_branch: raised
> patriciaLib.mk_ptree (patriciaLib.int_ptree_of_list [(1,``1``), (2, ``2``)]);
val it = “Branch 0 0 (Leaf 1 1) (Leaf 2 2)”: term
Comments
When working with large trees it is a good idea constrain term printing by setting Globals.max_print_depth.
See also
patriciaLib.dest_ptree,
patriciaLib.is_ptree
PTREE_ADD_CONV
PTREE_ADD_CONV
patriciaLib.PTREE_ADD_CONV : conv
Conversion for evaluating applications of patricia$ADD and
patricia$ADD_LIST.
The conversion PTREE_ADD_CONV evaluates terms of the form t |+ (m,n)
or t |++ l where t is a well-formed Patricia tree (correctly
constructed using patricia$Empty, patricia$Leaf and
patricia$Branch) and m is a natural number literal.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$ADD or patricia$ADD_LIST.
Example
> patriciaLib.PTREE_ADD_CONV ``Empty |+ (3, x:num)``;
val it = ⊢ <{}> |+ (3,x) = Leaf 3 x: thm
> DEPTH_CONV patriciaLib.PTREE_ADD_CONV ``Empty |+ (3, 2) |+ (2,1)``;
val it = ⊢ <{}> |+ (3,2) |+ (2,1) = Branch 0 0 (Leaf 3 2) (Leaf 2 1): thm
See also
PTREE_CONV
PTREE_CONV
patriciaLib.PTREE_CONV : conv
Conversion for evaluating Patricia tree operations.
The conversion PTREE_CONV evaluates Patricia tree operations such as
ADD, ADD_LIST, REMOVE, SIZE, PEEK and FIND. These
evaluations work for constants that are defined using Define_mk_ptree.
When adding to, or removing from, a Patricia tree a new contant will be
defined after patriciaLib.ptree_new_defn_depth operations. By default
ptree_new_defn_depth is ~1, which means that new constants are never
defined.
Example
Consider the following Patricia tree:
val ptree = Define_mk_ptree "ptree" (int_ptree_of_list [(1,``1``), (2, ``2``)]);
<<HOL message: Saved IS_PTREE theorem for new constant "ptree">>
val ptree = |- ptree = Branch 0 0 (Leaf 1 1) (Leaf 2 2): thm
Adding a list of updates expands into applications of ADD:
> real_time patriciaLib.PTREE_CONV ``ptree |++ [(3,3); (4,4); (5,5); (6,6); (7,7)]``;
realtime: 0.000s
val it =
⊢ ptree |++ [(3,3); (4,4); (5,5); (6,6); (7,7)] =
ptree |+ (3,3) |+ (4,4) |+ (5,5) |+ (6,6) |+ (7,7): thm
However, setting ptree_new_defn_depth will cause new definitions to be
made:
> patriciaLib.ptree_new_defn_depth := 2;
val it = (): unit
> real_time patriciaLib.PTREE_CONV ``ptree |++ [(3,3); (4,4); (5,5); (6,6); (7,7)]``;
realtime: 0.000s
val it =
⊢ ptree |++ [(3,3); (4,4); (5,5); (6,6); (7,7)] =
ptree |+ (3,3) |+ (4,4) |+ (5,5) |+ (6,6) |+ (7,7): thm
New definitions will also be made when removing elements:
> real_time patriciaLib.PTREE_CONV ``ptree2 \\ 6 \\ 5``;
realtime: 0.000s
val it = ⊢ ptree2 \\ 6 \\ 5 = ptree2 \\ 6 \\ 5: thm
Here, the conversion is not smart enough to work out that ptree3 is
the same as ptree1.
> (DEPTH_CONV patriciaLib.PTREE_DEFN_CONV THENC EVAL) ``ptree1 = ptree3``;
val it = ⊢ ptree1 = ptree3 ⇔ ptree1 = ptree3: thm
Look-up behaves as expected:
> real_time patriciaLib.PTREE_CONV ``ptree1 ' 2``;
realtime: 0.000s
val it = ⊢ ptree1 ' 2 = ptree1 ' 2: thm
> real_time patriciaLib.PTREE_CONV ``ptree1 ' 5``;
realtime: 0.000s
val it = ⊢ ptree1 ' 5 = ptree1 ' 5: thm
Comments
The conversion PTREE_CONV is automatically added to the standard
compset. Thus, EVAL will have the same behaviour when patriciaLib
is loaded.
Run-times should be respectable when working with large Patricia trees.
However, this is predicated on the assumption that relatively small
numbers of updates are made following an initial application of
Define_mk_ptree. In this sense, the Patricia tree development is best
suited to situations where users require fast "read-only" look-up; where
the work of building the look-up tree can be performed outside of the
logic (i.e. in ML).
See also
patriciaLib.Define_mk_ptree,
patriciaLib.PTREE_DEFN_CONV
PTREE_DEFN_CONV
PTREE_DEFN_CONV
patriciaLib.PTREE_DEFN_CONV : conv
Conversion for evaluating applications of ADD and REMOVE to Patricia
tree constants.
Given a constant c defined using Define_mk_ptree, the conversion
PTREE_DEFN_CONV will evaluate term of the form c |+ (k,x), c \\ k
and c where k is a natural number literal.
Example
> val ptree = patriciaLib.Define_mk_ptree "ptree" (patriciaLib.int_ptree_of_list [(1,``1``), (2, ``2``)]);
val ptree = ⊢ ptree = Branch 0 0 (Leaf 1 1) (Leaf 2 2): thm
> patriciaLib.PTREE_DEFN_CONV ``ptree \\ 1``;
val it = ⊢ ptree \\ 1 = Leaf 2 2: thm
> patriciaLib.PTREE_DEFN_CONV ``ptree |+ (3,3)``;
val it =
⊢ ptree |+ (3,3) =
Branch 0 0 (Branch 1 1 (Leaf 3 3) (Leaf 1 1)) (Leaf 2 2): thm
Comments
The conversion PTREE_DEFN_CONV has limited uses and is mostly used
internally by the conversion PTREE_CONV.
See also
patriciaLib.Define_mk_ptree,
patriciaLib.PTREE_CONV
PTREE_DEPTH_CONV
PTREE_DEPTH_CONV
patriciaLib.PTREE_DEPTH_CONV : conv
Conversion for evaluating applications of patricia$DEPTH.
The conversion PTREE_DEPTH_CONV evaluates terms of the form DEPTH t
where t is a well-formed Patricia tree (constructed by
patricia$Empty, patricia$Leaf and patricia$Branch).
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$DEPTH.
Example
> patriciaLib.PTREE_DEPTH_CONV ``DEPTH Empty``;
val it = ⊢ DEPTH <{}> = 0: thm
> patriciaLib.PTREE_DEPTH_CONV ``DEPTH (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
val it = ⊢ DEPTH (Branch 0 0 (Leaf 3 2) (Leaf 2 1)) = 2: thm
See also
PTREE_EVERY_LEAF_CONV
PTREE_EVERY_LEAF_CONV
patriciaLib.PTREE_EVERY_LEAF_CONV : conv
Conversion for evaluating applications of patricia$EVERY_LEAF.
The conversion PTREE_EVERY_LEAF_CONV evaluates terms of the form
EVERY_LEAF P t where t is a well-formed Patricia tree (constructed
by patricia$Empty, patricia$Leaf and patricia$Branch) and P is
predicate.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$EVERY_LEAF.
Example
> patriciaLib.PTREE_EVERY_LEAF_CONV ``EVERY_LEAF (=) Empty``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_EVERY_LEAF_CONV : conv -> conv
Argument: (Parse.Term [QUOTE " (*#loc 1 37*)EVERY_LEAF (=) Empty"])
: term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
> patriciaLib.PTREE_EVERY_LEAF_CONV ``EVERY_LEAF (\x y. (x < 3) ==> (y = 1)) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_EVERY_LEAF_CONV : conv -> conv
Argument:
(
Parse.Term
[
QUOTE
" (*#loc 1 37*)EVERY_LEAF (\\x y. (x < 3) ==> (y = 1)) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))"
]) : term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
> patriciaLib.PTREE_EVERY_LEAF_CONV ``EVERY_LEAF (\x y. x < 2) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_EVERY_LEAF_CONV : conv -> conv
Argument:
(
Parse.Term
[
QUOTE
" (*#loc 1 37*)EVERY_LEAF (\\x y. x < 2) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))"
]) : term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
See also
PTREE_EXISTS_LEAF_CONV
PTREE_EXISTS_LEAF_CONV
patriciaLib.PTREE_EXISTS_LEAF_CONV : conv
Conversion for evaluating applications of patricia$EXISTS_LEAF.
The conversion PTREE_EXISTS_LEAF_CONV evaluates terms of the form
EXISTS_LEAF P t where t is a well-formed Patricia tree (constructed
by patricia$Empty, patricia$Leaf and patricia$Branch) and P is
predicate.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$EXISTS_LEAF.
Example
> patriciaLib.PTREE_EXISTS_LEAF_CONV ``EXISTS_LEAF (=) Empty``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_EXISTS_LEAF_CONV : conv -> conv
Argument:
(Parse.Term [QUOTE " (*#loc 1 38*)EXISTS_LEAF (=) Empty"]) :
term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
> patriciaLib.PTREE_EXISTS_LEAF_CONV ``EXISTS_LEAF (\x y. y = 2) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_EXISTS_LEAF_CONV : conv -> conv
Argument:
(
Parse.Term
[
QUOTE
" (*#loc 1 38*)EXISTS_LEAF (\\x y. y = 2) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))"
]) : term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
> patriciaLib.PTREE_EXISTS_LEAF_CONV ``EXISTS_LEAF (\x y. y = 3) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_EXISTS_LEAF_CONV : conv -> conv
Argument:
(
Parse.Term
[
QUOTE
" (*#loc 1 38*)EXISTS_LEAF (\\x y. y = 3) (Branch 0 0 (Leaf 3 2) (Leaf 2 1))"
]) : term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
See also
PTREE_IN_PTREE_CONV
PTREE_IN_PTREE_CONV
patriciaLib.PTREE_IN_PTREE_CONV : conv
Conversion for evaluating applications of patricia$IN_PTREE.
The conversion PTREE_IN_PTREE_CONV evaluates terms of the form
n IN_PTREE t where t is a well-formed unit Patricia tree
(constructed by patricia$Empty, patricia$Leaf and patricia$Branch)
and n is a natural number literal.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$IN_PTREE.
Example
> patriciaLib.PTREE_IN_PTREE_CONV ``1 IN_PTREE Empty``;
Exception- HOL_ERR
(at Conv.RAND_CONV:
at Conv.REWR_CONV: lhs of thm doesn't match term) raised
> patriciaLib.PTREE_IN_PTREE_CONV ``3 IN_PTREE (Branch 0 0 (Leaf 3 ()) (Leaf 2 ()))``;
Exception- HOL_ERR
(at Conv.RAND_CONV:
at Conv.REWR_CONV: lhs of thm doesn't match term) raised
See also
PTREE_INSERT_PTREE_CONV
PTREE_INSERT_PTREE_CONV
patriciaLib.PTREE_INSERT_PTREE_CONV : conv
Conversion for evaluating applications of patricia$INSERT_PTREE.
The conversion PTREE_INSERT_PTREE_CONV evaluates terms of the form
m INSERT_PTREE_PTREE t where t is a well-formed unit Patricia tree
(correctly constructed using patricia$Empty, patricia$Leaf and
patricia$Branch) and m is a natural number literal.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$INSERT_PTREE.
Example
> patriciaLib.PTREE_INSERT_PTREE_CONV ``2 INSERT_PTREE Empty``;
val it = ⊢ <{2}> = Leaf 2 (): thm
> DEPTH_CONV patriciaLib.PTREE_INSERT_PTREE_CONV ``3 INSERT_PTREE 2 INSERT_PTREE Empty``;
val it = ⊢ <{3; 2}> = Branch 0 0 (Leaf 3 ()) (Leaf 2 ()): thm
See also
PTREE_IS_PTREE_CONV
PTREE_IS_PTREE_CONV
patriciaLib.PTREE_IS_PTREE_CONV : conv
Conversion for evaluating applications of patricia$IS_PTREE.
The conversion PTREE_IS_PTREE_CONV evaluates terms of the form
IS_PTREE t where t is any tree constructed by patricia$Empty,
patricia$Leaf and patricia$Branch. Well-formed trees correspond with
those that can be constructed by patricia$ADD.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$IS_PTREE.
Example
> patriciaLib.PTREE_IS_PTREE_CONV ``IS_PTREE Empty``;
val it = ⊢ IS_PTREE <{}> ⇔ T: thm
> patriciaLib.PTREE_IS_PTREE_CONV ``IS_PTREE (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
val it = ⊢ IS_PTREE (Branch 0 0 (Leaf 3 2) (Leaf 2 1)) ⇔ T: thm
> patriciaLib.PTREE_IS_PTREE_CONV ``IS_PTREE (Branch 0 0 (Leaf 3 2) (Leaf 1 1))``;
val it = ⊢ IS_PTREE (Branch 0 0 (Leaf 3 2) (Leaf 1 1)) ⇔ F: thm
See also
PTREE_PEEK_CONV
PTREE_PEEK_CONV
patriciaLib.PTREE_PEEK_CONV : conv
Conversion for evaluating applications of patricia$PEEK.
The conversion PTREE_PEEK_CONV evaluates terms of the form t ' m
where t is a well-formed Patricia tree (constructed by
patricia$Empty, patricia$Leaf and patricia$Branch) and m is a
natural number literal.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$PEEK.
Example
> patriciaLib.PTREE_PEEK_CONV ``Empty ' 3``;
Exception- HOL_ERR
(at Conv.RAND_CONV:
at Conv.REWR_CONV: lhs of thm doesn't match term) raised
> patriciaLib.PTREE_PEEK_CONV ``Branch 0 0 (Leaf 3 2) (Leaf 2 1) ' 3``;
Exception- HOL_ERR
(at Conv.RAND_CONV:
at Conv.REWR_CONV: lhs of thm doesn't match term) raised
See also
PTREE_REMOVE_CONV
PTREE_REMOVE_CONV
patriciaLib.PTREE_REMOVE_CONV : conv
Conversion for evaluating applications of patricia$REMOVE.
The conversion PTREE_REMOVE_CONV evaluates terms of the form t \\ m
where t is a well-formed Patricia tree (constructed by
patricia$Empty, patricia$Leaf and patricia$Branch) and m is a
natural number literal.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$REMOVE.
Example
> patriciaLib.PTREE_REMOVE_CONV ``Empty \\ 3``;
val it = ⊢ <{}> \\ 3 = <{}>: thm
> patriciaLib.PTREE_REMOVE_CONV ``Branch 0 0 (Leaf 3 2) (Leaf 2 1) \\ 3``;
val it = ⊢ Branch 0 0 (Leaf 3 2) (Leaf 2 1) \\ 3 = Leaf 2 1: thm
See also
PTREE_SIZE_CONV
PTREE_SIZE_CONV
patriciaLib.PTREE_SIZE_CONV : conv
Conversion for evaluating applications of patricia$SIZE.
The conversion PTREE_SIZE_CONV evaluates terms of the form SIZE t
where t is a well-formed Patricia tree (constructed by
patricia$Empty, patricia$Leaf and patricia$Branch).
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$SIZE.
Example
> patriciaLib.PTREE_SIZE_CONV ``SIZE Empty``;
val it = ⊢ SIZE <{}> = 0: thm
> patriciaLib.PTREE_SIZE_CONV ``SIZE (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
val it = ⊢ SIZE (Branch 0 0 (Leaf 3 2) (Leaf 2 1)) = 2: thm
See also
PTREE_TRANSFORM_CONV
PTREE_TRANSFORM_CONV
patriciaLib.PTREE_TRANSFORM_CONV : conv
Conversion for evaluating applications of patricia$TRANSFORM.
The conversion PTREE_TRANSFORM_CONV evaluates terms of the form
TRANSFORM f t where t is a well-formed Patricia tree (constructed by
patricia$Empty, patricia$Leaf and patricia$Branch) and f is map.
Failure
The conversion will fail if the supplied term is not a suitable
application of patricia$TRANSFORM.
Example
> patriciaLib.PTREE_TRANSFORM_CONV ``TRANSFORM ODD Empty``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_TRANSFORM_CONV : conv -> conv
Argument: (Parse.Term [QUOTE " (*#loc 1 36*)TRANSFORM ODD Empty"])
: term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
> patriciaLib.PTREE_TRANSFORM_CONV ``TRANSFORM ODD (Branch 0 0 (Leaf 3 2) (Leaf 2 1))``;
Exception- Type error in function application.
Function: patriciaLib.PTREE_TRANSFORM_CONV : conv -> conv
Argument:
(
Parse.Term
[
QUOTE
" (*#loc 1 36*)TRANSFORM ODD (Branch 0 0 (Leaf 3 2) (Leaf 2 1))"
]) : term
Reason: Can't unify term to term -> thm (Incompatible types)
Fail "Static Errors" raised
See also
pprint
pprint
Portable.pprint : ‘a PP.pprinter -> 'a -> unit
Pretty-prints a value to output
A call to pprint ppf x will call the pretty-printing function ppf on
value x, with the pretty-printing output printed. string that is
eventually returned to the user. The linewidth used for determining when
to wrap with newline characters is 72.
Failure
Fails if the pretty-printing function fails on the particular input value.
Example
> Portable.pprint PP.add_string "hello";
hello
val it = (): unit
See also
remove_external_wspace
remove_external_wspace
Portable.remove_external_wspace : string -> string
Removes trailing and leading whitespace characters from a string
A call to remove_external_wspace s returns a string identical to s
except that all leading and trailing characters for which Char.isSpace
is true have been removed. The implementation is (with the Basis's
Substring structure open):
string (dropl Char.isSpace (dropr Char.isSpace (full s)))
Failure
Never fails.
See also
remove_wspace
remove_wspace
Portable.remove_wspace : string -> string
Removes all whitespace characters from a string
A call to remove_wspace s returns a string identical to s except
that all of the characters for which Char.isSpace is true have been
removed. The implementation is
String.translate (fn c => if Char.isSpace c then "" else str c) s
Failure
Never fails.
See also
Portable.remove_external_wspace
unique_tmp_suffix
unique_tmp_suffix
Portable.unique_tmp_suffix : unit -> string
A short string suitable for embedding in temp filenames so that two processes writing to the same logical path pick disjoint temp paths and can each rename their own result into place without colliding.
Under Poly/ML the returned string is the decimal representation of
the process id (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())).
Under Moscow ML, where HOL builds are never run in parallel, the
result is derived from OS.FileSys.tmpName; it is still unique per
call but is not the literal process id.
Failure
Never fails.
DELETE_CONV
DELETE_CONV
pred_setLib.DELETE_CONV : conv -> conv
Reduce {t1;...;tn} DELETE t by deleting t from {t1;...;tn}.
The function DELETE_CONV is a parameterized conversion for reducing
finite sets of the form {t1;...;tn} DELETE t, where the term t and
the elements of {t1;...;tn} are of some base type ty. The first
argument to DELETE_CONV is expected to be a conversion that decides
equality between values of the base type ty. Given an equation
e1 = e2, where e1 and e2 are terms of type ty, this conversion
should return the theorem |- (e1 = e2) = T or the theorem
|- (e1 = e2) = F, as appropriate.
Given such a conversion conv, the function DELETE_CONV returns a
conversion that maps a term of the form {t1;...;tn} DELETE t to the
theorem
|- {t1;...;tn} DELETE t = {ti;...;tj}
where {ti;...;tj} is the subset of {t1;...;tn} for which the
supplied equality conversion conv proves
|- (ti = t) = F, ..., |- (tj = t) = F
and for all the elements tk in {t1;...;tn} but not in {ti;...;tj},
either conv proves |- (tk = t) = T or tk is alpha-equivalent to
t. That is, the reduced set {ti;...;tj} comprises all those elements
of the original set that are provably not equal to the deleted element
t.
Example
In the following example, the conversion REDUCE_CONV is supplied as a
parameter and used to test equality of the deleted value 2 with the
elements of the set.
- DELETE_CONV REDUCE_CONV ``{2; 1; SUC 1; 3} DELETE 2``;
> val it = |- {2; 1; SUC 1; 3} DELETE 2 = {1; 3} : thm
'
Failure
DELETE_CONV conv fails if applied to a term not of the form
{t1;...;tn} DELETE t. A call
DELETE_CONV conv ``{t1;...;tn} DELETE t`` fails unless for each
element ti of the set {t1;...;tn}, the term t is either
alpha-equivalent to ti or conv ``ti = t`` returns
|- (ti = t) = T or |- (ti = t) = F.
See also
pred_setLib.INSERT_CONV,
numLib.REDUCE_CONV
FINITE_CONV
FINITE_CONV
pred_setLib.FINITE_CONV : conv
Proves finiteness of sets of the form {t1;...;tn}.
The conversion FINITE_CONV expects its term argument to be an
assertion of the form FINITE {t1;...;tn}. Given such a term, the
conversion returns the theorem
|- FINITE {t1;...;tn} = T
Example
> pred_setLib.FINITE_CONV ``FINITE {1;2;3}``;
val it = ⊢ FINITE {1; 2; 3} ⇔ T: thm
> pred_setLib.FINITE_CONV ``FINITE ({}:num->bool)``;
val it = ⊢ FINITE ∅ ⇔ T: thm
Failure
Fails if applied to a term not of the form FINITE {t1;...;tn}.
IMAGE_CONV
IMAGE_CONV
pred_setLib.IMAGE_CONV : conv -> conv -> conv
Compute the image of a function on a finite set.
The function IMAGE_CONV is a parameterized conversion for computing
the image of a function f:ty1->ty2 on a finite set {t1;...;tn} of
type ty1->bool. The first argument to IMAGE_CONV is expected to be a
conversion that computes the result of applying the function f to each
element of this set. When applied to a term f ti, this conversion
should return a theorem of the form |- (f ti) = ri, where ri is the
result of applying the function f to the element ti. This conversion
is used by IMAGE_CONV to compute a theorem of the form
|- IMAGE f {t1;...;tn} = {r1;...;rn}
The second argument to IMAGE_CONV is used (optionally) to simplify the
resulting image set {r1;...;rn} by removing redundant occurrences of
values. This conversion expected to decide equality of values of the
result type ty2; given an equation e1 = e2, where e1 and e2 are
terms of type ty2, the conversion should return either
|- (e1 = e2) = T or |- (e1 = e2) = F, as appropriate.
Given appropriate conversions conv1 and conv2, the function
IMAGE_CONV returns a conversion that maps a term of the form
IMAGE f {t1;...;tn} to the theorem
|- IMAGE f {t1;...;tn} = {rj;...;rk}
where conv1 proves a theorem of the form |- (f ti) = ri for each
element ti of the set {t1;...;tn}, and where the set {rj;...;rk}
is the smallest subset of {r1;...;rn} such no two elements are
alpha-equivalent and conv2 does not map rl = rm to the theorem
|- (rl = rm) = T for any pair of values rl and rm in
{rj;...;rk}. That is, {rj;...;rk} is the set obtained by removing
multiple occurrences of values from the set {r1;...;rn}, where the
equality conversion conv2 (or alpha-equivalence) is used to determine
which pairs of terms in {r1;...;rn} are equal.
Example
The following is a very simple example in which REFL is used to
construct the result of applying the function f to each element of the
set {1; 2; 1; 4}, and NO_CONV is the supplied 'equality conversion'.
- IMAGE_CONV REFL NO_CONV ``IMAGE (f:num->num) {1; 2; 1; 4}``;
> val it = |- IMAGE f {1; 2; 1; 4} = {f 2; f 1; f 4} : thm
The result contains only one occurrence of f 1, even though NO_CONV
always fails, since IMAGE_CONV simplifies the resulting set by
removing elements that are redundant up to alpha-equivalence.
For the next example, we construct a conversion that maps SUC n for
any numeral n to the numeral standing for the successor of n.
- fun SUC_CONV tm =
let open numLib Arbnum
val n = dest_numeral (rand tm)
val sucn = mk_numeral (n + one)
in
SYM (num_CONV sucn)
end;
> val SUC_CONV = fn : term -> thm
The result is a conversion that inverts num_CONV:
- numLib.num_CONV ``4``;
> val it = |- 4 = SUC 3 : thm
- SUC_CONV ``SUC 3``;
> val it = |- SUC 3 = 4 : thm
The conversion SUC_CONV can then be used to compute the image of the
successor function on a finite set:
- IMAGE_CONV SUC_CONV NO_CONV ``IMAGE SUC {1; 2; 1; 4}``;
> val it = |- IMAGE SUC {1; 2; 1; 4} = {3; 2; 5} : thm
Note that 2 (= SUC 1) appears only once in the resulting set.
Finally, here is an example of using IMAGE_CONV to compute the image
of a paired addition function on a set of pairs of numbers:
- IMAGE_CONV (pairLib.PAIRED_BETA_CONV THENC reduceLib.ADD_CONV)
numLib.REDUCE_CONV
``IMAGE (\(n,m).n+m) {{(1,2), (3,4), (0,3), (1,3)}}``;
> val it = |- IMAGE (\(n,m). n + m) {(1,2); (3,4); (0,3); (1,3)} = {7; 3; 4}
Failure
IMAGE_CONV conv1 conv2 fails if applied to a term not of the form
IMAGE f {t1;...;tn}. An application of IMAGE_CONV conv1 conv2 to a
term IMAGE f {t1;...;tn} fails unless for all ti in the set
{t1;...;tn}, evaluating conv1 ``f ti`` returns
|- (f ti) = ri for some ri.
IN_CONV
IN_CONV
pred_setLib.IN_CONV : conv -> conv
Decision procedure for membership in finite sets.
The function IN_CONV is a parameterized conversion for proving or
disproving membership assertions of the general form:
t IN {t1,...,tn}
where {t1;...;tn} is a set of type ty->bool and t is a value of
the base type ty. The first argument to IN_CONV is expected to be a
conversion that decides equality between values of the base type ty.
Given an equation e1 = e2, where e1 and e2 are terms of type ty,
this conversion should return the theorem |- (e1 = e2) = T or the
theorem |- (e1 = e2) = F, as appropriate.
Given such a conversion, the function IN_CONV returns a conversion
that maps a term of the form t IN {t1;...;tn} to the theorem
|- t IN {t1;...;tn} = T
if t is alpha-equivalent to any ti, or if the supplied conversion
proves |- (t = ti) = T for any ti. If the supplied conversion proves
|- (t = ti) = F for every ti, then the result is the theorem
|- t IN {t1;...;tn} = F
In all other cases, IN_CONV will fail.
Example
In the following example, the conversion REDUCE_CONV is supplied as a
parameter and used to test equality of the candidate element 1 with
the actual elements of the given set.
- IN_CONV REDUCE_CONV ``2 IN {0;SUC 1;3}``;
> val it = |- 2 IN {0; SUC 1; 3} = T : thm
The result is T because REDUCE_CONV is able to prove that 2 is
equal to SUC 1. An example of a negative result is:
- IN_CONV REDUCE_CONV ``1 IN {0;2;3}``;
> val it = |- 1 IN {0; 2; 3} = F : thm
Finally the behaviour of the supplied conversion is irrelevant when the value to be tested for membership is alpha-equivalent to an actual element:
- IN_CONV NO_CONV ``1 IN {3;2;1}``;
> val it = |- 1 IN {3; 2; 1} = T : thm
The conversion NO_CONV always fails, but IN_CONV is nontheless able
in this case to prove the required result.
Failure
IN_CONV conv fails if applied to a term that is not of the form
t IN {t1;...;tn}. A call IN_CONV conv t IN {t1;...;tn} fails unless
the term t is alpha-equivalent to some ti, or
conv ``t = ti`` returns |- (t = ti) = T for some ti, or
conv ``t = ti`` returns |- (t = ti) = F for every ti.
See also
INSERT_CONV
INSERT_CONV
pred_setLib.INSERT_CONV : conv -> conv
Reduce t INSERT {t1;...;t;...;tn} to {t1;...;t;...;tn}.
The function INSERT_CONV is a parameterized conversion for reducing
finite sets of the form t INSERT {t1;...;tn}, where {t1;...;tn} is a
set of type ty->bool and t is equal to some element ti of this
set. The first argument to INSERT_CONV is expected to be a conversion
that decides equality between values of the base type ty. Given an
equation e1 = e2, where e1 and e2 are terms of type ty, this
conversion should return the theorem |- (e1 = e2) = T or the theorem
|- (e1 = e2) = F, as appropriate.
Given such a conversion, the function INSERT_CONV returns a conversion
that maps a term of the form t INSERT {t1;...;tn} to the theorem
|- t INSERT {t1;...;tn} = {t1;...;tn}
if t is alpha-equivalent to any ti in the set {t1,...,tn}, or if
the supplied conversion proves |- (t = ti) = T for any ti.
Example
In the following example, the conversion REDUCE_CONV is supplied as a
parameter and used to test equality of the inserted value 2 with the
remaining elements of the set.
- INSERT_CONV REDUCE_CONV ``2 INSERT {1;SUC 1;3}``;
> val it = |- {2; 1; SUC 1; 3} = {1; SUC 1; 3} : thm
In this example, the supplied conversion REDUCE_CONV is able to prove
that 2 is equal to SUC 1 and the set is therefore reduced. Note that
2 INSERT {1; SUC 1; 3} is just {2; 1; SUC 1; 3}.
A call to INSERT_CONV fails when the value being inserted is provably
not equal to any of the remaining elements:
- INSERT_CONV REDUCE_CONV ``1 INSERT {2;3}``;
! Uncaught exception:
! HOL_ERR
But this failure can, if desired, be caught using TRY_CONV.
The behaviour of the supplied conversion is irrelevant when the inserted value is alpha-equivalent to one of the remaining elements:
- INSERT_CONV NO_CONV ``y INSERT {x;y;z}``;
> val it = |- {y; x; y; z} = {x; y; z} : thm
The conversion NO_CONV always fails, but INSERT_CONV is nontheless
able in this case to prove the required result.
Note that DEPTH_CONV(INSERT_CONV conv) can be used to remove duplicate
elements from a finite set, but the following conversion is faster:
- fun SETIFY_CONV conv tm =
(SUB_CONV (SETIFY_CONV conv)
THENC
TRY_CONV (INSERT_CONV conv)) tm;
> val SETIFY_CONV = fn : conv -> conv
- SETIFY_CONV REDUCE_CONV ``{1;2;1;3;2;4;3;5;6}``;
> val it = |- {1; 2; 1; 3; 2; 4; 3; 5; 6} = {1; 2; 4; 3; 5; 6} : thm
Failure
INSERT_CONV conv fails if applied to a term not of the form
t INSERT {t1;...;tn}. A call
INSERT_CONV conv ``t INSERT {t1;...;tn} fails unless t is
alpha-equivalent to some ti, or conv ``t = ti`` returns
|- (t = ti) = T for some ti.
See also
pred_setLib.DELETE_CONV,
numLib.REDUCE_CONV
SET_INDUCT_TAC
SET_INDUCT_TAC
pred_setLib.SET_INDUCT_TAC : tactic
Tactic for induction on finite sets.
SET_INDUCT_TAC is an induction tacic for proving properties of finite
sets. When applied to a goal of the form
!s. FINITE s ==> P[s]
SET_INDUCT_TAC reduces this goal to proving that the property
\s.P[s] holds of the empty set and is preserved by insertion of an
element into an arbitrary finite set. Since every finite set can be
built up from the empty set {} by repeated insertion of values, these
subgoals imply that the property \s.P[s] holds of all finite sets.
The tactic specification of SET_INDUCT_TAC is:
A ?- !s. FINITE s ==> P
========================================================== SET_INDUCT_TAC
A |- P[{{}}/s]
A u {FINITE s', P[s'/s], ~e IN s'} ?- P[e INSERT s'/s]
where e is a variable chosen so as not to appear free in the
assumptions A, and s' is a primed variant of s that does not
appear free in A (usually, s' is just s).
Failure
SET_INDUCT_TAC (A,g) fails unless g has the form
!s. FINITE s ==> P, where the variable s has type ty->bool for
some type ty.
SET_SPEC_CONV
SET_SPEC_CONV
pred_setLib.SET_SPEC_CONV : conv
Axiom-scheme of specification for set abstractions.
The conversion SET_SPEC_CONV expects its term argument to be an
assertion of the form t IN {E | P}. Given such a term, the conversion
returns a theorem that defines the condition under which this membership
assertion holds. When E is just a variable v, the conversion
returns:
|- t IN {v | P} = P[t/v]
and when E is not a variable but some other expression, the theorem
returned is:
|- t IN {E | P} = ?x1...xn. (t = E) /\ P
where x1, ..., xn are the variables that occur free both in the
expression E and in the proposition P.
Example
> pred_setLib.SET_SPEC_CONV ``12 IN {n | n > N}``;
val it = ⊢ 12 ∈ {n | n > N} ⇔ 12 > N: thm
> pred_setLib.SET_SPEC_CONV ``p IN {(n,m) | n < m}``;
val it = ⊢ p ∈ {(n,m) | n < m} ⇔ ∃n m. p = (n,m) ∧ n < m: thm
Failure
Fails if applied to a term that is not of the form t IN {E | P}.
UNION_CONV
UNION_CONV
pred_setLib.UNION_CONV : conv -> conv
Reduce {t1;...;tn} UNION s to t1 INSERT (... (tn INSERT s)).
The function UNION_CONV is a parameterized conversion for reducing
sets of the form {t1;...;tn} UNION s, where {t1;...;tn} and s are
sets of type ty->bool. The first argument to UNION_CONV is expected
to be a conversion that decides equality between values of the base type
ty. Given an equation e1 = e2, where e1 and e2 are terms of type
ty, this conversion should return the theorem |- (e1 = e2) = T or
the theorem |- (e1 = e2) = F, as appropriate.
Given such a conversion, the function UNION_CONV returns a conversion
that maps a term of the form {t1;...;tn} UNION s to the theorem
|- {t1;...;tn} UNION s = ti INSERT ... (tj INSERT s)
where {ti;...;tj} is the set of all terms t that occur as elements
of {t1;...;tn} for which the conversion IN_CONV conv fails to prove
that |- (t IN s) = T (that is, either by proving |- (t IN s) = F
instead, or by failing outright).
Example
In the following example, REDUCE_CONV is supplied as a parameter to
UNION_CONV and used to test for membership of each element of the
first finite set {1;2;3} of the union in the second finite set
{SUC 0;3;4}.
- UNION_CONV REDUCE_CONV (Term`{1;2;3} UNION {SUC 0;3;4}`);
> val it = |- {1; 2; 3} UNION {SUC 0; 3; 4} = {2; SUC 0; 3; 4} : thm
The result is {2;SUC 0;3;4}, rather than {1;2;SUC 0;3;4}, because
UNION_CONV is able by means of a call to
- IN_CONV REDUCE_CONV (Term`1 IN {SUC 0;3;4}`);
to prove that 1 is already an element of the set {SUC 0;3;4}.
The conversion supplied to UNION_CONV need not actually prove equality
of elements, if simplification of the resulting set is not desired. For
example:
- UNION_CONV NO_CONV ``{1;2;3} UNION {SUC 0;3;4}``;
> val it = |- {1;2;3} UNION {SUC 0;3;4} = {1;2;SUC 0;3;4} : thm
In this case, the resulting set is just left unsimplified. Moreover, the
second set argument to UNION need not be a finite set:
- UNION_CONV NO_CONV ``{1;2;3} UNION s``;
> val it = |- {1;2;3} UNION s = 1 INSERT (2 INSERT (3 INSERT s)) : thm
And, of course, in this case the conversion argument to UNION_CONV is
irrelevant.
Failure
UNION_CONV conv fails if applied to a term not of the form
{t1;...;tn} UNION s.
See also
pred_setLib.IN_CONV,
numLib.REDUCE_CONV
INDUCT_THEN
INDUCT_THEN
Prim_rec.INDUCT_THEN : (thm -> thm_tactic -> tactic)
Structural induction tactic for automatically-defined concrete types.
The function INDUCT_THEN implements structural induction tactics for
arbitrary concrete recursive types of the kind definable by
define_type. The first argument to INDUCT_THEN is a structural
induction theorem for the concrete type in question. This theorem must
have the form of an induction theorem of the kind returned by
prove_induction_thm. When applied to such a theorem, the function
INDUCT_THEN constructs specialized tactic for doing structural
induction on the concrete type in question.
The second argument to INDUCT_THEN is a function that determines what
is be done with the induction hypotheses in the goal-directed proof by
structural induction. Suppose that th is a structural induction
theorem for a concrete data type ty, and that A ?- !x.P is a
universally-quantified goal in which the variable x ranges over values
of type ty. If the type ty has n constructors C1, ..., Cn and
'Ci(vs)' represents a (curried) application of the ith constructor
to a sequence of variables, then if ttac is a function that maps the
induction hypotheses hypi of the ith subgoal to the tactic:
A ?- P[Ci(vs)/x]
====================== MAP_EVERY ttac hypi
A1 ?- Gi
then INDUCT_THEN th ttac is an induction tactic that decomposes the
goal A ?- !x.P into a set of n subgoals, one for each constructor,
as follows:
A ?- !x.P
================================ INDUCT_THEN th ttac
A1 ?- G1 ... An ?- Gn
The resulting subgoals correspond to the cases in a structural induction
on the variable x of type ty, with induction hypotheses treated as
determined by ttac.
Failure
INDUCT_THEN th ttac g fails if th is not a structural induction
theorem of the form returned by prove_induction_thm, or if the goal
does not have the form A ?- !x:ty.P where ty is the type for which
th is the induction theorem, or if ttac fails for any subgoal in the
induction.
Example
The built-in structural induction theorem for lists is:
|- !P. P[] /\ (!t. P t ==> (!h. P(CONS h t))) ==> (!l. P l)
When INDUCT_THEN is applied to this theorem, it constructs and returns
a specialized induction tactic (parameterized by a theorem-tactic) for
doing induction on lists:
- val LIST_INDUCT_THEN = INDUCT_THEN listTheory.list_INDUCT;
The resulting function, when supplied with the thm_tactic
ASSUME_TAC, returns a tactic that decomposes a goal ?- !l.P[l] into
the base case ?- P[NIL] and a step case P[l] ?- !h. P[CONS h l],
where the induction hypothesis P[l] in the step case has been put on
the assumption list. That is, the tactic:
LIST_INDUCT_THEN ASSUME_TAC
does structural induction on lists, putting any induction hypotheses that arise onto the assumption list:
A ?- !l. P
=======================================================
A |- P[NIL/l] A u {P[l'/l]} ?- !h. P[(CONS h l')/l]
Likewise LIST_INDUCT_THEN STRIP_ASSUME_TAC will also do induction on
lists, but will strip induction hypotheses apart before adding them to
the assumptions (this may be useful if P is a conjunction or a
disjunction, or is existentially quantified). By contrast, the tactic:
LIST_INDUCT_THEN MP_TAC
will decompose the goal as follows:
A ?- !l. P
=====================================================
A |- P[NIL/l] A ?- P[l'/l] ==> !h. P[CONS h l'/l]
That is, the induction hypothesis becomes the antecedent of an implication expressing the step case in the induction, rather than an assumption of the step-case subgoal.
See also
Prim_rec.new_recursive_definition,
Prim_rec.prove_cases_thm,
Prim_rec.prove_constructors_distinct,
Prim_rec.prove_constructors_one_one,
Prim_rec.prove_induction_thm,
Prim_rec.prove_rec_fn_exists
new_recursive_definition
new_recursive_definition
Prim_rec.new_recursive_definition : {name:string, def:term, rec_axiom:thm} -> thm
Defines a primitive recursive function over a concrete recursive type.
new_recursive_definition provides a facility for defining primitive
recursive functions on arbitrary concrete recursive types. name is a
name under which the resulting definition will be saved in the current
theory segment. def is a term giving the desired primitive recursive
function definition. rec_axiom is the primitive recursion theorem for
the concrete type in question; this must be a theorem obtained from
define_type. The value returned by new_recursive_definition is a
theorem which states the primitive recursive definition requested by the
user. This theorem is derived by formal proof from an instance of the
general primitive recursion theorem given as the second argument.
A theorem th of the form returned by define_type is a primitive
recursion theorem for an automatically-defined concrete type ty. Let
C1, ..., Cn be the constructors of this type, and let '(Ci vs)'
represent a (curried) application of the ith constructor to a sequence
of variables. Then a curried primitive recursive function fn over ty
can be specified by a conjunction of (optionally universally-quantified)
clauses of the form:
fn v1 ... (C1 vs1) ... vm = body1 /\
fn v1 ... (C2 vs2) ... vm = body2 /\
.
.
fn v1 ... (Cn vsn) ... vm = bodyn
where the variables v1, ..., vm, vs are distinct in each clause,
and where in the ith clause fn appears (free) in bodyi only as
part of an application of the form:
fn t1 ... v ... tm
in which the variable v of type ty also occurs among the variables
vsi.
If tm is a conjunction of clauses, as described above, then
evaluating:
new_recursive_definition{name=name, rec_axiom=th, def=tm}
automatically proves the existence of a function fn that satisfies the
defining equations supplied as the fourth argument, and then declares a
new constant in the current theory with this definition as its
specification. This constant specification is returned as a theorem and
is saved in the current theory segment under the name name.
new_recursive_definition also allows the supplied definition to omit
clauses for any number of constructors. If a defining equation for the
ith constructor is omitted, then the value of fn at that
constructor:
fn v1 ... (Ci vsi) ... vn
is left unspecified (fn, however, is still a total function).
Failure
A call to new_recursive_definition fails if the supplied theorem is
not a primitive recursion theorem of the form returned by define_type;
if the term argument supplied is not a well-formed primitive recursive
definition; or if any other condition for making a constant
specification is violated (see the failure conditions for
new_specification).
Example
Given the following primitive recursion theorem for labelled binary trees:
|- !f0 f1.
?! fn.
(!x. fn(LEAF x) = f0 x) /\
(!b1 b2. fn(NODE b1 b2) = f1(fn b1)(fn b2)b1 b2)
new_recursive_definition can be used to define primitive recursive
functions over binary trees. Suppose the value of th is this theorem.
Then a recursive function Leaves, which computes the number of leaves
in a binary tree, can be defined recursively as shown below:
- val Leaves = new_recursive_definition
{name = "Leaves",
rec_axiom = th,
def= “(Leaves (LEAF (x:'a)) = 1) /\
(Leaves (NODE t1 t2) = (Leaves t1) + (Leaves t2))”};
> val Leaves =
|- (!x. Leaves (LEAF x) = 1) /\
!t1 t2. Leaves (NODE t1 t2) = Leaves t1 + Leaves t2 : thm
The result is a theorem which states that the constant Leaves
satisfies the primitive-recursive defining equations supplied by the
user.
The function defined using new_recursive_definition need not, in fact,
be recursive. Here is the definition of a predicate IsLeaf, which is
true of binary trees which are leaves, but is false of the internal
nodes in a binary tree:
- val IsLeaf = new_recursive_definition
{name = "IsLeaf",
rec_axiom = th,
def = “(IsLeaf (NODE t1 t2) = F) /\
(IsLeaf (LEAF (x:'a)) = T)”};
> val IsLeaf = |- (!t1 t2. IsLeaf (NODE t1 t2) = F) /\
!x. IsLeaf (LEAF x) = T : thm
Exception- unknown symbol .
unknown symbol .
Fail "Static Errors" raised
Note that the equations defining a (recursive or non-recursive) function
on binary trees by cases can be given in either order. Here, the NODE
case is given first, and the LEAF case second. The reverse order was
used in the above definition of Leaves.
new_recursive_definition also allows the user to partially specify the
value of a function defined on a concrete type, by allowing defining
equations for some of the constructors to be omitted. Here, for example,
is the definition of a function Label which extracts the label from a
leaf node. The value of Label applied to an internal node is left
unspecified:
- val Label = new_recursive_definition
{name = "Label",
rec_axiom = th,
def = “Label (LEAF (x:'a)) = x”};
> val Label = |- !x. Label (LEAF x) = x : thm
Curried functions can also be defined, and the recursion can be on any
argument. The next definition defines an infix function << which
expresses the idea that one tree is a proper subtree of another.
- val _ = set_fixity ("<<", Infixl 231);
- val Subtree = new_recursive_definition
{name = "Subtree",
rec_axiom = th,
def = “($<< (t:'a bintree) (LEAF (x:'a)) = F) /\
($<< t (NODE t1 t2) = (t = t1) \/
(t = t2) \/
($<< t t1) \/
($<< t t2))”};
> val Subtree =
|- (!t x. t << LEAF x = F) /\
!t t1 t2.
t << NODE t1 t2 = (t = t1) \/ (t = t2) \/
(t << t1) \/ (t << t2) : thm
Note that the fixity of the identifier << is set independently of the
definition.
See also
bossLib.Hol_datatype,
Prim_rec.prove_rec_fn_exists,
TotalDefn.Define,
Parse.set_fixity
prove_case_elim_thm
prove_case_elim_thm
Prim_rec.prove_case_elim_thm : {case_def : thm, nchotomy : thm} -> thm
Proves a theorem that eliminates applications of case constants with boolean type.
If case_def is the definition of a data type's case constant, where
each clause is of the form
!a1 .. ai f1 .. fm. type_CASE (ctor_i a1 .. ai) f1 .. fm = f_i a1 .. ai
and if nchotomy is a theorem describing how a data type's values are
classified by constructor, of the form
!v. (?a1 .. ai. v = ctor_1 a1 .. ai) \/
(?b1 .. bj. v = ctor_2 b1 .. bj) \/
...
then a call to
prove_case_elim_thm{case_def = case_def, nchotomy = nchotomy} will
return a theorem of the form
type_CASE v f1 .. fm <=>
(?a1 .. ai. v = ctor_1 a1 .. ai /\ f1 a1 .. ai) \/
(?b1 .. bj. v = ctor_2 b1 .. bj /\ f2 b1 .. bj) \/
...
Used as a rewrite theorem, this result will "eliminate" occurrences of the case-constant from a term, when the case-constant term has boolean type.
Failure
Will fail if the provided theorems are not of the required form. The
theorems stored in the TypeBase are of the correct form. The theorem
returned by Prim_rec.prove_cases_thm is of the correct form for the
nchotomy argument to this function.
Example
> prove_case_elim_thm {case_def = TypeBase.case_def_of ``:num``,
nchotomy = TypeBase.nchotomy_of ``:num``};
val it = ⊢ num_CASE x v f ⇔ x = 0 ∧ v ∨ ∃n. x = SUC n ∧ f n: thm
> prove_case_elim_thm {case_def = TypeBase.case_def_of ``:bool``,
nchotomy = TypeBase.nchotomy_of ``:bool``};
val it = ⊢ (if x then t1 else t2) ⇔ (x ⇔ T) ∧ t1 ∨ (x ⇔ F) ∧ t2: thm
See also
Prim_rec.prove_cases_thm,
Prim_rec.prove_case_rand_thm
prove_case_eq_thm
prove_case_eq_thm
Prim_rec.prove_case_eq_thm : {case_def : thm, nchotomy : thm} -> thm
Proves a rewrite for eliminating certain forms of case expression.
If case_def is the definition of a data type's case constant, where
each clause is of the form
!a1 .. ai f1 .. fm. type_CASE (ctor_i a1 .. ai) f1 .. fm = f_i a1 .. ai
and if nchotomy is a theorem describing how a data type's values are
classified by constructor, of the form
!v. (?a1 .. ai. v = ctor_1 a1 .. ai) \/
(?b1 .. bj. v = ctor_2 b1 .. bj) \/
...
then a call to
prove_case_elim_thm{case_def = case_def, nchotomy = nchotomy} will
return a theorem of the form
(type_CASE u f1 .. fm = v) <=>
(?a1 .. ai. u = ctor_1 a1 .. ai /\ f1 a1 .. ai = v) \/
(?b1 .. bj. u = ctor_2 b1 .. bj /\ f2 b1 .. bj = v) \/
...
Failure
Will fail if the provided theorems are not of the required form. The
theorems stored in the TypeBase are of the correct form. The theorem
returned by Prim_rec.prove_cases_thm is of the correct form for the
nchotomy argument to this function.
See also
Prim_rec.prove_case_elim_thm,
Prim_rec.prove_case_rand_thm
prove_case_rand_thm
prove_case_rand_thm
Prim_rec.prove_case_rand_thm : {case_def : thm, nchotomy : thm} -> thm
Proves a theorem that "lifts" applied case constants up within a term.
If case_def is the definition of a data type's case constant, where
each clause is of the form
!a1 .. ai f1 .. fm. type_CASE (ctor_i a1 .. ai) f1 .. fm = f_i a1 .. ai
and if nchotomy is a theorem describing how a data type's values are
classified by constructor, of the form
!v. (?a1 .. ai. v = ctor_1 a1 .. ai) \/
(?b1 .. bj. v = ctor_2 b1 .. bj) \/
...
then a call to
prove_case_rand_thm{case_def = case_def, nchotomy = nchotomy} will
return a theorem of the form
f (type_CASE x f1 .. fm) =
type_CASE x (\a1 .. ai. f (f1 a1 .. ai))
(\b1 .. bj. f (f2 b1 .. bj))
...
Given the typical pretty-printing provided for case-terms, the right-hand side of the above theorem will actually print as
case x of
ctor_1 a1 .. ai => f (f1 a1 .. ai)
| ctor_2 b1 .. bj => f (f2 b1 .. bj)
| ...
Failure
Will fail if the provided theorems are not of the required form. The
theorems stored in the TypeBase are of the correct form. The theorem
returned by Prim_rec.prove_cases_thm is of the correct form for the
nchotomy argument to this function.
Example
> prove_case_rand_thm {case_def = TypeBase.case_def_of ``:num``,
nchotomy = TypeBase.nchotomy_of ``:num``};
val it = ⊢ f' (num_CASE x v f) = case x of 0 => f' v | SUC n => f' (f n): thm
See also
prove_cases_thm
prove_cases_thm
Prim_rec.prove_cases_thm : (thm -> thm)
Proves a structural cases theorem for an automatically-defined concrete type.
prove_cases_thm takes as its argument a structural induction theorem,
in the form returned by prove_induction_thm for an
automatically-defined concrete type. When applied to such a theorem,
prove_cases_thm automatically proves and returns a theorem which
states that every value the concrete type in question is denoted by the
value returned by some constructor of the type.
Failure
Fails if the argument is not a theorem of the form returned by
prove_induction_thm
Example
Given the following structural induction theorem for labelled binary trees:
|- !P. (!x. P(LEAF x)) /\ (!b1 b2. P b1 /\ P b2 ==> P(NODE b1 b2)) ==>
(!b. P b)
prove_cases_thm proves and returns the theorem:
|- !b. (?x. b = LEAF x) \/ (?b1 b2. b = NODE b1 b2)
This states that every labelled binary tree b is either a leaf node
with a label x or a tree with two subtrees b1 and b2.
See also
Prim_rec.INDUCT_THEN,
Prim_rec.new_recursive_definition,
Prim_rec.prove_constructors_distinct,
Prim_rec.prove_constructors_one_one,
Prim_rec.prove_induction_thm,
Prim_rec.prove_rec_fn_exists
prove_constructors_distinct
prove_constructors_distinct
Prim_rec.prove_constructors_distinct : (thm -> thm)
Proves that the constructors of an automatically-defined concrete type yield distinct values.
prove_constructors_distinct takes as its argument a primitive
recursion theorem, in the form returned by define_type for an
automatically-defined concrete type. When applied to such a theorem,
prove_constructors_distinct automatically proves and returns a theorem
which states that distinct constructors of the concrete type in question
yield distinct values of this type.
Failure
Fails if the argument is not a theorem of the form returned by
define_type, or if the concrete type in question has only one
constructor.
Example
Given the following primitive recursion theorem for labelled binary trees:
|- !f0 f1.
?! fn.
(!x. fn(LEAF x) = f0 x) /\
(!b1 b2. fn(NODE b1 b2) = f1(fn b1)(fn b2)b1 b2)
prove_constructors_distinct proves and returns the theorem:
|- !x b1 b2. ~(LEAF x = NODE b1 b2)
This states that leaf nodes are different from internal nodes. When the concrete type in question has more than two constructors, the resulting theorem is just conjunction of inequalities of this kind.
See also
Prim_rec.INDUCT_THEN,
Prim_rec.new_recursive_definition,
Prim_rec.prove_cases_thm,
Prim_rec.prove_constructors_one_one,
Prim_rec.prove_induction_thm,
Prim_rec.prove_rec_fn_exists
prove_constructors_one_one
prove_constructors_one_one
Prim_rec.prove_constructors_one_one : (thm -> thm)
Proves that the constructors of an automatically-defined concrete type are injective.
prove_constructors_one_one takes as its argument a primitive recursion
theorem, in the form returned by define_type for an
automatically-defined concrete type. When applied to such a theorem,
prove_constructors_one_one automatically proves and returns a theorem
which states that the constructors of the concrete type in question are
injective (one-to-one). The resulting theorem covers only those
constructors that take arguments (i.e. that are not just constant
values).
Failure
Fails if the argument is not a theorem of the form returned by
define_type, or if all the constructors of the concrete type in
question are simply constants of that type.
Example
Given the following primitive recursion theorem for labelled binary trees:
|- !f0 f1.
?! fn.
(!x. fn(LEAF x) = f0 x) /\
(!b1 b2. fn(NODE b1 b2) = f1(fn b1)(fn b2)b1 b2)
prove_constructors_one_one proves and returns the theorem:
|- (!x x'. (LEAF x = LEAF x') = (x = x')) /\
(!b1 b2 b1' b2'.
(NODE b1 b2 = NODE b1' b2') = (b1 = b1') /\ (b2 = b2'))
This states that the constructors LEAF and NODE are both injective.
See also
Prim_rec.INDUCT_THEN,
Prim_rec.new_recursive_definition,
Prim_rec.prove_cases_thm,
Prim_rec.prove_constructors_distinct,
Prim_rec.prove_induction_thm,
Prim_rec.prove_rec_fn_exists
prove_induction_thm
prove_induction_thm
Prim_rec.prove_induction_thm : (thm -> thm)
Derives structural induction for an automatically-defined concrete type.
prove_induction_thm takes as its argument a primitive recursion
theorem, in the form returned by define_type for an
automatically-defined concrete type. When applied to such a theorem,
prove_induction_thm automatically proves and returns a theorem that
states a structural induction principle for the concrete type described
by the argument theorem. The theorem returned by prove_induction_thm
is in a form suitable for use with the general structural induction
tactic INDUCT_THEN.
Failure
Fails if the argument is not a theorem of the form returned by
define_type.
Example
Given the following primitive recursion theorem for labelled binary trees:
|- !f0 f1.
?! fn.
(!x. fn(LEAF x) = f0 x) /\
(!b1 b2. fn(NODE b1 b2) = f1(fn b1)(fn b2)b1 b2)
prove_induction_thm proves and returns the theorem:
|- !P. (!x. P(LEAF x)) /\ (!b1 b2. P b1 /\ P b2 ==> P(NODE b1 b2)) ==>
(!b. P b)
This theorem states the principle of structural induction on labelled
binary trees: if a predicate P is true of all leaf nodes, and if
whenever it is true of two subtrees b1 and b2 it is also true of the
tree NODE b1 b2, then P is true of all labelled binary trees.
See also
Prim_rec.INDUCT_THEN,
Prim_rec.new_recursive_definition,
Prim_rec.prove_cases_thm,
Prim_rec.prove_constructors_distinct,
Prim_rec.prove_constructors_one_one,
Prim_rec.prove_rec_fn_exists
prove_rec_fn_exists
prove_rec_fn_exists
Prim_rec.prove_rec_fn_exists : thm -> term -> thm
Proves the existence of a primitive recursive function over a concrete recursive type.
prove_rec_fn_exists is a version of new_recursive_definition which
proves only that the required function exists; it does not make a
constant specification. The first argument is a primitive recursion
theorem of the form generated by Hol_datatype, and the second is a
user-supplied primitive recursive function definition. The theorem which
is returned asserts the existence of the recursively-defined function in
question (if it is primitive recursive over the type characterized by
the theorem given as the first argument). See the entry for
new_recursive_definition for details.
Failure
As for new_recursive_definition.
Example
Given the following primitive recursion theorem for labelled binary trees:
|- !f0 f1.
?fn.
(!a. fn (LEAF a) = f0 a) /\
!a0 a1. fn (NODE a0 a1) = f1 a0 a1 (fn a0) (fn a1) : thm
prove_rec_fn_exists can be used to prove the existence of primitive
recursive functions over binary trees. Suppose the value of th is this
theorem. Then the existence of a recursive function Leaves, which
computes the number of leaves in a binary tree, can be proved as shown
below:
- prove_rec_fn_exists th
``(Leaves (LEAF (x:'a)) = 1) /\
(Leaves (NODE t1 t2) = (Leaves t1) + (Leaves t2))``;
> val it =
|- ?Leaves.
(!x. Leaves (LEAF x) = 1) /\
!t1 t2. Leaves (NODE t1 t2) = Leaves t1 + Leaves t2 : thm
The result should be compared with the example given under
new_recursive_definition.
See also
bossLib.Hol_datatype,
Prim_rec.new_recursive_definition
b
b
proofManagerLib.b : unit -> proof
Restores the proof state undoing the effects of a previous expansion.
The function b is part of the subgoal package. It is an abbreviation
for the function backup. For a description of the subgoal package, see
set_goal.
Failure
As for backup.
Back tracking in a goal-directed proof to undo errors or try different tactics.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.rd,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
backup
backup
proofManagerLib.backup : unit -> proof
Restores the proof state, undoing the effects of a previous expansion.
The function backup is part of the subgoal package. It may be
abbreviated by the function b. It allows backing up from the last
state change (caused by calls to expand, rotate and similar
functions). The package maintains a backup list of previous proof
states. A call to backup restores the state to the previous state
(which was on top of the backup list). The current state and the state
on top of the backup list are discarded. The maximum number of proof
states saved on the backup list can be set using set_backup. It
defaults to 15. Adding new proof states after the maximum is reached
causes the earliest proof state on the list to be discarded. The user
may backup repeatedly until the list is exhausted. The state restored
includes all unproven subgoals or, if a goal had been proved in the
previous state, the corresponding theorem. For a description of the
subgoal package, see set_goal.
Failure
The function backup will fail if the backup list is empty.
Example
> g `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`;
val it =
Proof manager status: 5 proofs.
5. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
Current goal:
0. p ⇒ q
------------------------------------
p
4. Incomplete goalstack:
Initial goal:
p ∧ q ⇒ r ∧ s
Current goal:
0. p
1. q
------------------------------------
p'
3. Incomplete goalstack:
Initial goal:
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
Current goal:
0. ∀x z y. x ≤ z ⇒ ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
1. ¬(x ≤ z)
------------------------------------
ABS_DIFF x y + ABS_DIFF y z ≤ ABS_DIFF x z
2. Incomplete goalstack:
Initial goal:
MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z
Current goal:
0. ∀x y z. x ≤ y ⇒ (MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z)
1. ¬(x ≤ y)
------------------------------------
MAX x y ≤ z ⇔ x ≤ z ∧ y ≤ z
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
> e CONJ_TAC;
OK..
2 subgoals:
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
> backup();
val it =
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]: proof
> e (REWRITE_TAC[listTheory.HD, listTheory.TL]);
OK..
val it =
Initial goal proved.
⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]: proof
Back tracking in a goal-directed proof to undo errors or try different tactics.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.b,
proofManagerLib.backup,
proofManagerLib.rd,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
e
e
proofManagerLib.e : tactic -> proof
Applies a tactic to the current goal, stacking the resulting subgoals.
The function e is part of the subgoal package. It is an abbreviation
for expand. For a description of the subgoal package, see set_goal.
Failure
As for expand.
Doing a step in an interactive goal-directed proof.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
eall
eall
proofManagerLib.eall : tactic -> proof
Applies a tactic to all goals in the current goal list, replacing the list with the resulting subgoals.
eall tac applies tac to all the goals in the current goal list,
replacing the goal list with the list of all the resulting subgoals. It
is an abbreviation for expand_list (ALLGOALS tac).
For interactively constructing suitable compound tactics: in an
interactive proof, the effect of e (tac1 THEN tac2) can be obtained by
e tac1 and then eall tac2.
See also
proofManagerLib.expand_list,
proofManagerLib.elt,
Tactical.ALLGOALS,
proofManagerLib.eta,
proofManagerLib.set_goal
elt
elt
proofManagerLib.elt : list_tactic -> proof
Applies a list-tactic to the current goal list, replacing it with the resulting subgoals.
The function elt is part of the subgoal package. It is an abbreviation
for expand_list. For a description of the subgoal package, see
set_goal.
Failure
As for expand_list.
Doing a step in an interactive goal-directed proof, where the step may affect the list of goals produced by the previous step.
See also
proofManagerLib.expand_list,
proofManagerLib.set_goal
enth
enth
proofManagerLib.enth : tactic -> int -> proof
Applies a tactic to one goal, referenced by number, in the current goal list, replacing that goal with the resulting subgoals.
enth tac i applies tac to all the i'th goal in the current goal
list, replacing that goal in the goal list with the subgoals produced by
tac. It is an abbreviation for expand_list (NTH_GOAL tac i).
For interactively constructing suitable compound tactics, for example to test whether a particular subgoal can be proved easily, before attacking the other subgoals.
See also
proofManagerLib.expand_list,
proofManagerLib.elt,
Tactical.NTH_GOAL,
proofManagerLib.set_goal,
proofManagerLib.r
eta
eta
proofManagerLib.eta : tactic -> proof
Applies a tactic to all goals, on which it succeeds, in the current goal list, replacing the list with the resulting subgoals.
eta tac tries to apply tac to all the goals in the current goal
list; replacing the goal list with the list of all the resulting
subgoals. If it fails on a goal, it has no effect on that goal. It is an
abbreviation for expand_list (TRYALL tac).
For interactively constructing suitable compound tactics: in an
interactive proof, the effect of e (tac1 THEN TRY tac2) can be
obtained by e tac1 and then eta tac2.
See also
proofManagerLib.expand_list,
proofManagerLib.elt,
Tactical.TRYALL, Tactical.TRY,
proofManagerLib.eall,
proofManagerLib.set_goal
expand
expand
proofManagerLib.expand : tactic -> proof
Applies a tactic to the current goal, stacking the resulting subgoals.
The function expand is part of the subgoal package. It may be
abbreviated by the function e. It applies a tactic to the current goal
to give a new proof state. The previous state is stored on the backup
list. If the tactic produces subgoals, the new proof state is formed
from the old one by removing the current goal from the goal stack and
adding a new level consisting of its subgoals. The corresponding
justification is placed on the justification stack. The new subgoals are
printed. If more than one subgoal is produced, they are printed from the
bottom of the stack so that the new current goal is printed last.
If a tactic solves the current goal (returns an empty subgoal list), then its justification is used to prove a corresponding theorem. This theorem is incorporated into the justification of the parent goal and printed. If the subgoal was the last subgoal of the level, the level is removed and the parent goal is proved using its (new) justification. This process is repeated until a level with unproven subgoals is reached. The next goal on the goal stack then becomes the current goal. This goal is printed. If all the subgoals are proved, the resulting proof state consists of the theorem proved by the justifications.
The tactic applied is a validating version of the tactic given. It
ensures that the justification of the tactic does provide a proof of the
goal from the subgoals generated by the tactic. It will cause failure if
this is not so. The tactical VALID performs this validation.
For a description of the subgoal package, see set_goal.
Failure
expand tac fails if the tactic tac fails for the top goal. It will
diverge if the tactic diverges for the goal. It will fail if there are
no unproven goals. This could be because no goal has been set using
set_goal or because the last goal set has been completely proved. It
will also fail in cases when the tactic is invalid.
Example
> g `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`;
val it =
Proof manager status: 1 proof.
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
> expand CONJ_TAC;
OK..
2 subgoals:
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
> expand (REWRITE_TAC[listTheory.HD]);
OK..
Goal proved.
⊢ HD [1; 2; 3] = 1
Remaining subgoals:
val it =
TL [1; 2; 3] = [2; 3]
> expand (REWRITE_TAC[listTheory.TL]);
OK..
Goal proved.
⊢ TL [1; 2; 3] = [2; 3]
val it =
Initial goal proved.
⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]: proof
In the following example an invalid tactic is used. It is invalid because it assumes something that is not on the assumption list of the goal. The justification adds this assumption to the assumption list so the justification would not prove the goal that was set.
> g `1=2`;
val it =
Proof manager status: 1 proof.
1. Incomplete goalstack:
Initial goal:
1 = 2
> expand (REWRITE_TAC[ASSUME (Term `1=2`)]);
Exception- OK..
HOL_ERR
(at Tactical.VALID: Invalid tactic: theorem has bad hypothesis 1 = 2) raised
Note that an invalid tactic may “succeed”. Thus, where tac1 is
invalid, and tac2 is valid (and both succeed), FIRST [tac1, tac2] is
invalid. For example, where theorem uth is [p] |- q and uth' is
[p'] |- q
val it =
Proof manager status: 1 proof.
1. Incomplete goalstack:
Initial goal:
0. p
------------------------------------
q
> e (FIRST (map ACCEPT_TAC [uth', uth])) ;
Exception- OK..
HOL_ERR (at Tactical.VALID: Invalid tactic: theorem has bad hypothesis p') raised
> e (FIRST (map (VALID o ACCEPT_TAC) [uth', uth])) ;
OK..
val it =
Initial goal proved.
[.] ⊢ q: proof
Doing a step in an interactive goal-directed proof.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.flatn,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal,
Tactical.VALID,
Tactical.VALIDATE
expand_list
expand_list
proofManagerLib.expand_list : list_tactic -> proof
Applies a list-tactic to replace the current goal list.
The function expand_list is part of the subgoal package. It may be
abbreviated by the function elt. It applies a tactic to the current
goal list (that is, the list of goals produced by the most recent use of
expand or expand_list) to give a new proof state. The previous state
is stored on the backup list. If the list-tactic produces subgoals, the
new proof state is formed from the old one by removing the current goal
list from the goal stack and replacing it by the list of subgoals
produced by the list-tactic. The corresponding justification is modified
accordingly, appropriate to the new goal list. The new subgoals are
printed. If more than one subgoal is produced, they are printed from the
bottom of the stack so that the new current goal is printed last.
If a list-tactic solves the current goal list (returns an empty subgoal list), then its justification is used to prove a corresponding theorem. This theorem is incorporated into the justification of the parent goal and printed. That level of goals is removed and the parent goal is proved using its (new) justification. This process is repeated until a level with unproven subgoals is reached. The next goal on the goal stack then becomes the current goal. This goal is printed. If all the subgoals are proved, the resulting proof state consists of the theorem proved by the justifications.
The list-tactic applied is a validating version of the list-tactic
given. It ensures that the justification of the list-tactic does provide
a proof of the goals from the subgoals generated by the tactic. It will
cause failure if this is not so. The tactical VALID_LT performs this
validation.
For a description of the subgoal package, see set_goal.
Failure
expand_list ltac fails if the tactic ltac fails for the current goal
list. It will diverge if the list-tactic diverges for the goal. It will
fail if there are no unproven goals. This could be because no goal has
been set using set_goal or because the last goal set has been
completely proved. It will also fail in cases when the list-tactic is
invalid.
Example
> g `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`;
val it =
Proof manager status: 2 proofs.
2. Completed goalstack: [.] ⊢ q
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
> expand CONJ_TAC;
OK..
2 subgoals:
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
> expand_list (ALLGOALS (REWRITE_TAC[listTheory.HD,listTheory.TL])) ;
OK..
val it =
Initial goal proved.
⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]: proof
Doing a step in an interactive goal-directed proof, in particular, a step which affects all the subgoals generated by the preceding step.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.expand_listf,
proofManagerLib.flatn,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
expand_listf
expand_listf
proofManagerLib.expand_listf : (list_tactic -> unit)
Applies a list-tactic to the current goal, stacking the resulting subgoals.
The function expand_listf is a faster version of expand_list. It
does not use a validated version of the list-tactic. That is, no check
is made that the justification of the list-tactic does prove the goals
from the subgoals it generates. If an invalid list-tactic is used, the
theorem ultimately proved may not match the goal originally set.
Alternatively, failure may occur when the justifications are applied in
which case the theorem would not be proved. For a description of the
subgoal package, see under set_goal.
Failure
Calling expand_listf ltac fails if the list-tactic ltac fails for
the current goal list. It will diverge if the list-tactic diverges for
the goals. It will fail if there are no unproven goals. This could be
because no goal has been set using set_goal or because the last goal
set has been completely proved. If an invalid tactic, whose
justification actually fails, has been used earlier in the proof,
expand_listf ltac may succeed in applying ltac and apparently prove
the current goals. It may then fail as it applies the justifications of
the tactics applied earlier.
Saving CPU time when doing goal-directed proofs, since the extra validation is not done. Redoing proofs quickly that are already known to work.
Comments
The CPU time saved may cause misery later. If an invalid tactic or list-tactic is used, this will only be discovered when the proof has apparently been finished and the justifications are applied.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.expand_list,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
expandf
expandf
proofManagerLib.expandf : (tactic -> unit)
Applies a tactic to the current goal, stacking the resulting subgoals.
The function expandf is a faster version of expand. It does not use
a validated version of the tactic. That is, no check is made that the
justification of the tactic does prove the goal from the subgoals it
generates. If an invalid tactic is used, the theorem ultimately proved
may not match the goal originally set. Alternatively, failure may occur
when the justifications are applied in which case the theorem would not
be proved. For a description of the subgoal package, see under
set_goal.
Failure
Calling expandf tac fails if the tactic tac fails for the top goal.
It will diverge if the tactic diverges for the goal. It will fail if
there are no unproven goals. This could be because no goal has been set
using set_goal or because the last goal set has been completely
proved. If an invalid tactic, whose justification actually fails, has
been used earlier in the proof, expandf tac may succeed in applying
tac and apparently prove the current goal. It may then fail as it
applies the justifications of the tactics applied earlier.
Example
- g `HD[1;2;3] = 1`;
`HD[1;2;3] = 1`
() : void
- expandf (REWRITE_TAC[HD;TL]);;
OK..
goal proved
|- HD[1;2;3] = 1
Previous subproof:
goal proved
() : void
The following example shows how the use of an invalid tactic can yield a theorem which does not correspond to the goal set.
- set_goal([], Term `1=2`);
`1 = 2`
() : void
- expandf (REWRITE_TAC[ASSUME (Term`1=2`)]);
OK..
goal proved
. |- 1 = 2
Previous subproof:
goal proved
() : void
The proof assumed something which was not on the assumption list. This
assumption appears in the assumption list of the theorem proved, even
though it was not in the goal. An attempt to perform the proof using
expand fails. The validated version of the tactic detects that the
justification produces a theorem which does not correspond to the goal
set. It therefore fails.
Saving CPU time when doing goal-directed proofs, since the extra validation is not done. Redoing proofs quickly that are already known to work.
Comments
The CPU time saved may cause misery later. If an invalid tactic is used, this will only be discovered when the proof has apparently been finished and the justifications are applied.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
flatn
flatn
proofManagerLib.flatn : int -> unit
Flattens the tree structure of subgoals on the subgoal package goal stack.
The function flatn is part of the subgoal package. For a general
description of the subgoal package, see set_goal.
The flatn function's basic step of operation is to take the the
current list of sub-goals and concatenate it with the previous list of
subgoals (excluding the first of that list, from which the current list
was obtained). The numeric argument passed to flatn specifies how many
times this operation is to be performed.
Failure
Raises the NO_PROOFS exception if there is no current proof
manipulated by the subgoal package.
If n is too large, or negative, the result will be a flat list of all
subgoals.
To view, reorder, or attack simultaneously, current and previously obtained subgoals.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
forget_history
forget_history
proofManagerLib.forget_history : unit -> unit
Clears the proof history.
The function forget_history is part of the subgoal package. A call to
forget_history clears the history of saved proof states. Subsequent
calls to backup or restart will behave as if the initial goal was
the state at the time of the call to forget_history. For a description
of the subgoal package, see set_goal.
Failure
The function forget_history only fails if no goalstack is being
managed.
Hiding an automatic preprocessing phase of a proof before handing it to the user.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
g
g
proofManagerLib.g : term quotation -> proofs
Initializes the subgoal package with a new goal which has no assumptions.
The call
g `tm`
is equivalent to
set_goal([],Term`tm`)
and clearly more convenient if a goal has no assumptions. For a
description of the subgoal package, see set_goal.
Failure
Fails unless the argument term has type bool.
Example
> g `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`;
val it =
Proof manager status: 3 proofs.
3. Completed goalstack: [.] ⊢ q
2. Completed goalstack: ⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
p
p
proofManagerLib.p : unit -> proof
Prints the top levels of the subgoal package goal stack.
The function p is part of the subgoal package. For a description of
the subgoal package, see set_goal.
Failure
Never fails.
Examining the proof state during an interactive proof session.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
r
r
proofManagerLib.r : int -> unit
Reorders the subgoals on top of the subgoal package goal stack.
The function r is part of the subgoal package. The name rotate may
also be used to access the same function. For a general description of
the subgoal package, see set_goal.
The r function's basic step of operation is to take the first element
of the current list of sub-goals and move it to the end of the same
list. The numeric argument passed to r specifies how many times this
operation is to be performed.
Failure
Raises the NO_PROOFS exception if there is no current proof
manipulated by the subgoal package. Raises a HOL_ERR if the current
goal state only has one sub-goal, or if the argument passed to r is
negative.
Interactively attacking subgoals in a different order to that generated by the subgoal package.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
rd
rd
proofManagerLib.rd : unit -> proof
Restores the proof state, redoing the effects of a previous expansion.
The function rd is part of the subgoal package. It is an abbreviation
for the function redo. For a description of the subgoal package, see
set_goal.
Failure
As for redo.
Back tracking in a goal-directed proof to undo errors or try different tactics.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.b,
proofManagerLib.backup,
proofManagerLib.rd,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
redo
redo
proofManagerLib.redo : unit -> proof
Restores the proof state, redoing the effects of a previous expansion.
The function redo is part of the subgoal package. It may be
abbreviated by the function rd. It undoes the action of backup,
returning to a state after an undone state change (caused by calls to
expand, rotate and similar functions). The function that caused the
original state change is not re-run; only the final state is restored.
Any regular state change will cause the redo stack to be discarded.
Failure
The function redo will fail if the redo list is empty.
Example
> g `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`;
val it =
Proof manager status: 4 proofs.
4. Completed goalstack: [.] ⊢ q
3. Completed goalstack: ⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
2. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
> e CONJ_TAC;
OK..
2 subgoals:
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
> backup();
val it =
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]: proof
> redo();
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
Back tracking in a goal-directed proof to undo errors or try different tactics.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.b,
proofManagerLib.backup,
proofManagerLib.rd,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
restart
restart
proofManagerLib.restart : unit -> proof
Returns the proof state to the initial goal.
The function restart is part of the subgoal package. A call to
restart clears the proof history and returns to the initial goal.
After a call to restart, the proof state is the same as it was after
the inital call to set_goal (or g). For a description of the subgoal
package, see set_goal.
Failure
The function restart only fails if no goalstack is being managed.
Restarting an interactive proof.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
restore
restore
proofManagerLib.restore : unit -> proof
Restores the proof state of the last save point, undoing the effects of expansions after the save point.
The function restore is part of the subgoal package. A call to
restore restores the proof state to the last save point (a proof state
saved by save). If the current state is a save point then restore
clears the current save point and returns to the last save point. If
there are no save points in the history, then restore returns to the
initial goal and is equivalent to restart. For a description of the
subgoal package, see set_goal.
Failure
The function restore will fail only if no goalstack is being managed.
Back tracking in a goal-directed proof to a user-defined save point.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
save
save
proofManagerLib.save : unit -> proof
Marks the current proof state as a save point, and clears the automatic undo history.
The function save is part of the subgoal package. A call to save
clears the automatic proof history and marks the current state as a save
point. A call to backup at a save point will fail. In contrast to
forget_history, however, save does not clear the initial goal or any
previous save points. Therefore a call to restore or restart at a
save point will succeed. For a description of the subgoal package, see
set_goal.
Failure
The function save will fail only if no goalstack is being managed.
Creating save points in an interactive proof, to allow user-directed
back tracking. This is in contrast to the automatic back tracking
facilitated by backup.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
set_backup
set_backup
proofManagerLib.set_backup : int -> unit
Limits the number of proof states saved on the subgoal package backup list.
The assignable variable set_backup is initially set to 12. Its value
is one less than the maximum number of proof states that may be saved on
the backup list. Adding a new proof state (by, for example, a call to
expand) after the maximum is reached causes the earliest proof state
on the list to be discarded. For a description of the subgoal package,
see set_goal.
Example
> set_backup 0;
val it = (): unit
> g `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`;
val it =
Proof manager status: 5 proofs.
5. Completed goalstack: [.] ⊢ q
4. Completed goalstack: ⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
3. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
2. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
Current goal:
HD [1; 2; 3] = 1
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
> e CONJ_TAC;
OK..
2 subgoals:
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
> e (REWRITE_TAC[listTheory.HD]);
OK..
Goal proved.
⊢ HD [1; 2; 3] = 1
Remaining subgoals:
val it =
TL [1; 2; 3] = [2; 3]
> b();
val it =
TL [1; 2; 3] = [2; 3]
HD [1; 2; 3] = 1
> b();
val it =
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]: proof
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
set_goal
set_goal
proofManagerLib.set_goal : term list * term -> unit
Initializes the subgoal package with a new goal.
The function set_goal initializes the subgoal management package. A
proof state of the package consists of either a goal stack and a
justification stack if a proof is in progress, or a theorem if a proof
has just been completed. set_goal sets a new proof state consisting of
an empty justification stack and a goal stack with the given goal as its
sole goal. The goal is printed.
Failure
Fails unless all terms in the goal are of type bool.
Example
> set_goal([], Term `(HD[1;2;3] = 1) /\ (TL[1;2;3] = [2;3])`);
val it =
Proof manager status: 6 proofs.
6. Completed goalstack: [.] ⊢ q
5. Completed goalstack: ⊢ HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
4. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
3. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
Current goal:
HD [1; 2; 3] = 1
2. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
1. Incomplete goalstack:
Initial goal:
HD [1; 2; 3] = 1 ∧ TL [1; 2; 3] = [2; 3]
Starting an interactive proof session with the subgoal package.
The subgoal package implements a simple framework for interactive goal-directed proof. When conducting a proof that involves many subgoals and tactics, the user must keep track of all the justifications and compose them in the correct order. While this is feasible even in large proofs, it is tedious. The subgoal package provides a way of building and traversing the tree of subgoals top-down, stacking the justifications and applying them properly.
The package maintains a proof state consisting of either a goal stack of outstanding goals and a justification stack, or a theorem. Tactics are used to expand the current goal (the one on the top of the goal stack) into subgoals and justifications. These are pushed onto the goal stack and justification stack, respectively, to form a new proof state. Several preceding proof states are saved and can be returned to if a mistake is made in the proof. The goal stack is divided into levels, a new level being created each time a tactic is successfully applied to give new subgoals. Alternatively a list-tactic can process the entire list of goals of the current level to change that level (rather than creating a new level). The subgoals of the current level may be considered in any order. Levels of the goal stack may be collapsed so that subgoals of a previous level appear as part of of the current level.
If a tactic solves the current goal (returns an empty subgoal list), then its justification is used to prove a corresponding theorem. This theorem is then incorporated into the justification of the parent goal. If the subgoal was the last subgoal of the level, the level is removed and the parent goal is proved using its (new) justification. This process is repeated until a level with unproven subgoals is reached. The next goal on the goal stack then becomes the current goal. If all the subgoals are proved, the resulting proof state consists of the theorem proved by the justifications. This theorem may be accessed and saved.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.expand_list,
proofManagerLib.flatn,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
top_goal
top_goal
proofManagerLib.top_goal : unit -> goal
Returns the current goal of the subgoal package.
The function top_goal is part of the subgoal package. It returns the
top goal of the goal stack in the current proof state. For a description
of the subgoal package, see set_goal.
Failure
A call to top_goal will fail if there are no unproven goals. This
could be because no goal has been set using set_goal or because the
last goal set has been completely proved.
Examining the proof state after a proof fails.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
top_thm
top_thm
proofManagerLib.top_thm : unit -> thm
Returns the theorem just proved using the subgoal package.
The function top_thm is part of the subgoal package. A proof state of
the package consists of either goal and justification stacks if a proof
is in progress or a theorem if a proof has just been completed. If the
proof state consists of a theorem, top_thm returns that theorem. For a
description of the subgoal package, see set_goal.
Failure
top_thm will fail if the proof state does not hold a theorem. This
will be so either because no goal has been set or because a proof is in
progress with unproven subgoals.
Accessing the result of an interactive proof session with the subgoal package.
See also
proofManagerLib.set_goal,
proofManagerLib.restart,
proofManagerLib.backup,
proofManagerLib.redo,
proofManagerLib.restore,
proofManagerLib.save,
proofManagerLib.set_backup,
proofManagerLib.expand,
proofManagerLib.expandf,
proofManagerLib.p,
proofManagerLib.top_thm,
proofManagerLib.top_goal
Psyntax
Psyntax
Psyntax : Psyntax_sig
A structure that provides a tuple-style environment for term manipulation.
Each function in the Psyntax structure has a corresponding "record
version" in the Rsyntax structure, and vice versa. One can flip-flop
between the two structures by opening one and then the other. One can
also use long identifiers in order to use both syntaxes at once.
Failure
Never fails.
Example
The following shows how to open the Psyntax structure and the
functions that subsequently become available in the top level
environment. Documentation for each of these functions is available
online.
- open Psyntax;
This command results in the following functions entering the top-level name-space. Term creation functions:
val mk_var = fn : string * hol_type -> term
val mk_const = fn : string * hol_type -> term
val mk_comb = fn : term * term -> term
val mk_abs = fn : term * term -> term
val mk_primed_var = fn : string * hol_type -> term
val mk_eq = fn : term * term -> term
val mk_imp = fn : term * term -> term
val mk_select = fn : term * term -> term
val mk_forall = fn : term * term -> term
val mk_exists = fn : term * term -> term
val mk_conj = fn : term * term -> term
val mk_disj = fn : term * term -> term
val mk_cond = fn : term * term * term -> term
val mk_let = fn : term * term -> term
Term "destructor" functions (i.e., those functions that pull a term apart, and reveal some of its internal structure):
val dest_var = fn : term -> string * hol_type
val dest_const = fn : term -> string * hol_type
val dest_comb = fn : term -> term * term
val dest_abs = fn : term -> term * term
val dest_eq = fn : term -> term * term
val dest_imp = fn : term -> term * term
val dest_select = fn : term -> term * term
val dest_forall = fn : term -> term * term
val dest_exists = fn : term -> term * term
val dest_conj = fn : term -> term * term
val dest_disj = fn : term -> term * term
val dest_cond = fn : term -> term * term * term
val dest_let = fn : term -> term * term
The lambda datatype for taking terms apart, which is the range of the
dest_term function.
datatype lambda =
VAR of string * hol_type
| CONST of {Name : string, Thy : string, Ty : hol_type}
| COMB of term * term
| LAMB of term * term
val dest_term : term -> lambda
See also
pure_ss
pure_ss
pureSimps.pure_ss : simpset
A simpset containing only the conditional rewrite generator and no additional rewrites.
This simpset sits at the root of the simpset hierarchy. It contains no rewrites, congruences, conversions or decision procedures. Instead it contains just the code which converts theorems passed to it as context into (possibly conditional) rewrites.
Simplification with pure_ss is analogous to rewriting with
PURE_REWRITE_TAC and others. The only difference is that the theorems
passed to SIMP_TAC pure_ss are interpreted as conditional rewrite
rules. Though the pure_ss can't take advantage of extra contextual
information garnered through congruences, it can still discharge side
conditions. (This is demonstrated in the examples below.)
Failure
Can't fail, as it is not a functional value.
Example
The theorem ADD_EQ_SUB from arithmeticTheory states that
|- !m n p. n <= p ==> ((m + n = p) = m = p - n)
We can use this result to make progress with the following goal in
conjunction with pure_ss in a way that no form of REWRITE_TAC could:
- ASM_SIMP_TAC pure_ss [ADD_EQ_SUB] ([“x <= y”], “z + x = y”);
> val it = ([([`x <= y`], `z = y - x`)], fn) : tactic_result
This example illustrates the way in which the simplifier can do
conditional rewriting. However, the lack of the congruence for
implications means that using pure_ss will not be able to discharge
the side condition in the goal below:
- SIMP_TAC pure_ss [ADD_EQ_SUB] ([], “x <= y ==> (z + x = y)”);
> val it = ([([], `x <= y ==> (z + x = y)`)], fn) : tactic_result
As bool_ss has the relevant congruence included, it does make progress
in the same situation:
- SIMP_TAC bool_ss [ADD_EQ_SUB] ([], “x <= y ==> (z + x = y)”);
> val it = ([([], `x <= y ==> (z = y - x)`)], fn) : tactic_result
The pure_ss simpset might be used in the most delicate simplification
situations, or, mimicking the way it is used within the distribution
itself, as a basis for the construction of other simpsets.
Comments
There is also a pureSimps.PURE_ss ssfrag value. Its usefulness is
questionable.
See also
boolSimps.bool_ss,
Rewrite.PURE_REWRITE_TAC,
simpLib.SIMP_CONV,
simpLib.SIMP_TAC
ABBREV_TAC
ABBREV_TAC
Q.ABBREV_TAC : term quotation -> tactic
Introduces an abbreviation into a goal.
The tactic Q.ABBREV_TAC q parses the quotation q in the context of
the goal to which it is applied. The result must be a term of the form
v = e with v a variable. The effect of the tactic is to replace the
term e wherever it occurs in the goal by v (or a primed variant of
v if v already occurs in the goal), and to add the assumption
Abbrev(v = e) to the goal's assumptions. Again, if v already occurs
free in the goal, then the new assumption will be Abbrev(v' = e), with
v' a suitably primed version of v.
It is not an error if the expression e does not occur anywhere within
the goal. In this situation, the effect of the tactic is simply to add
the assumption Abbrev(v = e).
The Abbrev constant is defined in markerTheory to be the identity
function over boolean values. It is used solely as a tag, so that
abbreviations can be found by other tools, and so that simplification
tactics such as RW_TAC will not eliminate them. When it sees them as
part of its context, the simplifier treats terms of the form
Abbrev(v = e) as assumptions e = v. In this way, the simplifier can
use abbreviations to create further sharing, after an abbreviation's
creation.
Abbreviation assumptions of this form "protect" their variable argument;
simplification tactics (e.g., fs) will not replace the variable v,
even though they may have been passed rewrites to use such as v = e'.
Failure
Fails if the quotation is ill-typed. This may happen because variables in the quotation that also appear in the goal are given the same type in the quotation as they have in the goal. Also fails if the variable of the equation appears in the expression that it is supposed to be abbreviating.
Example
Substitution in the goal:
> Q.ABBREV_TAC ‘n = 10’ ([], “10 < 9 * 10”);
val it = ([([“Abbrev(n = 10)”], “n < 9 * n”)], fn) :
(term list * term) list * (thm list -> thm)
and the assumptions:
> Q.ABBREV_TAC ‘m = n + 2’ ([“f (n + 2) < 6”], “n < 7”);
val it = ([([“Abbrev(m = n + 2)”, “f m < 6”], “n < 7”)], fn) :
(term list * term) list * (thm list -> thm)
and both
> Q.ABBREV_TAC ‘u = x ** 32’ ([“x ** 32 = f z”],
“g (x ** 32 + 6) - 10 < 65”);
val it =
([([“Abbrev(u = x ** 32)”, “u = f z”], “g (u + 6) - 10 < 65”)],
fn) :
(term list * term) list * (thm list -> thm)
Comments
The bossLib library provides qabbrev_tac as a synonym for
Q.ABBREV_TAC.
It is possible to abbreviate functions, using quotations such as
‘f = \n. n + 3’. When this is done ABBREV_TAC will not itself do
anything more than replace exact copies of the abstraction, but the
simplifier will subsequently see occurrences of the pattern and replace
them.
Thus:
> (qabbrev_tac ‘f = \x. x + 1’ >> asm_simp_tac bool_ss [])
([], “3 + 1 = 4 + 1”);
val it =
([([“Abbrev (f = (\x. x + 1))”], “f 3 = f 4”)], fn):
goal list * (thm list -> thm)
where the simplifier has seen occurrences of the x+1 pattern and
replaced it with calls to the f-abbreviation.
See also
BasicProvers.Abbr,
Q.HO_MATCH_ABBREV_TAC,
Q.MATCH_ABBREV_TAC,
Q.UNABBREV_TAC
HO_MATCH_ABBREV_TAC
HO_MATCH_ABBREV_TAC
Q.HO_MATCH_ABBREV_TAC : term quotation -> tactic
Introduces abbreviations by doing a higher-order match against the goal.
This tactic is just like Q.MATCH_ABBREV_TAC, but does a higher-order
match against the goal rather than a first order match. See the
documentation for MATCH_ABBREV_TAC for more details.
Example
The goal
?- !n. (n + 1) * (n - 1) = n * n - 1
is transformed by Q.HO_MATCH_ABBREV_TAC `!k. P k` to
Abbrev(P = (\n. (n + 1) * (n - 1) = n * n - 1)) ?- !k. P k
Note how the bound variable changes to match that used in the pattern.
See also
Q.ABBREV_TAC,
Q.MATCH_ABBREV_TAC
LIST_REFINE_EXISTS_TAC
LIST_REFINE_EXISTS_TAC
Q.LIST_REFINE_EXISTS_TAC : term quotation list -> tactic
Attacks existential goals, making existential variables more concrete.
Q.LIST_REFINE_EXISTS_TAC is similar to Q.REFINE_EXISTS_TAC, except
it accepts a list of quotations rather than a single one. It further
skips quotations of a single variable beginning with an underscore,
permitting straightforward refinement of nested existentials.
Note that quotations are parsed right-to-left, so earlier quotations are parsed in the context of later ones.
Failure
Fails if passed too many quotations for the current goal. Otherwise
fails similarly to Q.REFINE_EXISTS_TAC.
Example
- Q.LIST_REFINE_EXISTS_TAC [`_`,`SUC c`,`_`,`n + m`]
([``n = 2``,``c = 5``], ``∃a b c d. a + b = c + d``);
> val it =
([([``n = 2``, ``c = 5``], ``∃a c' m. a + SUC c = c' + (n + m)``)], fn)
: goal list * validation
Like Q.REFINE_EXISTS_TAC, Q.LIST_REFINE_EXISTS_TAC is useful if it
is clear that an existential goal can be solved by a term of particular
form, but it is not yet clear exactly what this term will be.
It is particularly useful when refining deeply-nested existentials, or many existentials at once.
Comments
This tactic is also available under the alias bossLib.qrefinel.
See also
Q.REFINE_EXISTS_TAC,
Tactic.EXISTS_TAC
MATCH_ABBREV_TAC
MATCH_ABBREV_TAC
Q.MATCH_ABBREV_TAC : term quotation -> tactic
Introduces abbreviations by matching a pattern against the goal statement.
When applied to the goal (asl, w), the tactic Q.MATCH_ABBREV_TAC q
parses the quotation q in the context of the goal, producing a term to
use as a pattern. The tactic then attempts a (first order) match of the
pattern against the term w. Variables that occur in both the pattern
and the goal are treated as "local constants", and will not acquire
instantiations.
For each variable v in the pattern that has not been treated as a
local constant, there will be an instantiation term t, such that the
substitution pattern [v1 |-> t1, v2 |-> t2, ...] produces w. The
effect of the tactic is to then perform abbreviations in the goal,
replacing each t with the corresponding v (as long as v does not
have a name beginning with an underscore character), and adding
assumptions of the form Abbrev(v = t) to the goal.
Because the tactic ignores underscore variables, the user can abbreviate
just those parts of the goal that are particularly relevant. Note also
that the standard parser treats variables consisting of entirely
underscores specially: each is expanded to a fresh name. This means that
a pattern can use _ repeatedly, and it will not cause the match to
look for the same instantiation for each occurrence. Nor it will require
corresponding sub-terms to have the same type.
Failure
MATCH_ABBREV_TAC fails if the pattern provided does not match the
goal, or if variables from the goal are used in the pattern in ways that
make the pattern fail to type-check.
Example
If the current goal is
?- (n + 10) * y <= 42315 /\ (!x y. x < y ==> f x < f y)
then applying the tactic Q.MATCH_ABBREV_TAC `X <= Y /\ P` results
in the goal
Abbrev(X = (n + 10) * y),
Abbrev(Y = 42315),
Abbrev(P = !x y. x < y ==> f x < f y)
?-
X <= Y /\ P
If the current goal is
?- (n + 10) * y <= 42315 /\ (!x y. x < y ==> f x < f y)
then applying the tactic Q.MATCH_ABBREV_TAC `a * _ <= b /\ _`
results in the goal
Abbrev (a = n + 10)
Abbrev (b = 42315)
?-
a * y <= b /\ !x y. x < y ==> f x < f y
See also
Q.ABBREV_TAC,
Q.HO_MATCH_ABBREV_TAC
MATCH_ASMSUB_RENAME_TAC
MATCH_ASMSUB_RENAME_TAC
Q.MATCH_ASMSUB_RENAME_TAC : term quotation -> string list -> tactic
Finds a match for a pattern in assumptions; instantiates goal to rename or abbreviate.
When applied to the goal (asl,w), the tactic
Q.MATCH_ASMSUB_RENAME_TAC q parses the quotation q in the context of
the goal, producing a term pat to use as a pattern. The tactic then
attempts a (first order) match of pat against each term in asl,
stopping when it finds an assumption that either matches pat in its
entirety, or has a sub-term that matches pat (holding existing free
variables from the goal constant).
In either case, the match will return an instantiation mapping the fresh
free variables of pat to terms occurring in the goal. This
instantiation drops its bindings for variables whose names begin with an
underscore, is next reversed, and is finally applied to the goal. This
will both cause free variables in the goal to be renamed, and for larger
terms to be replaced by variables (similar to what happens with the use
of SPEC_TAC).
Failure
Fails if there is no valid match for the pattern among the assumptions and their sub-terms. A valid match will not bind variables that are bound in the assumption being searched.
Example
In the following example, the variable x is treated as if a constant,
so the search for a match with the pattern does not succeed on the first
assumption (featuring P). Instead the second assumption provides the
instantiation, and so the variable z in the original is renamed to
n.
> Q.MATCH_ASMSUB_RENAME_TAC `x < n`
([``P(y < m):bool``, ``Q(x < z) : bool``], ``x + z < 10``);
val it = ([([``P (y < m)``, ``Q (x < n)``], ``x + n < 10``)],
fn): goal list * validation
See also
Q.MATCH_ASSUM_RENAME_TAC,
Q.MATCH_GOALSUB_RENAME_TAC
MATCH_ASSUM_ABBREV_TAC
MATCH_ASSUM_ABBREV_TAC
Q.MATCH_ASSUM_ABBREV_TAC : term quotation -> tactic
Introduces abbreviations by matching a pattern against an assumption.
When applied to the goal (asl, w), the tactic
Q.MATCH_ASSUM_ABBREV_TAC q parses the quotation q in the context of
the goal, producing a term to use as a pattern. The tactic then attempts
a (first order) match of the pattern against each term in asl,
stopping on the first matching assumption a. Variables that occur in
both the pattern and the goal are treated as "local constants", and will
not acquire instantiations.
For each variable v in the pattern that has not been treated as a
local constant, there will be an instantiation term t, such that the
substitution pattern[v1 |-> t1, v2 |-> t2, ...] produces a. The
effect of the tactic is to then perform abbreviations in the goal,
replacing each t with the corresponding v, and adding assumptions of
the form Abbrev(v = t) to the goal.
Failure
MATCH_ABBREV_TAC fails if the pattern provided does not match any
assumption, or if variables from the goal are used in the pattern in
ways that make the pattern fail to type-check.
Comments
This tactic improves on the following tedious workflow:
Q.PAT_ASSUM pat MP_TAC, Q.MATCH_ABBREV_TAC `pat ==> X`,
Q.UNABBREV_TAC `X`, STRIP_TAC.
See also
Q.MATCH_ABBREV_TAC,
Q.MATCH_ASSUM_RENAME_TAC
MATCH_ASSUM_RENAME_TAC
MATCH_ASSUM_RENAME_TAC
Q.MATCH_ASSUM_RENAME_TAC : term quotation -> tactic
Replaces selected terms with new variables by matching a pattern against an assumption.
When applied to the goal (asl, w), the tactic
Q.MATCH_ASSUM_RENAME_TAC q parses the quotation q in the context of
the goal, producing a term to use as a pattern. The tactic then attempts
a (first order) match of the pattern against each term in asl,
stopping on the first matching assumption a.
For each variable v in the pattern, there will be an instantiation
term t, such that the substitution
pattern[v1 |-> t1, v2 |-> t2, ...]
produces a. The effect of the tactic is to then replace each t with
the corresponding v, yielding a new goal. Note that underscores within
a pattern, though strictly speaking variables, are not included in this
reverse instantiation.
Failure
MATCH_ASSUM_RENAME_TAC fails if the pattern provided does not match
any assumption, or if variables from the goal are used in the pattern in
ways that make the pattern fail to type-check.
Example
If the current goal is
(f x = Pair C'' C0') ?- (f C'' = f C0')
then applying the tactic Q.MATCH_ASSUM_RENAME_TAC `_ = Pair c1 c2`
results in the goal
(f x = Pair c1 c2) ?- (f c1 = f c2)
Comments
This tactic improves on the following tedious workflow:
Q.PAT_ASSUM pat MP_TAC, Q.MATCH_ABBREV_TAC `pat ==> X`,
Q.UNABBREV_TAC `X`, markerLib.RM_ALL_ABBREVS_TAC, STRIP_TAC.
See also
MATCH_GOALSUB_RENAME_TAC
MATCH_GOALSUB_RENAME_TAC
Q.MATCH_GOALSUB_RENAME_TAC : term quotation -> tactic
Renames a goal in accordance with a pattern matched against a subterm of the goal.
A call to MATCH_GOALSUB_RENAME_TAC pat attempts to find a match for
the pattern pat in the current goal (using gen_find_term to find a
sub-term of the goal that matches). If a match is found, the goal is
adjusted so that the variables occurring in the pattern now also appear
in the goal. This may rename variables in the goal, or even cause larger
sub-terms to be replaced by variables (as with SPEC_TAC). Underscores
may be used in pat to indicate "don't care" bindings, where no
renaming or instantiation will take place.
Failure
Fails if there is no sub-term of the goal that matches the pattern. Fails if the instantiation changes a pattern variable that already exists in the goal.
Example
If the goal is
?- !x. x * 2 < y * (z + 1) * (y + a)
then applying Q.MATCH_GOALSUB_RENAME_TAC `y + c` will match the
pattern y + c against the various subterms within the goal. The first
obvious match, with z + 1 will be rejected because the variable y is
free in the goal, and is treated as if it were a local constant. Because
of this, y + a is the matching sub-term, and after renaming the goal
becomes
?- !x. x * 2 < y * (z + 1) * (y + c)
See also
MATCH_RENAME_TAC
MATCH_RENAME_TAC
Q.MATCH_RENAME_TAC : term quotation -> tactic
Replaces selected terms with new variables by matching a pattern against the goal statement.
When applied to the goal (asl, w), the tactic
Q.MATCH_RENAME_TAC q ls parses the quotation q in the context of the
goal, producing a term to use as a pattern. The tactic then attempts a
(first order) match of the pattern against the term w.
For each variable v in the pattern, there will be an instantiation
term t, such that the substitution
pattern[v1 |-> t1, v2 |-> t2, ...]
produces w. The effect of the tactic is to then replace each t with
the corresponding v, yielding a new goal. Note that underscores within
a pattern, though strictly speaking variables, are not included in this
reverse instantiation.
Failure
MATCH_RENAME_TAC fails if the pattern provided does not match the
goal, or if variables from the goal are used in the pattern in ways that
make the pattern fail to type-check.
Example
If the current goal is
?- (f x = Pair C'' C0') ==> (f C'' = f C0')
then applying the tactic
Q.MATCH_RENAME_TAC `(f x = Pair c1 c2) ==> _` results in the goal
?- (f x = Pair c1 c2) ==> (f c1 = f c2)
Comments
This tactic is equivalent to first applying Q.MATCH_ABBREV_TAC q, then
applying Q.RM_ABBREV_TAC `v` for each underscore in q.
See also
Q.MATCH_ABBREV_TAC,
Q.MATCH_ASSUM_RENAME_TAC
PAT_ABBREV_TAC
PAT_ABBREV_TAC
Q.PAT_ABBREV_TAC : term quotation -> tactic
Introduces an abbreviation within the goal statement.
When applied to the goal (asl, w), the tactic Q.PAT_ABBREV_TAC q
parses the quotation q in the context of the goal, producing an
equality term v = p. The tactic then uses HolKernel.gen_find_term to
search for a sub-term of w that p matches against. If such a
sub-term t is found then all occurrences of t (in asl and w)
will be replaced by v and an assumption Abbrev(v = t) is added to
the goal.
The trace variable "PAT_ABBREV_TAC: match var/const" controls whether
or not trivial matches (with constants or variables) are allowed. By
default trivial matches are permitted but when the trace variable is
false the tactic will ignore trivial matches, which could result in
failure.
Failure
PAT_ABBREV_TAC fails if q does not successfully parse as an equality
or if no matching sub-term is found in the goal, or if the only matching
sub-terms would bind pattern variables to variables that are bound in
the goal.
Example
If the current goal is
?- (n + 10) * y <= 42315
then applying the tactic Q.PAT_ABBREV_TAC `X = a * b: num` results
in the goal
Abbrev (X = (n + 10) * y)
?-
X <= 42315
By default trivial matches are permitted. If the current goal is
?- y <= 42315
then Q.PAT_ABBREV_TAC `X = a: num` will give
Abbrev (X = y)
?-
X <= 42315
However, if this is not desirable then setting
Feedback.set_trace "PAT_ABBREV_TAC: match var/const" 0
and applying Q.PAT_ABBREV_TAC `X = a: num` will give
Abbrev (X = 42315)
?-
y <= X
If the current goal is
?- !x. x < 3
then applying Q.PAT_ABBREV_TAC `v = (a < b)` will result in a
failure because the pattern's variable a would have to bind the bound
variable x in the goal.
See also
Q.ABBREV_TAC,
HolKernel.gen_find_term,
Q.MATCH_ABBREV_TAC
REFINE_EXISTS_TAC
REFINE_EXISTS_TAC
Q.REFINE_EXISTS_TAC : term quotation -> tactic
Attacks existential goals, making the existential variable more concrete.
The tactic Q.REFINE_EXISTS_TAC q parses the quotation q in the
context of the (necessarily existential) goal to which it is applied,
and uses the resulting term as the witness for the goal. However, if the
witness has any variables not already present in the goal, then these
are treated as new existentially quantified variables. If there are no
such "free" variables, then the behaviour is the same as EXISTS_TAC.
Failure
Fails if the goal is not existential, or if the quotation can not parse to a term of the same type as the existentially quantified variable.
Example
If the quotation doesn't mention any new variables:
- Q.REFINE_EXISTS_TAC `n` ([``n > x``], ``?m. m > x``);
> val it =
([([``n > x``], ``n > x``)], fn)
: (term list * term) list * (thm list -> thm)
If the quotation does mention any new variables, they are existentially quantified in the new goal:
- Q.REFINE_EXISTS_TAC `n + 2` ([``~P 0``], ``?p. P (p - 1)``);
> val it =
([([``~P 0``], ``?n. P (n + 2 - 1)``)], fn)
: (term list * term) list * (thm list -> thm)
Q.REFINE_EXISTS_TAC is useful if it is clear that an existential goal
will be solved by a term of particular form, while it is not yet clear
precisely what term this will be. Further proof activity should be able
to exploit the additional structure that has appeared in the place of
the existential variable.
See also
Q.LIST_REFINE_EXISTS_TAC,
Tactic.EXISTS_TAC
RENAME1_TAC
RENAME1_TAC
Q.RENAME1_TAC : term quotation -> tactic
Finds an instance of a pattern in a goal, and renames to use names from the pattern.
The tactic Q.RENAME1_TAC q is defined to be
MATCH_RENAME_TAC q ORELSE MATCH_ASSUM_RENAME_TAC q ORELSE
MATCH_GOALSUB_RENAME_TAC q ORELSE MATCH_ASMSUB_RENAME_TAC q
Failure
Fails if all of the constituent tactics fail.
Comments
This tactic can be used to force a particular set of names on a goal,
hopefully making the resulting tactic more robust in the face of
underlying implementation changes. Note though that successful use of
this tactic requires that the "new" names in the provided pattern really
be fresh for the goal. If one is really uncertain about what names might
be appearing in a goal, this condition may be difficult to ensure,
particularly as the tactic only looks for one instance of the pattern at
a time (but see Q.RENAME_TAC).
This tactic is also available under the alias bossLib.rename1.
See also
Q.MATCH_ASMSUB_RENAME_TAC,
Q.MATCH_ASSUM_RENAME_TAC,
Q.MATCH_GOALSUB_RENAME_TAC,
Q.MATCH_RENAME_TAC
RENAME_TAC
RENAME_TAC
Q.RENAME_TAC : term quotation list -> tactic
Renames free variables or subterms within a goal.
A call to RENAME_TAC qs searches the current goal for matches to the
patterns in the list qs, and then substitutes out the matches (in the
"reverse direction") so that the goal becomes one that uses the names
from qs. This can cause subterms within the goal to turn into simple
variables, but the usual intention is to rename free variables into the
variables that appear in the patterns.
The matching is done without reference to the goal's existing free
variables. If a variable in qs clashes with an existing variable in
the goal, then the goal's variable will be renamed away. It is
sufficient for variables to have the same name to "clash"; they need not
also have the same type. The search for matches begins by attempting to
find matches against the whole of the goal, against whole assumptions,
for sub-terms within the goal, and then sub-terms of assumptions.
These four different flavours of searching can additionally be
controlled by adding comments (* ... *) to the end of the relevant
quotation. The string in the comment has its whitespace stripped, and is
then split into fields using the pipe character | as a separator. If
the string consisting of the single character g is present, the
pattern is checked against the entirety of the goal's conclusion; the
string of character a causes a check against each individual
assumption; the strings sg and sa cause checks against sub-terms
present in the conclusion, or in any assumption respectively.
If multiple matches are possible, a variant tactic, Q.kRENAME_TAC, can
be used: this tactic takes an additional "continuation" tactic argument
that can be used to discriminate between these matches.
Patterns can use underscores to match anything without any change in the goal's naming being introduced. Underscores can match against sub-terms that include bound variables. Matching is first-order.
Failure
Fails if it is impossible to consistently match the combination of
patterns in the provided list of quotations (qs).
Example
If the goal is of the form
x < y, y < z ?- x < f a
then invoking Q.RENAME_TAC [`b < c`, `a < b`] will produce the
sub-goal:
a < b, b < c ?- a < f a'
where the goal's original a variable (which is not even of type
num), has been renamed away from a because that variable occurs in
the patterns. (If the right hand side of the inequality was simply a
and was thus of type num, it would also be renamed to a'.)
If Q.RENAME_TAC [`b < c`] is invoked on the same initial goal, the
result is:
b < y, y < z ?- b < c
illustrating the way in which variables can eliminate more complicated sub-terms.
The useful way in which underscores in patterns can be used to "dodge" terms including bound variables is illustrated in the next example, where the initial goal is:
(!a. f a < z), z < c ?- z < d
After applying Q.RENAME_TAC [`_ < x`, `x < c`], the goal becomes
(!a. f a < x), x < c' ?- x < c
The goal was chosen for the match to the second pattern because the goal is considered first. If the initial goal had been
(!a. f a < z), z < c ?- z < d /\ P z
then the result of the same application would be
(!a. f a < z), z < c ?- x < d /\ P x
because whole assumptions are considered before sub-terms of the goal.
The pattern-specification comments can be important when selecting for
certain assumptions. Here, Q.RENAME_TAC [‘x < _ (* a *)’] will fail
because there is no assumption of the required shape, even though the
shape appears as a subterm in the assumptions, and is the shape of the
goal's conclusion:
~(a < b) ?- c < d
Similarly, using the comment (* a|sg *) would also fail because the
pattern is not present as a sub-term of the goal's conclusion.
Comments
This function is also available under the name bossLib.rename.
Note that Q.RENAME_TAC [q] is not the same as Q.RENAME1_TAC q. The
latter pays attention to the goal's free variables, using these to
constrain the match to the pattern. In contrast, Q.RENAME_TAC
completely ignores all of the goal's free variables, such that using an
existing name in a pattern doesn't make any difference to the matching
behaviour.
See also
UNABBREV_TAC
UNABBREV_TAC
Q.UNABBREV_TAC : term quotation -> tactic
Removes an abbreviation from a goal's assumptions by substituting it out.
The argument to UNABBREV_TAC must be a quotation containing the name
of a variable that is abbreviated in the current goal. In other words,
when calling UNABBREV_TAC `v`, there must be an assumption of the
form Abbrev(v = e) in the goal's assumptions. This assumption is
removed, and all occurrences of the variable v in the goal are
replaced by e. If there are two abbreviation assumptions for v in
the goal, the more recent is removed.
Example
The goal
Abbrev(v = 2 * x + 1), v + x < 10 ?- P(v)
is transformed by Q.UNABBREV_TAC `v` to
2 * x + 1 + x < 10 ?- P(2 * x + 1)
Failure
Fails if there is no abbreviation of the required form in the goal's assumptions, or if the quotation doesn't parse to a variable.
See also
BasicProvers.Abbr,
Q.ABBREV_TAC
ASM_QUANT_INSTANTIATE_TAC
ASM_QUANT_INSTANTIATE_TAC
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC : quant_param list -> tactic
A tactic to instantiate quantifiers in a term using a given list of quantifier heuristic parameters.
This tactic is based on quantHeuristicsLib.QUANT_INSTANTIATE_CONV. It
tries to instantiate quantifiers. Free variables of the goal are seen as
universally quantified by this tactic. Therefore, it tries to
instantiate these free variables.
In contrast to quantHeuristicsLib.QUANT_INSTANTIATE_TAC this tactic
takes the assumptions of the goal into account.
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV,
quantHeuristicsLib.QUANT_INSTANTIATE_TAC
FAST_ASM_QUANT_INSTANTIATE_TAC
FAST_ASM_QUANT_INSTANTIATE_TAC
quantHeuristicsLib.FAST_ASM_QUANT_INSTANTIATE_TAC : quant_param list -> tactic
A fast version of quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC. It
does not preprocess the term in order to minimise the number of variable
occurrences.
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV,
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC
FAST_QUANT_INST_ss
FAST_QUANT_INST_ss
quantHeuristicsLib.FAST_QUANT_INST_ss : quant_param list -> simpLib.ssfrag
A simpset fragement corresponding to FAST_QUANT_INSTANTIATE_CONV.
See also
quantHeuristicsLib.FAST_QUANT_INSTANTIATE_CONV
FAST_QUANT_INSTANTIATE_CONV
FAST_QUANT_INSTANTIATE_CONV
quantHeuristicsLib.FAST_QUANT_INSTANTIATE_CONV : quant_param list -> conv
A fast version of quantHeuristicsLib.QUANT_INSTANTIATE_CONV. It does
not preprocess the term in order to minimise the number of variable
occurrences.
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV,
quantHeuristicsLib.FAST_QUANT_INSTANTIATE_TAC
FAST_QUANT_INSTANTIATE_TAC
FAST_QUANT_INSTANTIATE_TAC
quantHeuristicsLib.FAST_QUANT_INSTANTIATE_TAC : quant_param list -> tactic
A fast version of quantHeuristicsLib.QUANT_INSTANTIATE_TAC. It does
not preprocess the term in order to minimise the number of variable
occurrences.
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV,
quantHeuristicsLib.QUANT_INSTANTIATE_TAC
QUANT_INST_ss
QUANT_INST_ss
quantHeuristicsLib.QUANT_INST_ss : quant_param list -> simpLib.ssfrag
A simpset fragement corresponding to QUANT_INSTANTIATE_CONV.
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV
QUANT_INSTANTIATE_CONV
QUANT_INSTANTIATE_CONV
quantHeuristicsLib.QUANT_INSTANTIATE_CONV : quant_param list -> conv
Instantiate quantifiers in a term using a given list of quantifier heuristic parameters.
This conversion tries to instantiate quantifiers. Therefore, it uses the
given list of quantifier heuristic parameters. If the list is empty, it
knows about the usual Boolean Connectives, quantifiers and equations.
The parameter quantHeuristicsArgsLib.std_qp adds knowledge about
option-types, pairs, lists, records and natural numbers. The stateful
parameter quantHeuristicsArgsLib.Type_Base_qp can be used to extract
information about user defined datatypes.
Example
> quantHeuristicsLib.QUANT_INSTANTIATE_CONV [] ``?x. ((x=7) \/ (7 = x)) /\ P x``;
val it = ⊢ (∃x. (x = 7 ∨ 7 = x) ∧ P x) ⇔ P 7: thm
> quantHeuristicsLib.QUANT_INSTANTIATE_CONV [] ``?x. !y. (x=7) /\ P x y``;
val it = ⊢ (∃x. ∀y. x = 7 ∧ P x y) ⇔ ∀y. P 7 y: thm
> quantHeuristicsLib.QUANT_INSTANTIATE_CONV [] ``?x. (f(8 + 2) = f(x + 2)) /\ P(f (x + 2))``;
val it = ⊢ (∃x. f (8 + 2) = f (x + 2) ∧ P (f (x + 2))) ⇔ P (f (8 + 2)): thm
> quantHeuristicsLib.QUANT_INSTANTIATE_CONV [quantHeuristicsLibParameters.std_qp] ``!x. IS_SOME x ==> P x``;
val it = ⊢ (∀x. IS_SOME x ⇒ P x) ⇔ ∀x_x'. P (SOME x_x'): thm
> quantHeuristicsLib.QUANT_INSTANTIATE_CONV [quantHeuristicsLibParameters.std_qp] ``!l. (~(l = []) ==> (LENGTH l > 0))``;
val it = ⊢ (∀l. l ≠ [] ⇒ LENGTH l > 0) ⇔ ∀l_h l_t. LENGTH (l_h::l_t) > 0: thm
See also
quantHeuristicsLib.QUANT_INST_ss,
quantHeuristicsLib.QUANT_INSTANTIATE_TAC,
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC,
quantHeuristicsLib.FAST_QUANT_INSTANTIATE_CONV,
quantHeuristicsLib.FAST_QUANT_INST_ss,
quantHeuristicsLib.FAST_QUANT_INSTANTIATE_TAC
QUANT_INSTANTIATE_TAC
QUANT_INSTANTIATE_TAC
quantHeuristicsLib.QUANT_INSTANTIATE_TAC : quant_param list -> tactic
A tactic to instantiate quantifiers in a term using a given list of quantifier heuristic parameters.
This tactic is based on quantHeuristicsLib.QUANT_INSTANTIATE_CONV. It
tries to instantiate quantifiers. Free variables of the goal are seen as
universally quantified by this tactic. Therefore, it tries to
instantiate these free variables. In contrast to
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC this tactic does not take
the assumptions of the goal into account.
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV,
quantHeuristicsLib.ASM_QUANT_INSTANTIATE_TAC
QUANT_TAC
QUANT_TAC
quantHeuristicsLib.QUANT_TAC : (string * Parse.term Lib.frag list * Parse.term Parse.frag list list) list -> tactic
A tactic to instantiate quantifiers in a term using an explitly given list of (partial) instantiations.
This tactic can be seen as a generalisation of Q.EXISTS_TAC. When
applied to a term fragment u and a goal ?x. t, the tactic
EXISTS_TAC reduces the goal to t[u/x]. QUANT_TAC allows to perform
similar instantiations of quantifiers at subpositions, provided the
subposition occurs in a formula composed of standard operators that the
tactic can handle. It can - depending on negation level - instantiate
both existential and universal quantifiers. Moreover, it allows partial
instantiations and instantiating multiple variables at the same time.
QUANT_TAC gets a list of triples
(var_name, instantiation, free_vars) as an argument. var_name is the
name of the variable to be instantiated; instantiation is the term
this variable should be instantiated with. Finally, free_vars is a
list of free variables in instantiation that should remain quantified.
As this tactic adresses variables by their name, resulting proofs might not be robust. Therefore, this tactic should be used carefully.
Example
Given the goal
!x. (!z. P x z) ==> ?a b. Q a b z
where z and a are natural numbers, the call
QUANT_TAC [("z", `0`, []), ("a", `SUC a'`, [`a'`])] instantiates
z with 0 and a with SUC a', where a' is free. The variable z
is universally quantified, but in the antecedent of the implication.
Therefore, it can be safely instantiated. a is existentially
quantified. In this example we just want to say that a is not 0,
therefore a' is considered as a free variable and thus remains
existentially quantified. The call results in the goal
!x. ( P x 0) ==> ? b a'. Q (SUC a') b z
See also
SIMPLE_QUANT_INST_ss
SIMPLE_QUANT_INST_ss
quantHeuristicsLib.SIMPLE_QUANT_INST_ss : simpLib.ssfrag
A simpset fragment corresponding to
quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV.
See also
quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV,
bossLib.SQI_ss
SIMPLE_QUANT_INSTANTIATE_CONV
SIMPLE_QUANT_INSTANTIATE_CONV
quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV : conv
A conversion for instantiating quantifiers. In contrast to
quantHeuristicsLib.QUANT_INSTANTIATE_CONV it only searches for gap
guesses without free variables. As a result, it is much less powerful,
but also much faster than quantHeuristicsLib.QUANT_INSTANTIATE_CONV.
Failure
If no instantiation could be found.
Example
> quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV ``?x. P x /\ (x = 5)``
val it = ⊢ (∃x. P x ∧ x = 5) ⇔ P 5 ∧ 5 = 5: thm
> quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV ``!x. (x = 5) ==> P x``
val it = ⊢ (∀x. x = 5 ⇒ P x) ⇔ 5 = 5 ⇒ P 5: thm
> quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV ``!x. Q x ==> !z. Z z /\ (x = 5) ==> P x z``
val it =
⊢ (∀x. Q x ⇒ ∀z. Z z ∧ x = 5 ⇒ P x z) ⇔ Q 5 ⇒ ∀z. Z z ∧ 5 = 5 ⇒ P 5 z: thm
> quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV ``!x. ((3, x, y) = zxy) ==> P x``
val it =
⊢ (∀x. (3,x,y) = zxy ⇒ P x) ⇔
(3,FST (SND zxy),y) = zxy ⇒ P (FST (SND zxy)): thm
> quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV ``some x. (x = 2) /\ P x``
val it = ⊢ (some x. x = 2 ∧ P x) = if 2 = 2 ∧ P 2 then SOME 2 else NONE: thm
> quantHeuristicsLib.SIMPLE_QUANT_INSTANTIATE_CONV ``?x1 x2 x3. P x1 x2 /\ (x2::x1::l = 3::(f x3)::l')``
val it =
⊢ (∃x1 x2 x3. P x1 x2 ∧ x2::x1::l = 3::f x3::l') ⇔
∃x2 x3. P (f x3) x2 ∧ x2::f x3::l = 3::f x3::l': thm
See also
quantHeuristicsLib.QUANT_INSTANTIATE_CONV,
unwind.UNWIND_EXISTS_CONV,
unwind.UNWIND_FORALL_CONV,
quantHeuristicsLib.SIMPLE_QUANT_INST_ss,
bossLib.SQI_ss
ADD_CONV
ADD_CONV
reduceLib.ADD_CONV : conv
Calculates by inference the sum of two numerals.
If m and n are numerals (e.g. 0, 1, 2, 3,...) of type
:num, then ADD_CONV ``m + n`` returns the theorem:
|- m + n = s
where s is the numeral that denotes the sum of the natural numbers
denoted by m and n.
Failure
ADD_CONV tm fails unless tm is of the form ``m + n``, where
m and n are numerals of type :num.
Example
> reduceLib.ADD_CONV ``75 + 25``;
val it = ⊢ 75 + 25 = 100: thm
See also
AND_CONV
AND_CONV
reduceLib.AND_CONV : conv
Simplifies certain boolean conjunction expressions.
If tm corresponds to one of the forms given below, where t is an
arbitrary term of type bool, then AND_CONV tm returns the
corresponding theorem. Note that in the last case the conjuncts need
only be alpha-equivalent rather than strictly identical.
AND_CONV "T /\ t" = |- T /\ t = t
AND_CONV "t /\ T" = |- t /\ T = t
AND_CONV "F /\ t" = |- F /\ t = F
AND_CONV "t /\ F" = |- t /\ F = F
AND_CONV "t /\ t" = |- t /\ t = t
Failure
AND_CONV tm fails unless tm has one of the forms indicated above.
Example
#AND_CONV "(x = T) /\ F";;
|- (x = T) /\ F = F
#AND_CONV "T /\ (x = T)";;
|- T /\ (x = T) = (x = T)
#AND_CONV "(?x. x=T) /\ (?y. y=T)";;
|- (?x. x = T) /\ (?y. y = T) = (?x. x = T)
BEQ_CONV
BEQ_CONV
reduceLib.BEQ_CONV : conv
Simplifies certain expressions involving boolean equality.
If tm corresponds to one of the forms given below, where t is an
arbitrary term of type bool, then BEQ_CONV tm returns the
corresponding theorem. Note that in the last case the left-hand and
right-hand sides need only be alpha-equivalent rather than strictly
identical.
BEQ_CONV "T = t" = |- T = t = t
BEQ_CONV "t = T" = |- t = T = t
BEQ_CONV "F = t" = |- F = t = ~t
BEQ_CONV "t = F" = |- t = F = ~t
BEQ_CONV "t = t" = |- t = t = T
Failure
BEQ_CONV tm fails unless tm has one of the forms indicated above.
Example
#BEQ_CONV "T = T";;
|- (T = T) = T
#BEQ_CONV "F = T";;
|- (F = T) = F
#BEQ_CONV "(!x:*#**. x = (FST x,SND x)) = (!y:*#**. y = (FST y,SND y))";;
|- ((!x. x = FST x,SND x) = (!y. y = FST y,SND y)) = T
COND_CONV
COND_CONV
reduceLib.COND_CONV : conv
Simplifies certain conditional expressions.
If tm corresponds to one of the forms given below, where b has type
bool and t1 and t2 have the same type, then COND_CONV tm returns
the corresponding theorem. Note that in the last case the arms need only
be alpha-equivalent rather than strictly identical.
COND_CONV "F => t1 | t2" = |- (T => t1 | t2) = t2
COND_CONV "T => t1 | t2" = |- (T => t1 | t2) = t1
COND_CONV "b => t | t = |- (b => t | t) = t
Failure
COND_CONV tm fails unless tm has one of the forms indicated above.
Example
#COND_CONV "F => F | T";;
|- (F => F | T) = T
#COND_CONV "T => F | T";;
|- (T => F | T) = F
#COND_CONV "b => (\x. SUC x) | (\p. SUC p)";;
|- (b => (\x. SUC x) | (\p. SUC p)) = (\x. SUC x)
DIV_CONV
DIV_CONV
reduceLib.DIV_CONV : conv
Calculates by inference the result of dividing, with truncation, one numeral by another.
If m and n are numerals (e.g. 0, 1, 2, 3,...), then
DIV_CONV ``m DIV n`` returns the theorem:
|- m DIV n = s
where s is the numeral that denotes the result of dividing the natural
number denoted by m by the natural number denoted by n, with
truncation.
Failure
DIV_CONV tm fails unless tm is of the form ``m DIV n``,
where m and n are numerals, or if n denotes zero.
Example
> Arithconv.DIV_CONV ``0 DIV 0``;
val it = ⊢ 0 DIV 0 = 0: thm
> Arithconv.DIV_CONV ``x DIV 12``;
Exception- HOL_ERR
(at Conv.RAND_CONV:
at Thm.dest_cexp: term is not a compute value) raised
> Arithconv.DIV_CONV ``0 DIV 12``;
val it = ⊢ 0 DIV 12 = 0: thm
> Arithconv.DIV_CONV ``7 DIV 2``;
val it = ⊢ 7 DIV 2 = 3: thm
EXP_CONV
EXP_CONV
reduceLib.EXP_CONV : conv
Calculates by inference the result of raising one numeral to the power of another.
If m and n are numerals (e.g. 0, 1, 2, 3,...), then
EXP_CONV "m EXP n" returns the theorem:
|- m EXP n = s
where s is the numeral that denotes the result of raising the natural
number denoted by m to the power of the natural number denoted by n.
Failure
EXP_CONV tm fails unless tm is of the form "m EXP n", where m
and n are numerals.
Example
#EXP_CONV "0 EXP 0";;
|- 0 EXP 0 = 1
#EXP_CONV "15 EXP 0";;
|- 15 EXP 0 = 1
#EXP_CONV "12 EXP 1";;
|- 12 EXP 1 = 12
#EXP_CONV "2 EXP 6";;
|- 2 EXP 6 = 64
GE_CONV
GE_CONV
reduceLib.GE_CONV : conv
Proves result of less-than-or-equal-to ordering on two numerals.
If m and n are both numerals (e.g. 0, 1, 2, 3,...), then
GE_CONV "m >= n" returns the theorem:
|- (m >= n) = T
if the natural number denoted by m is greater than or equal to that
denoted by n, or
|- (m >= n) = F
otherwise.
Failure
GE_CONV tm fails unless tm is of the form "m >= n", where m and
n are numerals.
Example
#GE_CONV "15 >= 14";;
|- 15 >= 14 = T
#GE_CONV "100 >= 100";;
|- 100 >= 100 = T
#GE_CONV "0 >= 107";;
|- 0 >= 107 = F
GT_CONV
GT_CONV
reduceLib.GT_CONV : conv
Proves result of greater-than ordering on two numerals.
If m and n are both numerals (e.g. 0, 1, 2, 3,...) of type
:num, then GT_CONV "m > n" returns the theorem:
|- (m > n) = T
if the natural number denoted by m is greater than that denoted by
n, or
|- (m > n) = F
otherwise.
Failure
GT_CONV tm fails unless tm is of the form ``m > n``, where
m and n are numerals of type :num.
Example
> GT_CONV ``100 > 10``;
val it = |- 100 > 10 <=> T : thm
> GT_CONV ``15 > 15``;
val it = |- 15 > 15 <=> F : thm
> GT_CONV ``11 > 27``;
val it = |- 11 > 27 = F : thm
See also
IMP_CONV
IMP_CONV
reduceLib.IMP_CONV : conv
Simplifies certain implicational expressions.
If tm corresponds to one of the forms given below, where t is an
arbitrary term of type bool, then IMP_CONV tm returns the
corresponding theorem. Note that in the last case the antecedent and
consequent need only be alpha-equivalent rather than strictly identical.
IMP_CONV “T ==> t” = |- T ==> t = t
IMP_CONV “t ==> T” = |- t ==> T = T
IMP_CONV “F ==> t” = |- F ==> t = T
IMP_CONV “t ==> F” = |- t ==> F = ~t
IMP_CONV “t ==> t” = |- t ==> t = T
Failure
IMP_CONV tm fails unless tm has one of the forms indicated above.
Example
> IMP_CONV “T ==> F”;
val it = ⊢ T ⇒ F ⇔ F : thm
> IMP_CONV “F ==> x”;
val it = ⊢ F ⇒ x ⇔ T : thm
> IMP_CONV “(!z:(num)list. z = z) ==> (!x:(num)list. x = x)”;
val it = ⊢ (∀z. z = z) ⇒ (∀z. z = z) ⇔ T : thm
LE_CONV
LE_CONV
reduceLib.LE_CONV : conv
Proves result of less-than-or-equal-to ordering on two numerals.
If m and n are both numerals (e.g. 0, 1, 2, 3,...), then
LE_CONV "m <= n" returns the theorem:
|- (m <= n) = T
if the natural number denoted by m is less than or equal to that
denoted by n, or
|- (m <= n) = F
otherwise.
Failure
LE_CONV tm fails unless tm is of the form "m <= n", where m and
n are numerals.
Example
#LE_CONV "12 <= 198";;
|- 12 <= 198 = T
#LE_CONV "46 <= 46";;
|- 46 <= 46 = T
#LE_CONV "13 <= 12";;
|- 13 <= 12 = F
LT_CONV
LT_CONV
reduceLib.LT_CONV : conv
Proves result of less-than ordering on two numerals.
If m and n are both numerals (e.g. 0, 1, 2, 3,...) of type
:num, then LT_CONV ``m < n`` returns the theorem:
|- (m < n) = T
if the natural number denoted by m is less than that denoted by n,
or
|- (m < n) = F
otherwise.
Failure
LT_CONV tm fails unless tm is of the form ``m < n``, where
m and n are numerals of natural number type (:num).
Example
> LT_CONV ``0 < 12``;
val it = |- 0 < 12 <=> T : thm
> LT_CONV ``13 < 13``;
val it = |- 13 < 13 <=> F : thm
> LT_CONV ``25 < 12``;
val it = |- 25 < 12 <=> F : thm
See also
MOD_CONV
MOD_CONV
reduceLib.MOD_CONV : conv
Calculates by inference the remainder after dividing one numeral by another.
If m and n are numerals (e.g. 0, 1, 2, 3,...), then
MOD_CONV "m MOD n" returns the theorem:
|- m MOD n = s
where s is the numeral that denotes the remainder after dividing, with
truncation, the natural number denoted by m by the natural number
denoted by n.
Failure
MOD_CONV tm fails unless tm is of the form "m MOD n", where m
and n are numerals, or if n denotes zero.
Example
#MOD_CONV "0 MOD 0";;
evaluation failed MOD_CONV
#MOD_CONV "0 MOD 12";;
|- 0 MOD 12 = 0
#MOD_CONV "2 MOD 0";;
evaluation failed MOD_CONV
#MOD_CONV "144 MOD 12";;
|- 144 MOD 12 = 0
#MOD_CONV "7 MOD 2";;
|- 7 MOD 2 = 1
MUL_CONV
MUL_CONV
reduceLib.MUL_CONV : conv
Calculates by inference the product of two numerals.
If m and n are numerals (e.g. 0, 1, 2, 3,...), then
MUL_CONV "m * n" returns the theorem:
|- m * n = s
where s is the numeral that denotes the product of the natural numbers
denoted by m and n.
Failure
MUL_CONV tm fails unless tm is of the form "m * n", where m and
n are numerals.
Example
#MUL_CONV "0 * 12";;
|- 0 * 12 = 0
#MUL_CONV "1 * 1";;
|- 1 * 1 = 1
#MUL_CONV "6 * 11";;
|- 6 * 11 = 66
NEQ_CONV
NEQ_CONV
reduceLib.NEQ_CONV : conv
Proves equality or inequality of two numerals.
If m and n are both numerals (e.g. 0, 1, 2, 3,...), then
NEQ_CONV "m = n" returns the theorem:
|- (m = n) = T
if m and n are identical, or
|- (m = n) = F
if m and n are distinct.
Failure
NEQ_CONV tm fails unless tm is of the form "m = n", where m and
n are numerals.
Example
#NEQ_CONV "12 = 12";;
|- (12 = 12) = T
#NEQ_CONV "14 = 25";;
|- (14 = 25) = F
NOT_CONV
NOT_CONV
reduceLib.NOT_CONV : conv
Simplifies certain boolean negation expressions.
If tm corresponds to one of the forms given below, where t is an
arbitrary term of type bool, then NOT_CONV tm returns the
corresponding theorem.
NOT_CONV "~F" = |- ~F = T
NOT_CONV "~T" = |- ~T = F
NOT_CONV "~~t" = |- ~~t = t
Failure
NOT_CONV tm fails unless tm has one of the forms indicated above.
Example
#NOT_CONV "~~~~T";;
|- ~~~~T = ~~T
#NOT_CONV "~~T";;
|- ~~T = T
#NOT_CONV "~T";;
|- ~T = F
OR_CONV
OR_CONV
reduceLib.OR_CONV : conv
Simplifies certain boolean disjunction expressions.
If tm corresponds to one of the forms given below, where t is an
arbitrary term of type bool, then OR_CONV tm returns the
corresponding theorem. Note that in the last case the disjuncts need
only be alpha-equivalent rather than strictly identical.
OR_CONV "T \/ t" = |- T \/ t = T
OR_CONV "t \/ T" = |- t \/ T = T
OR_CONV "F \/ t" = |- F \/ t = t
OR_CONV "t \/ F" = |- t \/ F = t
OR_CONV "t \/ t" = |- t \/ t = t
Failure
OR_CONV tm fails unless tm has one of the forms indicated above.
Example
#OR_CONV "F \/ T";;
|- F \/ T = T
#OR_CONV "X \/ F";;
|- X \/ F = X
#OR_CONV "(!n. n + 1 = SUC n) \/ (!m. m + 1 = SUC m)";;
|- (!n. n + 1 = SUC n) \/ (!m. m + 1 = SUC m) = (!n. n + 1 = SUC n)
PRE_CONV
PRE_CONV
reduceLib.PRE_CONV : conv
Calculates by inference the predecessor of a numeral.
If n is a numeral (e.g. 0, 1, 2, 3,...), then
PRE_CONV "PRE n" returns the theorem:
|- PRE n = s
where s is the numeral that denotes the predecessor of the natural
number denoted by n.
Failure
PRE_CONV tm fails unless tm is of the form ``PRE n``, where
n is a numeral.
Example
> PRE_CONV ``PRE 0``;
val it = |- PRE 0 = 0 : thm
> PRE_CONV ``PRE 1``;
val it = |- PRE 1 = 0 : thm
> PRE_CONV ``PRE 22``;
val it = |- PRE 22 = 21 : thm
RED_CONV
RED_CONV
reduceLib.RED_CONV : conv
Performs arithmetic or boolean reduction at top level if possible.
The conversion RED_CONV attempts to apply, at the top level only, one
of the following conversions from the reduce library (only one can
succeed):
ADD_CONV AND_CONV BEQ_CONV COND_CONV
DIV_CONV EXP_CONV GE_CONV GT_CONV
IMP_CONV LE_CONV LT_CONV MOD_CONV
MUL_CONV NEQ_CONV NOT_CONV OR_CONV
PRE_CONV SBC_CONV SUC_CONV
Failure
Fails if none of the above conversions are applicable at top level.
Example
#RED_CONV "(2=3) = F";;
|- ((2 = 3) = F) = ~(2 = 3)
#RED_CONV "15 DIV 13";;
|- 15 DIV 13 = 1
#RED_CONV "100 + 100";;
|- 100 + 100 = 200
#RED_CONV "0 + x";;
evaluation failed RED_CONV
See also
reduceLib.REDUCE_CONV,
reduceLib.REDUCE_RULE,
reduceLib.REDUCE_TAC
REDUCE_CONV
REDUCE_CONV
reduceLib.REDUCE_CONV : conv
Performs arithmetic or boolean reduction at all levels possible.
The conversion REDUCE_CONV attempts to apply, in bottom-up order to
all suitable redexes, arithmetic computation conversions for all of the
standard operators from arithmeticTheory. The conversions are
implemented as rewrites applied by CBV_CONV. In particular, it is
designed to prove the appropriate reduction for an arbitrarily
complicated expression constructed from numerals, those operators, and
the boolean constants T and F, and will do this to all such
sub-expressions within a term.
Failure
Never fails, but may give a reflexive equation.
Example
> reduceLib.REDUCE_CONV “(2=3) = F”;
val it = ⊢ (2 = 3 ⇔ F) ⇔ T: thm
> reduceLib.REDUCE_CONV “if 100 < 200 then 2 EXP (8 DIV 2)
else 3 EXP ((26 EXP 0) * 3)”;
val it = ⊢ (if 100 < 200 then 2 ** (8 DIV 2) else 3 ** (26 ** 0 * 3)) = 16:
thm
> reduceLib.REDUCE_CONV “(15 = 16) \/ (15 < 16)”;
val it = ⊢ 15 = 16 ∨ 15 < 16 ⇔ T: thm
> reduceLib.REDUCE_CONV “1 + x”;
val it = ⊢ 1 + x = 1 + x: thm
> reduceLib.REDUCE_CONV “!x:num. x = x”;
val it = ⊢ (∀x. x = x) ⇔ ∀x. T: thm
Comments
This entry-point is also available as numLib.REDUCE_CONV.
See also
computeLib.CBV_CONV,
reduceLib.RED_CONV,
reduceLib.REDUCE_RULE,
reduceLib.REDUCE_TAC
REDUCE_RULE
REDUCE_RULE
reduceLib.REDUCE_RULE : thm -> thm
Performs arithmetic or boolean reduction on a theorem at all levels possible.
REDUCE_RULE attempts to transform a theorem by applying REDUCE_CONV.
Failure
Never fails, but may just return the original theorem.
Example
> reduceLib.REDUCE_RULE (ASSUME “x = 100 + (60 - 17)”);
val it = [.] ⊢ x = 143: thm
> reduceLib.REDUCE_RULE (REFL “100 + 12 DIV 6”);
val it = ⊢ T: thm
See also
reduceLib.RED_CONV,
reduceLib.REDUCE_CONV,
reduceLib.REDUCE_TAC
REDUCE_TAC
REDUCE_TAC
reduceLib.REDUCE_TAC : tactic
Performs arithmetic or boolean reduction on a goal at all levels possible.
REDUCE_TAC attempts to transform a goal by applying REDUCE_CONV. It
will prove any true goal which is constructed from numerals and the
boolean constants T and F.
Failure
Never fails, but may not advance the goal.
Example
The following example takes a couple of minutes' CPU time:
> g ‘((1 EXP 3) + (12 EXP 3) = 1729) /\ ((9 EXP 3) + (10 EXP 3) = 1729)’;
> e reduceLib.REDUCE_TAC;;
OK..
val it =
Initial goal proved
⊢ 1 EXP 3 + 12 EXP 3 = 1729 ∧ 9 EXP 3 + 10 EXP 3 = 1729 : proof
See also
reduceLib.RED_CONV,
reduceLib.REDUCE_CONV,
reduceLib.REDUCE_RULE
SBC_CONV
SBC_CONV
reduceLib.SBC_CONV : conv
Calculates by inference the difference of two numerals.
If m and n are numerals (e.g. 0, 1, 2, 3,...), then
SBC_CONV "m - n" returns the theorem:
|- m - n = s
where s is the numeral that denotes the difference of the natural
numbers denoted by m and n.
Failure
SBC_CONV tm fails unless tm is of the form "m - n", where m and
n are numerals.
Example
#SBC_CONV "25 - 30";;
|- 25 - 30 = 0
#SBC_CONV "200 - 200";;
|- 200 - 200 = 0
#SBC_CONV "60 - 17";;
|- 60 - 17 = 43
SUC_CONV
SUC_CONV
reduceLib.SUC_CONV : conv
Calculates by inference the successor of a numeral.
If n is a numeral (e.g. 0, 1, 2, 3,...), then
SUC_CONV "SUC n" returns the theorem:
|- SUC n = s
where s is the numeral that denotes the successor of the natural
number denoted by n.
Failure
SUC_CONV tm fails unless tm is of the form "SUC n", where n is a
numeral.
Example
#SUC_CONV "SUC 33";;
|- SUC 33 = 34
dest_res_abstract
dest_res_abstract
res_quanLib.dest_res_abstract : term -> (term # term # term)
Breaks apart a restricted abstract term into the quantified variable, predicate and body.
dest_res_abstract is a term destructor for restricted abstraction:
dest_res_abstract "\var::P. t"
returns ("var","P","t").
Failure
Fails with dest_res_abstract if the term is not a restricted
abstraction.
See also
res_quanLib.mk_res_abstract,
res_quanLib.is_res_abstract
dest_res_exists
dest_res_exists
res_quanLib.dest_res_exists : term -> (term # term # term)
Breaks apart a restricted existentially quantified term into the quantified variable, predicate and body.
dest_res_exists is a term destructor for restricted existential
quantification:
dest_res_exists "?var::P. t"
returns ("var","P","t").
Failure
Fails with dest_res_exists if the term is not a restricted existential
quantification.
See also
res_quanLib.mk_res_exists,
res_quanLib.is_res_exists,
res_quanLib.strip_res_exists
dest_res_exists_unique
dest_res_exists_unique
res_quanLib.dest_res_exists_unique : term -> (term # term # term)
Breaks apart a restricted unique existential quantified term into the quantified variable, predicate and body.
dest_res_exists_unique is a term destructor for restricted existential
quantification:
dest_res_exists_unique "?var::P. t"
returns ("var","P","t").
Failure
Fails with dest_res_exists_unique if the term is not a restricted
existential quantification.
See also
res_quanLib.mk_res_exists_unique,
res_quanLib.is_res_exists_unique
dest_res_forall
dest_res_forall
res_quanLib.dest_res_forall : term -> (term # term # term)
Breaks apart a restricted universally quantified term into the quantified variable, predicate and body.
dest_res_forall is a term destructor for restricted universal
quantification:
dest_res_forall "!var::P. t"
returns ("var","P","t").
Failure
Fails with dest_res_forall if the term is not a restricted universal
quantification.
See also
res_quanLib.mk_res_forall,
res_quanLib.is_res_forall,
res_quanLib.strip_res_forall
dest_res_select
dest_res_select
res_quanLib.dest_res_select : term -> (term # term # term)
Breaks apart a restricted choice quantified term into the quantified variable, predicate and body.
dest_res_select is a term destructor for restricted choice
quantification:
dest_res_select "@var::P. t"
returns ("var","P","t").
Failure
Fails with dest_res_select if the term is not a restricted choice
quantification.
See also
res_quanLib.mk_res_select,
res_quanLib.is_res_select
IMP_RES_FORALL_CONV
IMP_RES_FORALL_CONV
res_quanLib.IMP_RES_FORALL_CONV : conv
Converts an implication to a restricted universal quantification.
When applied to a term of the form !x. x IN P ==> Q, the conversion
IMP_RES_FORALL_CONV returns the theorem:
|- (!x. x IN P ==> Q) = !x::P. Q
Failure
Fails if applied to a term not of the form !x. x IN P ==> Q.
See also
is_res_abstract
is_res_abstract
res_quanLib.is_res_abstract : term -> bool
Tests a term to see if it is a restricted abstraction.
is_res_abstract "\var::P. t" returns true. If the term is not a
restricted abstraction the result is false.
Failure
Never fails.
See also
res_quanLib.mk_res_abstract,
res_quanLib.dest_res_abstract
is_res_exists
is_res_exists
res_quanLib.is_res_exists : term -> bool
Tests a term to see if it is a restricted existential quantification.
is_res_exists "?var::P. t" returns true. If the term is not a
restricted existential quantification the result is false.
Failure
Never fails.
See also
res_quanLib.mk_res_exists,
res_quanLib.dest_res_exists
is_res_exists_unique
is_res_exists_unique
res_quanLib.is_res_exists_unique : term -> bool
Tests a term to see if it is a restricted unique existential quantification.
is_res_exists_unique "?!var::P. t" returns true. If the term is not
a restricted unique existential quantification the result is false.
Failure
Never fails.
See also
res_quanLib.mk_res_exists_unique,
res_quanLib.dest_res_exists_unique
is_res_forall
is_res_forall
res_quanLib.is_res_forall : term -> bool
Tests a term to see if it is a restricted universal quantification.
is_res_forall "!var::P. t" returns true. If the term is not a
restricted universal quantification the result is false.
Failure
Never fails.
See also
res_quanLib.mk_res_forall,
res_quanLib.dest_res_forall
is_res_select
is_res_select
res_quanLib.is_res_select : term -> bool
Tests a term to see if it is a restricted choice quantification.
is_res_select "@var::P. t" returns true. If the term is not a
restricted choice quantification the result is false.
Failure
Never fails.
See also
res_quanLib.mk_res_select,
res_quanLib.dest_res_select
list_mk_res_exists
list_mk_res_exists
res_quanLib.list_mk_res_exists : ((term # term) list # term) -> term)
Iteratively constructs a restricted existential quantification.
list_mk_res_exists([("x1","P1");...;("xn","Pn")],"t")
returns "?x1::P1. ... ?xn::Pn. t".
Failure
Fails with list_mk_res_exists if the first terms xi in the pairs are
not a variable or if the second terms Pi in the pairs and t are not
of type ":bool" if the list is non-empty. If the list is empty the
type of t can be anything.
See also
res_quanLib.strip_res_exists,
res_quanLib.mk_res_exists
list_mk_res_forall
list_mk_res_forall
res_quanLib.list_mk_res_forall : (term # term) list # term) -> term
Iteratively constructs a restricted universal quantification.
list_mk_res_forall([("x1","P1");...;("xn","Pn")],"t")
returns "!x1::P1. ... !xn::Pn. t".
Failure
Fails with list_mk_res_forall if the first terms xi in the pairs are
not a variable or if the second terms Pi in the pairs and t are not
of type ":bool" if the list is non-empty. If the list is empty the
type of t can be anything.
See also
res_quanLib.strip_res_forall,
res_quanLib.mk_res_forall
mk_res_abstract
mk_res_abstract
res_quanLib.mk_res_abstract : (term # term # term) -> term
Term constructor for restricted abstraction.
mk_res_abstract("var","P","t") returns "\var :: P . t".
Failure
Fails with mk_res_abstract if the first term is not a variable or if
P and t are not of type ":bool".
See also
res_quanLib.dest_res_abstract,
res_quanLib.is_res_abstract
mk_res_exists
mk_res_exists
res_quanLib.mk_res_exists : ((term # term # term) -> term)
Term constructor for restricted existential quantification.
mk_res_exists("var","P","t") returns "?var :: P . t".
Failure
Fails with mk_res_exists if the first term is not a variable or if P
and t are not of type ":bool".
See also
res_quanLib.dest_res_exists,
res_quanLib.is_res_exists,
res_quanLib.list_mk_res_exists
mk_res_exists_unique
mk_res_exists_unique
res_quanLib.mk_res_exists_unique : (term # term # term) -> term
Term constructor for restricted unique existential quantification.
mk_res_exists_unique ("var","P","t") returns "?!var :: P . t".
Failure
Fails with mk_res_exists_unique if the first term is not a variable or
if P and t are not of type ":bool".
See also
res_quanLib.dest_res_exists_unique,
res_quanLib.is_res_exists_unique
mk_res_forall
mk_res_forall
res_quanLib.mk_res_forall : (term # term # term) -> term
Term constructor for restricted universal quantification.
mk_res_forall("var","P","t") returns "!var :: P . t".
Failure
Fails with mk_res_forall if the first term is not a variable or if P
and t are not of type ":bool".
See also
res_quanLib.dest_res_forall,
res_quanLib.is_res_forall,
res_quanLib.list_mk_res_forall
mk_res_select
mk_res_select
res_quanLib.mk_res_select : (term # term # term) -> term
Term constructor for restricted choice quantification.
mk_res_select("var","P","t") returns "@var :: P . t".
Failure
Fails with mk_res_select if the first term is not a variable or if P
and t are not of type ":bool".
See also
res_quanLib.dest_res_select,
res_quanLib.is_res_select
RES_EXISTS_CONV
RES_EXISTS_CONV
res_quanLib.RES_EXISTS_CONV : conv
Converts a restricted existential quantification to a conjunction.
When applied to a term of the form ?x::P. Q[x], the conversion
RES_EXISTS_CONV returns the theorem:
|- ?x::P. Q[x] = (?x. x IN P /\ Q[x])
which is the underlying semantic representation of the restricted existential quantification.
Failure
Fails if applied to a term not of the form ?x::P. Q.
See also
res_quanLib.RES_FORALL_CONV,
res_quanLib.RESQ_EXISTS_TAC
RES_EXISTS_UNIQUE_CONV
RES_EXISTS_UNIQUE_CONV
res_quanLib.RES_EXISTS_UNIQUE_CONV : conv
Converts a restricted unique existential quantification to a conjunction.
When applied to a term of the form ?!x::P. Q[x], the conversion
RES_EXISTS_UNIQUE_CONV returns the theorem:
|- ?!x::P. Q[x] = (?x::P. Q[x]) /\ (!x y::P. Q[x] /\ Q[y] ==> (x = y))
which is the underlying semantic representation of the restricted unique existential quantification.
Failure
Fails if applied to a term not of the form ?x!::P. Q.
See also
res_quanLib.RES_FORALL_CONV,
res_quanLib.RES_EXISTS_CONV
RES_FORALL_AND_CONV
RES_FORALL_AND_CONV
res_quanLib.RES_FORALL_AND_CONV : conv
Splits a restricted universal quantification across a conjunction.
When applied to a term of the form !x::P. Q /\ R, the conversion
RES_FORALL_AND_CONV returns the theorem:
|- (!x::P. Q /\ R) = ((!x::P. Q) /\ (!x::P. R))
Failure
Fails if applied to a term not of the form !x::P. Q /\ R.
RES_FORALL_CONV
RES_FORALL_CONV
res_quanLib.RES_FORALL_CONV : conv
Converts a restricted universal quantification to an implication.
When applied to a term of the form !x::P. Q, the conversion
RES_FORALL_CONV returns the theorem:
|- !x::P. Q = (!x. x IN P ==> Q)
which is the underlying semantic representation of the restricted universal quantification.
Failure
Fails if applied to a term not of the form !x::P. Q.
See also
res_quanLib.IMP_RES_FORALL_CONV
RES_FORALL_SWAP_CONV
RES_FORALL_SWAP_CONV
res_quanLib.RES_FORALL_SWAP_CONV : conv
Changes the order of two restricted universal quantifications.
When applied to a term of the form !x::P. !y::Q. R, the conversion
RES_FORALL_SWAP_CONV returns the theorem:
|- (!x::P. !y::Q. R) = !y::Q. !x::P. R
providing that x does not occur free in Q and y does not occur
free in P.
Failure
Fails if applied to a term not of the correct form.
See also
RES_SELECT_CONV
RES_SELECT_CONV
res_quanLib.RES_SELECT_CONV : conv
Converts a restricted choice quantification to a conjunction.
When applied to a term of the form @x::P. Q[x], the conversion
RES_SELECT_CONV returns the theorem:
|- @x::P. Q[x] = (@x. x IN P /\ Q[x])
which is the underlying semantic representation of the restricted choice quantification.
Failure
Fails if applied to a term not of the form @x::P. Q.
See also
res_quanLib.RES_FORALL_CONV,
res_quanLib.RES_EXISTS_CONV
RESQ_EXISTS_TAC
RESQ_EXISTS_TAC
res_quanLib.RESQ_EXISTS_TAC : term -> tactic
Strips the outermost restricted existential quantifier from the conclusion of a goal.
When applied to a goal A ?- ?x::P. t, the tactic RESQ_EXISTS_TAC
reduces it to a new subgoal A ?- P x' /\ t[x'/x] where x' is a
variant of x chosen to avoid clashing with any variables free in the
goal's assumption list. Normally x' is just x.
A ?- ?x::P. t
====================== RESQ_EXISTS_TAC
A ?- P x' /\ t[x'/x]
Failure
Fails unless the goal's conclusion is a restricted extistential quantification.
RESQ_GEN_TAC
RESQ_GEN_TAC
res_quanLib.RESQ_GEN_TAC : tactic
Strips the outermost restricted universal quantifier from the conclusion of a goal.
When applied to a goal A ?- !x::P. t, the tactic RESQ_GEN_TAC
reduces it to a new goal A,P x' ?- t[x'/x] where x' is a variant of
x chosen to avoid clashing with any variables free in the goal's
assumption list. Normally x' is just x.
A ?- !x::P. t
=================== RESQ_GEN_TAC
A,P x' ?- t[x'/x]
Failure
Fails unless the goal's conclusion is a restricted universal quantification.
The tactic REPEAT RESQ_GEN_TAC strips away a series of restricted
universal quantifiers, and is commonly used before tactics relying on
the underlying term structure.
See also
res_quanLib.RESQ_SPEC,
res_quanLib.RESQ_SPECL,
Tactic.STRIP_TAC,
Tactic.GEN_TAC,
Tactic.X_GEN_TAC
RESQ_HALF_SPEC
RESQ_HALF_SPEC
res_quanLib.RESQ_HALF_SPEC : thm -> thm
Strip a restricted universal quantification in the conclusion of a theorem.
When applied to a theorem A |- !x::P. t, the derived inference rule
RESQ_HALF_SPEC returns the theorem A |- !x. x IN P ==> t, i.e., it
transforms the restricted universal quantification to its underlying
semantic representation.
A |- !x::P. t
-------------------- RESQ_HALF_SPEC
A |- !x. x IN P ==> t
Failure
Fails if the theorem's conclusion is not a restricted universal quantification.
See also
res_quanLib.RESQ_SPEC,
res_quanLib.RESQ_SPECL
RESQ_IMP_RES_TAC
RESQ_IMP_RES_TAC
res_quanLib.RESQ_IMP_RES_TAC : thm_tactic
Repeatedly resolves a restricted universally quantified theorem with the assumptions of a goal.
The function RESQ_IMP_RES_TAC performs repeatedly resolution using a
restricted quantified theorem. It takes a restricted quantified theorem
and transforms it into an implication. This resulting theorem is used in
the resolution.
Given a theorem th, the theorem-tactic RESQ_IMP_RES_TAC applies
RESQ_IMP_RES_THEN repeatedly to resolve the theorem with the
assumptions.
Failure
Never fails
See also
res_quanLib.RESQ_IMP_RES_THEN,
res_quanLib.RESQ_RES_THEN,
res_quanLib.RESQ_RES_TAC,
Thm_cont.IMP_RES_THEN,
Tactic.IMP_RES_TAC,
Drule.MATCH_MP,
Drule.RES_CANON,
Tactic.RES_TAC,
Thm_cont.RES_THEN
RESQ_IMP_RES_THEN
RESQ_IMP_RES_THEN
res_quanLib.RESQ_IMP_RES_THEN : thm_tactical
Resolves a restricted universally quantified theorem with the assumptions of a goal.
The function RESQ_IMP_RES_THEN is the basic building block for
resolution using a restricted quantified theorem. It takes a restricted
quantified theorem and transforms it into an implication. This resulting
theorem is used in the resolution.
Given a theorem-tactic ttac and a theorem th, the theorem-tactical
RESQ_IMP_RES_THEN transforms the theorem into an implication th'. It
then passes th' together with ttac to IMP_RES_THEN to carry out
the resolution.
Failure
Evaluating RESQ_IMP_RES_THEN ttac th fails if the supplied theorem
th is not restricted universally quantified, or if the call to
IMP_RES_THEN fails.
See also
res_quanLib.RESQ_IMP_RES_TAC,
res_quanLib.RESQ_RES_THEN,
res_quanLib.RESQ_RES_TAC,
Thm_cont.IMP_RES_THEN,
Tactic.IMP_RES_TAC,
Drule.MATCH_MP,
Drule.RES_CANON,
Tactic.RES_TAC,
Thm_cont.RES_THEN
RESQ_MATCH_MP
RESQ_MATCH_MP
res_quanLib.RESQ_MATCH_MP : (thm -> thm -> thm)
Eliminating a restricted universal quantification with automatic matching.
When applied to theorems A1 |- !x::P. Q[x] and A2 |- P x', the
derived inference rule RESQ_MATCH_MP matches x' to x by
instantiating free or universally quantified variables in the first
theorem (only), and returns a theorem A1 u A2 |- Q[x'/x]. Polymorphic
types are also instantiated if necessary.
A1 |- !x::P.Q[x] A2 |- P x'
-------------------------------------- RESQ_MATCH_MP
A1 u A2 |- Q[x'/x]
Failure
Fails unless the first theorem is a (possibly repeatedly) restricted
universal quantification whose quantified variable can be instantiated
to match the conclusion of the second theorem, without instantiating any
variables which are free in A1, the first theorem's assumption list.
See also
Drule.MATCH_MP,
res_quanLib.RESQ_HALF_SPEC
RESQ_RES_TAC
RESQ_RES_TAC
res_quanLib.RESQ_RES_TAC : tactic
Enriches assumptions by repeatedly resolving restricted universal quantifications in them against the others.
RESQ_RES_TAC uses those assumptions which are restricted universal
quantifications in resolution in a way similar to RES_TAC. It calls
RESQ_RES_THEN repeatedly until there is no more resolution can be
done. The conclusions of all the new results are returned as additional
assumptions of the subgoal(s). The effect of RESQ_RES_TAC on a goal is
to enrich the assumption set with some of its collective consequences.
Failure
RESQ_RES_TAC cannot fail and so should not be unconditionally
REPEATed.
See also
res_quanLib.RESQ_IMP_RES_TAC,
res_quanLib.RESQ_IMP_RES_THEN,
res_quanLib.RESQ_RES_THEN,
Tactic.IMP_RES_TAC,
Thm_cont.IMP_RES_THEN,
Drule.RES_CANON,
Thm_cont.RES_THEN,
Tactic.RES_TAC
RESQ_RES_THEN
RESQ_RES_THEN
res_quanLib.RESQ_RES_THEN : thm_tactic -> tactic
Resolves all restricted universally quantified assumptions against other assumptions of a goal.
Like the function RESQ_IMP_RES_THEN, the function RESQ_RES_THEN
performs a single step resolution. The difference is that the restricted
universal quantification used in the resolution is taken from the
assumptions.
Given a theorem-tactic ttac, applying the tactic RESQ_RES_THEN ttac
to a goal (asml,gl) has the effect of:
MAP_EVERY (mapfilter ttac [... ; (ai,aj |- vi) ; ...]) (amsl ?- g)
where the theorems ai,aj |- vi are all the consequences that can be
drawn by a (single) matching modus-ponens inference from the assumptions
amsl and the implications derived from the restricted universal
quantifications in the assumptions.
Failure
Evaluating RESQ_RES_TAC ttac th fails if there are no restricted
universal quantifications in the assumptions, or if the theorem-tactic
ttac applied to all the consequences fails.
See also
res_quanLib.RESQ_IMP_RES_TAC,
res_quanLib.RESQ_IMP_RES_THEN,
res_quanLib.RESQ_RES_TAC,
Thm_cont.IMP_RES_THEN,
Tactic.IMP_RES_TAC,
Drule.MATCH_MP,
Drule.RES_CANON,
Tactic.RES_TAC,
Thm_cont.RES_THEN
RESQ_REWR_CANON
RESQ_REWR_CANON
res_quanLib.RESQ_REWR_CANON : thm -> thm
Transform a theorem into a form accepted for rewriting.
RESQ_REWR_CANON transforms a theorem into a form accepted by
COND_REWR_TAC. The input theorem should be headed by a series of
restricted universal quantifications in the following form
!x1::P1. ... !xn::Pn. u[xi] = v[xi])
Other variables occurring in u and v may be universally quantified.
The output theorem will have all ordinary universal quantifications
moved to the outer most level with possible renaming to prevent variable
capture, and have all restricted universal quantifications converted to
implications. The output theorem will be in the form accepted by
COND_REWR_TAC.
Failure
This function fails is the input theorem is not in the correct form.
See also
res_quanLib.RESQ_REWRITE1_TAC,
res_quanLib.RESQ_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWR_CONV
RESQ_REWRITE1_CONV
RESQ_REWRITE1_CONV
res_quanLib.RESQ_REWRITE1_CONV : thm list -> thm -> conv
Rewriting conversion using a restricted universally quantified theorem.
RESQ_REWRITE1_CONV is a rewriting conversion similar to
COND_REWRITE1_CONV. The only difference is the rewriting theorem it
takes. This should be an equation with restricted universal
quantification at the outer level. It is converted to a theorem in the
form accepted by the conditional rewriting conversion.
Suppose that th is the following theorem
A |- !x::P. Q[x] = R[x])
evaluating RESQ_REWRITE1_CONV thms th "t[x']" will return a theorem
A, P x' |- t[x'] = t'[x']
where t' is the result of substituting instances of R[x'/x] for
corresponding instances of Q[x'/x] in the original term t[x]. All
instances of P x' which do not appear in the original assumption
asml are added to the assumption. The theorems in the list thms are
used to eliminate the instances P x' if it is possible.
Failure
RESQ_REWRITE1_CONV fails if th cannot be transformed into the
required form by the function RESQ_REWR_CANON. Otherwise, it fails if
no match is found or the theorem cannot be instantiated.
See also
res_quanLib.RESQ_REWRITE1_TAC,
res_quanLib.RESQ_REWR_CANON,
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.search_top_down
RESQ_REWRITE1_TAC
RESQ_REWRITE1_TAC
res_quanLib.RESQ_REWRITE1_TAC : thm_tactic
Rewriting with a restricted universally quantified theorem.
RESQ_REWRITE1_TAC takes an equational theorem which is restricted
universally quantified at the outer level. It calls RESQ_REWR_CANON to
convert the theorem to the form accepted by COND_REWR_TAC and passes
the resulting theorem to this tactic which carries out conditional
rewriting.
Suppose that th is the following theorem
A |- !x::P. Q[x] = R[x])
Applying the tactic RESQ_REWRITE1_TAC th to a goal (asml,gl) will
return a main subgoal (asml',gl') where gl' is obtained by
substituting instances of R[x'/x] for corresponding instances of
Q[x'/x] in the original goal gl. All instances of P x' which do
not appear in the original assumption asml are added to it to form
asml', and they also become new subgoals (asml,P x').
Failure
RESQ_REWRITE1_TAC th fails if th cannot be transformed into the
required form by the function RESQ_REWR_CANON. Otherwise, it fails if
no match is found or the theorem cannot be instantiated.
See also
res_quanLib.RESQ_REWRITE1_CONV,
res_quanLib.RESQ_REWR_CANON,
Cond_rewrite.COND_REWR_TAC,
Cond_rewrite.COND_REWRITE1_CONV,
Cond_rewrite.COND_REWR_CONV,
Cond_rewrite.COND_REWR_CANON,
Cond_rewrite.search_top_down
RESQ_SPEC
RESQ_SPEC
res_quanLib.RESQ_SPEC : term -> thm -> thm
Specializes the conclusion of a possibly-restricted universally quantified theorem.
When applied to a term u and a theorem A |- !x::P. t, RESQ_SPEC
returns the theorem A, u IN P |- t[u/x]. If necessary, variables will
be renamed prior to the specialization to ensure that u is free for
x in t, that is, no variables free in u become bound after
substitution.
A |- !x::P. t
--------------------- RESQ_SPEC "u"
A, u IN P |- t[u/x]
Additionally, if the input theorem is a standard universal quantification, then RESQ_SPEC behaves like SPEC.
Failure
Fails if the theorem's conclusion is not restricted universally quantified, or if type instantiation fails.
Example
The following example shows how RESQ_SPEC renames bound variables if
necessary, prior to substitution: a straightforward substitution would
result in the clearly invalid theorem (\y. 0 < y) y |- y = y.
> val th = RESQ_GEN ``x:num`` ``\y. 0 < y`` (REFL ``x:num``);
val th = |- !x :: \y. 0 < y. x = x : thm
> RESQ_SPEC ``y:num`` th;
val it = (\y'. 0 < y') y |- y = y : thm
See also
res_quanLib.RESQ_HALF_SPECL,
res_quanLib.RESQ_SPECL
RESQ_SPECL
RESQ_SPECL
res_quanLib.RESQ_SPECL : (term list -> thm -> thm)
Specializes zero or more variables in the conclusion of a restricted universally quantified theorem.
When applied to a term list [u1;...;un] and a theorem
A |- !x1::P1. ... !xn::Pn. t, the inference rule RESQ_SPECL returns
the theorem
A,P1 u1,...,Pn un |- t[u1/x1]...[un/xn]
where the substitutions are made sequentially left-to-right in the same
way as for RESQ_SPEC, with the same sort of alpha-conversions applied
to t if necessary to ensure that no variables which are free in ui
become bound after substitution.
A |- !x1::P1. ... !xn::Pn. t
-------------------------------------------- RESQ_SPECL "[u1;...;un]"
A,P1 u1, ..., Pn un |- t[u1/x1]...[un/xn]
It is permissible for the term-list to be empty, in which case the
application of RESQ_SPECL has no effect.
Failure
Fails if one of the specialization of the restricted universally quantified variable in the original theorem fails.
See also
res_quanLib.RESQ_GEN_TAC,
res_quanLib.RESQ_SPEC
strip_res_exists
strip_res_exists
res_quanLib.strip_res_exists : (term -> ((term # term) list # term))
Iteratively breaks apart a restricted existentially quantified term.
strip_res_exists is an iterative term destructor for restricted
existential quantifications. It iteratively breaks apart a restricted
existentially quantified term into a list of pairs which are the
restricted quantified variables and predicates and the body.
strip_res_exists "?x1::P1. ... ?xn::Pn. t"
returns ([("x1","P1");...;("xn","Pn")],"t").
Failure
Never fails.
See also
res_quanLib.list_mk_res_exists,
res_quanLib.is_res_exists,
res_quanLib.dest_res_exists
strip_res_forall
strip_res_forall
res_quanLib.strip_res_forall : term -> ((term # term) list # term)
Iteratively breaks apart a restricted universally quantified term.
strip_res_forall is an iterative term destructor for restricted
universal quantifications. It iteratively breaks apart a restricted
universally quantified term into a list of pairs which are the
restricted quantified variables and predicates and the body.
strip_res_forall "!x1::P1. ... !xn::Pn. t"
returns ([("x1","P1");...;("xn","Pn")],"t").
Failure
Never fails.
See also
res_quanLib.list_mk_res_forall,
res_quanLib.is_res_forall,
res_quanLib.dest_res_forall
add_implicit_rewrites
add_implicit_rewrites
Rewrite.add_implicit_rewrites: thm list -> unit
Augments the built-in database of simplifications automatically included in rewriting.
Used to build up the power of the built-in simplification set.
See also
add_rewrites
add_rewrites
Rewrite.add_rewrites : rewrites -> thm list -> rewrites
Add theorems to a collection of rewrite rules.
The function add_rewrites processes each element in a list of theorems
and adds the resulting rewrite rules to a value of type rewrites.
Failure
Never fails.
Example
> load "pairTheory"; open pairTheory;
add_rewrites empty_rewrites (PAIR_MAP_THM::pairLib.pair_rws);
val it = (): unit
val it =
⊢ (f ## g) (x,y) = (f x,g y); ⊢ (FST x,SND x) = x; ⊢ FST (x,y) = x;
⊢ SND (x,y) = y
Number of rewrite rules = 4
: rewrites
For building bespoke rewrite rule sets.
See also
Rewrite.bool_rewrites,
Rewrite.empty_rewrites,
Rewrite.implicit_rewrites,
Rewrite.GEN_REWRITE_CONV,
Rewrite.GEN_REWRITE_RULE,
Rewrite.GEN_REWRITE_TAC
ASM_REWRITE_RULE
ASM_REWRITE_RULE
Rewrite.ASM_REWRITE_RULE : thm list -> thm -> thm
Rewrites a theorem including built-in rewrites and the theorem's assumptions.
ASM_REWRITE_RULE rewrites using the tautologies in
implicit_rewrites, the given list of theorems, and the set of
hypotheses of the theorem. All hypotheses are used. No ordering is
specified among applicable rewrites. Matching subterms are searched for
recursively, starting with the entire term of the conclusion and
stopping when no rewritable expressions remain. For more details about
the rewriting process, see GEN_REWRITE_RULE. To avoid using the set of
basic tautologies, see PURE_ASM_REWRITE_RULE.
Failure
ASM_REWRITE_RULE does not fail, but may result in divergence. To
prevent divergence where it would occur, ONCE_ASM_REWRITE_RULE can be
used.
See also
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_ASM_REWRITE_RULE,
Rewrite.PURE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.REWRITE_RULE
ASM_REWRITE_TAC
ASM_REWRITE_TAC
Rewrite.ASM_REWRITE_TAC : thm list -> tactic
Rewrites a goal using built-in rewrites and the goal's assumptions.
ASM_REWRITE_TAC generates rewrites with the tautologies in
implicit_rewrites, the set of assumptions, and a list of theorems
supplied by the user. These are applied top-down and recursively on the
goal, until no more matches are found. The order in which the set of
rewrite equations is applied is an implementation matter and the user
should not depend on any ordering. Rewriting strategies are described in
more detail under GEN_REWRITE_TAC. For omitting the common
tautologies, see the tactic PURE_ASM_REWRITE_TAC. To rewrite with only
a subset of the assumptions use FILTER_ASM_REWRITE_TAC.
Failure
ASM_REWRITE_TAC does not fail, but it can diverge in certain
situations. For rewriting to a limited depth, see
ONCE_ASM_REWRITE_TAC. The resulting tactic may not be valid if the
applicable replacement introduces new assumptions into the theorem
eventually proved.
Example
The use of assumptions in rewriting, specially when they are not in an obvious equational form, is illustrated below:
- let val asm = [Term `P x`]
val goal = Term `P x = Q x`
in
ASM_REWRITE_TAC[] (asm, goal)
end;
val it = ([([`P x`], `Q x`)], fn) : tactic_result
- let val asm = [Term `~P x`]
val goal = Term `P x = Q x`
in
ASM_REWRITE_TAC[] (asm, goal)
end;
val it = ([([`~P x`], `~Q x`)], fn) : tactic_result
See also
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC,
BasicProvers.VAR_EQ_TAC
bool_rewrites
bool_rewrites
Rewrite.bool_rewrites: rewrites
Contains a number of basic equalities useful in rewriting.
The variable bool_rewrites is a basic collection of rewrite rules
useful in expression simplification. The current collection is
- bool_rewrites;
> val it =
|- (x = x) = T; |- (T = t) = t; |- (t = T) = t; |- (F = t) = ~t;
|- (t = F) = ~t; |- ~~t = t; |- ~T = F; |- ~F = T; |- T /\ t = t;
|- t /\ T = t; |- F /\ t = F; |- t /\ F = F; |- t /\ t = t;
|- T \/ t = T; |- t \/ T = T; |- F \/ t = t; |- t \/ F = t;
|- t \/ t = t; |- T ==> t = t; |- t ==> T = T; |- F ==> t = T;
|- t ==> t = T; |- t ==> F = ~t; |- (if T then t1 else t2) = t1;
|- (if F then t1 else t2) = t2; |- (!x. t) = t; |- (?x. t) = t;
|- (\x. t1) t2 = t1
Number of rewrite rules = 28
: rewrites
The contents of bool_rewrites provide a standard basis upon which to
build bespoke rewrite rule sets for use by the functions in Rewrite.
See also
Rewrite.GEN_REWRITE_CONV,
Rewrite.GEN_REWRITE_RULE,
Rewrite.GEN_REWRITE_TAC,
Rewrite.REWRITE_RULE,
Rewrite.REWRITE_TAC,
Rewrite.add_rewrites,
Rewrite.add_implicit_rewrites,
Rewrite.empty_rewrites,
Rewrite.implicit_rewrites,
Rewrite.set_implicit_rewrites
empty_rewrites
empty_rewrites
Rewrite.empty_rewrites: rewrites
The empty database of rewrite rules.
Used to build other rewrite sets.
See also
Rewrite.bool_rewrites,
Rewrite.implicit_rewrites,
Rewrite.add_rewrites,
Rewrite.add_implicit_rewrites,
Rewrite.set_implicit_rewrites
FILTER_ASM_REWRITE_RULE
FILTER_ASM_REWRITE_RULE
Rewrite.FILTER_ASM_REWRITE_RULE : ((term -> bool) -> thm list -> thm -> thm)
Rewrites a theorem including built-in rewrites and some of the theorem's assumptions.
This function implements selective rewriting with a subset of the
assumptions of the theorem. The first argument (a predicate on terms) is
applied to all assumptions, and the ones which return true are used
(along with the set of basic tautologies and the given theorem list) to
rewrite the theorem. See GEN_REWRITE_RULE for more information on
rewriting.
Failure
FILTER_ASM_REWRITE_RULE does not fail. Using FILTER_ASM_REWRITE_RULE
may result in a diverging sequence of rewrites. In such cases
FILTER_ONCE_ASM_REWRITE_RULE may be used.
This rule can be applied when rewriting with all assumptions results in divergence. Typically, the predicate can model checks as to whether a certain variable appears on the left-hand side of an equational assumption, or whether the assumption is in disjunctive form.
Another use is to improve performance when there are many assumptions which are not applicable. Rewriting, though a powerful method of proving theorems in HOL, can result in a reduced performance due to the pattern matching and the number of primitive inferences involved.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.FILTER_ONCE_ASM_REWRITE_RULE,
Rewrite.FILTER_PURE_ASM_REWRITE_RULE,
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
FILTER_ASM_REWRITE_TAC
FILTER_ASM_REWRITE_TAC
Rewrite.FILTER_ASM_REWRITE_TAC : ((term -> bool) -> thm list -> tactic)
Rewrites a goal including built-in rewrites and some of the goal's assumptions.
This function implements selective rewriting with a subset of the
assumptions of the goal. The first argument (a predicate on terms) is
applied to all assumptions, and the ones which return true are used
(along with the set of basic tautologies and the given theorem list) to
rewrite the goal. See GEN_REWRITE_TAC for more information on
rewriting.
Failure
FILTER_ASM_REWRITE_TAC does not fail, but it can result in an invalid
tactic if the rewrite is invalid. This happens when a theorem used for
rewriting has assumptions which are not alpha-convertible to assumptions
of the goal. Using FILTER_ASM_REWRITE_TAC may result in a diverging
sequence of rewrites. In such cases FILTER_ONCE_ASM_REWRITE_TAC may be
used.
This tactic can be applied when rewriting with all assumptions results in divergence, or in an unwanted proof state. Typically, the predicate can model checks as to whether a certain variable appears on the left-hand side of an equational assumption, or whether the assumption is in disjunctive form. Thus it allows choice of assumptions to rewrite with in a position-independent fashion.
Another use is to improve performance when there are many assumptions which are not applicable. Rewriting, though a powerful method of proving theorems in HOL, can result in a reduced performance due to the pattern matching and the number of primitive inferences involved.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.FILTER_PURE_ASM_REWRITE_TAC,
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC
FILTER_ONCE_ASM_REWRITE_RULE
FILTER_ONCE_ASM_REWRITE_RULE
Rewrite.FILTER_ONCE_ASM_REWRITE_RULE : ((term -> bool) -> thm list -> thm -> thm)
Rewrites a theorem once including built-in rewrites and some of its assumptions.
The first argument is a predicate applied to the assumptions. The
theorem is rewritten with the assumptions for which the predicate
returns true, the given list of theorems, and the tautologies stored
in implicit_rewrites. It searches the term of the theorem once,
without applying rewrites recursively. Thus it avoids the divergence
which can result from the application of FILTER_ASM_REWRITE_RULE. For
more information on rewriting rules, see GEN_REWRITE_RULE.
Failure
Never fails.
This function is useful when rewriting with a subset of assumptions of a theorem, allowing control of the number of rewriting passes.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.FILTER_ASM_REWRITE_RULE,
Rewrite.FILTER_PURE_ASM_REWRITE_RULE,
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_ASM_REWRITE_RULE,
Conv.ONCE_DEPTH_CONV,
Rewrite.PURE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
FILTER_ONCE_ASM_REWRITE_TAC
FILTER_ONCE_ASM_REWRITE_TAC
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC : ((term -> bool) -> thm list -> tactic)
Rewrites a goal once including built-in rewrites and some of its assumptions.
The first argument is a predicate applied to the assumptions. The goal
is rewritten with the assumptions for which the predicate returns
true, the given list of theorems, and the tautologies stored in
implicit_rewrites. It searches the term of the goal once, without
applying rewrites recursively. Thus it avoids the divergence which can
result from the application of FILTER_ASM_REWRITE_TAC. For more
information on rewriting tactics, see GEN_REWRITE_TAC.
Failure
Never fails.
This function is useful when rewriting with a subset of assumptions of a goal, allowing control of the number of rewriting passes.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_PURE_ASM_REWRITE_TAC,
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Conv.ONCE_DEPTH_CONV,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC
FILTER_PURE_ASM_REWRITE_RULE
FILTER_PURE_ASM_REWRITE_RULE
Rewrite.FILTER_PURE_ASM_REWRITE_RULE : ((term -> bool) -> thm list -> thm ->thm)
Rewrites a theorem with some of the theorem's assumptions.
This function implements selective rewriting with a subset of the
assumptions of the theorem. The first argument (a predicate on terms) is
applied to all assumptions, and the ones which return true are used to
rewrite the goal. See GEN_REWRITE_RULE for more information on
rewriting.
Failure
FILTER_PURE_ASM_REWRITE_RULE does not fail. Using
FILTER_PURE_ASM_REWRITE_RULE may result in a diverging sequence of
rewrites. In such cases FILTER_PURE_ONCE_ASM_REWRITE_RULE may be used.
This rule can be applied when rewriting with all assumptions results in divergence. Typically, the predicate can model checks as to whether a certain variable appears on the left-hand side of an equational assumption, or whether the assumption is in disjunctive form.
Another use is to improve performance when there are many assumptions which are not applicable. Rewriting, though a powerful method of proving theorems in HOL, can result in a reduced performance due to the pattern matching and the number of primitive inferences involved.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.FILTER_ASM_REWRITE_RULE,
Rewrite.FILTER_ONCE_ASM_REWRITE_RULE,
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
FILTER_PURE_ASM_REWRITE_TAC
FILTER_PURE_ASM_REWRITE_TAC
Rewrite.FILTER_PURE_ASM_REWRITE_TAC : ((term -> bool) -> thm list -> tactic)
Rewrites a goal with some of the goal's assumptions.
This function implements selective rewriting with a subset of the
assumptions of the goal. The first argument (a predicate on terms) is
applied to all assumptions, and the ones which return true are used to
rewrite the goal. See GEN_REWRITE_TAC for more information on
rewriting.
Failure
FILTER_PURE_ASM_REWRITE_TAC does not fail, but it can result in an
invalid tactic if the rewrite is invalid. This happens when a theorem
used for rewriting has assumptions which are not alpha-convertible to
assumptions of the goal. Using FILTER_PURE_ASM_REWRITE_TAC may result
in a diverging sequence of rewrites. In such cases
FILTER_PURE_ONCE_ASM_REWRITE_TAC may be used.
This tactic can be applied when rewriting with all assumptions results in divergence, or in an unwanted proof state. Typically, the predicate can model checks as to whether a certain variable appears on the left-hand side of an equational assumption, or whether the assumption is in disjunctive form. Thus it allows choice of assumptions to rewrite with in a position-independent fashion.
Another use is to improve performance when there are many assumptions which are not applicable. Rewriting, though a powerful method of proving theorems in HOL, can result in a reduced performance due to the pattern matching and the number of primitive inferences involved.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC
FILTER_PURE_ONCE_ASM_REWRITE_RULE
FILTER_PURE_ONCE_ASM_REWRITE_RULE
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_RULE : ((term -> bool) -> thm list -> thm -> thm)
Rewrites a theorem once using some of its assumptions.
The first argument is a predicate applied to the assumptions. The
theorem is rewritten with the assumptions for which the predicate
returns true and the given list of theorems. It searches the term of
the theorem once, without applying rewrites recursively. Thus it avoids
the divergence which can result from the application of
FILTER_PURE_ASM_REWRITE_RULE. For more information on rewriting rules,
see GEN_REWRITE_RULE.
Failure
Never fails.
This function is useful when rewriting with a subset of assumptions of a theorem, allowing control of the number of rewriting passes.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.FILTER_ASM_REWRITE_RULE,
Rewrite.FILTER_ONCE_ASM_REWRITE_RULE,
Rewrite.FILTER_PURE_ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_ASM_REWRITE_RULE,
Conv.ONCE_DEPTH_CONV,
Rewrite.PURE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
FILTER_PURE_ONCE_ASM_REWRITE_TAC
FILTER_PURE_ONCE_ASM_REWRITE_TAC
Rewrite.FILTER_PURE_ONCE_ASM_REWRITE_TAC : ((term -> bool) -> thm list -> tactic)
Rewrites a goal once using some of its assumptions.
The first argument is a predicate applied to the assumptions. The goal
is rewritten with the assumptions for which the predicate returns true
and the given list of theorems. It searches the term of the goal once,
without applying rewrites recursively. Thus it avoids the divergence
which can result from the application of FILTER_PURE_ASM_REWRITE_TAC.
For more information on rewriting tactics, see GEN_REWRITE_TAC.
Failure
Never fails.
This function is useful when rewriting with a subset of assumptions of a goal, allowing control of the number of rewriting passes.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.FILTER_PURE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Conv.ONCE_DEPTH_CONV,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC
GEN_REWRITE_CONV
GEN_REWRITE_CONV
Rewrite.GEN_REWRITE_CONV : ((conv -> conv) -> rewrites -> thm list -> conv)
Rewrites a term, selecting terms according to a user-specified strategy.
Rewriting in HOL is based on the use of equational theorems as
left-to-right replacements on the subterms of an object theorem. This
replacement is mediated by the use of REWR_CONV, which finds matches
between left-hand sides of given equations in a term and applies the
substitution.
Equations used in rewriting are obtained from the theorem lists given as
arguments to the function. These are at first transformed into a form
suitable for rewriting. Conjunctions are separated into individual
rewrites. Theorems with conclusions of the form "~t" are transformed
into the corresponding equations "t = F". Theorems "t" which are not
equations are cast as equations of form "t = T".
If a theorem is used to rewrite a term, its assumptions are added to the assumptions of the returned theorem. The matching involved uses variable instantiation. Thus, all free variables are generalized, and terms are instantiated before substitution. Theorems may have universally quantified variables.
The theorems with which rewriting is done are divided into two groups, to facilitate implementing other rewriting tools. However, they are considered in an order-independent fashion. (That is, the ordering is an implementation detail which is not specified.)
The search strategy for finding matching subterms is the first argument to the rule. Matching and substitution may occur at any level of the term, according to the specified search strategy: the whole term, or starting from any subterm. The search strategy also specifies the depth of the search: recursively up to an arbitrary depth until no matches occur, once over the selected subterm, or any more complex scheme.
Failure
GEN_REWRITE_CONV fails if the search strategy fails. It may also cause
a non-terminating sequence of rewrites, depending on the search strategy
used.
This conversion is used in the system to implement all other rewritings conversions, and may provide a user with a method to fine-tune rewriting of terms.
Example
Suppose we have a term of the form:
"(1 + 2) + 3 = (3 + 1) + 2"
and we would like to rewrite the left-hand side with the theorem
ADD_SYM without changing the right hand side. This can be done by
using:
GEN_REWRITE_CONV (RATOR_CONV o ONCE_DEPTH_CONV) empty_rewrites [ADD_SYM] mythm
Other rules, such as ONCE_REWRITE_CONV, would match and substitute on
both sides, which would not be the desirable result.
As another example, REWRITE_CONV could be implemented as
GEN_REWRITE_CONV TOP_DEPTH_CONV (implicit_rewrites())
which specifies that matches should be searched recursively starting
from the whole term of the theorem, and implicit_rewrites must be
added to the user defined set of theorems employed in rewriting.
See also
Rewrite.ONCE_REWRITE_CONV,
Rewrite.PURE_REWRITE_CONV,
Conv.REWR_CONV,
Rewrite.REWRITE_CONV
GEN_REWRITE_RULE
GEN_REWRITE_RULE
Rewrite.GEN_REWRITE_RULE : ((conv -> conv) -> rewrites -> thm list -> thm -> thm)
Rewrites a theorem, selecting terms according to a user-specified strategy.
Rewriting in HOL is based on the use of equational theorems as
left-to-right replacements on the subterms of an object theorem. This
replacement is mediated by the use of REWR_CONV, which finds matches
between left-hand sides of given equations in a term and applies the
substitution.
Equations used in rewriting are obtained from the theorem lists given as
arguments to the function. These are at first transformed into a form
suitable for rewriting. Conjunctions are separated into individual
rewrites. Theorems with conclusions of the form "~t" are transformed
into the corresponding equations "t = F". Theorems "t" which are not
equations are cast as equations of form "t = T".
If a theorem is used to rewrite the object theorem, its assumptions are added to the assumptions of the returned theorem, unless they are alpha-convertible to existing assumptions. The matching involved uses variable instantiation. Thus, all free variables are generalized, and terms are instantiated before substitution. Theorems may have universally quantified variables.
The theorems with which rewriting is done are divided into two groups, to facilitate implementing other rewriting tools. However, they are considered in an order-independent fashion. (That is, the ordering is an implementation detail which is not specified.)
The search strategy for finding matching subterms is the first argument to the rule. Matching and substitution may occur at any level of the term, according to the specified search strategy: the whole term, or starting from any subterm. The search strategy also specifies the depth of the search: recursively up to an arbitrary depth until no matches occur, once over the selected subterm, or any more complex scheme.
Failure
GEN_REWRITE_RULE fails if the search strategy fails. It may also cause
a non-terminating sequence of rewrites, depending on the search strategy
used.
This rule is used in the system to implement all other rewriting rules, and may provide a user with a method to fine-tune rewriting of theorems.
Example
Suppose we have a theorem of the form:
thm = |- (1 + 2) + 3 = (3 + 1) + 2
and we would like to rewrite the left-hand side with the theorem
ADD_SYM without changing the right hand side. This can be done by
using:
GEN_REWRITE_RULE (RATOR_CONV o ONCE_DEPTH_CONV) empty_rewrites [ADD_SYM] mythm
Other rules, such as ONCE_REWRITE_RULE, would match and substitute on
both sides, which would not be the desirable result.
As another example, REWRITE_RULE could be implemented as
GEN_REWRITE_RULE TOP_DEPTH_CONV (implicit_rewrites())
which specifies that matches should be searched recursively starting
from the whole term of the theorem, and implicit_rewrites must be
added to the user defined set of theorems employed in rewriting.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.FILTER_ASM_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Conv.REWR_CONV,
Rewrite.REWRITE_RULE
GEN_REWRITE_TAC
GEN_REWRITE_TAC
Rewrite.GEN_REWRITE_TAC : ((conv -> conv) -> rewrites -> thm list -> tactic)
Rewrites a goal, selecting terms according to a user-specified strategy.
Distinct rewriting tactics differ in the search strategies used in
finding subterms on which to apply substitutions, and the built-in
theorems used in rewriting. In the case of REWRITE_TAC, this is a
recursive traversal starting from the body of the goal's conclusion
part, while in the case of ONCE_REWRITE_TAC, for example, the search
stops as soon as a term on which a substitution is possible is found.
GEN_REWRITE_TAC allows a user to specify a more complex strategy for
rewriting.
The basis of pattern-matching for rewriting is the notion of
conversions, through the application of REWR_CONV. Conversions are
rules for mapping terms with theorems equating the given terms to other
semantically equivalent ones.
When attempting to rewrite subterms recursively, the use of conversions
(and therefore rewrites) can be automated further by using functions
which take a conversion and search for instances at which they are
applicable. Examples of these functions are ONCE_DEPTH_CONV and
RAND_CONV. The first argument to GEN_REWRITE_TAC is such a function,
which specifies a search strategy; i.e. it specifies how subterms (on
which substitutions are allowed) should be searched for.
The second and third arguments are lists of theorems used for rewriting.
The order in which these are used is not specified. The theorems need
not be in equational form: negated terms, say "~ t", are transformed
into the equivalent equational form "t = F", while other
non-equational theorems with conclusion of form "t" are cast as the
corresponding equations "t = T". Conjunctions are separated into the
individual components, which are used as distinct rewrites.
Failure
GEN_REWRITE_TAC fails if the search strategy fails. It may also cause
a non-terminating sequence of rewrites, depending on the search strategy
used. The resulting tactic is invalid when a theorem which matches the
goal (and which is thus used for rewriting it with) has a hypothesis
which is not alpha-convertible to any of the assumptions of the goal.
Applying such an invalid tactic may result in a proof of a theorem which
does not correspond to the original goal.
Detailed control of rewriting strategy, allowing a user to specify a search strategy.
Example
Given a goal such as:
?- a - (b + c) = a - (c + b)
we may want to rewrite only one side of it with a theorem, say
ADD_SYM. Rewriting tactics which operate recursively result in
divergence; the tactic ONCE_REWRITE_TAC [ADD_SYM] rewrites on both
sides to produce the following goal:
?- a - (c + b) = a - (b + c)
as ADD_SYM matches at two positions. To rewrite on only one side of
the equation, the following tactic can be used:
GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) empty_rewrites [ADD_SYM]
which produces the desired goal:
?- a - (c + b) = a - (c + b)
As another example, one can write a tactic which will behave similarly
to REWRITE_TAC but will also include ADD_CLAUSES in the set of
theorems to use always:
val ADD_REWRITE_TAC = GEN_REWRITE_TAC TOP_DEPTH_CONV
(add_rewrites (implicit_rewrites ())
[ADD_CLAUSES])
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Conv.REWR_CONV,
Rewrite.REWRITE_TAC
implicit_rewrites
implicit_rewrites
Rewrite.implicit_rewrites: unit -> rewrites
Contains a number of theorems used, by default, in rewriting.
The variable implicit_rewrites holds a collection of rewrite rules
commonly used to simplify expressions. These rules include the clause
for reflexivity:
|- !x. (x = x) = T
as well as rules to reason about equality:
|- !t.
((T = t) = t) /\ ((t = T) = t) /\ ((F = t) = ~t) /\ ((t = F) = ~t)
Negations are manipulated by the following clauses:
|- (!t. ~~t = t) /\ (~T = F) /\ (~F = T)
The set of tautologies includes truth tables for conjunctions, disjunctions, and implications:
|- !t.
(T /\ t = t) /\
(t /\ T = t) /\
(F /\ t = F) /\
(t /\ F = F) /\
(t /\ t = t)
|- !t.
(T \/ t = T) /\
(t \/ T = T) /\
(F \/ t = t) /\
(t \/ F = t) /\
(t \/ t = t)
|- !t.
(T ==> t = t) /\
(t ==> T = T) /\
(F ==> t = T) /\
(t ==> t = T) /\
(t ==> F = ~t)
Simple rules for reasoning about conditionals are given by:
|- !t1 t2. ((T => t1 | t2) = t1) /\ ((F => t1 | t2) = t2)
Rewriting with the following tautologies allows simplification of universally and existentially quantified variables and abstractions:
|- !t. (!x. t) = t
|- !t. (?x. t) = t
|- !t1 t2. (\x. t1)t2 = t1
The value of implicit_rewrites can be augmented by
add_implicit_rewrites and altered by set_implicit_rewrites.
The initial value of implicit_rewrites is bool_rewrites.
The rewrite rules held in implicit_rewrites are automatically included
in the simplifications performed by some of the rewriting tools.
See also
Rewrite.GEN_REWRITE_RULE,
Rewrite.GEN_REWRITE_TAC,
Rewrite.REWRITE_RULE,
Rewrite.REWRITE_TAC,
Rewrite.bool_rewrites,
Rewrite.set_implicit_rewrites,
Rewrite.add_implicit_rewrites
ONCE_ASM_REWRITE_RULE
ONCE_ASM_REWRITE_RULE
Rewrite.ONCE_ASM_REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem once including built-in rewrites and the theorem's assumptions.
ONCE_ASM_REWRITE_RULE applies all possible rewrites in one step over
the subterms in the conclusion of the theorem, but stops after rewriting
at most once at each subterm. This strategy is specified as for
ONCE_DEPTH_CONV. For more details see ASM_REWRITE_RULE, which does
search recursively (to any depth) for matching subterms. The general
strategy for rewriting theorems is described under GEN_REWRITE_RULE.
Failure
Never fails.
This tactic is used when rewriting with the hypotheses of a theorem (as
well as a given list of theorems and implicit_rewrites), when more
than one pass is not required or would result in divergence.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.FILTER_ASM_REWRITE_RULE,
Rewrite.FILTER_ONCE_ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Conv.ONCE_DEPTH_CONV,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
ONCE_ASM_REWRITE_TAC
ONCE_ASM_REWRITE_TAC
Rewrite.ONCE_ASM_REWRITE_TAC : (thm list -> tactic)
Rewrites a goal once including built-in rewrites and the goal's assumptions.
ONCE_ASM_REWRITE_TAC behaves in the same way as ASM_REWRITE_TAC, but
makes one pass only through the term of the goal. The order in which the
given theorems are applied is an implementation matter and the user
should not depend on any ordering. See GEN_REWRITE_TAC for more
information on rewriting a goal in HOL.
Failure
ONCE_ASM_REWRITE_TAC does not fail and, unlike ASM_REWRITE_TAC, does
not diverge. The resulting tactic may not be valid, if the rewrites
performed add new assumptions to the theorem eventually proved.
Example
The use of ONCE_ASM_REWRITE_TAC to control the amount of rewriting
performed is illustrated below:
- ONCE_ASM_REWRITE_TAC []
([Term` (a:'a) = b`, Term `(b:'a) = c`], Term `P (a:'a): bool`);
> val it = ([([`a = b`, `b = c`], `P b`)], fn)
: (term list * term) list * (thm list -> thm)
- (ONCE_ASM_REWRITE_TAC [] THEN ONCE_ASM_REWRITE_TAC [])
([Term`(a:'a) = b`, Term`(b:'a) = c`], Term `P (a:'a): bool`);
> val it = ([([`a = b`, `b = c`], `P c`)], fn)
: (term list * term) list * (thm list -> thm)
ONCE_ASM_REWRITE_TAC can be applied once or iterated as required to
give the effect of ASM_REWRITE_TAC, either to avoid divergence or to
save inference steps.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC
ONCE_REWRITE_CONV
ONCE_REWRITE_CONV
Rewrite.ONCE_REWRITE_CONV : (thm list -> conv)
Rewrites a term, including built-in tautologies in the list of rewrites.
ONCE_REWRITE_CONV searches for matching subterms and applies rewrites
once at each subterm, in the manner specified for ONCE_DEPTH_CONV. The
rewrites which are used are obtained from the given list of theorems and
the set of tautologies stored in implicit_rewrites. See
GEN_REWRITE_CONV for the general method of using theorems to rewrite a
term.
Failure
ONCE_REWRITE_CONV does not fail; it does not diverge.
ONCE_REWRITE_CONV can be used to rewrite a term when recursive
rewriting is not desired.
See also
Rewrite.GEN_REWRITE_CONV,
Rewrite.PURE_ONCE_REWRITE_CONV,
Rewrite.PURE_REWRITE_CONV,
Rewrite.REWRITE_CONV
ONCE_REWRITE_RULE
ONCE_REWRITE_RULE
Rewrite.ONCE_REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem, including built-in tautologies in the list of rewrites.
ONCE_REWRITE_RULE searches for matching subterms and applies rewrites
once at each subterm, in the manner specified for ONCE_DEPTH_CONV. The
rewrites which are used are obtained from the given list of theorems and
the set of tautologies stored in implicit_rewrites. See
GEN_REWRITE_RULE for the general method of using theorems to rewrite
an object theorem.
Failure
ONCE_REWRITE_RULE does not fail; it does not diverge.
ONCE_REWRITE_RULE can be used to rewrite a theorem when recursive
rewriting is not desired.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
ONCE_REWRITE_TAC
ONCE_REWRITE_TAC
Rewrite.ONCE_REWRITE_TAC : thm list -> tactic
Rewrites a goal only once with implicit_rewrites and the supplied list
of theorems.
A set of equational rewrites is generated from the theorems supplied by
the user and the set of basic tautologies, and these are used to rewrite
the goal at all subterms at which a match is found in one pass over the
term part of the goal. The result is returned without recursively
applying the rewrite theorems to it. The order in which the given
theorems are applied is an implementation matter and the user should not
depend on any ordering. More details about rewriting can be found under
GEN_REWRITE_TAC.
Failure
ONCE_REWRITE_TAC does not fail and does not diverge. It results in an
invalid tactic if any of the applied rewrites introduces new assumptions
to the theorem eventually proved.
Example
Given a theorem list:
thl = [ |- a = b, |- b = c, |- c = a]
the tactic ONCE_REWRITE_TAC thl can be iterated as required without
diverging:
- ONCE_REWRITE_TAC thl ([], Term `P (a:'a) :bool`);
> val it = ([([], `P b`)], fn)
: (term list * term) list * (thm list -> thm)
- (ONCE_REWRITE_TAC thl THEN ONCE_REWRITE_TAC thl)
([], Term `P a`);
> val it = ([([], `P c`)], fn)
: (term list * term) list * (thm list -> thm)
- (NTAC 3 (ONCE_REWRITE_TAC thl)) ([], Term `P a`);
> val it = ([([], `P a`)], fn)
: (term list * term) list * (thm list -> thm)
ONCE_REWRITE_TAC can be used iteratively to rewrite when recursive
rewriting would diverge. It can also be used to save inference steps.
See also
Rewrite.ASM_REWRITE_TAC,
BoundedRewrites.Once,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC
PURE_ASM_REWRITE_RULE
PURE_ASM_REWRITE_RULE
Rewrite.PURE_ASM_REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem including the theorem's assumptions as rewrites.
The list of theorems supplied by the user and the assumptions of the
object theorem are used to generate a set of rewrites, without adding
implicitly the basic tautologies stored under implicit_rewrites. The
rule searches for matching subterms in a top-down recursive fashion,
stopping only when no more rewrites apply. For a general description of
rewriting strategies see GEN_REWRITE_RULE.
Failure
Rewriting with PURE_ASM_REWRITE_RULE does not result in failure. It
may diverge, in which case PURE_ONCE_ASM_REWRITE_RULE may be used.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.PURE_ONCE_ASM_REWRITE_RULE
PURE_ASM_REWRITE_TAC
PURE_ASM_REWRITE_TAC
Rewrite.PURE_ASM_REWRITE_TAC : (thm list -> tactic)
Rewrites a goal including the goal's assumptions as rewrites.
PURE_ASM_REWRITE_TAC generates a set of rewrites from the supplied
theorems and the assumptions of the goal, and applies these in a
top-down recursive manner until no match is found. See GEN_REWRITE_TAC
for more information on the group of rewriting tactics.
Failure
PURE_ASM_REWRITE_TAC does not fail, but it can diverge in certain
situations. For limited depth rewriting, see
PURE_ONCE_ASM_REWRITE_TAC. It can also result in an invalid tactic.
To advance or solve a goal when the current assumptions are expected to be useful in reducing the goal.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC
PURE_ONCE_ASM_REWRITE_RULE
PURE_ONCE_ASM_REWRITE_RULE
Rewrite.PURE_ONCE_ASM_REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem once, including the theorem's assumptions as rewrites.
PURE_ONCE_ASM_REWRITE_RULE excludes the basic tautologies in
implicit_rewrites from the theorems used for rewriting. It searches
for matching subterms once only, without recursing over already
rewritten subterms. For a general introduction to rewriting tools see
GEN_REWRITE_RULE.
Failure
PURE_ONCE_ASM_REWRITE_RULE does not fail and does not diverge.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_ASM_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_ASM_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
PURE_ONCE_ASM_REWRITE_TAC
PURE_ONCE_ASM_REWRITE_TAC
Rewrite.PURE_ONCE_ASM_REWRITE_TAC : (thm list -> tactic)
Rewrites a goal once, including the goal's assumptions as rewrites.
A set of rewrites generated from the assumptions of the goal and the
supplied theorems is used to rewrite the term part of the goal, making
only one pass over the goal. The basic tautologies are not included as
rewrite theorems. The order in which the given theorems are applied is
an implementation matter and the user should not depend on any ordering.
See GEN_REWRITE_TAC for more information on rewriting tactics in
general.
Failure
PURE_ONCE_ASM_REWRITE_TAC does not fail and does not diverge.
Manipulation of the goal by rewriting with its assumptions, in instances where rewriting with tautologies and recursive rewriting is undesirable.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC
PURE_ONCE_REWRITE_CONV
PURE_ONCE_REWRITE_CONV
Rewrite.PURE_ONCE_REWRITE_CONV : (thm list -> conv)
Rewrites a term once with only the given list of rewrites.
PURE_ONCE_REWRITE_CONV generates rewrites from the list of theorems
supplied by the user, without including the tautologies given in
implicit_rewrites. The applicable rewrites are employeded once,
without entailing in a recursive search for matches over the term. See
GEN_REWRITE_CONV for more details about rewriting strategies in HOL.
Failure
This rule does not fail, and it does not diverge.
See also
Rewrite.GEN_REWRITE_CONV,
Conv.ONCE_DEPTH_CONV,
Rewrite.ONCE_REWRITE_CONV,
Rewrite.PURE_REWRITE_CONV,
Rewrite.REWRITE_CONV
PURE_ONCE_REWRITE_RULE
PURE_ONCE_REWRITE_RULE
Rewrite.PURE_ONCE_REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem once with only the given list of rewrites.
PURE_ONCE_REWRITE_RULE generates rewrites from the list of theorems
supplied by the user, without including the tautologies given in
implicit_rewrites. The applicable rewrites are employeded once,
without entailing in a recursive search for matches over the theorem.
See GEN_REWRITE_RULE for more details about rewriting strategies in
HOL.
Failure
This rule does not fail, and it does not diverge.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Conv.ONCE_DEPTH_CONV,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE
PURE_ONCE_REWRITE_TAC
PURE_ONCE_REWRITE_TAC
Rewrite.PURE_ONCE_REWRITE_TAC : (thm list -> tactic)
Rewrites a goal using a supplied list of theorems, making one rewriting pass over the goal.
PURE_ONCE_REWRITE_TAC generates a set of rewrites from the given list
of theorems, and applies them at every match found through searching
once over the term part of the goal, without recursing. It does not
include the basic tautologies as rewrite theorems. The order in which
the rewrites are applied is unspecified. For more information on
rewriting tactics see GEN_REWRITE_TAC.
Failure
PURE_ONCE_REWRITE_TAC does not fail and does not diverge.
This tactic is useful when the built-in tautologies are not required as rewrite equations and recursive rewriting is not desired.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC
PURE_REWRITE_CONV
PURE_REWRITE_CONV
Rewrite.PURE_REWRITE_CONV : (thm list -> conv)
Rewrites a term with only the given list of rewrites.
This conversion provides a method for rewriting a term with the theorems
given, and excluding simplification with tautologies in
implicit_rewrites. Matching subterms are found recursively, until no
more matches are found. For more details on rewriting see
GEN_REWRITE_CONV.
PURE_REWRITE_CONV is useful when the simplifications that arise by
rewriting a theorem with implicit_rewrites are not wanted.
Failure
Does not fail. May result in divergence, in which case
PURE_ONCE_REWRITE_CONV can be used.
See also
Rewrite.GEN_REWRITE_CONV,
Rewrite.ONCE_REWRITE_CONV,
Rewrite.PURE_ONCE_REWRITE_CONV,
Rewrite.REWRITE_CONV
PURE_REWRITE_RULE
PURE_REWRITE_RULE
Rewrite.PURE_REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem with only the given list of rewrites.
This rule provides a method for rewriting a theorem with the theorems
given, and excluding simplification with tautologies in
implicit_rewrites. Matching subterms are found recursively starting
from the term in the conclusion part of the theorem, until no more
matches are found. For more details on rewriting see GEN_REWRITE_RULE.
PURE_REWRITE_RULE is useful when the simplifications that arise by
rewriting a theorem with implicit_rewrites are not wanted.
Failure
Does not fail. May result in divergence, in which case
PURE_ONCE_REWRITE_RULE can be used.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_ASM_REWRITE_RULE,
Rewrite.PURE_ONCE_REWRITE_RULE,
Rewrite.REWRITE_RULE
PURE_REWRITE_TAC
PURE_REWRITE_TAC
Rewrite.PURE_REWRITE_TAC : (thm list -> tactic)
Rewrites a goal with only the given list of rewrites.
PURE_REWRITE_TAC behaves in the same way as REWRITE_TAC, but without
the effects of the built-in tautologies. The order in which the given
theorems are applied is an implementation matter and the user should not
depend on any ordering. For more information on rewriting strategies see
GEN_REWRITE_TAC.
Failure
PURE_REWRITE_TAC does not fail, but it can diverge in certain
situations; in such cases PURE_ONCE_REWRITE_TAC may be used.
This tactic is useful when the built-in tautologies are not required as rewrite equations. It is sometimes useful in making more time-efficient replacements according to equations for which it is clear that no extra reduction via tautology will be needed. (The difference in efficiency is only apparent, however, in quite large examples.)
PURE_REWRITE_TAC advances goals but solves them less frequently than
REWRITE_TAC; to be precise, PURE_REWRITE_TAC only solves goals which
are rewritten to "T" (i.e. TRUTH) without recourse to any other
tautologies.
Example
It might be necessary, say for subsequent application of an induction
hypothesis, to resist reducing a term b = T to b.
- PURE_REWRITE_TAC [] ([], Term `b = T`);
> val it = ([([], `b = T`)], fn)
: (term list * term) list * (thm list -> thm)
- REWRITE_TAC [] ([], Term `b = T`);
> val it = ([([], `b`)], fn)
: (term list * term) list * (thm list -> thm)
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_TAC
REWRITE_CONV
REWRITE_CONV
Rewrite.REWRITE_CONV : (thm list -> conv)
Rewrites a term including built-in tautologies in the list of rewrites.
Rewriting a term using REWRITE_CONV utilizes as rewrites two sets of
theorems: the tautologies in the ML list implicit_rewrites and the
ones supplied by the user. The rule searches top-down and recursively
for subterms which match the left-hand side of any of the possible
rewrites, until none of the transformations are applicable. There is no
ordering specified among the set of rewrites.
Variants of this conversion allow changes in the set of equations used:
PURE_REWRITE_CONV and others in its family do not rewrite with the
theorems in implicit_rewrites.
The top-down recursive search for matches may not be desirable, as this
may increase the number of inferences being made or may result in
divergence. In this case other rewriting tools such as
ONCE_REWRITE_CONV and GEN_REWRITE_CONV can be used, or the set of
theorems given may be reduced.
See GEN_REWRITE_CONV for the general strategy for simplifying theorems
in HOL using equational theorems.
Failure
Does not fail, but may diverge if the sequence of rewrites is non-terminating.
Used to manipulate terms by rewriting them with theorems. While
resulting in high degree of automation, REWRITE_CONV can spawn a large
number of inference steps. Thus, variants such as PURE_REWRITE_CONV,
or other rules such as SUBST_CONV, may be used instead to improve
efficiency.
See also
Rewrite.GEN_REWRITE_CONV,
Rewrite.ONCE_REWRITE_CONV,
Rewrite.PURE_REWRITE_CONV,
Conv.REWR_CONV,
Drule.SUBST_CONV
REWRITE_RULE
REWRITE_RULE
Rewrite.REWRITE_RULE : (thm list -> thm -> thm)
Rewrites a theorem including built-in tautologies in the list of rewrites.
Rewriting a theorem using REWRITE_RULE utilizes as rewrites two sets
of theorems: the tautologies in the ML list implicit_rewrites and the
ones supplied by the user. The rule searches top-down and recursively
for subterms which match the left-hand side of any of the possible
rewrites, until none of the transformations are applicable. There is no
ordering specified among the set of rewrites.
Variants of this rule allow changes in the set of equations used:
PURE_REWRITE_RULE and others in its family do not rewrite with the
theorems in implicit_rewrites. Rules such as ASM_REWRITE_RULE add
the assumptions of the object theorem (or a specified subset of these
assumptions) to the set of possible rewrites.
The top-down recursive search for matches may not be desirable, as this
may increase the number of inferences being made or may result in
divergence. In this case other rewriting tools such as
ONCE_REWRITE_RULE and GEN_REWRITE_RULE can be used, or the set of
theorems given may be reduced.
See GEN_REWRITE_RULE for the general strategy for simplifying theorems
in HOL using equational theorems.
Failure
Does not fail, but may diverge if the sequence of rewrites is non-terminating.
Used to manipulate theorems by rewriting them with other theorems. While
resulting in high degree of automation, REWRITE_RULE can spawn a large
number of inference steps. Thus, variants such as PURE_REWRITE_RULE,
or other rules such as SUBST, may be used instead to improve
efficiency.
See also
Rewrite.ASM_REWRITE_RULE,
Rewrite.GEN_REWRITE_RULE,
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Conv.REWR_CONV,
Rewrite.REWRITE_CONV,
Thm.SUBST
REWRITE_TAC
REWRITE_TAC
Rewrite.REWRITE_TAC : (thm list -> tactic)
Rewrites a goal including built-in tautologies in the list of rewrites.
Rewriting tactics in HOL provide a recursive left-to-right matching and rewriting facility that automatically decomposes subgoals and justifies segments of proof in which equational theorems are used, singly or collectively. These include the unfolding of definitions, and the substitution of equals for equals. Rewriting is used either to advance or to complete the decomposition of subgoals.
REWRITE_TAC transforms (or solves) a goal by using as rewrite rules
(i.e. as left-to-right replacement rules) the conclusions of the given
list of (equational) theorems, as well as a set of built-in theorems
(common tautologies) held in the ML variable implicit_rewrites.
Recognition of a tautology often terminates the subgoaling process
(i.e. solves the goal).
The equational rewrites generated are applied recursively and to arbitrary depth, with matching and instantiation of variables and type variables. A list of rewrites can set off an infinite rewriting process, and it is not, of course, decidable in general whether a rewrite set has that property. The order in which the rewrite theorems are applied is unspecified, and the user should not depend on any ordering.
See GEN_REWRITE_TAC for more details on the rewriting process.
Variants of REWRITE_TAC allow the use of a different set of rewrites.
Some of them, such as PURE_REWRITE_TAC, exclude the basic tautologies
from the possible transformations. ASM_REWRITE_TAC and others include
the assumptions at the goal in the set of possible rewrites.
Still other tactics allow greater control over the search for rewritable
subterms. Several of them such as ONCE_REWRITE_TAC do not apply
rewrites recursively. GEN_REWRITE_TAC allows a rewrite to be applied
at a particular subterm.
Failure
REWRITE_TAC does not fail. Certain sets of rewriting theorems on
certain goals may cause a non-terminating sequence of rewrites.
Divergent rewriting behaviour results from a term t being immediately
or eventually rewritten to a term containing t as a sub-term. The
exact behaviour depends on the HOL implementation.
Example
The arithmetic theorem GREATER_DEF, |- !m n. m > n = n < m, is used
below to advance a goal:
- REWRITE_TAC [GREATER_DEF] ([],``5 > 4``);
> ([([], ``4 < 5``)], -) : subgoals
It is used below with the theorem LESS_0, |- !n. 0 < (SUC n), to
solve a goal:
- val (gl,p) =
REWRITE_TAC [GREATER_DEF, LESS_0] ([],``(SUC n) > 0``);
> val gl = [] : goal list
> val p = fn : proof
- p[];
> val it = |- (SUC n) > 0 : thm
Rewriting is a powerful and general mechanism in HOL, and an important
part of many proofs. It relieves the user of the burden of directing and
justifying a large number of minor proof steps. REWRITE_TAC fits a
forward proof sequence smoothly into the general goal-oriented
framework. That is, (within one subgoaling step) it produces and
justifies certain forward inferences, none of which are necessarily on a
direct path to the desired goal.
REWRITE_TAC may be more powerful a tactic than is needed in certain
situations; if efficiency is at stake, alternatives might be considered.
On the other hand, if more power is required, the simplification
functions (SIMP_TAC and others) may be appropriate.
See also
Rewrite.ASM_REWRITE_TAC,
Rewrite.GEN_REWRITE_TAC,
Rewrite.FILTER_ASM_REWRITE_TAC,
Rewrite.FILTER_ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_ASM_REWRITE_TAC,
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_ASM_REWRITE_TAC,
Rewrite.PURE_ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Conv.REWR_CONV,
Rewrite.REWRITE_CONV,
simpLib.SIMP_TAC,
Tactic.SUBST_TAC
set_implicit_rewrites
set_implicit_rewrites
Rewrite.set_implicit_rewrites: rewrites -> unit
Allows the user to control the built-in database of simplifications used in rewriting.
Failure
Never fails.
See also
Rewrite.empty_rewrites,
Rewrite.add_rewrites
SUBST_MATCH
SUBST_MATCH
Rewrite.SUBST_MATCH : (thm -> thm -> thm)
Substitutes in one theorem using another, equational, theorem.
Given the theorems A|-u=v and A'|-t, SUBST_MATCH (A|-u=v) (A'|-t)
searches for one free instance of u in t, according to a top-down
left-to-right search strategy, and then substitutes the corresponding
instance of v.
A |- u=v A' |- t
-------------------- SUBST_MATCH (A|-u=v) (A'|-t)
A u A' |- t[v/u]
SUBST_MATCH allows only a free instance of u to be substituted for
in t. An instance which contain bound variables can be substituted for
by using rewriting rules such as REWRITE_RULE, PURE_REWRITE_RULE and
ONCE_REWRITE_RULE.
Failure
SUBST_MATCH th1 th2 fails if the conclusion of the theorem th1 is
not an equation. Moreover, SUBST_MATCH (A|-u=v) (A'|-t) fails if no
instance of u occurs in t, since the matching algorithm fails. No
change is made to the theorem (A'|-t) if instances of u occur in
t, but they are not free (see SUBS).
Example
The commutative law for addition
- val thm1 = SPECL [Term `m:num`, Term `n:num`] arithmeticTheory.ADD_SYM;
> val thm1 = |- m + n = n + m : thm
is used to apply substitutions, depending on the occurrence of free instances
- SUBST_MATCH thm1 (ASSUME (Term `(n + 1) + (m - 1) = m + n`));
> val it = [.] |- m - 1 + (n + 1) = m + n : thm
- SUBST_MATCH thm1 (ASSUME (Term `!n. (n + 1) + (m - 1) = m + n`));
> val it = [.] |- !n. n + 1 + (m - 1) = m + n : thm
SUBST_MATCH is used when rewriting with the rules such as
REWRITE_RULE, using a single theorem is too extensive or would
diverge. Moreover, applying SUBST_MATCH can be much faster than using
the rewriting rules.
See also
Rewrite.ONCE_REWRITE_RULE,
Rewrite.PURE_REWRITE_RULE,
Rewrite.REWRITE_RULE,
Drule.SUBS, Thm.SUBST
Rsyntax
Rsyntax
Rsyntax
A structure that restores a record-style environment for term manipulation.
If one has opened the Psyntax structure, one can open the Rsyntax
structure to get record-style functions back.
Each function in the Rsyntax structure has a corresponding function in
the Psyntax structure, and vice versa. One can flip-flop between the two
structures by opening one and then the other. One can also use long
identifiers in order to use both syntaxes at once.
Failure
Never fails.
Example
The following shows how to open the Rsyntax structure and the functions that subsequently become available in the top level environment. Documentation for each of these functions is available online.
- open Rsyntax;
open Rsyntax
val INST = fn : term subst -> thm -> thm
val INST_TYPE = fn : hol_type subst -> thm -> thm
val INST_TY_TERM = fn : term subst * hol_type subst -> thm -> thm
val SUBST = fn : {thm:thm, var:term} list -> term -> thm -> thm
val SUBST_CONV = fn : {thm:thm, var:term} list -> term -> term -> thm
val define_new_type_bijections = fn
: {ABS:string, REP:string, name:string, tyax:thm} -> thm
val dest_abs = fn : term -> {Body:term, Bvar:term}
val dest_comb = fn : term -> {Rand:term, Rator:term}
val dest_cond = fn : term -> {cond:term, larm:term, rarm:term}
val dest_conj = fn : term -> {conj1:term, conj2:term}
val dest_cons = fn : term -> {hd:term, tl:term}
val dest_const = fn : term -> {Name:string, Ty:hol_type}
val dest_disj = fn : term -> {disj1:term, disj2:term}
val dest_eq = fn : term -> {lhs:term, rhs:term}
val dest_exists = fn : term -> {Body:term, Bvar:term}
val dest_forall = fn : term -> {Body:term, Bvar:term}
val dest_imp = fn : term -> {ant:term, conseq:term}
val dest_let = fn : term -> {arg:term, func:term}
val dest_list = fn : term -> {els:term list, ty:hol_type}
val dest_pabs = fn : term -> {body:term, varstruct:term}
val dest_pair = fn : term -> {fst:term, snd:term}
val dest_select = fn : term -> {Body:term, Bvar:term}
val dest_type = fn : hol_type -> {Args:hol_type list, Tyop:string}
val dest_var = fn : term -> {Name:string, Ty:hol_type}
val inst = fn : hol_type subst -> term -> term
val match_term = fn : term -> term -> term subst * hol_type subst
val match_type = fn : hol_type -> hol_type -> hol_type subst
val mk_abs = fn : {Body:term, Bvar:term} -> term
val mk_comb = fn : {Rand:term, Rator:term} -> term
val mk_cond = fn : {cond:term, larm:term, rarm:term} -> term
val mk_conj = fn : {conj1:term, conj2:term} -> term
val mk_cons = fn : {hd:term, tl:term} -> term
val mk_const = fn : {Name:string, Ty:hol_type} -> term
val mk_disj = fn : {disj1:term, disj2:term} -> term
val mk_eq = fn : {lhs:term, rhs:term} -> term
val mk_exists = fn : {Body:term, Bvar:term} -> term
val mk_forall = fn : {Body:term, Bvar:term} -> term
val mk_imp = fn : {ant:term, conseq:term} -> term
val mk_let = fn : {arg:term, func:term} -> term
val mk_list = fn : {els:term list, ty:hol_type} -> term
val mk_pabs = fn : {body:term, varstruct:term} -> term
val mk_pair = fn : {fst:term, snd:term} -> term
val mk_primed_var = fn : {Name:string, Ty:hol_type} -> term
val mk_select = fn : {Body:term, Bvar:term} -> term
val mk_type = fn : {Args:hol_type list, Tyop:string} -> hol_type
val mk_var = fn : {Name:string, Ty:hol_type} -> term
val new_binder = fn : {Name:string, Ty:hol_type} -> unit
val new_constant = fn : {Name:string, Ty:hol_type} -> unit
val new_infix = fn : {Name:string, Prec:int, Ty:hol_type} -> unit
val new_recursive_definition = fn
: {def:term, fixity:fixity, name:string, rec_axiom:thm} -> thm
val new_specification = fn
: {consts:{const_name:string, fixity:fixity} list,
name:string, sat_thm:thm}
-> thm
val new_type = fn : {Arity:int, Name:string} -> unit
val new_type_definition = fn
: {inhab_thm:thm, name:string, pred:term} -> thm
val subst = fn : term subst -> term -> term
val subst_occs = fn : int list list -> term subst -> term -> term
val type_subst = fn : hol_type subst -> hol_type -> hol_type
See also
++
++
op simpLib.++ : simpset * ssfrag -> simpset
Infix operator for adding an ssfrag item into a simpset.
bossLib.++ is identical to simpLib.++.
If the incoming fragment has a name and that name is currently in the
simpset's excluded set (set up by an earlier exclude_ssfrags call —
e.g. via the Proof[exclude_frags = ...] attribute), the addition is a
silent no-op and ss ++ frag returns ss unchanged. Use force_add
(or, in the rewrite-list of a simplification tactic, the SF marker) to
override that prohibition.
See also
bossLib.++,
simpLib.exclude_ssfrags,
simpLib.force_add
AC
AC
simpLib.AC : thm -> thm -> thm
Packages associativity and commutativity theorems for use in the simplifier.
The AC function combines an associativity and commutativity theorem.
The resulting theorem can be passed to the simplifier as if a rewrite,
but will rather be used by the simplifier as the basis for performing
AC-normalisation.
The theorems can be combined in either order, can be partly generalised, and need not express associativity in any particular direction from left to right.
Failure
AC never fails, but if applied to theorems that are not of the
required form, the simplifier will raise an exception when it attempts
to use the result.
Example
> SIMP_CONV bool_ss [AC arithmeticTheory.ADD_COMM arithmeticTheory.ADD_ASSOC] ``3 + x + y + 1``;
val it = ⊢ 3 + x + y + 1 = x + (y + (1 + 3)): thm
> SIMP_CONV bool_ss [AC (GSYM arithmeticTheory.ADD_ASSOC) arithmeticTheory.ADD_COMM] ``x + 1 + y + 3``;
val it = ⊢ x + 1 + y + 3 = x + (y + (1 + 3)): thm
See also
ASM_SIMP_RULE
ASM_SIMP_RULE
simpLib.ASM_SIMP_RULE : simpset -> thm list -> thm -> thm
Simplifies a theorem, using the theorem's assumptions as rewrites in addition to the provided rewrite theorems and simpset.
Failure
Never fails, but may diverge.
Example
> simpLib.ASM_SIMP_RULE bool_ss [] (ASSUME (Term `x = 3`))
val it = [.] ⊢ T: thm
The assumptions can be used to simplify the conclusion of the theorem. For example, if the conclusion of a theorem is an implication, the antecedent together with the hypotheses may help simplify the conclusion.
See also
simpLib.SIMP_CONV,
simpLib.SIMP_RULE
ASM_SIMP_TAC
ASM_SIMP_TAC
simpLib.ASM_SIMP_TAC : simpset -> thm list -> tactic
Re-exported from bossLib.ASM_SIMP_TAC. See that
entry for full documentation.
Cong
Cong
simpLib.Cong : thm -> thm
Marks a theorem as a congruence rule for the simplifier.
The Cong function marks (or "tags") a theorem so that when passed to
the simplifier, it is not used as a rewrite, but rather as a congruence
rule. This is a simpler way of adding a congruence rule to the
simplifier than using the underlying SSFRAG function.
Failure
Never fails. On the other hand, Cong does not check that the theorem
passed as an argument is a valid congruence rule, and invalid congruence
rules may have unpredictable effects on the behaviour of the simplifier.
Example
- SIMP_CONV pure_ss [] ``!x::P. x IN P /\ Q x``;
<<HOL message: inventing new type variable names: 'a>>
! Uncaught exception:
! UNCHANGED
- RES_FORALL_CONG;
> val it =
|- (P = Q) ==>
(!x. x IN Q ==> (f x = g x)) ==>
(RES_FORALL P f = RES_FORALL Q g) : thm
- SIMP_CONV pure_ss [Cong RES_FORALL_CONG] ``!x::P. x IN P ``;
<<HOL message: inventing new type variable names: 'a>>
> val it = |- (!x::P. x IN P /\ Q x) = !x::P. T /\ Q x : thm
(Note that RES_FORALL_CONG is already included in bool_ss and all
simpsets built on it.)
See also
exclude_ssfrags
exclude_ssfrags
simpLib.exclude_ssfrags : string list -> simpset -> simpset
Removes named simpset fragments and records the exclusion in the simpset.
A call to exclude_ssfrags fragnames simpset returns a simpset that is
the same as simpset except that
- every fragment with a name in
fragnameshas been removed from the simpset's history (as withremove_ssfrags); and - the names in
fragnamesare recorded in the simpset's excluded set, so that any subsequent attempt to add a fragment with one of those names via the++operator is a silent no-op.
Use force_add (or, in user-facing thm-list arguments to simplification
tactics, the SF marker) to opt back in: it adds a fragment and removes
its name from the excluded set in one step.
This is the function used to implement the Proof[exclude_frags = ...]
attribute on theorem proofs.
Failure
Never fails (unlike remove_ssfrags, no Conv.UNCHANGED is raised when
none of the names match a fragment in the simpset).
Example
> val base = simpLib.exclude_ssfrags ["ARITH"] (srw_ss());
val base =
Included fragments (with 1 anonymous fragment [remove using name ""]):
ABBREV, ARITH_RWTS, ASCIInumbers, BOOL, COMBIN, CONG, ConseqConv,
Datatype bool$itself, Datatype cv$cv, Datatype example$atree,
Datatype example$example, Datatype fcp$bit0, Datatype fcp$bit1,
Datatype fcp$cart, Datatype foo$exp, Datatype foo$foo,
Datatype foo$point, Datatype integer$int, Datatype list$list,
Datatype min$bool, Datatype min$fun, Datatype num$num,
Datatype one$one, Datatype option$option, Datatype pair$prod,
Datatype patricia$ptree, Datatype string$char, Datatype sum$sum,
Datatype ternaryComparisons$ordering, GSPEC_SIMP, LABEL_CONG, MOD,
NORMEQ, NOT, Omega, PURE, REAL_REDUCE, RMULCANON, RMULRELNORM,
SET_SPEC, UNWIND, While, arithmetic, bag, basicSize, bit, bitstring,
blast, bool, combin, cooper, cv, cv_prim, cv_rep, cv_type, divides,
fcp, frac, gcd, hide, hol, hrat, hreal, ind_type, indexedLists,
intExtension, intReduce, int_arith, integer, integer_word, iterate,
list, list EQ, logroot, marker, normalForms, normalizer, num, numeral,
numeral_bit, numpair, numposrep, one, option, pair, patricia,
patternMatches, patternMatchesSimp, permutes, pred_set, prim_rec,
primeFactor, quantHeuristics, quotient, rat, real, real_arith, realax,
reduce, relation, rich_list, sat, sizes, sorting, string, sum, sum_num,
ternaryComparisons, word arith, word ground, word logic, word shift,
word subtract, words
Rewrites (with 689 anonymous rewrites)
Other net names/keys:
.rewrite:ADD_0'.1, .rewrite:ADD_INV_0_EQ'.1, .rewrite:ADD_INV_0_EQ'.2,
.rewrite:ADD_MONO_LESS_EQ.1, .rewrite:ADD_SUB'.1,
.rewrite:COND_BOOL_CLAUSES.1, .rewrite:COND_BOOL_CLAUSES.2,
.rewrite:COND_BOOL_CLAUSES.3, .rewrite:COND_BOOL_CLAUSES.4,
.rewrite:EQ_MONO_ADD_EQ.1, .rewrite:EXCLUDED_MIDDLE'.1,
[...Output elided...]
> List.exists (fn n => n = "ARITH")
(simpLib.ssfrag_names_of (base ++ numSimps.ARITH_ss));
val it = false: bool
> List.exists (fn n => n = "ARITH")
(simpLib.ssfrag_names_of
(simpLib.force_add base numSimps.ARITH_ss));
val it = true: bool
See also
simpLib.remove_ssfrags,
simpLib.force_add,
bossLib.SF
force_add
force_add
simpLib.force_add : simpset -> ssfrag -> simpset
Adds a simpset fragment, overriding any active exclusion of its name.
A call to force_add simpset frag returns a simpset that is simpset
augmented with frag (as if by ++). In addition, if frag has a name
that is currently in the simpset's excluded set (because of an earlier
exclude_ssfrags call), that name is removed from the excluded set so
that subsequent ++ of a fragment with the same name will also succeed.
This function is the override mechanism for exclude_ssfrags: while
++ is silent when the incoming fragment is currently excluded,
force_add lifts the exclusion for that name and performs the addition.
force_add is what underlies the behaviour of the SF marker in
thm-list arguments to simplification tactics: writing simp[SF FRAG_ss]
inside a Proof[exclude_frags = FRAG] body re-enables FRAG_ss for
that simp call.
Failure
Never fails.
See also
simpLib.exclude_ssfrags,
simpLib.++,
bossLib.SF
FULL_SIMP_TAC
FULL_SIMP_TAC
simpLib.FULL_SIMP_TAC : simpset -> thm list -> tactic
Re-exported from bossLib.FULL_SIMP_TAC. See that
entry for full documentation.
mk_simpset
mk_simpset
simpLib.mk_simpset : ssfrag list -> simpset
Creates a simpset by combining a list of ssfrag values.
This function creates a simpset value by repeatedly adding (as per the
++ operator) simpset fragment values to the base empty_ss.
Failure
Never fails.
Creates simpsets, which are a necessary argument to any simplification function.
See also
simpLib.++, simpLib.rewrites,
simpLib.SIMP_CONV
register_frag
register_frag
simpLib.register_frag : ssfrag -> ssfrag
Registers a simpset fragment for later use with SF.
A call to simpLib.register_frag sfrag records a mapping from the name
of sfrag to the sfrag value. This internal database is then used by
simplification tactics when they see theorems created with calls to
SF.
Failure
Fails is the fragment sfrag is anonymous.
See also
remove_ssfrags
remove_ssfrags
simpLib.remove_ssfrags : string list -> simpset -> simpset
Removes named simpset fragments from a simpset.
A call to remove_ssfrags fragnames simpset returns a simpset that is
the same as simpset except that the simpset fragments with names in
the list fragnames are no longer included. As a special case, the
empty name "" matches all unnamed fragments within simpset and
causes them to be removed.
Failure
If no member of fragnames names a fragment in simpset, the
Conv.UNCHANGED exception is raised.
Example
> SIMP_CONV (srw_ss()) [] “MAP ($+ 1) [3;4;5]”;
val it = ⊢ MAP ($+ 1) [3; 4; 5] = [1 + 3; 1 + 4; 1 + 5]: thm
> val myss = simpLib.remove_ssfrags ["REDUCE"] (srw_ss());
Exception- UNCHANGED raised
> SIMP_CONV myss [] “MAP ($+ 1) [3;4;5]”;
Exception- Value or constructor (myss) has not been declared
Fail "Static Errors" raised
Comparison with exclude_ssfrags
remove_ssfrags only strips matching fragments from the simpset's
history; a subsequent ss ++ FRAG_ss would re-add them. By contrast,
exclude_ssfrags also records the exclusion in the simpset itself, so
that subsequent ++ of a fragment with one of the named names is a
silent no-op (until cleared via force_add / SF). exclude_ssfrags
also never raises Conv.UNCHANGED. The Proof[exclude_frags = ...]
attribute uses exclude_ssfrags.
See also
simpLib.exclude_ssfrags,
simpLib.force_add,
BasicProvers.diminish_srw_ss
rewrites
rewrites
simpLib.rewrites : thm list -> ssfrag
Re-exported from bossLib.rewrites. See that
entry for full documentation.
SIMP_CONV
SIMP_CONV
simpLib.SIMP_CONV : simpset -> thm list -> conv
Re-exported from bossLib.SIMP_CONV. See that
entry for full documentation.
SIMP_PROVE
SIMP_PROVE
simpLib.SIMP_PROVE : simpset -> thm list -> term -> thm
Like SIMP_CONV, but converts boolean terms to theorem with same
conclusion.
SIMP_PROVE ss thml is equivalent to EQT_ELIM o SIMP_CONV ss thml.
Failure
Fails if the term can not be shown to be equivalent to true. May diverge.
Example
Applying the tactic
ASSUME_TAC (SIMP_PROVE arith_ss [] ``x < y ==> x < y + 6``)
to the goal ?- x + y = 10 yields the new goal
x < y ==> x < y + 6 ?- x + y = 10
Using SIMP_PROVE here allows ASSUME_TAC to add a new fact, where the
equality with truth that SIMP_CONV would produce would be less useful.
SIMP_PROVE is useful when constructing theorems to be passed to other
tools, where those other tools would prefer not to have theorems of the
form |- P = T.
See also
simpLib.SIMP_CONV,
simpLib.SIMP_RULE,
simpLib.SIMP_TAC
SIMP_RULE
SIMP_RULE
simpLib.SIMP_RULE : simpset -> thm list -> thm -> thm
Re-exported from bossLib.SIMP_RULE. See that
entry for full documentation.
SIMP_TAC
SIMP_TAC
simpLib.SIMP_TAC : simpset -> thm list -> tactic
Re-exported from bossLib.SIMP_TAC. See that
entry for full documentation.
SSFRAG
SSFRAG
simpLib.SSFRAG : { ac : (thm * thm) list,
congs : thm list,
convs : {conv : (term list -> conv) -> term list -> conv,
key : (term list * term) option,
name : string,
trace : int} list,
dprocs : Traverse.reducer list,
filter : (controlled_thm -> controlled_thm list) option,
name : string option,
rewrs : thm list } -> ssfrag
Constructs ssfrag values.
The ssfrag type is the way in which simplification components are
packaged up and made available to the simplifier (though ssfrag values
must first be turned into simpsets, either by addition to an existing
simpset, or with the mk_simpset function).
The big record type passed to SSFRAG as an argument has seven fields.
Here we describe each in turn.
The ac field is a list of "AC theorem" pairs. Each such pair is the
pair of theorems stating that a given binary function is associative and
commutative. The theorems can be given in either order, can present the
associativity theorem in either direction, and can be generalised to any
extent.
The congs field is a list of congruence theorems justifying the
addition of theorems to simplification contexts. For example, the
congruence theorem for implication is
|- (P = P') ==> (P' ==> (Q = Q')) ==> (P ==> Q = P' ==> Q')
This theorem encodes a rewriting strategy. The consequent of the chain
of implications is the form of term in question, where the appropriate
components have been rewritten. Then, in left-to-right order, the
various antecedents of the implication specify the rewriting strategy
which gives rise to the consequent. In this example, P is first
simplified to P' without any additional context, then, using P' as
additional context, simplification of Q proceeds, producing Q'.
Another example is a rule for conjunction:
|- (P ==> (Q = Q')) ==> (Q' ==> (P = P')) ==> ((P /\ Q) = (P' /\ Q'))
Here P is assumed while Q is simplified to Q'. Then, Q' is
assumed while P is simplified to P'. If an antecedent doesn't
involve the relation in question (here, equality) then it is treated as
a side-condition, and the simplifier will be recursively invoked to try
and solve it.
Higher-order congruence rules are also possible. These provide a method for dealing with bound variables. The following is a rule for the restricted universal quantifier, for example:
|- (P = Q) ==> (!v. v IN Q ==> (f v = g v)) ==>
(RES_FORALL P f = RES_FORALL Q g)
(If f is an abstraction, \x. t, then RES_FORALL P f is
pretty-printed as !x::P. t) Terms in the conclusions of higher-order
congruence rules that might be abstractions (such as f above) should
be kept as variables, rather than written out as abstractions. In other
words, the conclusion of the congruence rule above should not be written
as
RES_FORALL P (\v. f v) = RES_FORALL Q (\v. g v)
The convs field is a list of conversions that the simplifier will
apply. Each conversion added to an ssfrag value is done so in a record
consisting of four fields.
The conv field of this subsidiary record type includes the value of
the conversion itself. When the simplifier applies the conversion it is
actually passed two extra arguments (as the type indicates). The first
is a solver function that can be used to recursively do side-condition
solving, and the second is a stack of side-conditions that have been
accumulated to date. Many conversions will typically ignore these
arguments (as in the example below).
The key field of the subsidiary record type is an optional pattern,
specifying the places where the conversion should be applied. If the
value is NONE, then the conversion will be applied to all sub-terms.
If the value is SOME(lcs, t), then the term t is used as a pattern
specifying those terms to which the conversion should be applied.
Further, the list lcs (which must be a list of variables), specifies
those variables in t which shouldn't be generalised against; they are
effectively local constants. Note, however, that the types in the
pattern term t will not be used to eliminate possible matches, so that
if a match is desired with a particular type instantiation of a term,
then the conversion will need to reject the input itself. The name and
trace fields are only relevant to the debugging facilities of the
simplifier.
The dprocs field of the record passed to SSFRAG is where decision
procedures can be specified. Documentation describing the construction
and use of values of type reducer is available in the DESCRIPTION.
The filter field of the record is an optional function, which, if
present, is composed with the standard simplifier's function for
generating rewrites from theorems, and replaces that function. The
version of this present in bool_ss and its descendents will, for
example, turn |- P /\ Q into |- P and |- Q, and |- ~(t1 = t2)
into |- (t1 = t2) = F and |- (t2 = t1) = F.
The controlled_thm type is defined in the module BoundedRewrites,
and pairs a theorem with a bound, which is either the value UNBOUNDED
or the constructor BOUNDED applied to an integer reference. The
reference is used to limit the number of times a rewrite may be applied.
The filter gets information as to whether and how a rewrite is bounded
as this can affect its decision on whether or not to include a rewrite
at all (if it looks as if it will loop, and the bound is UNBOUNDED, it
should be dropped, but it may choose to keep it if there is bound
present).
The rewrs field of the record is a list of rewrite theorems that are
to be applied.
The name field of the record is an optional name for the simpset
fragment that is used when it, and simpsets that it becomes part of are
pretty-printed.
Failure
Never fails. Failure to provide theorems of just the right form may cause later application of simplification functions to fail, documentation to the contrary notwithstanding.
Example
Given a conversion MUL_CONV to calculate multiplications, the
following illustrates how this can be added to a simpset:
- val ssd = SSFRAG {ac = [], congs = [],
convs = [{conv = K (K MUL_CONV),
key= SOME ([], Term`x * y`),
name = "MUL_CONV",
trace = 2}],
dprocs = [], filter = NONE, rewrs = []};
> val ssd =
SSFRAG{ac = [], congs = [],
convs =
[{conv = fn, key = SOME([], `x * y`), name = "MUL_CONV",
trace = 2}], dprocs = [], filter = NONE, rewrs = []}
: ssfrag
- SIMP_CONV bool_ss [] (Term`3 * 4`);
> val it = |- 3 * 4 = 3 * 4 : thm
- SIMP_CONV (bool_ss ++ ssd) [] (Term`3 * 4`);
> val it = |- 3 * 4 = 12 : thm
Given the theorems ADD_SYM and ADD_ASSOC from arithmeticTheory, we
can construct a normaliser for additive terms.
- val ssd2 = SSFRAG {ac = [(SPEC_ALL ADD_ASSOC, SPEC_ALL ADD_SYM)],
congs = [], convs = [], dprocs = [],
filter = NONE, rewrs = []};
> val ssd2 =
SSFRAG{ac = [(|- m + n + p = (m + n) + p, |- m + n = n + m)],
congs = [], convs = [], dprocs = [], filter = NONE,
rewrs = []}
: ssfrag
- SIMP_CONV (bool_ss ++ ssd2) [] (Term`(y + 3) + x + 4`);
(* note that the printing of + in this example is that of a
right associative operator.*)
> val it = |- (y + 3) + x + 4 = 3 + 4 + x + y : thm
See also
simpLib.++,
boolSimps.bool_ss,
simpLib.Cong,
simpLib.mk_simpset,
simpLib.rewrites,
simpLib.SIMP_CONV
type_ssfrag
type_ssfrag
simpLib.type_ssfrag : hol_type -> ssfrag
Returns a simpset fragment for simplifying types' constructors.
A call to type_ssfrag ty function returns a simpset fragment that
embodies simplification routines for the type ty.
The fragment includes rewrites that express injectivity and disjointness
of constructors, and which simplify case expressions applied to terms
that have constructors at the outermost level.
Failure
Fails if the string argument does not correspond to a type stored in the
TypeBase.
Example
> val ss = simpLib.type_ssfrag “:'a list”;
val ss =
Simplification set fragment: Datatype list$list
Rewrite rules:
[list$list simpl. 5]
⊢ (∀f. list_size f [] = 0) ∧
∀f a0 a1. list_size f (a0::a1) = 1 + (f a0 + list_size f a1)
[list$list simpl. 4]
⊢ ∀a0 a1 a0' a1'. a0::a1 = a0'::a1' ⇔ a0 = a0' ∧ a1 = a1'
[list$list simpl. 3] ⊢ ∀a1 a0. a0::a1 ≠ []
[list$list simpl. 2] ⊢ ∀a1 a0. [] ≠ a0::a1
[list$list simpl. 1]
⊢ (∀v f. list_CASE [] v f = v) ∧
∀a0 a1 v f. list_CASE (a0::a1) v f = f a0 a1: ssfrag
> SIMP_CONV (bool_ss ++ ss) [] ``h::t = []``;
val it = ⊢ h::t = [] ⇔ F: thm
Comments
RW_TAC and SRW_TAC automatically include these simpset fragments.
See also
BasicProvers.RW_TAC,
BasicProvers.srw_ss,
bossLib.type_rws,
simpLib.SIMP_CONV, TypeBase
view_struct
view_struct
smlOpen.view_struct : string -> (string list * string list * string list * string list)
Shows SML identifiers included in a structure (or substructure) s.
The first field contains values, the second exceptions (i.e Match), the third constructions (i.e SOME) and the fourth substructures. This output is computed by inspecting PolyML.globalNameSpace () in an external HOL4 environment.
Failure
Fails if the structure s cannot be loaded by a script in the directory
src/AI/sml_inspection/open.
Example
> load "smlOpen"; open smlOpen;
val it = (): unit
> view_struct "Math";
val it =
(["sin", "sinh", "cos", "tan", "cosh", "e", "asin", "tanh", "atan2", "ln",
"acos", "log10", "pi", "sqrt", "atan", "exp", "pow"], [], [], []):
string list * string list * string list * string list
> view_struct "HolKernel.Definition";
val it =
(["new_definition", "new_specification", "located_new_type_definition",
"located_new_definition", "gen_new_specification",
"located_new_specification", "new_definition_hook",
"new_type_definition", "located_gen_new_specification"], [], [], []):
string list * string list * string list * string list
Comments
Including a Holmakefile in the directory src/AI/sml_inspection/open
with the line INCLUDES = path-to-your-structure should remove the
requirement for the structure to be in sigobj.
See also
smlExecute.quse_string,
smlExecScripts.exec_script
timeout
timeout
smlTimeout.timeout : real -> ('a -> 'b) -> 'a -> 'b
Interrupts a function f after a time limit.
In case the limit is reached, the exception FunctionTimeout is raised, otherwise it behaves in the same way as a call to "f" on its argument.
Failure
Fails when the call to f exceeds the time limit or if f fails.
Example
> load "smlTimeout"; open smlTimeout;
val it = (): unit
> timeout 0.1 (fn (x:int) => (raise Match):int) 5;
Exception- Match raised
> timeout 0.2 OS.Process.sleep (Time.fromReal 2.0);
Exception- FunctionTimeout raised
> timeout 1.0 (fn x => x) 5;
val it = 5: int
Comments
Relies on a conditional variable to decide if and when to send an
Interrupt signal to the worker thread in which the function f is
called. In the case an interrupt is needed, a bit of time is given to
the function f to catch the Interrupt and return a result. This last
step has been implemented with a busy waiting loop that has
experimentally been determined to be more efficient than relying on an
additional condition variable.
ABS_TAC
ABS_TAC
Tactic.ABS_TAC : tactic
Strips lambda abstraction on both sides of an equation.
When applied to a goal of the form A ?- (\x. M) = (\y. N) (where M
and N may or may not mention their respective bound variables), the
tactic ABS_TAC strips away the lambda abstractions:
A ?- (\x. f x) = (\y. g y)
============================ ABS_TAC
A ?- f x = g x
Failure
Fails unless the goal has the above form, namely an equation both sides of which consist of a lamdba abstraction.
Comments
When the lambda abstractions' bound variables conflict with existing free variables in the goal, variants of those names may occur in the goal that results.
See also
Tactic.AP_TERM_TAC,
Tactic.AP_THM_TAC
ACCEPT_TAC
ACCEPT_TAC
Tactic.ACCEPT_TAC : thm_tactic
Solves a goal if supplied with the desired theorem (up to alpha-conversion).
ACCEPT_TAC maps a given theorem th to a tactic that solves any goal
whose conclusion is alpha-convertible to the conclusion of th.
Failure
ACCEPT_TAC th (A,g) fails if the term g is not alpha-convertible to
the conclusion of the supplied theorem th.
Example
ACCEPT_TAC applied to the axiom
BOOL_CASES_AX = |- !t. (t = T) \/ (t = F)
will solve the goal
?- !x. (x = T) \/ (x = F)
but will fail on the goal
?- !x. (x = F) \/ (x = T)
Used for completing proofs by supplying an existing theorem, such as an axiom, or a lemma already proved.
See also
AP_TERM_TAC
AP_TERM_TAC
Tactic.AP_TERM_TAC : tactic
Strips a function application from both sides of an equational goal.
AP_TERM_TAC reduces a goal of the form A ?- f x = f y by stripping
away the function applications, giving the new goal A ?- x = y.
A ?- f x = f y
================ AP_TERM_TAC
A ?- x = y
Failure
Fails unless the goal is equational, with both sides being applications of the same function.
See also
Thm.AP_TERM, Thm.AP_THM,
Tactic.AP_THM_TAC,
Tactic.MK_COMB_TAC,
Tactic.ABS_TAC
AP_THM_TAC
AP_THM_TAC
Tactic.AP_THM_TAC : tactic
Strips identical operands from functions on both sides of an equation.
When applied to a goal of the form A ?- f x = g x, the tactic
AP_THM_TAC strips away the operands of the function application:
A ?- f x = g x
================ AP_THM_TAC
A ?- f = g
Failure
Fails unless the goal has the above form, namely an equation both sides of which consist of function applications to the same arguments.
See also
Thm.AP_TERM,
Tactic.AP_TERM_TAC,
Thm.AP_THM,
Tactic.MK_COMB_TAC,
Tactic.ABS_TAC, Drule.EXT
ASM_CASES_TAC
ASM_CASES_TAC
Tactic.ASM_CASES_TAC : term -> tactic
Given a term, produces a case split based on whether or not that term is true.
Given a term u, ASM_CASES_TAC applied to a goal produces two
subgoals, one with u as an assumption and one with ~u:
A ?- t
================================ ASM_CASES_TAC u
A u {u} ?- t A u {~u} ?- t
ASM_CASES_TAC u is implemented by
DISJ_CASES_TAC(SPEC u EXCLUDED_MIDDLE), where EXCLUDED_MIDDLE is the
axiom |- !u. u \/ ~u.
Failure
By virtue of the implementation (see above), the decomposition fails if
EXCLUDED_MIDDLE cannot be instantiated to u, e.g. if u does not
have boolean type.
Example
The tactic ASM_CASES_TAC u can be used to produce a case analysis on
u:
- let val u = Term `u:bool`
val g = Term `(P:bool -> bool) u`
in
ASM_CASES_TAC u ([],g)
end;
([([`u`], `P u`),
([`~u`], `P u`)], fn) : tactic_result
Performing a case analysis according to whether a given term is true or false.
See also
Tactic.BOOL_CASES_TAC,
Tactic.COND_CASES_TAC,
Tactic.DISJ_CASES_TAC,
Thm.SPEC,
Tactic.STRUCT_CASES_TAC,
BasicProvers.Cases,
bossLib.Cases_on
ASSUME_TAC
ASSUME_TAC
Tactic.ASSUME_TAC : thm_tactic
Adds an assumption to a goal.
Given a theorem th of the form A' |- u, and a goal, ASSUME_TAC th
adds u to the assumptions of the goal.
A ?- t
============== ASSUME_TAC (A' |- u)
A u {u} ?- t
Note that unless A' is a subset of A, this tactic is invalid.
Failure
Never fails.
Example
Given a goal g of the form {x = y, y = z} ?- P, where x, y and
z have type :'a, the theorem x = y, y = z |- x = z can, first, be
inferred by forward proof
let val eq1 = Term `(x:'a) = y`
val eq2 = Term `(y:'a) = z`
in
TRANS (ASSUME eq1) (ASSUME eq2)
end;
and then added to the assumptions. This process requires the explicit
text of the assumptions, as well as invocation of the rule ASSUME:
let val eq1 = Term `(x:'a) = y`
val eq2 = Term `(y:'a) = z`
val goal = ([eq1,eq2],Parse.Term `P:bool`)
in
ASSUME_TAC (TRANS (ASSUME eq1) (ASSUME eq2)) goal
end;
val it = ([([`x = z`, `x = y`, `y = z`], `P`)], fn) : tactic_result
This is the naive way of manipulating assumptions; there are more advanced proof styles (more elegant and less transparent) that achieve the same effect, but this is a perfectly correct technique in itself.
Alternatively, the axiom EQ_TRANS could be added to the assumptions of
g:
let val eq1 = Term `(x:'a) = y`
val eq2 = Term `(y:'a) = z`
val goal = ([eq1,eq2], Term `P:bool`)
in
ASSUME_TAC EQ_TRANS goal
end;
val it =
([([`!x y z. (x = y) /\ (y = z) ==> (x = z)`,
`x = y`,`y = z`],`P`)],fn) : tactic_result
A subsequent resolution (see RES_TAC) would then be able to add the
assumption x = z to the subgoal shown above. (Aside from purposes of
example, it would be more usual to use IMP_RES_TAC than ASSUME_TAC
followed by RES_TAC in this context.)
ASSUME_TAC is the naive way of manipulating assumptions (i.e. without
recourse to advanced tacticals); and it is useful for enriching the
assumption list with lemmas as a prelude to resolution (RES_TAC,
IMP_RES_TAC), rewriting with assumptions (ASM_REWRITE_TAC and so
on), and other operations involving assumptions.
See also
Tactic.ACCEPT_TAC,
Tactic.IMP_RES_TAC,
Tactic.RES_TAC,
Tactic.STRIP_ASSUME_TAC
BETA_TAC
BETA_TAC
Tactic.BETA_TAC : tactic
Beta-reduces all the beta-redexes in the conclusion of a goal.
When applied to a goal A ?- t, the tactic BETA_TAC produces a new
goal which results from beta-reducing all beta-redexes, at any depth, in
t. Variables are renamed where necessary to avoid free variable
capture.
A ?- ...((\x. s1) s2)...
========================== BETA_TAC
A ?- ...(s1[s2/x])...
Failure
Never fails, but will have no effect if there are no beta-redexes.
See also
Thm.BETA_CONV,
Tactic.BETA_TAC,
PairedLambda.PAIRED_BETA_CONV
BOOL_CASES_TAC
BOOL_CASES_TAC
Tactic.BOOL_CASES_TAC : (term -> tactic)
Performs boolean case analysis on a (free) term in the goal.
When applied to a term x (which must be of type bool but need not be
simply a variable), and a goal A ?- t, the tactic BOOL_CASES_TAC
generates the two subgoals corresponding to A ?- t but with any free
instances of x replaced by F and T respectively.
A ?- t
============================ BOOL_CASES_TAC "x"
A ?- t[F/x] A ?- t[T/x]
The term given does not have to be free in the goal, but if it isn't,
BOOL_CASES_TAC will merely duplicate the original goal twice.
Failure
Fails unless the term x has type bool.
Example
The goal:
?- (b ==> ~b) ==> (b ==> a)
can be completely solved by using BOOL_CASES_TAC on the variable b,
then simply rewriting the two subgoals using only the inbuilt
tautologies, i.e. by applying the following tactic:
BOOL_CASES_TAC (Parse.Term `b:bool`) THEN REWRITE_TAC[]
Avoiding fiddly logical proofs by brute-force case analysis, possibly only over a key term as in the above example, possibly over all free boolean variables.
See also
Tactic.ASM_CASES_TAC,
Tactic.COND_CASES_TAC,
Tactic.DISJ_CASES_TAC,
Tactic.STRUCT_CASES_TAC
CCONTR_TAC
CCONTR_TAC
Tactic.CCONTR_TAC : tactic
Assumes the negation of the conclusion of a goal.
Given a goal A ?- t, CCONTR_TAC makes a new goal which is to prove
F by assuming also the negation of the conclusion t.
A ?- t
==========
A, -t ?- F
Failure
Never fails
See also
Tactic.CHECK_ASSUME_TAC,
Thm.CCONTR, Drule.CONTRAPOS,
Thm.NOT_ELIM
CHECK_ASSUME_TAC
CHECK_ASSUME_TAC
Tactic.CHECK_ASSUME_TAC : thm_tactic
Adds a theorem to the assumption list of goal, unless it solves the goal.
When applied to a theorem A' |- s and a goal A ?- t, the tactic
CHECK_ASSUME_TAC checks whether the theorem will solve the goal (this
includes the possibility that the theorem is just A' |- F). If so, the
goal is duly solved. If not, the theorem is added to the assumptions of
the goal, unless it is already there.
A ?- t
============== CHECK_ASSUME_TAC (A' |- F) [special case 1]
A ?- t
============== CHECK_ASSUME_TAC (A' |- t) [special case 2]
A ?- t
============== CHECK_ASSUME_TAC (A' |- s) [general case]
A u {s} ?- t
Unless A' is a subset of A, the tactic will be invalid, although it
will not fail.
Failure
Never fails.
See also
Tactic.ACCEPT_TAC,
Tactic.ASSUME_TAC,
Tactic.CONTR_TAC,
Tactic.DISCARD_TAC,
Tactic.MATCH_ACCEPT_TAC
CHOOSE_TAC
CHOOSE_TAC
Tactic.CHOOSE_TAC : thm_tactic
Adds the body of an existentially quantified theorem to the assumptions of a goal.
When applied to a theorem A' |- ?x. t and a goal, CHOOSE_TAC adds
t[x'/x] to the assumptions of the goal, where x' is a variant of x
which is not free in the goal or assumption list; normally x' is just
x.
A ?- u
==================== CHOOSE_TAC (A' |- ?x. t)
A u {t[x'/x]} ?- u
Unless A' is a subset of A, this is not a valid tactic.
Failure
Fails unless the given theorem is existentially quantified.
Example
Suppose we have a goal asserting that the output of an electrical circuit (represented as a boolean-valued function) will become high at some time:
?- ?t. output(t)
and we have the following theorems available:
t1 = |- ?t. input(t)
t2 = !t. input(t) ==> output(t+1)
Then the goal can be solved by the application of:
CHOOSE_TAC th1
THEN EXISTS_TAC (Term `t+1`)
THEN UNDISCH_TAC (Term `input (t:num) :bool`)
THEN MATCH_ACCEPT_TAC th2
Comments
To do similarly with several existentially quantified variables, use
REPEAT_TCL CHOOSE_THEN ASSUME_TAC in place of CHOOSE_TAC
See also
Thm_cont.CHOOSE_THEN,
Tactic.X_CHOOSE_TAC,
Thm_cont.REPEAT_TCL
COND_CASES_TAC
COND_CASES_TAC
Tactic.COND_CASES_TAC : tactic
Induces a case split on a conditional expression in the goal.
COND_CASES_TAC searches for a conditional sub-term in the term of a
goal, i.e. a sub-term of the form p=>u|v, choosing one by its own
criteria if there is more than one. It then induces a case split over
p as follows:
A ?- t
============================================================== COND_CASES_TAC
A u {p} ?- t[u/(p=>u|v),T/p] A u {~p} ?- t[v/(p=>u|v),F/p]
where p is not a constant, and the term p=>u|v is free in t. Note
that it both enriches the assumptions and inserts the assumed value into
the conditional.
Failure
COND_CASES_TAC fails if there is no conditional sub-term as described
above.
Example
For "x", "y", "z1" and "z2" of type ":*", and "P:*->bool",
COND_CASES_TAC ([], "x = (P y => z1 | z2)");;
([(["P y"], "x = z1"); (["~P y"], "x = z2")], -) : subgoals
but it fails, for example, if "y" is not free in the term part of the
goal:
COND_CASES_TAC ([], "!y. x = (P y => z1 | z2)");;
evaluation failed COND_CASES_TAC
In contrast, ASM_CASES_TAC does not perform the replacement:
ASM_CASES_TAC "P y" ([], "x = (P y => z1 | z2)");;
([(["P y"], "x = (P y => z1 | z2)"); (["~P y"], "x = (P y => z1 | z2)")],
-)
: subgoals
Useful for case analysis and replacement in one step, when there is a
conditional sub-term in the term part of the goal. When there is more
than one such sub-term and one in particular is to be analyzed,
COND_CASES_TAC cannot be depended on to choose the 'desired' one. It
can, however, be used repeatedly to analyze all conditional sub-terms of
a goal.
See also
Tactic.ASM_CASES_TAC,
Tactic.DISJ_CASES_TAC,
Tactic.STRUCT_CASES_TAC
CONJ_ASM1_TAC
CONJ_ASM1_TAC
Tactic.CONJ_ASM1_TAC : tactic
Reduces a conjunctive goal to two subgoals: prove the first conjunct, then the second assuming the first.
When applied to a goal A ?- t1 /\ t2, the tactic CONJ_ASM1_TAC
reduces it to two subgoals corresponding to the first conjunct then the
second conjunct.
A ?- t1 /\ t2
========================== CONJ_ASM1_TAC
A ?- t1 A u {t1} ?- t2
Failure
Fails unless the conclusion of the goal is a conjunction.
See also
Tactic.CONJ_ASM2_TAC,
Tactic.CONJ_TAC,
Tactical.USE_SG_THEN
CONJ_ASM2_TAC
CONJ_ASM2_TAC
Tactic.CONJ_ASM2_TAC : tactic
Reduces a conjunctive goal to two subgoals: prove the first conjunct assuming the second, then prove the second conjunct.
When applied to a goal A ?- t1 /\ t2, the tactic CONJ_ASM2_TAC
reduces it to two subgoals corresponding to the two conjuncts, assuming
the first to prove the second.
A ?- t1 /\ t2
========================== CONJ_ASM2_TAC
A u {t2} ?- t1 A ?- t2
Failure
Fails unless the conclusion of the goal is a conjunction.
See also
Tactic.CONJ_ASM1_TAC,
Tactic.CONJ_TAC,
Tactical.USE_SG_THEN
CONJ_TAC
CONJ_TAC
Tactic.CONJ_TAC : tactic
Reduces a conjunctive goal to two separate subgoals.
When applied to a goal A ?- t1 /\ t2, the tactic CONJ_TAC reduces it
to the two subgoals corresponding to each conjunct separately.
A ?- t1 /\ t2
====================== CONJ_TAC
A ?- t1 A ?- t2
Failure
Fails unless the conclusion of the goal is a conjunction.
See also
CONTR_TAC
CONTR_TAC
Tactic.CONTR_TAC : thm_tactic
Solves any goal from contradictory theorem.
When applied to a contradictory theorem A' |- F, and a goal A ?- t,
the tactic CONTR_TAC completely solves the goal. This is an invalid
tactic unless A' is a subset of A.
A ?- t
======== CONTR_TAC (A' |- F)
Failure
Fails unless the theorem is contradictory, i.e. has F as its
conclusion.
See also
Tactic.CHECK_ASSUME_TAC,
Drule.CONTR, Thm.CCONTR,
Drule.CONTRAPOS, Thm.NOT_ELIM
CONV_TAC
CONV_TAC
Tactic.CONV_TAC : (conv -> tactic)
Makes a tactic from a conversion.
If c is a conversion, then CONV_TAC c is a tactic that applies c
to the goal. That is, if c maps a term "g" to the theorem
|- g = g', then the tactic CONV_TAC c reduces a goal g to the
subgoal g'. More precisely, if c "g" returns A' |- g = g', then:
A ?- g
=============== CONV_TAC c
A ?- g'
If c raises UNCHANGED then CONV_TAC c reduces a goal to itself.
Note that the conversion c should return a theorem whose assumptions
are also among the assumptions of the goal (normally, the conversion
will returns a theorem with no assumptions). CONV_TAC does not fail if
this is not the case, but the resulting tactic will be invalid, so the
theorem ultimately proved using this tactic will have more assumptions
than those of the original goal.
Failure
CONV_TAC c applied to a goal A ?- g fails if c fails (other than
by raising UNCHANGED) when applied to the term g. The function
returned by CONV_TAC c will also fail if the ML function c:term->thm
is not, in fact, a conversion (i.e. a function that maps a term t to a
theorem |- t = t').
CONV_TAC is used to apply simplifications that can't be expressed as
equations (rewrite rules). For example, a goal can be simplified by
beta-reduction, which is not expressible as a single equation, using the
tactic
CONV_TAC(DEPTH_CONV BETA_CONV)
The conversion BETA_CONV maps a beta-redex "(\x.u)v" to the theorem
|- (\x.u)v = u[v/x]
and the ML expression (DEPTH_CONV BETA_CONV) evaluates to a conversion
that maps a term "t" to the theorem |- t=t' where t' is obtained
from t by beta-reducing all beta-redexes in t. Thus
CONV_TAC(DEPTH_CONV BETA_CONV) is a tactic which reduces beta-redexes
anywhere in a goal.
See also
Abbrev.conv, Conv.UNCHANGED,
Conv.CONV_RULE
DEEP_INTRO_TAC
DEEP_INTRO_TAC
Tactic.DEEP_INTRO_TAC : thm -> tactic
Applies an introduction-rule backwards; instantiating a predicate variable.
The function DEEP_INTRO_TAC expects a theorem of the form
antecedents ==> P (term-pattern)
where P is a variable, and term-pattern is a pattern describing the
form of an expected sub-term in the goal. When th is of this form, the
tactic DEEP_INTRO_TAC th finds a higher-order instantiation for the
variable P and a first order instantiation for the variables in
term-pattern such that the instantiated conclusion of th is
identical to the goal. It then applies MATCH_MP_TAC to turn the goal
into an instantiation of the antecedents of th.
Failure
Fails if there is no (free) instance of term-pattern in the goal. Also
fails if th is not of the required form.
Example
The theorem SELECT_ELIM_THM states
|- !P Q. (?x. P x) /\ (!x. P x ==> Q x) ==> Q ($@ P)
This is of the required form for use by DEEP_INTRO_TAC, and can be
used to transform a goal mentioning Hilbert Choice (the @ operator)
into one that doesn't. Indeed, this is how SELECT_ELIM_TAC is
implemented.
See also
Tactic.MATCH_MP_TAC,
Tactic.SELECT_ELIM_TAC
DISCARD_TAC
DISCARD_TAC
Tactic.DISCARD_TAC : thm_tactic
Discards a theorem already present in a goal's assumptions.
When applied to a theorem A' |- s and a goal, DISCARD_TAC checks
that s is simply T (true), or already exists (up to
alpha-conversion) in the assumption list of the goal. In either case,
the tactic has no effect. Otherwise, it fails.
A ?- t
======== DISCARD_TAC (A' |- s)
A ?- t
Failure
Fails if the above conditions are not met, i.e. the theorem's conclusion
is not T or already in the assumption list (up to alpha-conversion).
See also
Tactical.POP_ASSUM,
Tactical.POP_ASSUM_LIST
DISCH_TAC
DISCH_TAC
Tactic.DISCH_TAC : tactic
Moves the antecedent of an implicative goal into the assumptions.
A ?- u ==> v
============== DISCH_TAC
A u {u} ?- v
Note that DISCH_TAC treats ~u as u ==> F, so will also work when
applied to a goal with a negated conclusion.
Failure
DISCH_TAC will fail for goals which are not implications or negations.
Solving goals of the form u ==> v by rewriting v with u, although
the use of DISCH_THEN is usually more elegant in such cases.
Comments
If the antecedent already appears in the assumptions, it will be duplicated.
See also
Thm.DISCH, Drule.DISCH_ALL,
Thm_cont.DISCH_THEN,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Drule.NEG_DISCH,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
DISJ1_TAC
DISJ1_TAC
Tactic.DISJ1_TAC : tactic
Selects the left disjunct of a disjunctive goal.
A ?- t1 \/ t2
=============== DISJ1_TAC
A ?- t1
Failure
Fails if the goal is not a disjunction.
See also
Thm.DISJ1, Thm.DISJ2,
Tactic.DISJ2_TAC
DISJ2_TAC
DISJ2_TAC
Tactic.DISJ2_TAC : tactic
Selects the right disjunct of a disjunctive goal.
A ?- t1 \/ t2
=============== DISJ2_TAC
A ?- t2
Failure
Fails if the goal is not a disjunction.
See also
Thm.DISJ1, Tactic.DISJ1_TAC,
Thm.DISJ2
DISJ_CASES_TAC
DISJ_CASES_TAC
Tactic.DISJ_CASES_TAC : thm_tactic
Produces a case split based on a disjunctive theorem.
Given a theorem th of the form A |- u \/ v, DISJ_CASES_TAC th
applied to a goal produces two subgoals, one with u as an assumption
and one with v:
A ?- t
============================ DISJ_CASES_TAC (A |- u \/ v)
A u {u} ?- t A u {v}?- t
Failure
Fails if the given theorem does not have a disjunctive conclusion.
Example
Given the simple fact about arithmetic th,
|- (m = 0) \/ (?n. m = SUC n), the tactic DISJ_CASES_TAC th can be
used to produce a case split:
- DISJ_CASES_TAC th ([],Term`(P:num -> bool) m`);
([([`m = 0`], `P m`),
([`?n. m = SUC n`], `P m`)], fn) : tactic_result
Performing a case analysis according to a disjunctive theorem.
See also
Tactic.ASSUME_TAC,
Tactic.ASM_CASES_TAC,
Tactic.COND_CASES_TAC,
Thm_cont.DISJ_CASES_THEN,
Tactic.STRUCT_CASES_TAC
drule
drule
Tactic.drule : thm -> tactic
Performs one step of resolution (or modus ponens) against implication theorem.
If theorem th is of the form A |- t, where t is of the form
!x1..xn. P .. /\ ... ==> Q or !x1..xn. P .. ==> Q, then a call to
drule th (asl,g) looks for an assumption in asl that matches the
pattern P .. in t. It then performs instantiation of th's
universally quantified and free variables, transforms any conjunctions
on the left into a minimal number of chained implications, and calls
MP once to generate a consequent theorem A |- t'. This theorem is
then passed to MP_TAC, turning the goal into (asl, t' ==> g). (We
assume that A is a subset of asl; otherwise the tactic is invalid.)
Failure
A call to drule th (asl,g) will fail if th is not a (possibly
universally quantified) implication (or negation), or if there are no
assumptions in asl matching the "first" hypothesis of th.
Example
The DIV_LESS theorem states:
!n d. 0 < n /\ 1 < d ==> (n DIV d < n)
Then:
> drule arithmeticTheory.DIV_LESS ([“1 < x”, “0 < y”], “P:bool”);
val it =
([([“1 < x”, “0 < y”], “(!d. 1 < d ==> y DIV d < y) ==> P”)], fn):
goal list * validation
Comments
The drule tactic is similar to, but a great deal more controlled than,
the IMP_RES_TAC tactic, which will look for a great many more possible
instantiations and resolutions to perform. IMP_RES_TAC also puts all
of its derived consequences into the assumption list; drule can be
sure that there will be just one such consequence, and puts this into
the goal directly.
The related dxrule tactic removes the matching assumption from the
assumption list. In this example above, the resulting assumption list
would just contain 1 < x, having lost the 0 < y which was resolved
against the DIV_LESS theorem.
The drule tactic uses the MP_TAC thm_tactic as its fixed
continuation; the drule_then variation takes a thm_tactic
continuation as its first parameter and applies this to the result of
the instantiation and MP call. There is also a dxrule_then, that
combines both variations described here.
Finally, note that the implicational theorem may itself have come from
the goal's assumptions, extracted with tools such as FIRST_ASSUM and
PAT_ASSUM.
See also
Tactic.drule_all,
Tactic.IMP_RES_TAC
drule_all
drule_all
Tactic.drule_all : thm -> tactic
Attempts to discharge all of a theorem's antecedents from assumptions
If th is a theorem with a conclusion that is a (possibly universally
quantified) implication (or negation), the theorem-tactic drule_all
(implicitly) normalises it have form
!v1 .. vn. P1 ==> (P2 ==> (P3 ==> ... Q)...)
where each Pi is not a conjunction. (In other words, P /\ Q ==> R is
normalised to P ==> (Q ==> R).) An application of drule_all th to a
goal then attempts to find a consistent instantiation so that all of the
Pi antecedents can be discharged by appeal to the goal's assumptions.
If this repeated instantiation and use of MP is possible, then the
(instantiated) conclusion Q is added to the goal with the MP_TAC
thm_tactic.
When finding assumptions, those that have been most recently added to the assumption list will be preferred.
Failure
An invocation of drule_all th can only fail when applied to a goal. It
can then fail if th is not an implication, or if all of th's
implications cannot be eliminated by matching against the goal's
assumptions.
Example
The LESS_LESS_EQ_TRANS theorem states:
!m n p. m < n /\ n <= p ==> m < p
Then:
> drule_all arithmeticTheory.LESS_LESS_EQ_TRANS
([“x < w”, “1 < x”, “z <= y”, “x <= z”, “y < z”], “P:bool”);
val it =
([([“x < w”, “1 < x”, “z <= y”, “x <= z”, “y < z”],
“1 < z ==> P”)], fn): goal list * validation
Note how the other possible instance of the theorem (chaining y < z
and z <= y) is not found.
Comments
The variant dxrule_all removes used assumptions from the assumption
list as they resolve against the theorem. The variant drule_all_then
allows a continuation other than MP_TAC to be used. The variant
dxrule_all_then combines both.
A negated conclusion (~Q) is not treated as an implication (Q ==> F)
so the tactic will not attempt to find an instantiation of Q among the
assumptions.
See also
Tactic.drule,
Tactic.IMP_RES_TAC
EQ_MP_TAC
EQ_MP_TAC
Tactic.EQ_MP_TAC : thm -> tactic
A tactic that reverses EQ_MP, requiring proof of an equality.
A call to EQ_MP_TAC th, with th's conclusion being boolean term p,
changes a goal (G, q) to be (G,p <=> q). If p <=> q is indeed
provable, then an application of EQ_MP to that theorem and the
provided th will be a proof of q (all in the context of assumptions
G).
Failure
Never fails.
Example
> EQ_MP_TAC (CONJ TRUTH TRUTH) ([], “p ∧ q”);
val it = ([([], “T ∧ T ⇔ p ∧ q”)], fn): goal list * validation
Comments
Application of this tactic might be a prelude to showing that a number
of sub-terms from the theorem's conclusion and the goal are equal (with
tactics such as AP_TERM_TAC and CONG_TAC).
See also
Tactic.AP_TERM_TAC,
Tactic.AP_THM_TAC,
Tactic.CONG_TAC, Thm.EQ_MP,
Tactic.MP_TAC
EQ_TAC
EQ_TAC
Tactic.EQ_TAC : tactic
Reduces goal of equality of boolean terms to forward and backward implication.
When applied to a goal A ?- t1 = t2, where t1 and t2 have type
bool, the tactic EQ_TAC returns the subgoals A ?- t1 ==> t2 and
A ?- t2 ==> t1.
A ?- t1 = t2
================================= EQ_TAC
A ?- t1 ==> t2 A ?- t2 ==> t1
Failure
Fails unless the conclusion of the goal is an equation between boolean terms.
Comments
Also available under the names eq_tac and iff_tac.
See also
Thm.EQ_IMP_RULE,
Drule.IMP_ANTISYM_RULE
EXISTS_TAC
EXISTS_TAC
Tactic.EXISTS_TAC : (term -> tactic)
Reduces existentially quantified goal to one involving a specific witness.
When applied to a term u and a goal ?x. t, the tactic EXISTS_TAC
reduces the goal to t[u/x] (substituting u for all free instances of
x in t, with variable renaming if necessary to avoid free variable
capture).
A ?- ?x. t
============= EXISTS_TAC "u"
A ?- t[u/x]
Failure
Fails unless the goal's conclusion is existentially quantified and the term supplied has the same type as the quantified variable in the goal.
Example
The goal:
?- ?x. x=T
can be solved by:
EXISTS_TAC ``T`` THEN REFL_TAC
See also
FILTER_DISCH_TAC
FILTER_DISCH_TAC
Tactic.FILTER_DISCH_TAC : (term -> tactic)
Conditionally moves the antecedent of an implicative goal into the assumptions.
FILTER_DISCH_TAC will move the antecedent of an implication into the
assumptions, provided its parameter does not occur in the antecedent.
A ?- u ==> v
============== FILTER_DISCH_TAC w
A u {u} ?- v
Note that DISCH_TAC treats ~u as u ==> F. Unlike DISCH_TAC, the
antecedent will be STRIPed into its various components before being
ASSUMEd. This stripping includes generating multiple goals for
case-analysis of disjunctions. Also, unlike DISCH_TAC, should any
component of the discharged antecedent directly imply or contradict the
goal, then this simplification will also be made. Again, unlike
DISCH_TAC, FILTER_DISCH_TAC will not duplicate identical or
alpha-equivalent assumptions.
Failure
FILTER_DISCH_TAC will fail if a term which is identical, or
alpha-equivalent to w occurs free in the antecedent, or if the theorem
is not an implication or a negation.
Comments
FILTER_DISCH_TAC w behaves like
FILTER_DISCH_THEN STRIP_ASSUME_TAC w.
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Tactic.FILTER_DISCH_THEN,
Drule.NEG_DISCH,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
FILTER_DISCH_THEN
FILTER_DISCH_THEN
Tactic.FILTER_DISCH_THEN : (thm_tactic -> term -> tactic)
Conditionally gives to a theorem-tactic the antecedent of an implicative goal.
If FILTER_DISCH_THEN's second argument, a term, does not occur in the
antecedent, then FILTER_DISCH_THEN removes the antecedent and then
creates a theorem by ASSUMEing it. This new theorem is passed to
FILTER_DISCH_THEN's first argument, which is subsequently expanded.
For example, if
A ?- t
======== f (ASSUME u)
B ?- v
then
A ?- u ==> t
============== FILTER_DISCH_THEN f
B ?- v
Note that FILTER_DISCH_THEN treats ~u as u ==> F.
Failure
FILTER_DISCH_THEN will fail if a term which is identical, or
alpha-equivalent to w occurs free in the antecedent.
FILTER_DISCH_THEN will also fail if the theorem is an implication or a
negation.
Comments
FILTER_DISCH_THEN is most easily understood by first understanding
DISCH_THEN.
For preprocessing an antecedent before moving it to the assumptions, or for using antecedents and then throwing them away.
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Tactic.FILTER_DISCH_TAC,
Drule.NEG_DISCH,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
FILTER_GEN_TAC
FILTER_GEN_TAC
Tactic.FILTER_GEN_TAC : (term -> tactic)
Strips off a universal quantifier, but fails for a given quantified variable.
When applied to a term s and a goal A ?- !x. t, the tactic
FILTER_GEN_TAC fails if the quantified variable x is the same as
s, but otherwise advances the goal in the same way as GEN_TAC,
i.e. returns the goal A ?- t[x'/x] where x' is a variant of x
chosen to avoid clashing with any variables free in the goal's
assumption list. Normally x' is just x.
A ?- !x. t
============== FILTER_GEN_TAC "s"
A ?- t[x'/x]
Failure
Fails if the goal's conclusion is not universally quantified or the quantified variable is equal to the given term.
See also
Thm.GEN, Tactic.GEN_TAC,
Thm.GENL, Drule.GEN_ALL,
Thm.SPEC, Drule.SPECL,
Drule.SPEC_ALL,
Tactic.SPEC_TAC,
Tactic.STRIP_TAC
FILTER_STRIP_TAC
FILTER_STRIP_TAC
Tactic.FILTER_STRIP_TAC : term -> tactic
Conditionally strips apart a goal by eliminating the outermost connective.
Stripping apart a goal in a more careful way than is done by STRIP_TAC
may be necessary when dealing with quantified terms and implications.
FILTER_STRIP_TAC behaves like STRIP_TAC, but it does not strip apart
a goal if it contains a given term.
If u is a term, then FILTER_STRIP_TAC u is a tactic that removes one
outermost occurrence of one of the connectives !, ==>, ~ or /\
from the conclusion of the goal t, provided the term being stripped
does not contain u. A negation ~t is treated as the implication
t ==> F. FILTER_STRIP_TAC u also breaks apart conjunctions without
applying any filtering.
If t is a universally quantified term, FILTER_STRIP_TAC u strips off
the quantifier:
A ?- !x.v
================ FILTER_STRIP_TAC ``u`` [where x is not u]
A ?- v[x'/x]
where x' is a primed variant that does not appear free in the
assumptions A. If t is a conjunction, no filtering is done and
FILTER_STRIP_TAC u simply splits the conjunction:
A ?- v /\ w
================= FILTER_STRIP_TAC ``u``
A ?- v A ?- w
If t is an implication and the antecedent does not contain a free
instance of u, then FILTER_STRIP_TAC u moves the antecedent into the
assumptions and recursively splits the antecedent according to the
following rules (see STRIP_ASSUME_TAC):
A ?- v1 /\ ... /\ vn ==> v A ?- v1 \/ ... \/ vn ==> v
============================ =================================
A u {v1,...,vn} ?- v A u {v1} ?- v ... A u {vn} ?- v
A ?- ?x.w ==> v
====================
A u {w[x'/x]} ?- v
where x' is a variant of x.
Failure
FILTER_STRIP_TAC u (A,t) fails if t is not a universally quantified
term, an implication, a negation or a conjunction; or if the term being
stripped contains u in the sense described above (conjunction
excluded).
Example
When trying to solve the goal
?- !n. m <= n /\ n <= m ==> (m = n)
the universally quantified variable n can be stripped off by using
FILTER_STRIP_TAC ``m:num``
and then the implication can be stripped apart by using
FILTER_STRIP_TAC ``m:num = n``
FILTER_STRIP_TAC is used when stripping outer connectives from a goal
in a more delicate way than STRIP_TAC. A typical application is to
keep stripping by using the tactic REPEAT (FILTER_STRIP_TAC u) until
one hits the term u at which stripping is to stop.
See also
Tactic.CONJ_TAC,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.FILTER_GEN_TAC,
Tactic.STRIP_ASSUME_TAC,
Tactic.STRIP_TAC
FILTER_STRIP_THEN
FILTER_STRIP_THEN
Tactic.FILTER_STRIP_THEN : (thm_tactic -> term -> tactic)
Conditionally strips a goal, handing an antecedent to the theorem-tactic.
Given a theorem-tactic ttac, a term u and a goal (A,t),
FILTER_STRIP_THEN ttac u removes one outer connective (!, ==>, or
~) from t, if the term being stripped does not contain a free
instance of u. A negation ~t is treated as the implication
t ==> F. The theorem-tactic ttac is applied only when stripping an
implication, by using the antecedent stripped off. FILTER_STRIP_THEN
also breaks conjunctions.
FILTER_STRIP_THEN behaves like STRIP_GOAL_THEN, if the term being
stripped does not contain a free instance of u. In particular,
FILTER_STRIP_THEN STRIP_ASSUME_TAC behaves like FILTER_STRIP_TAC.
Failure
FILTER_STRIP_THEN ttac u (A,t) fails if t is not a universally
quantified term, an implication, a negation or a conjunction; or if the
term being stripped contains the term u (conjunction excluded); or if
the application of ttac fails, after stripping the goal.
Example
When solving the goal
?- (n = 1) ==> (n * n = n)
the application of FILTER_STRIP_THEN SUBST1_TAC "m:num" results in the
goal
?- 1 * 1 = 1
FILTER_STRIP_THEN is used when manipulating intermediate results using
theorem-tactics, after stripping outer connectives from a goal in a more
delicate way than STRIP_GOAL_THEN.
See also
Tactic.CONJ_TAC,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.FILTER_GEN_TAC,
Tactic.FILTER_STRIP_TAC,
Tactic.STRIP_ASSUME_TAC,
Tactic.STRIP_GOAL_THEN
FREEZE_THEN
FREEZE_THEN
Tactic.FREEZE_THEN : thm_tactical
'Freezes' a theorem to prevent instantiation of its free variables.
FREEZE_THEN expects a tactic-generating function f:thm->tactic and a
theorem (A1 |- w) as arguments. The tactic-generating function f is
applied to the theorem (w |- w). If this tactic generates the subgoal:
A0 ?- t
========= f (w |- w)
A ?- t1
then applying FREEZE_THEN f (A1 |- w) to the goal (A0 ?- t) produces
the subgoal:
A0 ?- t
=================== FREEZE_THEN f (A1 |- w)
A - {w}, A1 ?- t1
Since the term w is a hypothesis of the argument to the function f,
none of the free variables present in w may be instantiated or
generalized. The hypothesis is discharged by PROVE_HYP upon the
completion of the proof of the subgoal.
Failure
Failures may arise from the tactic-generating function. An invalid tactic arises if the hypotheses of the theorem are not alpha-convertible to assumptions of the goal.
Example
Given the goal ([ ``b < c``, ``a < b`` ], ``SUC a <= c``), and
the specialized variant of the theorem LESS_TRANS:
th = |- !p. a < b /\ b < p ==> a < p
IMP_RES_TAC th will generate several unneeded assumptions:
{b < c, a < b, a < c, !p. c < p ==> b < p, !a'. a' < a ==> a' < b}
?- SUC a <= c
which can be avoided by first 'freezing' the theorem, using the tactic
FREEZE_THEN IMP_RES_TAC th
This prevents the variables a and b from being instantiated.
{b < c, a < b, a < c} ?- SUC a <= c
Used in serious proof hacking to limit the matches achievable by resolution and rewriting.
See also
Thm.ASSUME,
Tactic.IMP_RES_TAC,
Drule.PROVE_HYP,
Tactic.RES_TAC, Conv.REWR_CONV
FULL_STRUCT_CASES_TAC
FULL_STRUCT_CASES_TAC
Tactic.FULL_STRUCT_CASES_TAC : thm_tactic
A form of STRUCT_CASES_TAC that also applies the case analysis to the
assumption list.
See STRUCT_CASES_TAC.
Failure
Fails unless provided with a theorem that is a conjunction of (possibly multiply existentially quantified) terms which assert the equality of a variable with some given terms.
Example
Suppose we have the goal:
~(l:(*)list = []) ?- (LENGTH l) > 0
then we can get rid of the universal quantifier from the inbuilt list
theorem list_CASES:
list_CASES = !l. (l = []) \/ (?t h. l = CONS h t)
and then use FULL_STRUCT_CASES_TAC. This amounts to applying the
following tactic:
FULL_STRUCT_CASES_TAC (SPEC_ALL list_CASES)
which results in the following two subgoals:
~(CONS h t = []) ?- (LENGTH(CONS h t)) > 0
~([] = []) ?- (LENGTH[]) > 0
Note that this is a rather simple case, since there are no constraints, and therefore the resulting subgoals have no extra assumptions.
Generating a case split from the axioms specifying a structure.
See also
Tactic.ASM_CASES_TAC,
Tactic.BOOL_CASES_TAC,
Tactic.COND_CASES_TAC,
Tactic.DISJ_CASES_TAC,
Tactic.STRUCT_CASES_TAC
GEN_TAC
GEN_TAC
Tactic.GEN_TAC : tactic
Strips the outermost universal quantifier from the conclusion of a goal.
When applied to a goal A ?- !x. t, the tactic GEN_TAC reduces it to
A ?- t[x'/x] where x' is a variant of x chosen to avoid clashing
with any variables free in the goal's assumption list. Normally x' is
just x.
A ?- !x. t
============== GEN_TAC
A ?- t[x'/x]
Failure
Fails unless the goal's conclusion is universally quantified.
The tactic REPEAT GEN_TAC strips away any universal quantifiers, and
is commonly used before tactics relying on the underlying term
structure.
See also
Tactic.FILTER_GEN_TAC,
Thm.GEN, Thm.GENL,
Drule.GEN_ALL, Thm.SPEC,
Drule.SPECL, Drule.SPEC_ALL,
Tactic.SPEC_TAC,
Tactic.STRIP_TAC,
Tactic.X_GEN_TAC
GSUBST_TAC
GSUBST_TAC
Tactic.GSUBST_TAC : ((term * term) list -> term -> term) -> thm list -> tactic
Makes term substitutions in a goal using a supplied substitution function.
GSUBST_TAC is the basic substitution tactic by means of which other
tactics such as SUBST_OCCS_TAC and SUBST_TAC are defined. Given a
list [(v1,w1),...,(vk,wk)] of pairs of terms and a term w, a
substitution function replaces occurrences of wj in w with vj
according to a specific substitution criterion. Such a criterion may be,
for example, to substitute all the occurrences or only some selected
ones of each wj in w.
Given a substitution function sfn,
GSUBST_TAC sfn [A1|-t1=u1,...,An|-tn=un] (A,t) replaces occurrences of
ti in t with ui according to sfn.
A ?- t
============================= GSUBST_TAC sfn [A1|-t1=u1,...,An|-tn=un]
A ?- t[u1,...,un/t1,...,tn]
The assumptions of the theorems used to substitute with are not added to
the assumptions A of the goal, while they are recorded in the proof.
If any Ai is not a subset of A (up to alpha-conversion), then
GSUBST_TAC sfn [A1|-t1=u1,...,An|-tn=un] results in an invalid tactic.
GSUBST_TAC automatically renames bound variables to prevent free
variables in ui becoming bound after substitution.
Failure
GSUBST_TAC sfn [th1,...,thn] (A,t) fails if the conclusion of each
theorem in the list is not an equation. No change is made to the goal if
the occurrences to be substituted according to the substitution function
sfn do not appear in t.
GSUBST_TAC is used to define substitution tactics such as
SUBST_OCCS_TAC and SUBST_TAC. It may also provide the user with a
tool for tailoring substitution tactics.
See also
Tactic.SUBST1_TAC,
Tactic.SUBST_OCCS_TAC,
Tactic.SUBST_TAC
HINT_EXISTS_TAC
HINT_EXISTS_TAC
Tactic.HINT_EXISTS_TAC : tactic
Reduces an existentially quantified goal by finding a witness which, from the assumption list, satisfies at least partially the body of the existential.
When applied to a goal ?x. t1 /\ ... /\ tn, the tactic
HINT_EXISTS_TAC looks for an assumption of the form ti[u/x], where
i belongs to 1..n, and reduces the goal by taking u as a witness
for x.
Failure
Fails unless the goal contains an assumption of the expected form.
Example
-
The goal:
b = 0, a < 1, c > 0 ?- ?x. x < 1
is turned by HINT_EXISTS_TAC into:
b = 0, a < 1, c > 0 ?- a < 1
-
However the tactic also allows to make progress if only one conjunct of the existential is satisfied. For instance, the goal:
b = 0, a < 1, c > 0 ?- ?x. x < 1 /\ x + x = c
is turned by HINT_EXISTS_TAC into:
b = 0, a < 1, c > 0 ?- a < 1 /\ a + a = c
-
The location of the conjunct does not matter, the goal:
b = 0, a < 1, c > 0 ?- ?x. x + x = c /\ x < 1
is turned by HINT_EXISTS_TAC into:
b = 0, a < 1, c > 0 ?- a + a = c /\ a < 1
-
It can be convenient to chain the call to
HINT_EXISTS_TACwith one toASM_REWRITE_TACin order to remove automatically the satisfied conjunct:b = 0, a < 1, c > 0 ?- ?x. x + x = c /\ x < 1
is turned by HINT_EXISTS_TAC THEN ASM_REWRITE_TAC[] into:
b = 0, a < 1, c > 0 ?- a + a = c
Avoid providing a witness explicitly, in order to make the tactic script less fragile.
See also
HO_MATCH_MP_TAC
HO_MATCH_MP_TAC
Tactic.HO_MATCH_MP_TAC : thm_tactic
Reduces the goal using a supplied implication, with higher-order matching.
When applied to a theorem of the form
A' |- !x1...xn. s ==> t
HO_MATCH_MP_TAC produces a tactic that reduces a goal whose conclusion
t' is a substitution and/or type instance of t to the corresponding
instance of s. Any variables free in s but not in t will be
existentially quantified in the resulting subgoal:
A ?- t'
====================== HO_MATCH_MP_TAC (A' |- !x1...xn. s ==> t)
A ?- ?z1...zp. s'
where z1, ..., zp are (type instances of) those variables among
x1, ..., xn that do not occur free in t. Note that this is not a
valid tactic unless A' is a subset of A.
Example
The following goal might be solved by case analysis:
> g `!n:num. n <= n * n`;
We can "manually" perform induction by using the following theorem:
> numTheory.INDUCTION;
- val it : thm = |- !P. P 0 /\ (!n. P n ==> P (SUC n)) ==> (!n. P n)
which is useful with HO_MATCH_MP_TAC because of higher-order matching:
> e(HO_MATCH_MP_TAC numTheory.INDUCTION);
- val it : goalstack = 1 subgoal (1 total)
`0 <= 0 * 0 /\ (!n. n <= n * n ==> SUC n <= SUC n * SUC n)`
The goal can be finished with SIMP_TAC arith_ss [].
Failure
Fails unless the theorem is an (optionally universally quantified) implication whose consequent can be instantiated to match the goal.
See also
Tactic.MATCH_MP_TAC,
bossLib.Induct_on, Thm.EQ_MP,
Drule.MATCH_MP, Thm.MP,
Tactic.MP_TAC,
ConseqConv.CONSEQ_CONV_TAC
IMP_RES_TAC
IMP_RES_TAC
Tactic.IMP_RES_TAC : thm_tactic
Enriches assumptions by repeatedly resolving an implication with them.
Given a theorem th, the theorem-tactic IMP_RES_TAC uses RES_CANON
to derive a canonical list of implications, each of which has the form:
A |- u1 ==> u2 ==> ... ==> un ==> v
IMP_RES_TAC then tries to repeatedly 'resolve' these theorems against
the assumptions of a goal by attempting to match the antecedents u1,
u2, ..., un (in that order) to some assumption of the goal (i.e. to
some candidate antecedents among the assumptions). If all the
antecedents can be matched to assumptions of the goal, then an instance
of the theorem
A u {a1,...,an} |- v
called a 'final resolvent' is obtained by repeated specialization of the
variables in the implicative theorem, type instantiation, and
applications of modus ponens. If only the first i antecedents u1,
..., ui can be matched to assumptions and then no further matching is
possible, then the final resolvent is an instance of the theorem:
A u {a1,...,ai} |- u(i+1) ==> ... ==> v
All the final resolvents obtained in this way (there may be several,
since an antecedent ui may match several assumptions) are added to the
assumptions of the goal, in the stripped form produced by using
STRIP_ASSUME_TAC. If the conclusion of any final resolvent is a
contradiction 'F' or is alpha-equivalent to the conclusion of the
goal, then IMP_RES_TAC solves the goal.
Failure
Never fails.
See also
Tactic.drule,
Thm_cont.IMP_RES_THEN,
Drule.RES_CANON,
Tactic.RES_TAC,
Thm_cont.RES_THEN
impl_keep_tac
impl_keep_tac
Tactic.impl_keep_tac : tactic
Implements a version of implication-left sequent calculus rule as tactic
Given a goal of the form A ?- ((p ==> q) ==> r), an application of
impl_tac will produce two sub-goals: A ?- p and A, p ?- (q ==> r).
This can be useful if p should be dealt with in isolation, when, say,
the tactics that solve p can't safely be applied to q and/or r.
This tactic differs from impl_tac in that it keeps p as an
assumption in the second sub-goal.
Failure
Fails if the goal is not an implication with another implication as its
antecdent. Note that for the purpose of this tactic, a negation ~p is
viewed as the implication p ==> F. This means that impl_tac will
succeed when applied to goals whose conclusions are ~p ==> q,
~(p ==> q) and ~~p.
See also
Tactic.impl_tac,
Thm_cont.PROVEHYP_THEN
impl_tac
impl_tac
Tactic.impl_tac : tactic
Implements analogue of implication-left sequent calculus rule as tactic
Given a goal of the form A ?- ((p ==> q) ==> r), an application of
impl_tac will produce two sub-goals: A ?- p and A ?- (q ==> r).
This can be useful if p should be dealt with in isolation, when, say,
the tactics that solve p can't safely be applied to q and/or r.
Failure
Fails if the goal is not an implication with another implication as its
antecdent. Note that for the purpose of this tactic, a negation ~p is
viewed as the implication p ==> F. This means that impl_tac will
succeed when applied to goals whose conclusions are ~p ==> q,
~(p ==> q) and ~~p.
See also
Tactic.impl_keep_tac,
Thm_cont.PROVEHYP_THEN
irule
irule
Tactic.irule : thm_tactic
Reduces the goal using a supplied implication, with matching.
When applied to a theorem of the form
A' |- !x1...xn. s ==> !y1...ym. t ==> !z1...zk. u
irule produces a tactic that reduces a goal whose conclusion u' is a
substitution and/or type instance of u to the corresponding instances
of s and of t. Any variables free in s or t but not in u will
be existentially quantified in the resulting subgoal, and a variable
free in both s and t will result in a subgoal which is s /\ t,
existentially quantified
The following diagram is simplified: more implications and quantified variables than shown are allowed.
A ?- u'
========================= irule (A' |- !x. s ==> !y. t ==> u)
A ?- (?z. s') /\ ?w. t'
where z and w are (type instances of) variables among x, y that
do not occur free in s, t. The assumptions A', instantiated, are
added as further new subgoals.
Failure
Fails unless the theorem, when stripped of universal quantification and antecedents of implications, can be instantiated to match the goal.
Comments
The supplied theorem is pre-processed using IRULE_CANON, which removes
the universal quantifiers and antecedents of implications, and
existentially quantifies variables which were instantiated but appeared
only in the antecedents of implications.
Then MATCH_MP_TAC or MATCH_ACCEPT_TAC is applied (depending on
whether or not the result of the preprocessing is an implication). To
avoid preprocessing entirely, one can use prim_irule.
Example
With goal R a (f b) and theorem thm being
|- !x u. P u x ==> !w y. Q w x y ==> R x (f y)
the proof step e (irule thm) gives new goal
(?u. P u a) /\ ?w. Q w a b.
With goal a = b and theorem trans
|- !x y. (x = y) ==> !z. (y = z) ==> (x = z)
the proof step e (irule trans) gives new goal
?y. (a = y) /\ (y = b)
See also
Tactic.irule_at,
Tactic.MATCH_MP_TAC,
Tactic.prim_irule,
Drule.IRULE_CANON
irule_at
irule_at
Tactic.irule_at : match_position -> thm -> tactic
Applies an implicational theorem backwards in a particular position in the goal
A call to irule_at pos th, with th an "implicational" theorem of
general form ∀xs... P ⇒ Q, will attempt to find an instance of term
Q at position pos within the current goal, and replace it with an
appropriately instantiated version of P. (It is possible for P to be
empty, in which case the term is effectively replaced by truth.) The
possible positions encoded by pos are all "positive", meaning that
this process is sound (it may nonetheless turn a provable goal into an
unprovable one).
The possible positions encoded by parameter pos view the goal as if it
is of form ?ys. c1 ∧ ... ∧ cn, where the existential prefix ys may
be empty, and where there may only be one conjunct. If pos encodes the
choice of conjunct cj, then irule_at pos will instantiate type
variables and term variables from xs in th, and variables from ys
in the goal so as to make cj unify with Q. The conjunct cj will
then be replaced with the correspondingly instantiated P, which may
itself be multiple conjunctions. While the goal may lose variables from
ys because they have been instantiated, it may also acquire new
variables from xs; these will be added to the goal's existential
prefix.
The new goal will be assembled to put new conjuncts first, followed by
conjuncts from the original goal in their original order (these
conjuncts may still be different if existential variables from ys have
been instantiated). If two conjuncts become the same because of variable
instantiation, only one will be present in the resulting goal. There is
some effort made to keep variables from the existential prefix with the
same names, but some renaming may occur, and the new goal's existential
variables will be ordered arbitrarily. If the new goal has no conjuncts,
then the tactic has proved the original.
There are four possible forms for the pos parameter. If it is of form
Pos f, f will be a function of type term list -> term, and this
function will be passed the list of conjuncts. The returned term should
be one of those conjuncts. Typical values for this function are hd,
last and el i, for positive integers i. If the pos parameter is
of form Pat q, the quotation q will be parsed in the context of the
goal (honouring the goal's free variables), generating a set of possible
terms (multiple terms are possible because of ambiguities caused by
overloading) that are then viewed as patterns against which the
conjuncts of the goal are matched. The first conjunct that matches the
earliest pattern in the sequence of possible parses, and which unifies
with th's conclusion, is used.
The pattern form Concl is used to indicate that the entire goal
(including its existential prefix) should be viewed as the desired
target for th. This results in a call to irule th being made.
Finally, the pattern form Any is used to have the tactic search for
any conjunct that matches the conclusion (as with a pattern of
‘_:bool’), and if no conjunct unifies with th's conclusion, to then
try to call irule th, as is done with the Concl pattern form.
Failure
Fails if the position parameter fails to specify a term, or if that term
does not unify with the implicational theorem's conclusion. A position
may fail to specify a term in mulitple ways depending on the form of the
position. A position of form Pos f will fail if the function f fails
when applied to the goal's conjuncts. (Note that there is no failure if
f returns a term that is not actually a conjunct; if this term
unifies, this will simply result in new conjuncts appearing in the goal
without any old conjuncts being removed.)
A position of form Pat q can fail if no conjunct of the goal matches
any of the terms parsed to by q. The other position forms always
return at least one term to be considered. Failure after this point will
only follow if none of these terms unifies with the implicational
theorem's conclusion.
Example
Solving a goal outright:
?- ∃x. x ≤ 3
============== irule_at (Pos hd) (DECIDE “y ≤ y”)
Refining a goal under an existential prefix (the theorem RTC_SUBSET
states that ∀x y. R x y ⇒ RTC R x y):
?- ∃x y z. P x ∧ RTC R x (f y) ∧ Q y z
======================================== irule_at Any RTC_SUBSET
?- ∃z y0 x. R x (f y0) ∧ P x ∧ Q y0 z
Instantiating existential variables (with LESS_MONO stating that
m < n ⇒ SUC m < SUC n):
?- ∃x y z. P x ∧ SUC x < y ∧ Q y z
====================================== irule_at Any LESS_MONO
?- ∃z n m. m < n ∧ P m ∧ Q (SUC n) z
Comments
The underlying operation is resolution, where one resolvent is always
the conclusion of th, and the other is the conjunct from the goal
selected by the position parameter. The goal is viewed as a literal
clause by negating it (via the action of goal_assum).
See also
Tactic.irule,
Tactic.MATCH_MP_TAC
KNOW_TAC
KNOW_TAC
Tactic.KNOW_TAC : term -> tactic
A shorthand form of SUBGOAL_THEN.
A call to KNOW_TAC t is equivalent to a call to
SUBGOAL_THEN t MP_TAC.
Failure
A call to KNOW_TAC t will fail on being applied to a goal if the
provided term t is not of boolean type.
Comments
If t is to be created through parsing a user-provided string, it may
be helpful to do that parsing in the context of the current goal, for
which Q_TAC may be helpful.
Equally, the by and suffices_by tactics have a similar effect:
taking a quotation, and generating two subgoals to be proved. In all
cases, the behaviour is to give the user an opportunity to be creative
in the specification of the fresh sub-goal that arises from applying
modus ponens backwards.
See also
bossLib.by, Tactical.Q_TAC,
Tactic.SUBGOAL_THEN,
Tactic.SUFF_TAC,
bossLib.suffices_by
LAST_ASSUME_TAC
LAST_ASSUME_TAC
Tactic.LAST_ASSUME_TAC : thm_tactic
Adds an assumption to the top of the assumptions.
Given a theorem th of the form A' |- u, and a goal,
LAST_ASSUME_TAC th adds u to the assumptions of the goal.
A ?- t
============== LAST_ASSUME_TAC (A' |- u)
{u} u A ?- t
Note that unless A' is a subset of A, this tactic is invalid.
Failure
Never fails.
LAST_ASSUME_TAC is the naive way of manipulating assumptions
(i.e. without recourse to advanced tacticals); and it is useful for
enriching the assumption list with lemmas as a prelude to resolution
(RES_TAC, IMP_RES_TAC), rewriting with assumptions
(ASM_REWRITE_TAC and so on), and other operations involving
assumptions.
See also
MATCH_ACCEPT_TAC
MATCH_ACCEPT_TAC
Tactic.MATCH_ACCEPT_TAC : thm_tactic
Solves a goal which is an instance of the supplied theorem.
When given a theorem A' |- t and a goal A ?- t' where t can be
matched to t' by instantiating variables which are either free or
universally quantified at the outer level, including appropriate type
instantiation, MATCH_ACCEPT_TAC completely solves the goal.
A ?- t'
========= MATCH_ACCEPT_TAC (A' |- t)
Unless A' is a subset of A, this is an invalid tactic.
Failure
Fails unless the theorem has a conclusion which is instantiable to match that of the goal.
Example
The following example shows variable and type instantiation at work. We
can use the polymorphic list theorem HD:
HD = |- !h t. HD(CONS h t) = h
to solve the goal:
?- HD [1;2] = 1
simply by:
MATCH_ACCEPT_TAC HD
Comments
prim_irule is similar, with differences in the details
See also
Tactic.ACCEPT_TAC,
Tactic.prim_irule
MATCH_MP_TAC
MATCH_MP_TAC
Tactic.MATCH_MP_TAC : thm_tactic
Reduces the goal using a supplied implication, with matching.
When applied to a theorem of the form
A' |- !x1...xn. s ==> !y1...ym. t
MATCH_MP_TAC produces a tactic that reduces a goal whose conclusion
t' is a substitution and/or type instance of t to the corresponding
instance of s. Any variables free in s but not in t will be
existentially quantified in the resulting subgoal:
A ?- !v1...vi. t'
====================== MATCH_MP_TAC (A' |- !x1...xn. s ==> !y1...ym. t)
A ?- ?z1...zp. s'
where z1, ..., zp are (type instances of) those variables among
x1, ..., xn that do not occur free in t. Note that this is not a
valid tactic unless A' is a subset of A.
Failure
Fails unless the theorem is an (optionally universally quantified)
implication whose consequent can be instantiated to match the goal. The
generalized variables v1, ..., vi must occur in s' in order for
the conclusion t of the supplied theorem to match t'.
Comments
The tactic irule builds on MATCH_MP_TAC, normalising the input
theorem more aggressively so that it succeeds more often.
See also
ConseqConv.CONSEQ_CONV_TAC,
Thm.EQ_MP, Tactic.irule,
Drule.MATCH_MP, Thm.MP,
Tactic.MP_TAC
MK_COMB_TAC
MK_COMB_TAC
Tactic.MK_COMB_TAC : tactic
Breaks an equality between applications into two equality goals: one for the functions, and other for the arguments.
MK_COMB_TAC reduces a goal of the form A ?- f x = g y to the goals
A ?- f = g and A ?- x = y.
A ?- f x = g y
=========================== MK_COMB_TAC
A ?- f = g, A ?- x = y
Failure
Fails unless the goal is equational, with both sides being applications.
See also
Thm.MK_COMB, Thm.AP_TERM,
Thm.AP_THM,
Tactic.AP_TERM_TAC,
Tactic.AP_THM_TAC
MP_TAC
MP_TAC
Tactic.MP_TAC : thm_tactic
Reduces a goal to implication from a known theorem.
When applied to the theorem A' |- s and the goal A ?- t, the tactic
MP_TAC reduces the goal to A ?- s ==> t. Unless A' is a subset of
A, this is an invalid tactic.
A ?- t
============== MP_TAC (A' |- s)
A ?- s ==> t
Failure
Never fails.
See also
Tactic.MATCH_MP_TAC, Thm.MP,
Tactic.UNDISCH_TAC
mp_then
mp_then
Tactic.mp_then : match_position -> thm_tactic -> thm -> thm -> tactic
Matches two theorems against each other and then continues
The mp_then tactic combines two theorems (one or both of which will
typically come from the current goal's assumptions) using modus ponens
in a controlled way, and then passes the result of this to a
continuation theorem-tactic.
Thus mp_then ttac pos ith th is a tactic in the usual "_then"
fashion which produces a theorem and then applies the ttac
continuation to that result. The theorems ith and th are the two
theorems: ith contains the implication, and the other has a conclusion
matching one of the antecedents of the implication.
An implication's antecedents are calculated by first normalising the implication so that it is of the form
!v1 .. vn. ant1 /\ ant2 .. /\ antn ==> concl
The pos parameter indicates how to find the antecedent. There are four
possible forms for pos (constructors for the match_position type).
It can be Any, which tells mp_then to search for anything that
works. It can be Pat q, with q a quotation, which means to find
anything matching q that works. It can be Pos f, where f is a
function of type term list -> term, and is typically a value such as
hd, el n for some number n or last. This function is passed the
list of all ith's antecedents to pick the right one. Finally, the
pos parameter might be Concl, meaning that the conclusion of ith
is treated as a negated assumption. This allows implications to be used
in a contrapositive way.
In practice, there are some common patterns for obtaining ith and
th. Apart from the fully applied version above, you might also see:
<sel>_assum (mp_then pos ttac ith)
<sel>_assum (<sel>_assum o mp_then pos ttac)
disch_then(<sel>_assum o mp_then pos ttac)
where <sel> is one of first, last, qpat and goal, possibly
with an appended _x; the usual ways of obtaining theorems from the
current goal. Where there are two selectors used, the outermost is used
for the selection of the implicational theorem and the innermost selects
th. In the first example, the ith value is provided in the call, and
is presumably an existing theorem rather than an assumption from the
goal.
The goal_assum selector is worth special mention since it's especially
useful with mp_then: it turns an existentially quantified goal
?x. P x into the assumption !x. P x ==> F thereby providing a
theorem with antecedents to match on. In conjunction with mp_tac
(which will put the revised implication back into the goal as an
existential once more) it has the effect of instantiating the
existential quantifier in order to match a provided subterm (similar to
part_match_exists_tac or asm_exists_tac).
Finally, note that the Pat and Any position selectors will backtrack
across the set of theorem antecedents to find a match that makes the
whole application succeed.
Failure
If the provided implicational theorem doesn't have a match at a
compatible position for the second provided theorem, or if no such match
then allows the continuation ttac to succeed.
See also
Tactical.goal_assum,
Tactic.resolve_then
NTAC
NTAC
Tactic.NTAC : int -> tactic -> tactic
Apply tactic a specified number of times.
An invocation NTAC n tac applies the tactic tac exactly n times.
If n <= 0 then the goal is unchanged.
Failure
Fails if tac fails.
Example
Suppose we have the following goal:
?- x = y
We apply a tactic for symmetry of equality 3 times:
NTAC 3 (PURE_ONCE_REWRITE_TAC [EQ_SYM_EQ])
and obtain
?- y = x
Controlling iterated application tactics.
See also
Rewrite.PURE_ONCE_REWRITE_TAC,
Tactical.REPEAT, Conv.REPEATC
prim_irule
prim_irule
Tactic.prim_irule : thm_tactic
For a goal which is an instance of the conclusion of the supplied theorem, replace the goal by the instantiated hypotheses of the supplied theorem.
When given a theorem th = A' |- t and a goal A ?- t' where t can
be matched to t' by instantiating free variables, including
appropriate type instantiation, prim_irule replaces the goal by new
subgoals which are the hypotheses A', instantiated
The order of the new subgoals corresponds to the order in which hyp th
returns the hypotheses A'
Failure
Fails unless the theorem has a conclusion which is instantiable to match that of the goal.
Comments
irule also pre-processes the supplied theorem, which will normally be
useful
prim_irule differs from MATCH_ACCEPT_TAC in that hypotheses of the
supplied theorem may also be substituted, and will appear as new
subgoals
See also
Tactic.irule,
Tactic.MATCH_ACCEPT_TAC,
Tactic.ACCEPT_TAC
REFL_TAC
REFL_TAC
Tactic.REFL_TAC : tactic
Solves a goal which is an equation between alpha-equivalent terms.
When applied to a goal A ?- t = t', where t and t' are
alpha-equivalent, REFL_TAC completely solves it.
A ?- t = t'
============= REFL_TAC
Failure
Fails unless the goal is an equation between alpha-equivalent terms.
See also
Tactic.ACCEPT_TAC,
Tactic.MATCH_ACCEPT_TAC,
Rewrite.REWRITE_TAC
RES_TAC
RES_TAC
Tactic.RES_TAC : tactic
Enriches assumptions by repeatedly resolving them against each other.
RES_TAC searches for pairs of assumed assumptions of a goal (that is,
for a candidate implication and a candidate antecedent, respectively)
which can be 'resolved' to yield new results. The conclusions of all the
new results are returned as additional assumptions of the subgoal(s).
The effect of RES_TAC on a goal is to enrich the assumptions set with
some of its collective consequences.
When applied to a goal A ?- g, the tactic RES_TAC uses RES_CANON
to obtain a set of implicative theorems in canonical form from the
assumptions A of the goal. Each of the resulting theorems (if there
are any) will have the form:
A |- u1 ==> u2 ==> ... ==> un ==> v
RES_TAC then tries to repeatedly 'resolve' these theorems against the
assumptions of a goal by attempting to match the antecedents u1, u2,
..., un (in that order) to some assumption of the goal (i.e. to some
candidate antecedents among the assumptions). If all the antecedents can
be matched to assumptions of the goal, then an instance of the theorem
A u {a1,...,an} |- v
called a 'final resolvent' is obtained by repeated specialization of the
variables in the implicative theorem, type instantiation, and
applications of modus ponens. If only the first i antecedents u1,
..., ui can be matched to assumptions and then no further matching is
possible, then the final resolvent is an instance of the theorem:
A u {a1,...,ai} |- u(i+1) ==> ... ==> v
All the final resolvents obtained in this way (there may be several,
since an antecedent ui may match several assumptions) are added to the
assumptions of the goal, in the stripped form produced by using
STRIP_ASSUME_TAC. If the conclusion of any final resolvent is a
contradiction 'F' or is alpha-equivalent to the conclusion of the
goal, then RES_TAC solves the goal.
Failure
RES_TAC cannot fail and so should not be unconditionally
REPEATed. However, since the final resolvents added to the original
assumptions are never used as 'candidate antecedents' it is sometimes
necessary to apply RES_TAC more than once to derive the desired
result.
See also
Tactic.IMP_RES_TAC,
Thm_cont.IMP_RES_THEN,
Drule.RES_CANON,
Thm_cont.RES_THEN
RULE_ASSUM_TAC
RULE_ASSUM_TAC
Tactic.RULE_ASSUM_TAC : ((thm -> thm) -> tactic)
Maps an inference rule over the assumptions of a goal.
When applied to an inference rule f and a goal ({A1,...,An} ?- t),
the RULE_ASSUM_TAC tactical applies the inference rule to each of the
ASSUMEd assumptions to give a new goal.
{A1,...,An} ?- t
==================================== RULE_ASSUM_TAC f
{f(A1 |- A1),...,f(An |- An)} ?- t
Failure
The application of RULE_ASSUM_TAC f to a goal fails iff f fails when
applied to any of the assumptions of the goal.
Comments
It does not matter if the goal has no assumptions, but in this case
RULE_ASSUM_TAC has no effect.
See also
Tactic.RULE_L_ASSUM_TAC,
Tactical.ASSUM_LIST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST,
Tactical.POP_ASSUM_LIST
RULE_L_ASSUM_TAC
RULE_L_ASSUM_TAC
Tactic.RULE_L_ASSUM_TAC : ((thm -> thm list) -> tactic)
Maps an inference rule, which produces a list of result theorems, over the assumptions of a goal.
When applied to an inference rule f and a goal ({A1,...,An} ?- t),
the RULE_L_ASSUM_TAC tactical applies the inference rule to each of
the ASSUMEd assumptions to give a new goal.
{A1,...,An} ?- t
==================================== RULE_L_ASSUM_TAC f
{f(A1 |- A1),...,f(An |- An)} ?- t
Here each f(Ai |- Ai) is a list of assumptions.
Failure
The application of RULE_L_ASSUM_TAC f to a goal fails iff f fails
when applied to any of the assumptions of the goal.
Comments
It does not matter if the goal has no assumptions, but in this case
RULE_L_ASSUM_TAC has no effect.
Example
With a goal
g
------------------------------------
0. a /\ b
1. c
2. d /\ e /\ f
the tactic RULE_L_ASSUM_TAC CONJUNCTS gives the new goal
g
------------------------------------
0. a
1. b
2. c
3. d
4. e
5. f
RULE_L_ASSUM_TAC can also be used to delete unwanted assumptions: let
f ass = [ass] for an assumption which is to be kept, and f ass = []
for an assumption which is to be deleted.
See also
Tactic.RULE_ASSUM_TAC,
Tactical.ASSUM_LIST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST,
Tactical.POP_ASSUM_LIST
SELECT_ELIM_TAC
SELECT_ELIM_TAC
Tactic.SELECT_ELIM_TAC : tactic
Eliminates a Hilbert-choice ("selection") term from the goal.
SELECT_ELIM_TAC searches the goal it is applied to for terms involving
the Hilbert-choice operator, of the form @x. .... If such a term is
found, then the tactic will produce a new goal, where the choice term
has disappeared. The resulting goal will require the proof of the
non-emptiness of the choice term's predicate, and that any possible
choice of value from that predicate will satisfy the original goal.
Thus, SELECT_ELIM_TAC can be seen as a higher-order match against the
theorem
|- !P Q. (?x. P x) /\ (!x. P x ==> Q x) ==> Q ($@ P)
where the new goal is the antecedent of the implication. (This theorem
is SELECT_ELIM_THM, from theory bool.)
Example
When applied to this goal,
- SELECT_ELIM_TAC ([], ``(@x. x < 4) < 5``);
> val it = ([([], ``(?x. x < 4) /\ !x. x < 4 ==> x < 5``)], fn) :
(term list * term) list * (thm list -> thm)
the resulting goal requires the proof of the existence of a number less than 4, and also that any such number is also less than 5.
Failure
Fails if there are no choice terms in the goal.
Comments
If the choice-term's predicate is everywhere false, goals involving such
terms will be true only if the choice of term makes no difference at
all. Such situations can be handled with the use of SPEC_TAC. Note
also that the choice of select term to eliminate is made in an
unspecified manner.
See also
Tactic.DEEP_INTRO_TAC,
Drule.SELECT_ELIM,
Drule.SELECT_INTRO,
Drule.SELECT_RULE,
Tactic.SPEC_TAC
SPEC_TAC
SPEC_TAC
Tactic.SPEC_TAC : term * term -> tactic
Generalizes a goal.
When applied to a pair of terms (u,x), where x is just a variable,
and a goal A ?- t, the tactic SPEC_TAC generalizes the goal to
A ?- !x. t[x/u], that is, all instances of u are turned into x.
A ?- t
================= SPEC_TAC (u,x)
A ?- !x. t[x/u]
Failure
Fails unless x is a variable with the same type as u.
Removing unnecessary speciality in a goal, particularly as a prelude to an inductive proof.
See also
Thm.GEN, Thm.GENL,
Drule.GEN_ALL, Tactic.GEN_TAC,
Thm.SPEC, Drule.SPECL,
Drule.SPEC_ALL,
Tactic.STRIP_TAC
STRIP_ASSUME_TAC
STRIP_ASSUME_TAC
Tactic.STRIP_ASSUME_TAC : thm_tactic
Splits a theorem into a list of theorems and then adds them to the assumptions.
Given a theorem th and a goal (A,t), STRIP_ASSUME_TAC th splits
th into a list of theorems. This is done by recursively breaking
conjunctions into separate conjuncts, cases-splitting disjunctions, and
eliminating existential quantifiers by choosing arbitrary variables.
Schematically, the following rules are applied:
A ?- t
====================== STRIP_ASSUME_TAC (A' |- v1 /\ ... /\ vn)
A u {v1,...,vn} ?- t
A ?- t
================================= STRIP_ASSUME_TAC (A' |- v1 \/ ... \/ vn)
A u {v1} ?- t ... A u {vn} ?- t
A ?- t
==================== STRIP_ASSUME_TAC (A' |- ?x.v)
A u {v[x'/x]} ?- t
where x' is a variant of x.
If the conclusion of th is not a conjunction, a disjunction or an
existentially quantified term, the whole theorem th is added to the
assumptions.
As assumptions are generated, they are examined to see if they solve the goal (either by being alpha-equivalent to the conclusion of the goal or by deriving a contradiction).
The assumptions of the theorem being split are not added to the
assumptions of the goal(s), but they are recorded in the proof. This
means that if A' is not a subset of the assumptions A of the goal
(up to alpha-conversion), STRIP_ASSUME_TAC (A'|-v) results in an
invalid tactic.
Failure
Never fails.
Example
When solving the goal
?- m = 0 + m
assuming the clauses for addition with STRIP_ASSUME_TAC ADD_CLAUSES
results in the goal
{m + (SUC n) = SUC(m + n), (SUC m) + n = SUC(m + n),
m + 0 = m, 0 + m = m, m = 0 + m} ?- m = 0 + m
while the same tactic directly solves the goal
?- 0 + m = m
STRIP_ASSUME_TAC is used when applying a previously proved theorem to
solve a goal, or when enriching its assumptions so that resolution,
rewriting with assumptions and other operations involving assumptions
have more to work with.
See also
Tactic.ASSUME_TAC,
Tactic.CHOOSE_TAC,
Thm_cont.CHOOSE_THEN,
Thm_cont.CONJUNCTS_THEN,
Tactic.DISJ_CASES_TAC,
Thm_cont.DISJ_CASES_THEN
STRIP_GOAL_THEN
STRIP_GOAL_THEN
Tactic.STRIP_GOAL_THEN : thm_tactic -> tactic
Splits a goal by eliminating one outermost connective, applying the given theorem-tactic to the antecedents of implications.
Given a theorem-tactic ttac and a goal (A,t), STRIP_GOAL_THEN
removes one outermost occurrence of one of the connectives !, ==>,
~ or /\ from the conclusion of the goal t. If t is a universally
quantified term, then STRIP_GOAL_THEN strips off the quantifier:
A ?- !x.u
============== STRIP_GOAL_THEN ttac
A ?- u[x'/x]
where x' is a primed variant that does not appear free in the
assumptions A. If t is a conjunction, then STRIP_GOAL_THEN simply
splits the conjunction into two subgoals:
A ?- v /\ w
================= STRIP_GOAL_THEN ttac
A ?- v A ?- w
If t is an implication u ==> v and if:
A ?- v
=============== ttac (u |- u)
A' ?- v'
then:
A ?- u ==> v
==================== STRIP_GOAL_THEN ttac
A' ?- v'
Finally, a negation ~t is treated as the implication t ==> F.
Failure
STRIP_GOAL_THEN ttac (A,t) fails if t is not a universally
quantified term, an implication, a negation or a conjunction. Failure
also occurs if the application of ttac fails, after stripping the
goal.
Example
When solving the goal
?- (n = 1) ==> (n * n = n)
a possible initial step is to apply
STRIP_GOAL_THEN SUBST1_TAC
thus obtaining the goal
?- 1 * 1 = 1
STRIP_GOAL_THEN is used when manipulating intermediate results
(obtained by stripping outer connectives from a goal) directly, rather
than as assumptions.
See also
Tactic.CONJ_TAC,
Thm_cont.DISCH_THEN,
Tactic.FILTER_STRIP_THEN,
Tactic.GEN_TAC,
Tactic.STRIP_ASSUME_TAC,
Tactic.STRIP_TAC
STRIP_TAC
STRIP_TAC
Tactic.STRIP_TAC : tactic
Splits a goal by eliminating one outermost connective.
Given a goal (A,t), STRIP_TAC removes one outermost occurrence of
one of the connectives !, ==>, ~ or /\ from the conclusion of
the goal t. If t is a universally quantified term, then STRIP_TAC
strips off the quantifier:
A ?- !x.u
============== STRIP_TAC
A ?- u[x'/x]
where x' is a primed variant that does not appear free in the
assumptions A. If t is a conjunction, then STRIP_TAC simply splits
the conjunction into two subgoals:
A ?- v /\ w
================= STRIP_TAC
A ?- v A ?- w
If t is an implication, STRIP_TAC moves the antecedent into the
assumptions, stripping conjunctions, disjunctions and existential
quantifiers according to the following rules:
A ?- v1 /\ ... /\ vn ==> v A ?- v1 \/ ... \/ vn ==> v
============================ =================================
A u {v1,...,vn} ?- v A u {v1} ?- v ... A u {vn} ?- v
A ?- ?x.w ==> v
====================
A u {w[x'/x]} ?- v
where x' is a primed variant of x that does not appear free in A.
Finally, a negation ~t is treated as the implication t ==> F.
Failure
STRIP_TAC (A,t) fails if t is not a universally quantified term, an
implication, a negation or a conjunction.
Example
Applying STRIP_TAC twice to the goal:
?- !n. m <= n /\ n <= m ==> (m = n)
results in the subgoal:
{n <= m, m <= n} ?- m = n
When trying to solve a goal, often the best thing to do first is
REPEAT STRIP_TAC to split the goal up into manageable pieces.
See also
Tactic.CONJ_TAC,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Tactic.GEN_TAC,
Tactic.STRIP_ASSUME_TAC,
Tactic.STRIP_GOAL_THEN
STRUCT_CASES_TAC
STRUCT_CASES_TAC
Tactic.STRUCT_CASES_TAC : thm_tactic
Performs very general structural case analysis.
When it is applied to a theorem of the form:
th = A' |- ?y11...y1m. (x=t1) /\ (B11 /\ ... /\ B1k) \/ ... \/
?yn1...ynp. (x=tn) /\ (Bn1 /\ ... /\ Bnp)
in which there may be no existential quantifiers where a 'vector' of
them is shown above, STRUCT_CASES_TAC th splits a goal A ?- s into
n subgoals as follows:
A ?- s
===============================================================
A u {B11,...,B1k} ?- s[t1/x] ... A u {Bn1,...,Bnp} ?- s[tn/x]
that is, performs a case split over the possible constructions (the
ti) of a term, providing as assumptions the given constraints, having
split conjoined constraints into separate assumptions. Note that unless
A' is a subset of A, this is an invalid tactic.
Failure
Fails unless the theorem has the above form, namely a conjunction of
(possibly multiply existentially quantified) terms which assert the
equality of the same variable x and the given terms.
Example
Suppose we have the goal:
?- ~(l:(*)list = []) ==> (LENGTH l) > 0
then we can get rid of the universal quantifier from the inbuilt list
theorem list_CASES:
list_CASES = !l. (l = []) \/ (?t h. l = CONS h t)
and then use STRUCT_CASES_TAC. This amounts to applying the following
tactic:
STRUCT_CASES_TAC (SPEC_ALL list_CASES)
which results in the following two subgoals:
?- ~(CONS h t = []) ==> (LENGTH(CONS h t)) > 0
?- ~([] = []) ==> (LENGTH[]) > 0
Note that this is a rather simple case, since there are no constraints, and therefore the resulting subgoals have no assumptions.
Generating a case split from the axioms specifying a structure.
See also
Tactic.ASM_CASES_TAC,
Tactic.BOOL_CASES_TAC,
Tactic.COND_CASES_TAC,
Tactic.DISJ_CASES_TAC
SUBST1_TAC
SUBST1_TAC
Tactic.SUBST1_TAC : thm_tactic
Makes a simple term substitution in a goal using a single equational theorem.
Given a theorem A'|-u=v and a goal (A,t), the tactic
SUBST1_TAC (A'|-u=v) rewrites the term t into t[v/u], by
substituting v for each free occurrence of u in t:
A ?- t
============= SUBST1_TAC (A'|-u=v)
A ?- t[v/u]
The assumptions of the theorem used to substitute with are not added to
the assumptions of the goal but are recorded in the proof. If A' is
not a subset of the assumptions A of the goal (up to
alpha-conversion), then SUBST1_TAC (A'|-u=v) results in an invalid
tactic.
SUBST1_TAC automatically renames bound variables to prevent free
variables in v becoming bound after substitution.
Failure
SUBST1_TAC th (A,t) fails if the conclusion of th is not an
equation. No change is made to the goal if no free occurrence of the
left-hand side of th appears in t.
Example
When trying to solve the goal
?- m * n = (n * (m - 1)) + n
substituting with the commutative law for multiplication
SUBST1_TAC (SPECL ["m:num"; "n:num"] MULT_SYM)
results in the goal
?- n * m = (n * (m - 1)) + n
SUBST1_TAC is used when rewriting with a single theorem using tactics
such as REWRITE_TAC is too expensive or would diverge. Applying
SUBST1_TAC is also much faster than using rewriting tactics.
See also
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST_ALL_TAC,
Tactic.SUBST_TAC
SUBST_ALL_TAC
SUBST_ALL_TAC
Tactic.SUBST_ALL_TAC : thm_tactic
Substitutes using a single equation in both the assumptions and conclusion of a goal.
SUBST_ALL_TAC breaches the style of natural deduction, where the
assumptions are kept fixed. Given a theorem A|-u=v and a goal
([t1;...;tn], t), SUBST_ALL_TAC (A|-u=v) transforms the assumptions
t1,...,tn and the term t into t1[v/u],...,tn[v/u] and t[v/u]
respectively, by substituting v for each free occurrence of u in
both the assumptions and the conclusion of the goal.
{t1,...,tn} ?- t
================================= SUBST_ALL_TAC (A|-u=v)
{t1[v/u],...,tn[v/u]} ?- t[v/u]
The assumptions of the theorem used to substitute with are not added to
the assumptions of the goal, but they are recorded in the proof. If A
is not a subset of the assumptions of the goal (up to alpha-conversion),
then SUBST_ALL_TAC (A|-u=v) results in an invalid tactic.
SUBST_ALL_TAC automatically renames bound variables to prevent free
variables in v becoming bound after substitution.
Failure
SUBST_ALL_TAC th (A,t) fails if the conclusion of th is not an
equation. No change is made to the goal if no occurrence of the
left-hand side of th appears free in (A,t).
Example
Simplifying both the assumption and the term in the goal
{0 + m = n} ?- 0 + (0 + m) = n
by substituting with the theorem |- 0 + m = m for addition
SUBST_ALL_TAC (CONJUNCT1 ADD_CLAUSES)
results in the goal
{m = n} ?- 0 + m = n
See also
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST1_TAC,
Tactic.SUBST_TAC
SUBST_OCCS_TAC
SUBST_OCCS_TAC
Tactic.SUBST_OCCS_TAC : (int list * thm) list -> tactic
Makes substitutions in a goal at specific occurrences of a term, using a list of theorems.
Given a list (l1,A1|-t1=u1),...,(ln,An|-tn=un) and a goal (A,t),
SUBST_OCCS_TAC replaces each ti in t with ui, simultaneously, at
the occurrences specified by the integers in the list li = [o1,...,ok]
for each theorem Ai|-ti=ui.
A ?- t
============================= SUBST_OCCS_TAC [(l1,A1|-t1=u1),...,
A ?- t[u1,...,un/t1,...,tn] (ln,An|-tn=un)]
The assumptions of the theorems used to substitute with are not added to
the assumptions A of the goal, but they are recorded in the proof. If
any Ai is not a subset of A (up to alpha-conversion),
SUBST_OCCS_TAC [(l1,A1|-t1=u1),...,(ln,An|-tn=un)] results in an
invalid tactic.
SUBST_OCCS_TAC automatically renames bound variables to prevent free
variables in ui becoming bound after substitution.
Failure
SUBST_OCCS_TAC [(l1,th1),...,(ln,thn)] (A,t) fails if the conclusion
of any theorem in the list is not an equation. No change is made to the
goal if the supplied occurrences li of the left-hand side of the
conclusion of thi do not appear in t.
Example
When trying to solve the goal
?- (m + n) + (n + m) = (m + n) + (m + n)
applying the commutative law for addition on the third occurrence of the
subterm m + n
SUBST_OCCS_TAC [([3], SPECL [Term `m:num`, Term `n:num`]
arithmeticTheory.ADD_SYM)]
results in the goal
?- (m + n) + (n + m) = (m + n) + (n + m)
SUBST_OCCS_TAC is used when rewriting a goal at specific occurrences
of a term, and when rewriting tactics such as REWRITE_TAC,
PURE_REWRITE_TAC, ONCE_REWRITE_TAC, SUBST_TAC, etc. are too
extensive or would diverge.
See also
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST1_TAC,
Tactic.SUBST_TAC
SUBST_TAC
SUBST_TAC
Tactic.SUBST_TAC : (thm list -> tactic)
Makes term substitutions in a goal using a list of theorems.
Given a list of theorems A1|-u1=v1,...,An|-un=vn and a goal (A,t),
SUBST_TAC rewrites the term t into the term t[v1,...,vn/u1,...,un]
by simultaneously substituting vi for each occurrence of ui in t
with vi:
A ?- t
============================= SUBST_TAC [A1|-u1=v1,...,An|-un=vn]
A ?- t[v1,...,vn/u1,...,un]
The assumptions of the theorems used to substitute with are not added to
the assumptions A of the goal, while they are recorded in the proof.
If any Ai is not a subset of A (up to alpha-conversion), then
SUBST_TAC [A1|-u1=v1,...,An|-un=vn] results in an invalid tactic.
SUBST_TAC automatically renames bound variables to prevent free
variables in vi becoming bound after substitution.
Failure
SUBST_TAC [th1,...,thn] (A,t) fails if the conclusion of any theorem
in the list is not an equation. No change is made to the goal if no
occurrence of the left-hand side of the conclusion of thi appears in
t.
Example
When trying to solve the goal
?- (n + 0) + (0 + m) = m + n
by substituting with the theorems
- val thm1 = SPEC_ALL arithmeticTheory.ADD_SYM
val thm2 = CONJUNCT1 arithmeticTheory.ADD_CLAUSES;
thm1 = |- m + n = n + m
thm2 = |- 0 + m = m
applying SUBST_TAC [thm1, thm2] results in the goal
?- (n + 0) + m = n + m
SUBST_TAC is used when rewriting (for example, with REWRITE_TAC) is
extensive or would diverge. Substituting is also much faster than
rewriting.
See also
Rewrite.ONCE_REWRITE_TAC,
Rewrite.PURE_REWRITE_TAC,
Rewrite.REWRITE_TAC,
Tactic.SUBST1_TAC,
Tactic.SUBST_ALL_TAC
SUFF_TAC
SUFF_TAC
Tactic.SUFF_TAC : term -> tactic
Introduces an implicational subgoal.
A call to SUFF_TAC t on the goal asl ?- g introduces two subgoals:
asl ?- t ==> g and asl ?- t. At a high-level, the user's claim is
that term t suffices (hence the name) to prove the goal. The first new
goal to be discharged is the check for this; the second is to actually
show t.
Failure
Will fail if t is not of type :bool.
See also
Tactic.SUBGOAL_THEN,
bossLib.suffices_by
SYM_TAC
SYM_TAC
Tactic.SYM_TAC : tactic
Flips an equality at the top-level of a goal
An application of SYM_TAC behaves as follows:
G ?- x = y
================= SYM_TAC
G ?- y = x
Failure
Fails if the goal is not an equality.
Comments
Also available as the alias sym_tac.
See also
TRANS_TAC
TRANS_TAC
Tactic.TRANS_TAC : thm -> term -> tactic
Applies transitivity theorem to goal with chosen intermediate term.
When applied to a 'transitivity' theorem, i.e. one of the form
|- !xs. R1 x y /\ R2 y z ==> R3 x z
and a term t, TRANS_TAC produces a tactic that reduces a goal with
conclusion of the form R3 s u to one with conclusion
R1 s t /\ R2 t u.
A ?- R3 s u
======================== TRANS_TAC (|- !xs. R1 x y /\ R2 y z ==> R3 x z) `t`
A ?- R1 s t /\ R2 t u
Example
Consider the simple inequality goal:
> g `n < (m + 2) * (n + 1)`;
We can use the following transitivity theorem
> LESS_EQ_LESS_TRANS;
val it = |- !m n p. m <= n /\ n < p ==> m < p: thm
# e (TRANS_TAC LESS_EQ_LESS_TRANS ``1 * (n + 1)``);
OK..
1 subgoal:
val it =
n <= 1 * (n + 1) /\ 1 * (n + 1) < (m + 2) * (n + 1)
: proof
Failure
Fails unless the input theorem is of the expected form (some of the
relations R1, R2 and R3 may be, and often are, the same) and the
conclusion matches the goal, in the usual sense of higher-order
matching.
Comments
The effect of TRANS_TAC th t can often be replicated by the more
primitive tactic sequence MATCH_MP_TAC th THEN EXISTS_TAC t. The use
of TRANS_TAC is not only less verbose, but it is also more general in
that it ensures correct type-instantiation of the theorem, whereas in
highly polymorphic theorems the use of MATCH_MP_TAC may leave the
wrong types for the subsequent EXISTS_TAC step.
If R1 x y, etc. are actually overloads of negated terms, e.g.,
~(R1' y x), TRANS_TAC can still work. Such overloads are common for
many definitions of "less" as an overload of "not less-or-equal",
i.e. x < y is an overload of ~(y <= x).
See also
UNDISCH_TAC
UNDISCH_TAC
Tactic.UNDISCH_TAC : term -> tactic
Undischarges an assumption and deletes all assumptions that are alpha-equivalent to it.
Let a1 to an be the assumptions that are alpha-equivalent to v,
then
A ?- t
============================== UNDISCH_TAC v
A - {a1, ..., an} ?- v ==> t
In particular, if v is among the assumptions of the goal and no other
assumption is alpha-equivalent to it, then UNDISCH_TAC behaves as the
opposite of DISCH_TAC:
A ?- t
==================== UNDISCH_TAC v
A - {v} ?- v ==> t
Failure
UNDISCH_TAC fails if no assumption is alpha-equivalent to v.
Comments
In the typical use v is among the assumptions. If only a single
assumption alpha-equivalent to v, but it is different from v then
the action of UNDISCH_TAC can be seen as undischarging followed by
alpha-conversion.
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Drule.NEG_DISCH,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL
WEAKEN_TAC
WEAKEN_TAC
Tactic.WEAKEN_TAC : (term -> bool) -> tactic
Deletes assumption from goal.
Given an ML predicate P mapping terms to true or false and a goal
(asl,g), an invocation WEAKEN_TAC P (asl,g) removes the first
element (call it tm) that P holds of from asl, returning the goal
(asl - tm,g).
Failure
Fails if the assumption list of the goal is empty, or if P holds of no
element in asl.
Example
Suppose we want to dispose of the equality assumption in the following goal:
C x
------------------------------------
0. A = B
1. B x
The following application of WEAKEN_TAC does the job.
- e (WEAKEN_TAC is_eq);
OK..
1 subgoal:
> val it =
C x
------------------------------------
B x
Occasionally useful for getting rid of superfluous assumptions.
See also
Tactical.PAT_ASSUM,
Tactical.POP_ASSUM
X_CHOOSE_TAC
X_CHOOSE_TAC
Tactic.X_CHOOSE_TAC : term -> thm_tactic
Assumes a theorem, with existentially quantified variable replaced by a given witness.
X_CHOOSE_TAC expects a variable y and theorem with an existentially
quantified conclusion. When applied to a goal, it adds a new assumption
obtained by introducing the variable y as a witness for the object x
whose existence is asserted in the theorem.
A ?- t
=================== X_CHOOSE_TAC y (A1 |- ?x. w)
A u {w[y/x]} ?- t (y not free anywhere)
Failure
Fails if the theorem's conclusion is not existentially quantified, or if
the first argument is not a variable. Failures may arise in the
tactic-generating function. An invalid tactic is produced if the
introduced variable is free in w, t or A, or if the theorem has
any hypothesis which is not alpha-convertible to an assumption of the
goal.
Example
Given a goal of the form
{n < m} ?- ?x. m = n + (x + 1)
the following theorem may be applied:
th = [n < m] |- ?p. m = n + p
by the tactic (X_CHOOSE_TAC (Term`q:num`) th) giving the subgoal:
{n < m, m = n + q} ?- ?x. m = n + (x + 1)
See also
Thm.CHOOSE,
Thm_cont.CHOOSE_THEN,
Thm_cont.X_CHOOSE_THEN
X_GEN_TAC
X_GEN_TAC
Tactic.X_GEN_TAC : (term -> tactic)
Specializes a goal with the given variable.
When applied to a term x', which should be a variable, and a goal
A ?- !x. t, the tactic X_GEN_TAC returns the goal A ?- t[x'/x].
A ?- !x. t
============== X_GEN_TAC "x'"
A ?- t[x'/x]
Failure
Fails unless the goal's conclusion is universally quantified and the term a variable of the appropriate type. It also fails if the variable given is free in either the assumptions or (initial) conclusion of the goal.
See also
Tactic.FILTER_GEN_TAC,
Thm.GEN, Thm.GENL,
Drule.GEN_ALL, Thm.SPEC,
Drule.SPECL, Drule.SPEC_ALL,
Tactic.SPEC_TAC,
Tactic.STRIP_TAC
ADD_SGS_TAC
ADD_SGS_TAC
Tactical.ADD_SGS_TAC : term list -> tactic -> tactic
Adds extra sub-goals to the outcome of a tactic, as may be required to make an invalid tactic valid.
Suppose tac applied to the goal (asl,w) produces new goal list gl.
Then ADD_SGS_TAC tml tac (asl,w) produces, as new goals, gl and,
additionally, (asl,tm) for each tm in tml.
Then, if the justification returned by tac, when applied to the proved
goals gl, gives a theorem which uses some additional assumption tm
in tml, then the proved goal (asl,tm) is used to remove tm from
the assumption list of that theorem.
Failure
ADD_SGS_TAC tml tac (asl,w) fails if tac (asl,w) fails.
Where a tactic tac requires certain assumptions tml to be present in
the goal, which are not present but are capable of being proved,
ADD_SGS_TAC tml tac will conveniently set up new subgoals to prove the
missing assumptions.
Comments
VALIDATE tac is similar and will usually be easier to use, but its
extra new subgoals may occur in an unpredictable order.
Example
Given a goal with an implication in the assumptions, one can split it into two subgoals, defining an auxiliary function
> fun split_imp_asm th =
let val (tm, thu) = UNDISCH_TM th ;
in ADD_SGS_TAC [tm] (ASSUME_TAC thu) end ;
val split_imp_asm = fn: thm -> Tactical.tactic
This can be used as follows:
val it =
Proof manager status: 3 proofs.
3. Incomplete goalstack:
Initial goal:
∃R. WF R ∧ (∀rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)) ∧
∀rst x ord. R (ord,FILTER ($¬ ∘ ord x) rst) (ord,x::rst)
2. Incomplete goalstack:
Initial goal:
1 + 2 = 2 + 1
Current goal:
∀(x,y). x + y = y + x
1. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
> e (FIRST_X_ASSUM split_imp_asm) ;
OK..
2 subgoals:
val it =
0. q
------------------------------------
r
p
To propose a term, prove it as a subgoal and then use it to prove the
goal, as is done using SUBGOAL_THEN tm ASSUME_TAC, can also be done by
ADD_SGS_TAC [tm] (ASSUME_TAC (ASSUME tm))
See also
Tactic.impl_tac, Tactical.VALIDATE,
Tactical.GEN_VALIDATE
ALL_LT
ALL_LT
Tactical.ALL_LT : list_tactic
Passes on a goal list unchanged.
ALL_LT applied to a goal list gl simply produces the goal list gl.
It is the identity for the THEN_LT tactical.
Failure
Never fails.
Example
To apply tactic tac1 to a goal, and then to apply tac2 to all
resulting subgoals except the first, use
tac1 THEN_LT SPLIT_LT 1 (ALL_LT, ALLGOALS tac2)
See also
Tactical.THEN_LT,
Tactical.SPLIT_LT,
Tactical.ALLGOALS
ALL_TAC
ALL_TAC
Tactical.ALL_TAC : tactic
Passes on a goal unchanged.
ALL_TAC applied to a goal g simply produces the subgoal list [g].
It is the identity for the THEN tactical.
Failure
Never fails.
Example
The tactic
INDUCT_THEN numTheory.INDUCTION THENL [ALL_TAC, tac]
applied to a goal g, applies INDUCT_THEN numTheory.INDUCTION to g
to give a basis and step subgoal; it then returns the basis unchanged,
along with the subgoals produced by applying tac to the step.
Used to write tacticals such as REPEAT. Also, it is often used as a
place-holder in building compound tactics using tacticals such as
THENL.
See also
Prim_rec.INDUCT_THEN,
Tactical.NO_TAC,
Tactical.REPEAT,
Tactical.THENL
ALLGOALS
ALLGOALS
Tactical.ALLGOALS : tactic -> list_tactic
Applies a tactic to every goal in a list
If tac is a tactic, ALLGOALS tac is a list-tactic which applies the
tactic tac to all the goals in the given list.
Failure
The application of ALLGOALS to a tactic never fails. The resulting
list-tactic fails if tac fails when applied to any of the goals in the
given list.
Example
Where tac1 and tac2 are tactics, tac1 THEN_LT ALLGOALS tac2 is
equivalent to tac1 THEN tac2
See also
Tactical.THEN_LT,
Tactical.THEN
ASSUM_LIST
ASSUM_LIST
Tactical.ASSUM_LIST : (thm list -> tactic) -> tactic
Applies a tactic generated from the goal's assumption list.
When applied to a function of type thm list -> tactic and a goal,
ASSUM_LIST constructs a tactic by applying f to a list of ASSUMEd
assumptions of the goal, then applies that tactic to the goal.
ASSUM_LIST f ({A1,...,An} ?- t)
= f [A1 |- A1, ... , An |- An] ({A1,...,An} ?- t)
Failure
Fails if the function fails when applied to the list of ASSUMEd
assumptions, or if the resulting tactic fails when applied to the goal.
Comments
There is nothing magical about ASSUM_LIST: the same effect can usually
be achieved just as conveniently by using ASSUME a wherever the
assumption a is needed. If ASSUM_LIST is used, it is extremely
unwise to use a function which selects elements from its argument list
by number, since the ordering of assumptions should not be relied on.
Example
The tactic:
ASSUM_LIST SUBST_TAC
makes a single parallel substitution using all the assumptions, which can be useful if the rewriting tactics are too blunt for the required task.
Making more careful use of the assumption list than simply rewriting or using resolution.
See also
Rewrite.ASM_REWRITE_TAC,
Tactical.EVERY_ASSUM,
Tactic.IMP_RES_TAC,
Tactical.POP_ASSUM,
Tactical.POP_ASSUM_LIST,
Rewrite.REWRITE_TAC
CHANGED_TAC
CHANGED_TAC
Tactical.CHANGED_TAC : (tactic -> tactic)
Makes a tactic fail if it has no effect.
When applied to a tactic T, the tactical CHANGED_TAC gives a new
tactic which is the same as T if that has any effect, and otherwise
fails.
Failure
The application of CHANGED_TAC to a tactic never fails. The resulting
tactic fails if the basic tactic either fails or has no effect.
See also
CONJ_VALIDATE
CONJ_VALIDATE
Tactical.CONJ_VALIDATE : tactic -> tactic
Adds requirement to prove assumptions that would make a tactic invalid.
A call to CONJ_VALIDATE tac g behaves the same as tac g if this
tactic application is valid (meaning that when the tactic's validation
function is applied to the resulting sub-goals, the generated theorem
has no more assumptions than the original goal).
If the tactic's application is not valid because the resulting theorem
has the wrong conclusion, CONJ_VALIDATE tac g will fail. If the
resulting theorem has hypotheses not present in the goal state, then
these hypotheses are added to the new goals as new proof obligations.
The way in which this addition is done depends on how many subgoals
tac generated when applied to g.
If tac completely solves g (though in an invalid way), the excess
hypotheses h1...hn are bundled into a big conjunction and this becomes
the one remaining goal. If tac g results in more than one new goal,
then CONJ_VALIDATE tac g will produce one extra goal, consisting of a
conjunction of hypotheses, as above. Finally, if tac g produces
exactly one new goal to prove, and if the new goal's assumptions are a
subset of the original goal's, CONJ_VALIDATE tac g will do the same,
but with the conjunction of extra hypotheses to prove conjoined to that
one goal's conclusion. If there is one new goal, but its assumptions are
not a subset, then a separate sub-goal is generated.
Failure
A call CONJ_VALIDATE tac g will fail if tac g fails, or if tac g's
validation function produces a theorem whose conclusion is not the same
as g's conclusion.
Comments
CONJ_VALIDATE performs the same role as VALIDATE but tries to
preserve the property of having a single successor goal in its argument
tactics; when it does generate extra sub-goals, it also generates only
one such.
Because CONJ_VALIDATE prefers to generate just one sub-goal, the
result may be a state where one ends up having to prove a hypothesis in
a weaker context (with fewer assumptions) to hand than if VALIDATE had
been used.
See also
EVERY
EVERY
Tactical.EVERY : (tactic list -> tactic)
Sequentially applies all the tactics in a given list of tactics.
When applied to a list of tactics [T1; ... ;Tn], and a goal g, the
tactical EVERY applies each tactic in sequence to every subgoal
generated by the previous one. This can be represented as:
EVERY [T1;...;Tn] = T1 THEN ... THEN Tn
If the tactic list is empty, the resulting tactic has no effect.
Failure
The application of EVERY to a tactic list never fails. The resulting
tactic fails iff any of the component tactics do.
Comments
It is possible to use EVERY instead of THEN, but probably
stylistically inferior. EVERY is more useful when applied to a list of
tactics generated by a function.
See also
Tactical.FIRST,
Tactical.MAP_EVERY,
Tactical.THEN
EVERY_ASSUM
EVERY_ASSUM
Tactical.EVERY_ASSUM : (thm_tactic -> tactic)
Sequentially applies all tactics given by mapping a function over the assumptions of a goal.
When applied to a theorem-tactic f and a goal ({A1,...,An} ?- C),
the EVERY_ASSUM tactical maps f over a list of ASSUMEd assumptions
then applies the resulting tactics, in sequence, to the goal:
EVERY_ASSUM f ({A1,...,An} ?- C)
= (f(A1 |- A1) THEN ... THEN f(An |- An)) ({A1,...,An} ?- C)
If the goal has no assumptions, then EVERY_ASSUM has no effect.
Failure
The application of EVERY_ASSUM to a theorem-tactic and a goal fails if
the theorem-tactic fails when applied to any of the ASSUMEd
assumptions of the goal, or if any of the resulting tactics fail when
applied sequentially.
See also
Tactical.ASSUM_LIST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST,
Tactical.THEN
EVERY_LT
EVERY_LT
Tactical.EVERY_LT : (list_tactic list -> list_tactic)
Sequentially applies all the list-tactics in a given list of list-tactics.
When applied to a list of list-tactics [LT1; ... ;LTn], and a goal
g, the tactical EVERY_LT applies each list-tactic in sequence to
every subgoal generated by the previous one. This can be represented as:
EVERY_LT [LT1;...;LTn] = LT1 THEN_LT ... THEN_LT LTn
If the list-tactic list is empty, the resulting list-tactic has no effect.
Failure
The application of EVERY_LT to a list-tactic list never fails. The
resulting list-tactic fails iff any of the component list-tactics do.
Comments
It is possible to use EVERY_LT instead of THEN_LT, but probably
stylistically inferior. EVERY_LT is more useful when applied to a list
of list-tactics generated by a function.
See also
FAIL_LT
FAIL_LT
Tactical.FAIL_LT : string -> list_tactic
List-tactic which always fails, with the supplied string.
Whatever goal list it is applied to, FAIL_LT s always fails with the
string s.
Failure
The application of FAIL_LT to a string never fails; the resulting
list-tactic always fails.
See also
Tactical.FAIL_TAC,
Tactical.ALL_LT,
Tactical.NO_LT
FAIL_TAC
FAIL_TAC
Tactical.FAIL_TAC : string -> tactic
Tactic which always fails, with the supplied string.
Whatever goal it is applied to, FAIL_TAC s always fails with the
string s.
Failure
The application of FAIL_TAC to a string never fails; the resulting
tactic always fails.
Example
The following example uses the fact that if a tactic t1 solves a goal,
then the tactic t1 THEN t2 never results in the application of t2 to
anything, because t1 produces no subgoals. In attempting to solve the
following goal:
?- if x then T else T
the tactic
REWRITE_TAC[] THEN FAIL_TAC "Simple rewriting failed to solve goal"
will fail with the message provided, whereas:
CONV_TAC COND_CONV THEN FAIL_TAC "Using COND_CONV failed to solve goal"
will silently solve the goal because COND_CONV reduces it to just
?- T.
See also
Tactical.ALL_TAC,
Tactical.NO_TAC
FIRST
FIRST
Tactical.FIRST : (tactic list -> tactic)
Applies the first tactic in a tactic list which succeeds.
When applied to a list of tactics [T1;...;Tn], and a goal g, the
tactical FIRST tries applying the tactics to the goal until one
succeeds. If the first tactic which succeeds is Tm, then the effect is
the same as just Tm. Thus FIRST effectively behaves as follows:
FIRST [T1;...;Tn] = T1 ORELSE ... ORELSE Tn
Failure
The application of FIRST to a tactic list never fails. The resulting
tactic fails iff all the component tactics do when applied to the goal,
or if the tactic list is empty.
See also
Tactical.EVERY,
Tactical.ORELSE
FIRST_ASSUM
FIRST_ASSUM
Tactical.FIRST_ASSUM : (thm_tactic -> tactic)
Maps a theorem-tactic over the assumptions, applying first successful tactic.
The tactic
FIRST_ASSUM ttac ([A1; ...; An], g)
has the effect of applying the first tactic which can be produced by
ttac from the ASSUMEd assumptions (A1 |- A1), ..., (An |- An)
and which succeeds when applied to the goal. Failures of ttac to
produce a tactic are ignored.
Failure
Fails if ttac (Ai |- Ai) fails for every assumption Ai, or if the
assumption list is empty, or if all the tactics produced by ttac fail
when applied to the goal.
Example
The tactic
FIRST_ASSUM (fn asm => CONTR_TAC asm ORELSE ACCEPT_TAC asm)
searches the assumptions for either a contradiction or the desired conclusion. The tactic
FIRST_ASSUM MATCH_MP_TAC
searches the assumption list for an implication whose conclusion matches the goal, reducing the goal to the antecedent of the corresponding instance of this implication.
Comments
By default, the assumption list is printed in reverse order, with the
head of the list printed last. To process the assumption list in the
opposite order, use LAST_ASSUM
See also
Tactical.FIRST_X_ASSUM,
Tactical.LAST_ASSUM,
Tactical.ASSUM_LIST,
Tactical.EVERY,
Tactical.EVERY_ASSUM,
Tactical.FIRST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST
FIRST_LT
FIRST_LT
Tactical.FIRST_LT : tactic -> list_tactic
Applies a tactic to the first goal in the goal-list that works.
Given a list of goals gl, an application of FIRST_LT tac to gl
will try to apply tac to each goal in gl in turn. If no goal lets
tac succeed, the whole application fails also. Otherwise, the first
goal on which tac succeeds will generate a (possibly empty) list of
new sub-goals. These new sub-goals are pushed onto the front of the rest
of gl.
Failure
The application of FIRST_LT to a tactic never fails. The resulting
list-tactic fails if the goal list is empty, or if argument tac fails
on each goal in the list gl.
Example
> FIRST_LT CONJ_TAC [([], “p ⇒ q”), ([“a ∨ b”], “p /\ q”)]
val it = ([([“a ∨ b”], “p”), ([“a ∨ b”], “q”), ([], “p ⇒ q”)], fn):
goal list * list_validation
See also
Tactical.THEN_LT,
Tactical.HEADGOAL
FIRST_PROVE
FIRST_PROVE
Tactical.FIRST_PROVE : (tactic list -> tactic)
Applies the first tactic in a tactic list which completely proves the goal.
When applied to a list of tactics [T1;...;Tn], and a goal g, the
tactical FIRST_PROVE tries applying the tactics to the goal until one
proves the goal. If the first tactic which proves the goal is Tm, then
the effect is the same as just Tm. Thus FIRST_PROVE effectively
behaves as follows:
FIRST_PROVE [T1;...;Tn] = (T1 THEN NO_TAC) ORELSE ... ORELSE (Tn THEN NO_TAC)
Failure
The application of FIRST_PROVE to a tactic list never fails. The
resulting tactic fails iff none of the supplied tactics completely
proves the goal by itself, or if the tactic list is empty.
See also
Tactical.EVERY,
Tactical.ORELSE,
Tactical.FIRST
FIRST_X_ASSUM
FIRST_X_ASSUM
Tactical.FIRST_X_ASSUM : thm_tactic -> tactic
Maps a theorem-tactic over the assumptions, applying first successful tactic and removing the assumption that gave rise to the successful tactic.
The tactic
FIRST_X_ASSUM ttac ([A1; ...; An], g)
has the effect of applying the first tactic which can be produced by
ttac from the ASSUMEd assumptions (A1 |- A1), ..., (An |- An)
and which succeeds when applied to the goal. The assumption which
produced the successful theorem-tactic is removed from the assumption
list (before ttac is applied). Failures of ttac to produce a tactic
are ignored.
Failure
Fails if ttac (Ai |- Ai) fails for every assumption Ai, or if the
assumption list is empty, or if all the tactics produced by ttac fail
when applied to the goal.
Example
The tactic
FIRST_X_ASSUM SUBST_ALL_TAC
searches the assumptions for an equality and causes its right hand side
to be substituted for its left hand side throughout the goal and
assumptions. It also removes the equality from the assumption list.
Using FIRST_ASSUM above would leave an equality on the assumption list
of the form x = x. The tactic
FIRST_X_ASSUM MATCH_MP_TAC
searches the assumption list for an implication whose conclusion matches the goal, reducing the goal to the antecedent of the corresponding instance of this implication and removing the implication from the assumption list.
Comments
The "X" in the name of this tactic is a mnemonic for the "crossing out" or removal of the assumption found.
By default, the assumption list is printed in reverse order, with the
head of the list printed last. To process the assumption list in the
opposite order, use LAST_X_ASSUM
See also
Tactical.FIRST_ASSUM,
Tactical.LAST_X_ASSUM,
Tactical.ASSUM_LIST,
Tactical.EVERY,
Tactical.PAT_ASSUM,
Tactical.EVERY_ASSUM,
Tactical.FIRST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST,
Thm_cont.UNDISCH_THEN
GEN_VALIDATE
GEN_VALIDATE
Tactical.GEN_VALIDATE : bool -> tactic -> tactic
Where a tactic requires assumptions to be in the goal, add those assumptions as new subgoals.
See VALIDATE, which is implemented as GEN_VALIDATE true.
Suppose tac applied to the goal (asl,g) produces a justification
that creates a theorem A |- g'. Then GEN_VALIDATE false adds new
subgoals for members of A, regardless of whether they are present in
asl.
Failure
Fails by design if tac, when applied to a goal, produces a proof which
is invalid on account of proving a theorem whose conclusion differs from
that of the goal.
Also fails if tac fails when applied to the given goal.
Example
For example, where theorem uthr' is [p', q] |- r
[...Lines elided...]
4. Incomplete goalstack:
Initial goal:
∃R. WF R ∧ (∀rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)) ∧
∀rst x ord. R (ord,FILTER ($¬ ∘ ord x) rst) (ord,x::rst)
3. Incomplete goalstack:
Initial goal:
1 + 2 = 2 + 1
Current goal:
∀(x,y). x + y = y + x
2. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
Current goal:
p
1. Incomplete goalstack:
Initial goal:
0. q
1. p
------------------------------------
r
> e (VALIDATE (ACCEPT_TAC uthr')) ;
OK..
1 subgoal:
val it =
0. q
1. p
------------------------------------
p'
but, instead of that,
> e (GEN_VALIDATE false (ACCEPT_TAC uthr')) ;
OK..
2 subgoals:
val it =
0. q
1. p
------------------------------------
q
0. q
1. p
------------------------------------
p'
Use GEN_VALIDATE false rather than VALIDATE when programming
compound tactics if you want to know what the resulting subgoals will
be, regardless of what the assumptions of the goal are.
See also
Tactical.VALID,
Tactical.VALIDATE,
Tactical.ADD_SGS_TAC
GEN_VALIDATE_LT
GEN_VALIDATE_LT
Tactical.GEN_VALIDATE_LT : bool -> list_tactic -> list_tactic
Where a list-tactic requires assumptions to be in the goal, add those assumptions as new subgoals.
See VALIDATE_LT, which is implemented as GEN_VALIDATE_LT true.
When list-tactic ltac is applied to a goal list gl it produces a new
goal list gl' and a justification. When the justification is applied
to a list thl' of theorems which are the new goals gl', proved, it
produces a list thl of theorems (which, for a valid list-tactic are
the goals gl, proved).
But GEN_VALIDATE_LT false ltac also returns extra subgoals
corresponding to the assumptions of thl.
See GEN_VALIDATE for more details.
Failure
Fails by design if ltac, when applied to a goal list, produces a proof
which is invalid on account of proving a theorem whose conclusion
differs from that of the corresponding goal.
Also fails if ltac fails when applied to the given goals.
Compared with VALIDATE_LT ltac, GEN_VALIDATE_LT false ltac can
produces extra, unnecessary, subgoals. But since the subgoals produced
are predictable, regardless of the assumptions of the goal, which may be
useful when coding compound tactics.
See also
Tactical.VALID,
Tactical.VALID_LT,
Tactical.VALIDATE,
Tactical.VALIDATE_LT,
Tactical.GEN_VALIDATE
goal_assum
goal_assum
Tactical.goal_assum : thm_tactic -> tactic
Makes the goal available as a (negated) assumption for a theorem-tactic.
An application of goal_assum ttac to the goal (A,w0) can be seen as
a tactic that first transforms the goal into (w1::A,F) (as if starting
a proof by contradiction, normalising ¬w0 into an equivalent w1);
pops the new assumption w1 and applies the theorem-tactic ttac to
this theorem (w1 ⊢ w1); and when this completes, renormalises the
conclusion of the goal if it has turned into something of the form
w2 ⇒ F.
The first normalisation phase will turn something of the form ¬p into
p⇒F, and will also flip outermost existential quantifiers into
universals. Thus, if the w0 term was ∃x. P x ∧ Q (f x), the w1
term will be ∀x. P x ∧ Q (f x) ⇒ F. The second normalisation phase
will undo this, so that if the effect of ttac is equivalent to a call
of MP_TAC th' with th' a universally quantified implication into
falsity, then the goal will again become an existentially quantified
conjunction.
Failure
Fails if ttac fails when applied to the theorem w1 ⊢ w1 and the goal
(A,F).
See also
HEADGOAL
HEADGOAL
Tactical.HEADGOAL : tactic -> list_tactic
The list-tactic which applies a tactic to the first member of a list of goals.
If tac is a tactic, HEADGOAL tac is a list-tactic which applies the
tactic tac to the first member of a list of goals.
Failure
The application of HEADGOAL to a tactic never fails. The resulting
list-tactic fails the goal list is empty or or finally if tac fails
when applied to the first member of the goal list.
Applying a tactic to the first subgoal.
Example
Where tac1 and tac2 are tactics, tac1 THEN_LT HEADGOAL tac2
applies tac1 to a goal, and then applies tac2 to the first resulting
subgoal.
See also
Tactical.THEN_LT,
Tactical.NTH_GOAL,
Tactical.THEN1,
Tactical.LASTGOAL
IF
IF
Tactical.IF : tactic -> tactic -> tactic -> tactic
Implements an if-then-else for tactics, using exceptions as failure.
Applying the tactic IF gt tt et to a goal g first applies gt to
g. If this tactic application succeeds (does not throw an exception),
then the tactic tt is applied to all of the generated sub-goals. (If
there are none because gt has completely proved the goal, this has no
effect and the result is a proved goal.) If gt g raises an exception,
then et is applied to g.
Failure
The application of IF to three tactic arguments never fails. The
resulting tactic will fail on a goal g if gt g succeeds and tt
fails on one of the resulting subgoals, or if gt g and et g both
fail.
Example
> IF CONJ_TAC CONJ_TAC DISCH_TAC ([], “(p1 ∧ p2) ∧ (q1 ∧ q2)”);
val it = ([([], “p1”), ([], “p2”), ([], “q1”), ([], “q2”)], fn):
goal list * validation
> IF CONJ_TAC CONJ_TAC DISCH_TAC ([], “p ⇒ q”);
val it = ([([“p”], “q”)], fn): goal list * validation
> IF CONJ_TAC CONJ_TAC DISCH_TAC ([], ``(p1 ∧ p2) ∧ q``);
Exception- HOL_ERR at Tactic.CONJ_TAC: raised
> IF CONJ_TAC CONJ_TAC DISCH_TAC ([], “p ∨ q”);
Exception- HOL_ERR at Tactic.DISCH_TAC: raised
Comments
A call to IF gt tt et does not behave the same as
(gt THEN tt) ORELSE et because the latter catches possible errors in
the application of tt to the goals generated by gt.
See also
Tactical.ORELSE, Tactical.THEN
LAST_ASSUM
LAST_ASSUM
Tactical.LAST_ASSUM : (thm_tactic -> tactic)
Maps a theorem-tactic over the assumptions, in reverse order, applying first successful tactic.
LAST_ASSUM behaves like FIRST_ASSUM, except that it goes through the
list of assumptions in reverse order
See also
Tactical.FIRST_ASSUM,
Tactical.LAST_X_ASSUM
LAST_X_ASSUM
LAST_X_ASSUM
Tactical.LAST_X_ASSUM : thm_tactic -> tactic
Maps a theorem-tactic over the assumptions, in reverse order, applying first successful tactic and removing the assumption that gave rise to the successful tactic.
LAST_X_ASSUM behaves like FIRST_X_ASSUM, except that it goes through
the list of assumptions in reverse order
See also
Tactical.FIRST_X_ASSUM,
Tactical.LAST_ASSUM
LASTGOAL
LASTGOAL
Tactical.LASTGOAL : tactic -> list_tactic
The list-tactic which applies a tactic to the last member of a list of goals.
If tac is a tactic, LASTGOAL tac is a list-tactic which applies the
tactic tac to the last member of a list of goals.
Failure
The application of LASTGOAL to a tactic never fails. The resulting
list-tactic fails the goal list is empty or or finally if tac fails
when applied to the last member of the goal list.
Applying a tactic to the last subgoal.
Example
Where tac1 and tac2 are tactics, tac1 THEN_LT LASTGOAL tac2
applies tac1 to a goal, and then applies tac2 to the last resulting
subgoal.
See also
Tactical.THEN_LT,
Tactical.NTH_GOAL,
Tactical.HEADGOAL
MAP_EVERY
MAP_EVERY
Tactical.MAP_EVERY : (('a -> tactic) -> 'a list -> tactic)
Sequentially applies all tactics given by mapping a function over a list.
When applied to a tactic-producing function f and an operand list
[x1;...;xn], the elements of which have the same type as f's domain
type, MAP_EVERY maps the function f over the list, producing a list
of tactics, then applies these tactics in sequence as in the case of
EVERY. The effect is:
MAP_EVERY f [x1;...;xn] = (f x1) THEN ... THEN (f xn)
If the operand list is empty, then MAP_EVERY has no effect.
Failure
The application of MAP_EVERY to a function and operand list fails iff
the function fails when applied to any element in the list. The
resulting tactic fails iff any of the resulting tactics fails.
Example
A convenient way of doing case analysis over several boolean variables is:
MAP_EVERY BOOL_CASES_TAC ["var1:bool";...;"varn:bool"]
See also
Tactical.EVERY,
Tactical.FIRST,
Tactical.MAP_FIRST,
Tactical.THEN
MAP_FIRST
MAP_FIRST
Tactical.MAP_FIRST : (('a -> tactic) -> 'a list -> tactic)
Applies first tactic that succeeds in a list given by mapping a function over a list.
When applied to a tactic-producing function f and an operand list
[x1,...,xn], the elements of which have the same type as f's domain
type, MAP_FIRST maps the function f over the list, producing a list
of tactics, then tries applying these tactics to the goal till one
succeeds. If f(xm) is the first to succeed, then the overall effect is
the same as applying f(xm). Thus:
MAP_FIRST f [x1,...,xn] = (f x1) ORELSE ... ORELSE (f xn)
Failure
The application of MAP_FIRST to a function and tactic list fails iff
the function does when applied to any of the elements of the list. The
resulting tactic fails iff all the resulting tactics fail when applied
to the goal.
See also
Tactical.EVERY,
Tactical.FIRST,
Tactical.MAP_EVERY,
Tactical.ORELSE
NO_LT
NO_LT
Tactical.NO_LT : list_tactic
List-tactic which always fails.
Whatever goal list it is applied to, NO_LT always fails with string
`NO_LT`.
Failure
Always fails.
See also
Tactical.NO_TAC,
Tactical.ALL_LT,
Tactical.FAIL_LT
NO_TAC
NO_TAC
Tactical.NO_TAC : tactic
Tactic which always fails.
Whatever goal it is applied to, NO_TAC always fails with string
`NO_TAC`.
Failure
Always fails.
See also
Tactical.ALL_TAC,
Thm_cont.ALL_THEN,
Tactical.FAIL_TAC,
Thm_cont.NO_THEN
NTH_GOAL
NTH_GOAL
Tactical.NTH_GOAL : tactic -> int -> list_tactic
The list-tactic which applies a tactic to the n'th member of a list of
goals.
If tac is a tactic, NTH_GOAL n tac is a list-tactic which applies
the tactic tac to the n'th member of a list of goals.
Note that in the interactive system, subgoals are printed in reverse order of their numbering.
Failure
The application of NTH_GOAL to a tactic and integer never fails. The
resulting list-tactic fails if n is less than 1 or greater than the
length of the goal list, or finally if tac fails when applied to the
n'th member of the goal list.
Applying a tactic to a particular subgoal.
Example
Where tac1 and tac2 are tactics, tac1 THEN_LT NTH_GOAL n tac2
applies tac1 to a goal, and then applies tac2 to the n'th
resulting subgoal.
See also
Tactical.THEN_LT,
Tactical.THEN1,
Tactical.HEADGOAL,
Tactical.LASTGOAL
NULL_OK_LT
NULL_OK_LT
Tactical.NULL_OK_LT : list_tactic -> list_tactic
Makes a list-tactic succeed with no effect when applied to the empty goal list.
For any list-tactic ltac, the application NULL_OK_LT ltac gives a
new list-tactic which has the same effect as ltac when applied to a
non-empty goal list. Applied to the empty goal list it succeeds with no
effect.
Failure
The application of NULL_OK_LT to a list-tactic ltac never fails. The
resulting list-tactic fails if applied to a non-empty goal list on which
ltac fails.
See also
Tactical.ALL_LT,
Tactical.THENL
ORELSE
ORELSE
op Tactical.ORELSE : tactic * tactic -> tactic
Applies first tactic, and if it fails, applies the second instead.
If T1 and T2 are tactics, T1 ORELSE T2 is a tactic which applies
T1 to a goal, and if it fails, applies T2 to the goal instead.
Failure
The application of ORELSE to a pair of tactics never fails. The
resulting tactic fails if both T1 and T2 fail when applied to the
relevant goal.
See also
Tactical.EVERY,
Tactical.FIRST, Tactical.IF,
Tactical.THEN
ORELSE_LT
ORELSE_LT
op Tactical.ORELSE_LT : list_tactic * list_tactic -> list_tactic
Applies first list-tactic, and if it fails, applies the second instead.
If ltac1 and ltac2 are list-tactics, ltac1 ORELSE_LT ltac2 is a
list-tactic which applies ltac1 to a goal list, and if it fails,
applies ltac2 to the goals.
Failure
The application of ORELSE_LT to a pair of list-tactics never fails.
The resulting list-tactic fails if both ltac1 and ltac2 fail when
applied to the relevant goals.
See also
Tactical.ORELSE,
Tactical.THEN_LT
PAT_ASSUM
PAT_ASSUM
Tactical.PAT_ASSUM : term -> thm_tactic -> tactic
Finds the first assumption that matches the term argument, applies the theorem tactic to it. The matching assumption remains in the assumption list.
The tactic
PAT_ASSUM tm ttac ([A1, ..., An], g)
finds the first Ai which matches tm using higher-order pattern
matching in the sense of ho_match_term. Free variables in the pattern
that are also free in the assumptions or the goal must not be bound by
the match. In effect, these variables are being treated as local
constants.
Failure
Fails if the term doesn't match any of the assumptions, or if the theorem-tactic fails when applied to the first assumption that does match the term.
Example
The tactic
PAT_ASSUM ``x:num = y`` SUBST_ALL_TAC
searches the assumptions for an equality over numbers and causes its
right hand side to be substituted for its left hand side throughout the
goal and assumptions. It also removes the equality from the assumption
list. Trying to use FIRST_ASSUM above (i.e., replacing PAT_ASSUM
with FIRST_ASSUM and dropping the term argument entirely) would
require that the desired equality was the first such on the list of
assumptions.
If one is trying to solve the goal
{ !x. f x = g (x + 1), !x. g x = f0 (f x)} ?- f x = g y
rewriting with the assumptions directly will cause a loop. Instead, one
might want to rewrite with the formula for f. This can be done in an
assumption-order-independent way with
PAT_ASSUM (Term`!x. f x = f' x`) (fn th => REWRITE_TAC [th])
This use of the tactic exploits higher order matching to match the RHS
of the assumption, and the fact that f is effectively a local constant
in the goal to find the correct assumption.
Comments
The behavior of PAT_ASSUM changed in Kananaskis 12. The old
PAT_ASSUM (and qpat_assum, Q.PAT_ASSUM) was changed to include an
extra _X_ (or _x_), indicating that the matching assumption is
pulled out of the assumption list. The old name now provides a version
that doesn't pull the assumption out of the list.
See also
Tactical.PAT_X_ASSUM,
Tactical.ASSUM_LIST,
Tactical.EVERY,
Tactical.EVERY_ASSUM,
Tactical.FIRST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST,
Thm_cont.UNDISCH_THEN,
Term.match_term
PAT_X_ASSUM
PAT_X_ASSUM
Tactical.PAT_X_ASSUM : term -> thm_tactic -> tactic
Finds the first assumption that matches the term argument, applies the theorem tactic to it, and removes this assumption.
The tactic
PAT_X_ASSUM tm ttac ([A1, ..., An], g)
finds the first Ai which matches tm using higher-order pattern
matching in the sense of ho_match_term. Free variables in the pattern
that are also free in the assumptions or the goal must not be bound by
the match. In effect, these variables are being treated as local
constants.
Failure
Fails if the term doesn't match any of the assumptions, or if the theorem-tactic fails when applied to the first assumption that does match the term.
See also
Tactical.PAT_ASSUM,
Tactical.ASSUM_LIST,
Tactical.EVERY,
Tactical.EVERY_ASSUM,
Tactical.FIRST,
Tactical.MAP_EVERY,
Tactical.MAP_FIRST,
Thm_cont.UNDISCH_THEN,
Term.match_term
POP_ASSUM
POP_ASSUM
Tactical.POP_ASSUM : thm_tactic -> tactic
Applies tactic generated from the first element of a goal's assumption list.
When applied to a theorem-tactic and a goal, POP_ASSUM applies the
theorem-tactic to the ASSUMEd first element of the assumption list,
and applies the resulting tactic to the goal without the first
assumption in its assumption list:
POP_ASSUM f ({A1,...,An} ?- t) = f (A1 |- A1) ({A2,...,An} ?- t)
Failure
Fails if the assumption list of the goal is empty, or the theorem-tactic fails when applied to the popped assumption, or if the resulting tactic fails when applied to the goal (with depleted assumption list).
Comments
It is possible simply to use the theorem ASSUME A1 as required rather
than use POP_ASSUM; this will also maintain A1 in the assumption
list, which is generally useful. In addition, this approach can equally
well be applied to assumptions other than the first.
There are admittedly times when POP_ASSUM is convenient, but it is
most unwise to use it if there is more than one assumption in the
assumption list, since this introduces a dependency on the ordering,
which is vulnerable to changes in the HOL system.
Another point to consider is that if the relevant assumption has been
obtained by DISCH_TAC, it is often cleaner to use DISCH_THEN with a
theorem-tactic. For example, instead of:
DISCH_TAC THEN POP_ASSUM (SUBST1_TAC o SYM)
one might use
DISCH_THEN (SUBST1_TAC o SYM)
The tactical POP_ASSUM is also available under the lower-case version
of the name, pop_assum.
Example
The goal:
{4 = SUC x} ?- x = 3
can be solved by:
POP_ASSUM
(fn th => REWRITE_TAC[REWRITE_RULE[num_CONV “4”, INV_SUC_EQ] th])
Making more delicate use of an assumption than rewriting or resolution using it.
See also
Tactical.ASSUM_LIST,
Tactical.EVERY_ASSUM,
Tactic.IMP_RES_TAC,
Tactical.POP_ASSUM_LIST,
Tactical.POP_LAST_ASSUM,
Rewrite.REWRITE_TAC
POP_ASSUM_LIST
POP_ASSUM_LIST
Tactical.POP_ASSUM_LIST : (thm list -> tactic) -> tactic
Generates a tactic from the assumptions, discards the assumptions and applies the tactic.
When applied to a function and a goal, POP_ASSUM_LIST applies the
function to a list of theorems corresponding to the ASSUMEd
assumptions of the goal, then applies the resulting tactic to the goal
with an empty assumption list.
POP_ASSUM_LIST f ({A1,...,An} ?- t) = f [A1 |- A1, ..., An |- An] (?- t)
Failure
Fails if the function fails when applied to the list of ASSUMEd
assumptions, or if the resulting tactic fails when applied to the goal
with no assumptions.
Comments
There is nothing magical about POP_ASSUM_LIST: the same effect can be
achieved by using ASSUME a explicitly wherever the assumption a is
used. If POP_ASSUM_LIST is used, it is unwise to select elements by
number from the ASSUMEd-assumption list, since this introduces a
dependency on ordering.
Example
Suppose we have a goal of the following form:
{a /\ b, c, (d /\ e) /\ f} ?- t
Then we can split the conjunctions in the assumption list apart by applying the tactic:
POP_ASSUM_LIST (MAP_EVERY STRIP_ASSUME_TAC)
which results in the new goal:
{a, b, c, d, e, f} ?- t
Making more delicate use of the assumption list than simply rewriting or using resolution.
See also
Tactical.ASSUM_LIST,
Tactical.EVERY_ASSUM,
Tactic.IMP_RES_TAC,
Tactical.POP_ASSUM,
Rewrite.REWRITE_TAC
POP_LAST_ASSUM
POP_LAST_ASSUM
Tactical.POP_LAST_ASSUM : thm_tactic -> tactic
Applies tactic generated from the last element of a goal's assumption list.
When applied to a theorem-tactic and a goal, POP_LAST_ASSUM applies
the theorem-tactic to the ASSUMEd last element of the assumption list,
and applies the resulting tactic to the goal without that assumption in
its assumption list:
POP_LAST_ASSUM f ({A1,...,Am,An} ?- t) = f (An |- An) ({A1,...,Am} ?- t)
Failure
Fails if the assumption list of the goal is empty, or the theorem-tactic fails when applied to the popped assumption, or if the resulting tactic fails when applied to the goal (with depleted assumption list).
Comments
The tactical POP_LAST_ASSUM is also available under the lower-case
version of the name, pop_last_assum.
See also
Tactical.ASSUM_LIST,
Tactical.EVERY_ASSUM,
Tactic.IMP_RES_TAC,
Tactical.POP_ASSUM,
Rewrite.REWRITE_TAC
PRED_ASSUM
PRED_ASSUM
Tactical.PRED_ASSUM : (term -> bool) -> thm_tactic -> tactic
Discharges a selected assumption and passes it to a theorem-tactic.
PRED_ASSUM finds the first assumption satisfying the prediate given,
removes it from the assumption list, ASSUMEs it, passes it to the
theorem-tactic and then applies the consequent tactic. Thus, where t
is the first assumption satisfying p,
PRED_ASSUM p f ([a1,... ai, t, aj, ... an], goal) =
f (ASSUME t) ([a1,... ai, aj,... an], goal)
For example (again, where t is the first assumption in A u {t}
satisfying p), if
A ?- c
======== f (ASSUME t)
B ?- v
then
A u {t} ?- c
=============== PRED_ASSUM p f
B ?- v
Failure
PRED_ASSUM p will fail on goals where no assumption safisfies p.
See also
Thm_cont.UNDISCH_THEN,
Tactical.PAT_ASSUM,
Tactical.POP_ASSUM,
Tactic.UNDISCH_TAC
prove
prove
Tactical.prove : term * tactic -> thm
Attempts to prove a boolean term using the supplied tactic.
When applied to a term-tactic pair (tm,tac), the function prove
attempts to prove the goal ?- tm, that is, the term tm with no
assumptions, using the tactic tac. If prove succeeds, it returns the
corresponding theorem A |- tm, where the assumption list A may not
be empty if the tactic is invalid; prove has no inbuilt
validity-checking.
By default this function calls TAC_PROOF (q.v.) with a wrapper that augments that underlying function’s error-reporting, but this call is made via a user-updatable reference. This means there are contexts in which this function may, for example, automatically assert all terms it is passed as theorems using mk_thm.
Comments
To emulate interactive use and its variations, prove is appropriate; to get fixed behaviour, use TAC_PROOF.
Failure
Fails if the term is not of type bool (and so cannot possibly be the
conclusion of a theorem), or if the tactic does not solve the goal.
See also
Tactical.prove_goal, Tactical.set_prover, Tactical.TAC_PROOF.
prove_goal
prove_goal
Tactical.prove_goal : goal * tactic -> thm
Proves a goal with a tactic.
By default (using the function TAC_PROOF (q.v.)), a call to prove_goal((asl,g), tac) attempts to prove the specified goal (asl,g) by applying the tactic tac to it, generating a result (sgs,vf). This result has sgs a list of subgoals and vf a validation function. If sgs is empty, then the value of vf [] is returned.
If the provided tactic is valid, the resulting theorem will have hypotheses that are a subset of the assumptions asl, and will have a conclusion that is alpha-equivalent to g.
The default behaviour can be changed with the function Tactical.set_prover.
Failure
Fails if the goal (asl,g) is not well-typed (all members of the list asl must be of type :bool as must be the conclusion g), or if the supplied tactic does not prove the goal.
Comments
Tactical.prove_goal is to TAC_PROOF as Tactical.prove is to Tactical.default_prover.
See also
Tactical.prove,
Tactical.set_prover,
Tactical.TAC_PROOF.
Q_TAC
Q_TAC
Tactical.Q_TAC : (term -> tactic) -> term quotation -> tactic
A tactical that parses in the context of a goal, a la the Q library.
When applied to a term tactic T and a quotation q, the tactic
Q_TAC T q first parses the quotation q in the context of the goal to
yield the term tm, and then applies the tactic T tm to the goal.
Failure
The application of Q_TAC to a term tactic T and a quotation q
never fails. The resulting composite tactic Q_TAC T q fails when
applied to a goal if either q cannot be parsed, or T tm fails when
applied to the goal.
Comments
Useful for avoiding decorating terms with type abbreviations.
See also
Tactical.EVERY,
Tactical.FIRST,
Tactical.ORELSE,
Tactical.THEN, Tactical.THEN1,
Tactical.THENL
REPEAT
REPEAT
Tactical.REPEAT : (tactic -> tactic)
Repeatedly applies a tactic until it fails.
The tactic REPEAT T is a tactic which applies T to a goal, and while
it succeeds, continues applying it to all subgoals generated.
Failure
The application of REPEAT to a tactic never fails, and neither does
the composite tactic, even if the basic tactic fails immediately.
See also
Tactical.EVERY,
Tactical.FIRST,
Tactical.ORELSE,
Tactical.THEN, Tactical.THENL
REPEAT_LT
REPEAT_LT
Tactical.REPEAT_LT : (list_tactic -> list_tactic)
Repeatedly applies a list-tactic until it fails.
The list-tactic REPEAT_LT ltac is a list-tactic which applies ltac
to a goal list, and while it succeeds, continues applying it to the
resulting subgoal list.
Failure
The application of REPEAT_LT to a list-tactic never fails, and neither
does the composite list-tactic, even if the basic list-tactic fails
immediately.
See also
Tactical.REPEAT,
Tactical.THEN_LT
REVERSE
REVERSE
Tactical.REVERSE : (tactic -> tactic)
Reverses the order of the generated subgoals.
The tactic REVERSE T is a tactic which applies T to a goal, and
reverses the order of the subgoals generated by T.
Failure
The application of REVERSE to a tactic T never fails. The resulting
composite tactic REVERSE T fails when applied to a goal if and only if
T fails.
Comments
Intended for use with THEN1 to pick the 'easy' subgoal.
Example
Given a goal
G1 /\ G2
use
CONJ_TAC THEN1 T0
THEN ...
if the first conjunct is easily dispatched with T0, and
REVERSE CONJ_TAC THEN1 T0
THEN ...
if it is the second conjunct that yields.
See also
Tactical.EVERY,
Tactical.FIRST,
Tactical.ORELSE,
Tactical.THEN, Tactical.THEN1,
Tactical.THENL
REVERSE_LT
REVERSE_LT
Tactical.REVERSE_LT : list_tactic
Reverses the order of a list of subgoals.
The list-tactic REVERSE_LT reverses the order of a list of subgoals.
Failure
Never fails.
Example
Where tac is a tactic, tac THEN_LT REVERSE_LT is equivalent to
REVERSE tac
See also
Tactical.THEN_LT,
Tactical.REVERSE,
Tactical.ROTATE_LT
ROTATE_LT
ROTATE_LT
Tactical.ROTATE_LT : int -> list_tactic
Rotates a list of goals
ROTATE_LT n gl rotates a goal list gl by n places. For n >= 0,
this means moving the first n goals to the end of the list. A negative
n means rotating the list in the opposite direction.
Failure
Never fails.
Example
To bring the third goal to first position, leaving the others in order, use
SPLIT_LT 3 (ROTATE_LT ~1, ALL_LT)
Comments
Using SPLIT_LT, ROTATE_LT and REVERSE_LT, any reordering of a list
of goals is possible.
See also
proofManagerLib.rotate,
proofManagerLib.r,
Tactical.SPLIT_LT,
Tactical.REVERSE_LT,
Tactical.ALL_LT
SELECT_LT
SELECT_LT
Tactical.SELECT_LT : tactic -> list_tactic
Applies a tactic to the all the goals in the goal-list for which the tactic succeeds.
Given a list of goals gl, an application of SELECT_LT tac to gl
will try to apply tac to each goal in gl in turn. If no goal lets
tac succeed, the goal state remains unchanged. Otherwise, the goals
for which tac succeeds will generate (possibly empty) list(s) of new
sub-goals. These new sub-goals are pushed onto the front of the rest of
gl.
Failure
The application of SELECT_LT to a tactic never fails. The resulting
list-tactic also never fails.
Example
> SELECT_LT CONJ_TAC [([], “r ∧ s”), ([], “p ⇒ q”), ([“a ∨ b”], “p ∧ q”)]
val it =
([([], “r”), ([], “s”), ([“a ∨ b”], “p”), ([“a ∨ b”], “q”), ([], “p ⇒ q”)],
fn): goal list * list_validation
See also
Tactical.SELECT_LT_THEN,
Tactical.FIRST_LT,
Tactical.THEN_LT,
Tactical.HEADGOAL
SELECT_LT_THEN
SELECT_LT_THEN
Tactical.SELECT_LT_THEN : tactic -> tactic -> list_tactic
Applies the first tactic to all goals in the goal-list for which the tactic succeeds. Then applies the second tactic to the goals resulting from the first tactic.
Given a list of goals gl, an application of SELECT_LT tac1 tac2 to
gl will try to apply tac1 to each goal in gl in turn. If no goal
lets tac1 succeed, the goal state remains unchanged. Otherwise, the
goals for which tac1 succeeds will generate (possibly empty) list(s)
of new sub-goals. tac2 will be applied to each of these new sub-goals.
The resulting subgoals after applying tac2 are pushed onto the front
of the rest of gl.
Failure
The application of SELECT_LT_THEN to tactic arguments tac1, tac2
never fails. The resulting list-tactic fails only when tac2 fails on a
subgoal produced by applying tac1 to the current goals.
Example
> SELECT_LT_THEN DISJ1_TAC ALL_TAC
[([], “T ∨ s”), ([], “p ⇒ q”), ([“a ∨ b”], “p ∨ q”)]
val it = ([([], “T”), ([“a ∨ b”], “p”), ([], “p ⇒ q”)], fn):
goal list * list_validation
> SELECT_LT_THEN DISJ1_TAC (ACCEPT_TAC TRUTH)
[([], “T ∨ s”), ([], “p ⇒ q”), ([“a ∨ b”], “p ∨ q”)]
Exception- HOL_ERR (at Tactical.SELECT_LT_THEN: Could not apply second tactic) raised
See also
Tactical.SELECT_LT,
Tactical.FIRST_LT,
Tactical.THEN_LT,
Tactical.HEADGOAL
set_prover
set_prover
Tactical.set_prover : (goal * tactic -> thm) -> unit
Specifies the function to be used by prove_goal and prove.
A call to set_prover f sets the function used by prove_goal and prove to be f.
The initial value is TAC_PROOF.
The prove function takes a single term t as argument and passes this along with an empty list of assumptions to f.
Failure
Never fails.
Comments
This function is used by Holmake when called with the --noqof and --fast options to set the prove function to one that will call cheat as appropriate (if a tactic otherwise fails, or in all cases, respectively).
See also
Tactical.prove,
Tactical.prove_goal.
SPLIT_LT
SPLIT_LT
Tactical.SPLIT_LT : int -> list_tactic * list_tactic -> list_tactic
Splits a list of goals into two and applies a list-tactic to each part
For list-tactics ltac1 and ltac2, integer n and goal list gl,
the application SPLIT_LT n (ltac1, ltac2) gl applies ltac1 to the
first n goals in gl, and ltac2 to the remainder. If n is
negative, ltac1 is applied to the goals before the last -n, and
ltac2 to the last -n goals.
Failure
The application SPLIT_LT n (ltac1, ltac2) never fails, but when
applied to a goal list, it fails if the index n is (in absolute value)
larger then the length of the list, or if either of the list-tactics
ltac1 and ltac2 fails.
Example
To apply tactic tac1 to a goal, and then to apply tac2 to all
resulting subgoals except the first, use
tac1 THEN_LT SPLIT_LT 1 (ALL_LT, ALLGOALS tac2)
See also
Tactical.THEN_LT,
Tactical.ALL_LT,
Tactical.ALLGOALS
store_thm
store_thm
Tactical.store_thm : string * term * tactic -> thm
Proves and then stores a theorem in the current theory segment.
The call store_thm(name, t, tac) is equivalent to
save_thm(name, prove(t, tac)).
Failure
Whenever prove fails to prove the given term.
Saving theorems for retrieval in later sessions. Binding the result of
store_thm to an ML variable makes it easy to access the theorem in the
current terminal session.
See also
Tactical.prove,
Theory.save_thm
SUBGOAL_THEN
SUBGOAL_THEN
Tactical.SUBGOAL_THEN : term -> thm_tactic -> tactic
Allows the user to introduce a lemma.
The user proposes a lemma and is then invited to prove it under the
current assumptions. The lemma is then used with the thm_tactic to
simplify the goal. That is, if
A1 ?- t1
========== f (u |- u)
A2 ?- t2
then
A1 ?- t1
==================== SUBGOAL_THEN u f
A1 ?- u A2 ?- t2
Typically f (u |- u) will be an invalid tactic because it would return
a validation function which generated the theorem A1,u |- t1 from the
theorem A2 |- t2. Nonetheless, the tactic SUBGOAL_THEN u f is valid
because of the extra sub-goal where u must be proved.
Failure
SUBGOAL_THEN will fail if an attempt is made to use a nonboolean term
as a lemma.
When combined with rotate, SUBGOAL_THEN allows the user to defer
some part of a proof and to continue with another part. SUBGOAL_THEN
is most convenient when the tactic solves the original goal, leaving
only the subgoal. For example, suppose the user wishes to prove the goal
{n = SUC m} ?- (0 = n) ==> t
Using SUBGOAL_THEN to focus on the case in which ~(n = 0), rewriting
establishes it truth, leaving only the proof that ~(n = 0). That is,
SUBGOAL_THEN (Term `~(0 = n)`) (fn th => REWRITE_TAC [th])
generates the following subgoals:
{n = SUC m} ?- ~(0 = n)
?- T
Comments
Some users may expect the generated tactic to be f (A1 |- u), rather
than f (u |- u).
TAC_PROOF
TAC_PROOF
Tactical.TAC_PROOF : goal * tactic -> thm
Attempts to prove a goal using a given tactic.
When applied to a goal-tactic pair (A ?- t,tac), the TAC_PROOF
function attempts to prove the goal A ?- t, using the tactic tac. If
it succeeds, it returns the theorem A' |- t corresponding to the goal,
where the assumption list A' may be a proper superset of A unless
the tactic is valid; there is no inbuilt validity checking.
Failure
Fails unless the goal has hypotheses and conclusions all of type bool,
and the tactic can solve the goal.
See also
BasicProvers.PROVE, Tactical.prove,
Tactical.VALID
TACS_TO_LT
TACS_TO_LT
Tactical.TACS_TO_LT : tactic list -> list_tactic
The list-tactic which applies a list of tactics to the corresponding members of a list of goals.
If T1,...,Tn are tactics, TACS_TO_LT [T1,...,Tn] is a list-tactic
which applies the tactics T1,...,Tn to the corresponding goals.
Failure
The application of TACS_TO_LT to a tactic list never fails. The
resulting list-tactic fails if length of the goal list is not the same
as that of the tactic list, or finally if Ti fails when applied to the
i'th member of the goal list.
Applying different tactics to different subgoals.
Example
Where tac1 is a tactic and tacs2 is a list of tactics,
tac1 THEN_LT TACS_TO_LT tacs2 is equivalent to tac1 THENL tacs2
See also
Tactical.THEN_LT,
Tactical.THENL
THEN
THEN
op Tactical.THEN : tactic * tactic -> tactic}
op THEN : list_tactic * tactic -> list_tactic
Applies a tactic to all subgoals produced by a tactic or list-tactic.
If T1 and T2 are tactics, T1 THEN T2 is a tactic which applies
T1 to a goal, then applies the tactic T2 to all the subgoals
generated. If T1 solves the goal then T2 is never applied.
Alternatively, T1 may be a list-tactic which is applied to an initial
list of goals.
Failure
The application of THEN to a pair of tactics never fails. The
resulting tactic fails if T1 fails when applied to the goal, or if
T2 does when applied to any of the resulting subgoals.
Comments
Although normally used to sequence tactics which generate a single subgoal, it is worth remembering that it is sometimes useful to apply the same tactic to multiple subgoals; sequences like the following:
EQ_TAC THENL [ASM_REWRITE_TAC[], ASM_REWRITE_TAC[]]
can be replaced by the briefer:
EQ_TAC THEN ASM_REWRITE_TAC[]
See also
Tactical.EVERY,
Tactical.ORELSE,
Tactical.THENL,
Tactical.THEN_LT
THEN1
THEN1
op Tactical.THEN1 : tactic * tactic -> tactic
A tactical like THEN that applies the second tactic only to the first
subgoal.
If T1 and T2 are tactics, T1 THEN1 T2 is a tactic which applies
T1 to a goal, then applies the tactic T2 to the first subgoal
generated. T1 must produce at least one subgoal, and T2 must
completely solve the first subgoal of T1.
Failure
The application of THEN1 to a pair of tactics never fails. The
resulting tactic fails if T1 fails when applied to the goal, if T1
does not produce at least one subgoal (i.e., T1 completely solves the
goal), or if T2 does not completely solve the first subgoal generated
by T1.
Comments
THEN1 can be applied to make the proof more linear, avoiding
unnecessary THENLs. It is especially useful when used with REVERSE.
Example
For example, given the goal
simple_goal /\ complicated_goal
the tactic
(CONJ_TAC THEN1 T0)
THEN T1
THEN T2
THEN ...
THEN Tn
avoids the extra indentation of
CONJ_TAC THENL
[T0,
T1
THEN T2
THEN ...
THEN Tn]
See also
Tactical.EVERY,
Tactical.ORELSE,
Tactical.REVERSE,
Tactical.THEN, Tactical.THENL
THEN_LT
THEN_LT
op Tactical.THEN_LT : tactic * list_tactic -> tactic
op THEN_LT : list_tactic * list_tactic -> list_tactic
Applies a list-tactic to the corresponding subgoals generated by a tactic or by a previous list-tactic.
If tac is a tactic and ltac is a list-tactic, then
tac THEN_LT ltac is a tactic which applies tac to a goal, and if it
does not fail, applies the list-tactic ltac to the resulting list of
subgoals.
If ltac1 and ltac2 are list-tactics, then ltac1 THEN_LT ltac2 is a
list-tactic which applies ltac1 to a goal list, and if it does not
fail, applies ltac2 to the resulting list of goals.
Failure
The application of THEN_LT to a tactic or list-tactic and a
list-tactic never fails.
The tactic tac THEN_LT ltac fails if tac fails when applied to the
goal, or if ltac fails when applied to the resulting subgoal list.
The list-tactic ltac1 THEN_LT ltac2 fails if ltac1 fails when
applied to the goal list, or if ltac2 fails when applied to the goal
list result of ltac1.
Applying a combination of tactics to a list of subgoals, or otherwise manipulating a list of subgoals.
Example
Where tac1 and tac2 are tactics, tac1 THEN_LT ALLGOALS tac2 is
equivalent to tac1 THEN tac2
Where tac1 is a tactic and tacs2 is a list of tactics,
tac1 THEN_LT NULL_OK_LT (TACS_TO_LT tacs2) is equivalent to
tac1 THENL tacs2
Where tac is a tactic, tac THEN_LT REVERSE_LT is equivalent to
REVERSE tac
See also
Tactical.ALLGOALS,
Tactical.THEN,
Tactical.TACS_TO_LT,
Tactical.THENL,
Tactical.NULL_OK_LT,
Tactical.NTH_GOAL,
Tactical.REVERSE_LT,
Tactical.REVERSE
THENL
THENL
op Tactical.THENL : tactic * tactic list -> tactic
op THENL : list_tactic * tactic list -> list_tactic
Applies a list of tactics to the corresponding subgoals generated by a tactic or a list-tactic.
If T is a tactic or list-tactic and T1,...,Tn are tactics,
T THENL [T1,...,Tn] is a tactic or list-tactic which applies T to a
goal or goal list, and if it does not fail, applies the tactics
T1,...,Tn to the corresponding subgoals, unless T completely solves
the goal(s).
Failure
The application of THENL to a (list-)tactic and tactic list never
fails. The resulting tactic fails if T fails when applied to the
goal(s), or if the goal list is not empty and its length is not the same
as that of the tactic list, or finally if Ti fails when applied to the
i'th subgoal generated by T.
Applying different tactics to different subgoals.
See also
Tactical.EVERY,
Tactical.ORELSE,
Tactical.THEN,
Tactical.THEN_LT
TRY
TRY
Tactical.TRY : (tactic -> tactic)
Makes a tactic have no effect rather than fail.
For any tactic T, the application TRY T gives a new tactic which has
the same effect as T if that succeeds, and otherwise has no effect.
Failure
The application of TRY to a tactic never fails. The resulting tactic
never fails.
See also
Tactical.CHANGED_TAC,
Tactical.VALID
TRY_LT
TRY_LT
Tactical.TRY_LT : (list_tactic -> list_tactic)
Makes a list-tactic have no effect rather than fail.
For any list-tactic ltac, the application TRY_LT ltac gives a new
list-tactic which has the same effect as ltac if that succeeds, and
otherwise has no effect.
Failure
The application of TRY_LT to a list-tactic never fails. The resulting
list-tactic never fails.
See also
TRYALL
TRYALL
Tactical.TRYALL : tactic -> list_tactic
Tries to apply a tactic to every goal in a list
If tac is a tactic, TRYALL tac is a list-tactic which, when applied
to a list of goals, applies the tactic tac to each goal for which it
succeeds. When tac fails on a goal, TRYALL tac has no effect on that
goal.
Failure
The application of TRYALL to a tactic never fails. The resulting
list-tactic never fails.
Example
Where tac1 and tac2 are tactics, tac1 THEN_LT TRYALL tac2 is
equivalent to tac1 THEN TRY tac2
See also
Tactical.TRY,
Tactical.THEN_LT,
Tactical.THEN, Tactical.TRY,
Tactical.ALLGOALS
USE_SG_THEN
USE_SG_THEN
Tactical.USE_SG_THEN : thm_tactic -> int -> int -> list_tactic
Allows the user to use one subgoal to prove another
In USE_SG_THEN ttac nu np, of the current goal list, subgoal number
nu can be used in proving subgoal number np. Subgoal number nu is
used as a lemma by ttac to simplify subgoal number np. That is, if
subgoal number nu is A ?- u, subgoal number np is A1 ?- t1, and
A1 ?- t1
========== ttac (u |- u)
A2 ?- t2
then the list-tactic USE_SG_THEN ttac nu np gives this same result
(new subgoal(s)) for subgoal np.
This list-tactic will be invalid unless A is a subset of A1.
Note that in the interactive system, subgoals are printed in reverse order of their numbering.
Failure
USE_SG_THEN will fail ttac (u |- u) fails on subgoal number np, or
if indices np or nu are out of range. Note that the subgoals in the
current subgoal list are numbered starting from 1.
Where two subgoals are similar and not easy to prove, one can be used to help prove the other.
Example
Here subgoal 1 is assumed, so as to help in proving subgoal 2.
r \/ s
------------------------------------
0. p
1. q
r
------------------------------------
0. p
1. q
2 subgoals
:
proof
> elt (USE_SG_THEN ASSUME_TAC 1 2) ;
OK..
2 subgoals:
val it =
0. q
1. p
2. p'
------------------------------------
q
0. q
1. p
------------------------------------
p'
Here is an example where the assumptions differ. Subgoal 2 is used to
solve subgoal 1, but the assumption p' of subgoal 2 remains to be
proved. Without VALIDATE_LT, the list-tactic would be invalid.
r
------------------------------------
0. p'
1. q
r
------------------------------------
0. p
1. q
2 subgoals
:
proof
> elt (VALIDATE_LT (USE_SG_THEN ACCEPT_TAC 2 1)) ;
Exception- OK..
HOL_ERR at Tactic.ACCEPT_TAC: raised
Comments
Some users may expect the generated tactic to be ttac (A |- u), rather
than ttac (u |- u).
VALID
VALID
Tactical.VALID : tactic -> tactic
Makes a tactic fail if it would otherwise return an invalid proof.
If tac applied to the goal (asl,g) produces a justification that
does not create a theorem A |- g, with A a subset of asl, then
VALID tac (asl,g) fails (raises an exception). If tac produces a
valid proof on the goal, then the behaviour of VALID tac (asl,g) is
the same as tac (asl,g)
Failure
Fails by design if tac produces an invalid proof when applied to a
goal. Also fails if tac fails when applied to the given goal.
See also
proofManagerLib.expand,
Tactical.VALIDATE
VALID_LT
VALID_LT
Tactical.VALID_LT : list_tactic -> list_tactic
Makes a list-tactic fail if it would otherwise return an invalid proof.
When list-tactic ltac is applied to a goal list gl it produces a new
goal list gl' and a justification. When the justification is applied
to a list thl' of theorems which are the new goals gl', proved, it
should produce a list thl of theorems which are the goals gl,
proved.
Precisely, for each goal (asl, g) in gl, the corresponding theorem
in thl should be A |- g, with A a subset of asl. If this is not
the case, then the list-tactic is invalid, and VALID_LT ltac gl fails
(raises an exception). Otherwise, VALID_LT ltac gl behaves the same as
ltac gl.
Failure
VALID_LT ltac gl fails by design if ltac gl produces new goals and
justification which do not prove the given goals gl. Also fails if its
ltac gl fails.
See also
Tactical.VALID,
Tactical.VALIDATE_LT,
proofManagerLib.elt,
proofManagerLib.expand_list
VALIDATE
VALIDATE
Tactical.VALIDATE : tactic -> tactic
Makes a tactic valid if its invalidity is due to relying on assumptions not present in the goal.
Suppose tac applied to the goal (asl,g) produces a justification
that creates a theorem A |- g'. If A a not a subset of asl, then
the tactic is invalid (and VALID tac (asl,g) fails, ie, raises an
exception). But VALIDATE tac (asl,g) produces a subgoal list augmented
by the members of A missing from asl.
If g' differs from g, both VALID tac (asl,g) and
VALIDATE tac (asl,g) fail.
Failure
Fails by design if tac, when applied to a goal, produces a proof which
is invalid on account of proving a theorem whose conclusion differs from
that of the goal.
Also fails if tac fails when applied to the given goal.
Example
For example, where theorem uth' is [p'] |- q
[...Lines elided...]
5. Incomplete goalstack:
Initial goal:
∃R. WF R ∧ (∀rst x ord. R (ord,FILTER (ord x) rst) (ord,x::rst)) ∧
∀rst x ord. R (ord,FILTER ($¬ ∘ ord x) rst) (ord,x::rst)
4. Incomplete goalstack:
Initial goal:
1 + 2 = 2 + 1
Current goal:
∀(x,y). x + y = y + x
3. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
Current goal:
p
2. Incomplete goalstack:
Initial goal:
0. q
1. p
------------------------------------
r
Current goal:
0. q
1. p
------------------------------------
p'
1. Incomplete goalstack:
Initial goal:
0. p
------------------------------------
q
> e (ACCEPT_TAC uth') ;
Exception- OK..
HOL_ERR (at Tactical.VALID: Invalid tactic: theorem has bad hypothesis p') raised
> e (VALIDATE (ACCEPT_TAC uth')) ;
OK..
1 subgoal:
val it =
0. p
------------------------------------
p'
Given a goal with an implication in the assumptions, one can split it into two subgoals.
[...Lines elided...]
1. Incomplete goalstack:
Initial goal:
0. p ⇒ q
------------------------------------
r
> e (VALIDATE (POP_ASSUM (ASSUME_TAC o UNDISCH))) ;
OK..
2 subgoals:
val it =
0. q
------------------------------------
r
0. p ⇒ q
------------------------------------
p
Meanwhile, to propose a term, prove it as a subgoal and then use it to
prove the goal, as is done using SUBGOAL_THEN tm ASSUME_TAC, can also
be done by VALIDATE (ASSUME_TAC (ASSUME tm)))
Where a tactic tac requires certain assumptions to be present in the
goal, which are not present but are capable of being proved,
VALIDATE tac will conveniently set up new subgoals to prove the
missing assumptions.
See also
proofManagerLib.expand,
Tactical.VALID,
Tactical.GEN_VALIDATE,
Tactical.ADD_SGS_TAC,
Tactical.SUBGOAL_THEN
VALIDATE_LT
VALIDATE_LT
Tactical.VALIDATE_LT : list_tactic -> list_tactic
Makes a list-tactic valid if its invalidity is due to relying on assumptions not present in one of the goals.
When list-tactic ltac is applied to a goal list gl it produces a new
goal list gl' and a justification. When the justification is applied
to a list thl' of theorems which are the new goals gl', proved, it
should produce a list thl of theorems which are the goals gl,
proved.
A list-tactic can be invalid due to proving a theorem whose conclusion
differs from that of the corresponding goal, or due to proving a theorem
which contains extra assumptions relative to the corresponding goal. In
this latter case, VALIDATE_LT ltac makes the list-tactic valid by
returning extra subgoals to prove those extra assumptions.
See VALID_LT for more details.
Failure
Fails by design if ltac, when applied to a goal list, produces a proof
which is invalid on account of proving a theorem whose conclusion
differs from that of the corresponding goal.
Also fails if ltac fails when applied to the given goals.
Example
Where uthr' is [p', q] |- r and uths' is [p, q'] |- s
OK..
2 subgoals:
val it =
0. p
1. q
------------------------------------
s
0. p
1. q
------------------------------------
r
> elt (ALLGOALS (FIRST (map ACCEPT_TAC [uthr', uths']))) ;
Exception- OK..
HOL_ERR
(at Tactical.VALID_LT: Invalid list-tactic: theorem has bad hypothesis p') raised
> elt (VALIDATE_LT (ALLGOALS (FIRST (map ACCEPT_TAC [uthr', uths'])))) ;
OK..
2 subgoals:
val it =
0. p
1. q
------------------------------------
q'
0. p
1. q
------------------------------------
p'
Where a tactic ltac requires certain assumptions to be present in one
of the goals, which are not present but are capable of being proved,
VALIDATE_LT ltac will conveniently set up new subgoals to prove the
missing assumptions.
See also
Tactical.VALID,
Tactical.VALID_LT,
Tactical.VALIDATE,
proofManagerLib.elt,
proofManagerLib.expand_list
tactictoe
tactictoe
tacticToe.tactictoe : term -> thm
A call to the rule tacticToe.tactictoe on a term tm is equivalent to
a call to the tactic tacticToe.ttt on the goal ([],tm).
See also
ttt
ttt
tacticToe.ttt : tactic
General purpose tactic relying on a automatic selection of tactics
extracted from human-written proof scripts. It returns an automatically
generated proof script that solves the goal. A good practice is to
replace the call of tacticToe.ttt by the generated proof script.
Select relevant tactics and theorems for proving a goal using the k-nearest neighbor premise selection algorithm and relies on Monte Carlo tree search to expand multiple proof trees. In practice, this means that the intermediate goals created by better ranked tactics are explored more deeply.
Failure
Fails if the supplied goal does not contain boolean terms only. Or if
the search saturates, this typically happens when there is not enough
recorded tactics. Or if the search times out. This timeout can be
modifed by tacticToe.set_timeout. Or if the proof fails to
reconstruct.
Example
- load "tttUnfold"; load "tacticToe"; open tacticToe;
- tttUnfold.ttt_record (); (* takes multiple hours the first time it is called *)
- ttt ([],``1+1=2``);
Comments
See src/tactictoe/README for more information on how to record the
tactic data. See more examples in src/tactictoe/examples.
See also
isEmpty
isEmpty
Tag.isEmpty : tag -> bool
Tells if a tag is empty.
An invocation isEmpty t returns true just in case t is the empty
tag. Only theorems built solely by HOL proof have an empty tag.
Failure
Never fails.
Example
> Tag.isEmpty (Thm.tag NOT_FORALL_THM);
val it = false: bool
See also
merge
merge
Tag.merge : tag -> tag -> tag
Combine two tags into one.
When two theorems interact via inference, their tags are merged. This propagates to the new theorem the fact that either or both were constructed via shortcut.
Failure
Never fails.
Example
> Tag.merge (Tag.read "foo") (Tag.read "bar");
val it = [oracles: ##] [axioms: ]: tag
> Tag.merge it (Tag.read "foo");
val it = [oracles: ##] [axioms: ]: tag
Comments
Although it is not harmful to use this entrypoint, there is little reason to, since the merge operation is only used inside the HOL kernel.
See also
Tag.read, Thm.mk_oracle_thm,
Thm.tag
pp_tag
pp_tag
Tag.pp_tag : tag Parse.pprinter
Prettyprinter for tags.
An invocation pp_tag t will produce a pretty representation for tag
t. Such a pretty-printer can be used to produce outputs, or return
strings, or to combine with other pretty representations to create
compound values.
Failure
Never fails.
Example
> show_tags := true;
val it = (): unit
> Portable.pprint Tag.pp_tag (Tag.read "fooble");
[oracles: fooble] [axioms: ]
val it = (): unit
read
read
Tag.read : string -> tag
Make a tag suitable for use by mk_oracle_thm.
In order to construct a tag usable by mk_oracle_thm, one uses read,
which takes a string and makes it into a tag.
Failure
The string must be an alphanumeric, i.e., start with an alphabetic character and thereafter consist only of alphabetic or numeric characters.
Example
> Tag.read "Shamboozled";
val it = [oracles: #] [axioms: ]: tag
See also
tag
tag
Tag.type tag
Abstract type of oracle tags.
The type tag is used to track the use of oracles in HOL. An 'oracle'
is a source of theorems that are not proved, but just asserted. In HOL,
such unproven 'theorems' are used to incorporate the results of external
proof tools. Each theorem coming from an oracle has a tag attached to
it. This tag gets copied to any theorems hereditarily generated from an
oracular theorem by inference.
See also
PTAUT_CONV
PTAUT_CONV
tautLib.PTAUT_CONV : conv
Tautology checker. Proves closed propositional formulae true or false.
Given a term of the form "!x1 ... xn. t" where t contains only
Boolean constants, Boolean-valued variables, Boolean equalities,
implications, conjunctions, disjunctions, negations and Boolean-valued
conditionals, and all the variables in t appear in x1 ... xn, the
conversion PTAUT_CONV proves the term to be either true or false, that
is, one of the following theorems is returned:
|- (!x1 ... xn. t) = T
|- (!x1 ... xn. t) = F
This conversion also accepts propositional terms that are not fully universally quantified. However, for such a term, the conversion will only succeed if the term is valid.
Failure
Fails if the term is not of the form "!x1 ... xn. f[x1,...,xn]" where
f[x1,...,xn] is a propositional formula (except that the variables do
not have to be universally quantified if the term is valid).
Example
#PTAUT_CONV ``!x y z w. (((x \/ ~y) ==> z) /\ (z ==> ~w) /\ w) ==> y``;
|- (!x y z w. (x \/ ~y ==> z) /\ (z ==> ~w) /\ w ==> y) = T
#PTAUT_CONV ``(((x \/ ~y) ==> z) /\ (z ==> ~w) /\ w) ==> y``;
|- (x \/ ~y ==> z) /\ (z ==> ~w) /\ w ==> y = T
#PTAUT_CONV ``!x. x = T``;
|- (!x. x = T) = F
#PTAUT_CONV ``x = T``;
Uncaught exception:
HOL_ERR
See also
tautLib.PTAUT_PROVE,
tautLib.PTAUT_TAC,
tautLib.TAUT_CONV
PTAUT_PROVE
PTAUT_PROVE
tautLib.PTAUT_PROVE : term -> thm
Tautology checker. Proves propositional formulae.
Given a term that contains only Boolean constants, Boolean-valued
variables, Boolean equalities, implications, conjunctions, disjunctions,
negations and Boolean-valued conditionals, PTAUT_PROVE returns the
term as a theorem if it is valid. The variables in the term may be
universally quantified.
Failure
Fails if the term is not a valid propositional formula.
Example
#PTAUT_PROVE ``!x y z w. (((x \/ ~y) ==> z) /\ (z ==> ~w) /\ w) ==> y``;
|- !x y z w. (x \/ ~y ==> z) /\ (z ==> ~w) /\ w ==> y
#PTAUT_PROVE ``(((x \/ ~y) ==> z) /\ (z ==> ~w) /\ w) ==> y``;
|- (x \/ ~y ==> z) /\ (z ==> ~w) /\ w ==> y
#PTAUT_PROVE ``!x. x = T``;
Uncaught exception:
HOL_ERR
#PTAUT_PROVE ``x = T``;
Uncaught exception:
HOL_ERR
See also
tautLib.PTAUT_CONV,
tautLib.PTAUT_TAC,
tautLib.TAUT_PROVE
PTAUT_TAC
PTAUT_TAC
tautLib.PTAUT_TAC : tactic
Tautology checker. Proves propositional goals.
Given a goal with a conclusion that contains only Boolean constants, Boolean-valued variables, Boolean equalities, implications, conjunctions, disjunctions, negations and Boolean-valued conditionals, this tactic will prove the goal if it is valid. If all the variables in the conclusion are universally quantified, this tactic will also reduce an invalid goal to false.
Failure
Fails if the conclusion of the goal is not of the form
!x1 ... xn. f[x1,...,xn] where f[x1,...,xn] is a propositional
formula (except that the variables do not have to be universally
quantified if the goal is valid).
See also
tautLib.PTAUT_CONV,
tautLib.PTAUT_PROVE,
tautLib.TAUT_TAC
TAUT_CONV
TAUT_CONV
tautLib.TAUT_CONV : conv
Tautology checker. Proves instances of propositional formulae.
Given an instance t of a valid propositional formula, TAUT_CONV
proves the theorem |- t = T. A propositional formula is a term
containing only Boolean constants, Boolean-valued variables, Boolean
equalities, implications, conjunctions, disjunctions, negations and
Boolean-valued conditionals. An instance of a formula is the formula
with one or more of the variables replaced by terms of the same type.
The conversion accepts terms with or without universal quantifiers for
the variables.
Failure
Fails if the term is not an instance of a propositional formula or if the instance is not a valid formula.
Example
#TAUT_CONV
# ``!x n y. ((((n = 1) \/ ~x) ==> y) /\ (y ==> ~(n < 0)) /\ (n < 0)) ==> x``;
|- (!x n y. ((n = 1) \/ ~x ==> y) /\ (y ==> ~n < 0) /\ n < 0 ==> x) = T
#TAUT_CONV ``((((n = 1) \/ ~x) ==> y) /\ (y ==> ~(n < 0)) /\ (n < 0)) ==> x``;
|- ((n = 1) \/ ~x ==> y) /\ (y ==> ~n < 0) /\ n < 0 ==> x = T
#TAUT_CONV ``!n. (n < 0) \/ (n = 0)``;
Uncaught exception:
HOL_ERR
See also
tautLib.TAUT_PROVE,
tautLib.TAUT_TAC,
tautLib.PTAUT_CONV
TAUT_PROVE
TAUT_PROVE
tautLib.TAUT_PROVE : term -> thm
Tautology checker. Proves propositional formulae (and instances of them).
Given an instance of a valid propositional formula, TAUT_PROVE returns
the instance of the formula as a theorem. A propositional formula is a
term containing only Boolean constants, Boolean-valued variables,
Boolean equalities, implications, conjunctions, disjunctions, negations
and Boolean-valued conditionals. An instance of a formula is the formula
with one or more of the variables replaced by terms of the same type.
The conversion accepts terms with or without universal quantifiers for
the variables.
Failure
Fails if the term is not an instance of a propositional formula or if the instance is not a valid formula.
Example
#TAUT_PROVE
# ``!x n y. ((((n = 1) \/ ~x) ==> y) /\ (y ==> ~(n < 0)) /\ (n < 0)) ==> x``;
|- !x n y. ((n = 1) \/ ~x ==> y) /\ (y ==> ~n < 0) /\ n < 0 ==> x
#TAUT_PROVE ``((((n = 1) \/ ~x) ==> y) /\ (y ==> ~(n < 0)) /\ (n < 0)) ==> x``;
|- ((n = 1) \/ ~x ==> y) /\ (y ==> ~n < 0) /\ n < 0 ==> x
#TAUT_PROVE ``!n. (n < 0) \/ (n = 0)``;
Uncaught exception:
HOL_ERR
See also
tautLib.TAUT_CONV,
tautLib.TAUT_TAC,
tautLib.PTAUT_PROVE
TAUT_TAC
TAUT_TAC
tautLib.TAUT_TAC : tactic
Tautology checker. Proves propositional goals (and instances of them).
Given a goal that is an instance of a propositional formula, this tactic will prove the goal provided it is valid. A propositional formula is a term containing only Boolean constants, Boolean-valued variables, Boolean equalities, implications, conjunctions, disjunctions, negations and Boolean-valued conditionals. An instance of a formula is the formula with one or more of the variables replaced by terms of the same type. The tactic accepts goals with or without universal quantifiers for the variables.
Failure
Fails if the conclusion of the goal is not an instance of a propositional formula or if the instance is not a valid formula.
See also
tautLib.TAUT_CONV,
tautLib.TAUT_PROVE,
tautLib.PTAUT_TAC
aconv
aconv
Term.aconv : term -> term -> bool
Tests for alpha-convertibility of terms.
When applied to two terms, aconv returns true if they are
alpha-convertible, and false otherwise. Two terms are
alpha-convertible if they differ only in the way that names have been
given to bound variables.
Failure
Never fails.
Example
> aconv (Term `?x y. x /\ y`) (Term `?y x. y /\ x`)
val it = true: bool
See also
all_atoms
all_atoms
Term.all_atoms : term -> term set
Returns variables and constants occurring in a term.
A call to all_atoms t will return the set of all the variables and
constants that appear in a term. The variables include those that occur
under binders, even if only in binding position. Multiple instances of
the same (polymorphic) constant can occur in the result if those
instances are present in the term.
Because bound variables are returned as part of the result,
alpha-equivalent terms will not necessarily give the same results when
all_atoms is applied to them.
Failure
Never fails.
Example
> HOLset.listItems (all_atoms ``!v. v /\ p``);
val it = [“p”, “v”, “$!”, “$/\”]: term list
> show_types := true;
val it = (): unit
> HOLset.listItems (all_atoms ``!v. v /\ !f. f v``);
val it =
[“(f :bool -> bool)”, “(v :bool)”, “($! :(bool -> bool) -> bool)”,
“($! :((bool -> bool) -> bool) -> bool)”, “$/\”]: term list
> HOLset.listItems (all_atoms ``!v:'a. T``);
val it = [“(v :α)”, “($! :(α -> bool) -> bool)”, “T”]: term list
Comments
There is a companion function all_atomsl taking an accumulator, which
has type term list -> term set -> term set.
See also
all_consts
all_consts
Term.all_consts : unit -> term list
All known constants in the current theory.
An invocation all_consts returns a list of all declared constants in
the current theory, i.e., all constants in the current theory segment
and in its ancestry.
Failure
Never fails.
Example
> all_consts();
val it =
[“words$word_xor”, “words$word_xnor”, “words$word_to_oct_string”,
“words$word_to_oct_list”, “words$word_to_hex_string”,
“words$word_to_hex_list”, “words$word_to_dec_string”,
“words$word_to_dec_list”, “words$word_to_bin_string”,
“words$word_to_bin_list”, “words$word_sub”, “words$word_smin”,
“words$word_smax”, “words$word_slice”, “words$word_signed_bits”,
“words$word_sign_extend”, “words$word_rrx”, “words$word_ror_bv”,
“words$word_ror”, “words$word_rol_bv”, “words$word_rol”,
“words$word_reverse”, “words$word_replicate”, “words$word_rem”,
“words$word_reduce”, “words$word_quot”, “words$word_or”,
“words$word_nor”, “words$word_nand”, “words$word_mul”, “words$word_msb”,
“words$word_modify”, “words$word_mod”, “words$word_min”,
“words$word_max”, “words$word_lt”, “words$word_lsr_bv”, “words$word_lsr”,
“words$word_lsl_bv”, “words$word_lsl”, “words$word_lsb”, “words$word_ls”,
“words$word_log2”, “words$word_lo”, “words$word_len”, “words$word_le”,
“words$word_join”, “words$word_hs”, “words$word_hi”, “words$word_gt”,
“words$word_ge”, “words$word_from_oct_string”,
“words$word_from_oct_list”, “words$word_from_hex_string”,
“words$word_from_hex_list”, “words$word_from_dec_string”,
“words$word_from_dec_list”, “words$word_from_bin_string”,
“words$word_from_bin_list”, “words$word_extract”,
“words$word_exp_tailrec”, “words$word_exp”, “words$word_div”,
“words$word_concat”, “words$word_compare”, “words$word_bits”,
“words$word_bit”, “words$word_asr_bv”, “words$word_asr”,
“words$word_and”, “words$word_add”, “words$word_abs”, “words$word_T”,
“words$word_L2”, “words$word_L”, “words$word_H”, “words$word_2comp”,
“words$word_1comp”, “words$w2w”, “words$w2s”, “words$w2n”, “words$w2l”,
“words$sw2sw”, “words$saturate_w2w”, “words$saturate_sub”,
“words$saturate_n2w”, “words$saturate_mul”, “words$saturate_add”,
“words$s2w”, “words$reduce_xor”, “words$reduce_xnor”, “words$reduce_or”,
“words$reduce_nor”, “words$reduce_nand”, “words$reduce_and”,
“words$nzcv”, “words$n2w_itself”, “words$n2w”, “words$l2w”,
“words$dimword”, ...]: term list
See also
all_vars
all_vars
Term.all_vars : term -> term list
Returns the set of all variables in a term.
An invocation all_vars tm returns a list representing the set of all
bound and free term variables occurring in tm.
Failure
Never fails.
Example
> all_vars ``!x y. x /\ y /\ y ==> z``;
val it = [“z”, “y”, “x”]: term list
Comments
Code should not depend on how elements are arranged in the result of
all_vars.
See also
Term.all_atoms,
Term.all_varsl, Term.free_vars
all_varsl
all_varsl
Term.all_varsl : term list -> term list
Returns the set of all variables in a list of terms.
An invocation all_varsl [t1,...,tn] returns a list representing the
set of all term variables occurring in t1,...,tn.
Failure
Never fails.
Example
> all_varsl [Term `x /\ y /\ y ==> x`,
Term `!a. a ==> p ==> y`];
val it = [“x”, “y”, “p”, “a”]: term list
Comments
Code should not depend on how elements are arranged in the result of
all_varsl.
See also
Term.all_atoms, Term.all_vars,
Term.empty_varset,
Term.free_vars_lr,
Term.free_vars,
Term.free_varsl, Term.FVL,
Type.type_vars
beta_conv
beta_conv
Term.beta_conv : term -> term
Performs one step of beta-reduction.
Beta-reduction is one of the primitive operations in the lambda
calculus. A step of beta-reduction may be performed by beta_conv M,
where M is the application of a lambda abstraction to an argument,
i.e., has the form ((\v.N) P). The beta-reduction occurs by
systematically replacing every free occurrence of v in N by P.
Care is taken so that no free variable of P becomes captured in this
process.
Failure
If M is not the application of an abstraction to an argument.
Example
> beta_conv (mk_comb (Term `\(x:'a) (y:'b). x`, Term `(P:bool -> 'a) Q`));
val it = “λy. P Q”: term
> beta_conv (mk_comb (Term `\(x:'a) (y:'b) (y':'b). x`, Term `y:'a`));
val it = “λy' y'. y”: term
Comments
More complex strategies for coding up full beta-reduction can be coded
up in ML. The conversions of Larry Paulson support this activity as
inference steps.
For programming derived rules of inference.
See also
Thm.BETA_CONV,
Drule.RIGHT_BETA,
Drule.LIST_BETA_CONV,
Drule.RIGHT_LIST_BETA,
Conv.DEPTH_CONV,
Conv.TOP_DEPTH_CONV,
Conv.REDEPTH_CONV
body
body
Term.body : term -> term
Returns the body of an abstraction.
If M is a lambda abstraction, i.e, has the form \v. t, then body M
returns t.
Failure
Fails unless M is an abstraction.
See also
bvar
bvar
Term.bvar : term -> term
Returns the bound variable of an abstraction.
If M is a lambda abstraction, i.e, has the form \v. t, then bvar M
returns v.
Failure
Fails unless M is an abstraction.
See also
compare
compare
Term.compare : term * term -> order
Ordering on terms.
An invocation compare (M,N) will return one of
{LESS, EQUAL, GREATER}, according to an ordering on terms. The
ordering is transitive and total, and equates alpha-convertible terms.
Failure
Never fails.
Example
> compare (T,F);
val it = GREATER: order
> compare (Term `\x y. x /\ y`, Term `\y z. y /\ z`);
val it = EQUAL: order
Comments
Used to build high performance datastructures for dealing with sets having many terms.
See also
Term.empty_tmset,
Term.var_compare
decls
decls
Term.decls : string -> term list
Returns a list of constants having the same name.
An invocation Term.decls s returns a list of constants found in the
current theory having the name s. If there are no constants with name
s, then the empty list is returned.
Failure
Never fails.
Example
> decls "+";
val it = [“$+”]: term list
> map dest_thy_const it;
val it = [{Name = "+", Thy = "arithmetic", Ty = “:num -> num -> num”}]:
{Name: string, Thy: string, Ty: hol_type} list
Comments
Useful for untangling confusion arising from overloading and also the possibility to declare two different constants with the same name in different theories.
See also
Type.decls,
Term.dest_thy_const
dest_abs
dest_abs
Term.dest_abs : term -> term * term
Breaks apart an abstraction into abstracted variable and body.
dest_abs is a term destructor for abstractions: if M is a term of
the form \v.t, then dest_abs M returns (v,t).
Failure
Fails if it is not given a lambda abstraction.
See also
Term.mk_abs, Term.is_abs,
Term.dest_var,
Term.dest_const,
Term.dest_comb,
boolSyntax.strip_abs
dest_comb
dest_comb
Term.dest_comb : term -> term * term
Breaks apart a combination (function application) into rator and rand.
dest_comb is a term destructor for combinations. If term M has the
form f x, then dest_comb M equals (f,x).
Failure
Fails if the argument is not a function application.
See also
Term.mk_comb, Term.is_comb,
Term.dest_var,
Term.dest_const,
Term.dest_abs,
boolSyntax.strip_comb
dest_const
dest_const
Term.dest_const : term -> string * hol_type
Breaks apart a constant into name and type.
dest_const is a term destructor for constants. If M is a constant
with name c and type ty, then dest_const M returns (c,ty).
Failure
Fails if M is not a constant.
Comments
In Hol98, constants also carry the theory they are declared in. A more
precise and robust way to analyze a constant is with dest_thy_const.
See also
Term.mk_const,
Term.mk_thy_const,
Term.dest_thy_const,
Term.is_const, Term.dest_abs,
Term.dest_comb, Term.dest_var
dest_term
dest_term
Term.dest_term : term -> lambda
Breaks terms into a type with SML constructors for pattern-matching.
A call to dest_term t returns a value of type lambda, which has SML
definition
datatype lambda =
VAR of string * hol_type
| CONST of {Name:string, Thy:string, Ty:hol_type}
| COMB of term * term
| LAMB of term * term
This type encodes all possible forms of term.
Failure
Never fails.
Example
> dest_term ``SUC 2``;
val it =
COMB
(Const
({epoch = 0, name = {Name = "SUC", Thy = "num"}, uptodate = ref true},
GRND
(
Tyapp
(({epoch = 0, name = {Name = "fun", Thy = "min"}, uptodate =
ref true}, 2),
[Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"}, uptodate =
ref true}, 0), []),
Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"}, uptodate =
ref true}, 0), [])])
)),
Comb
(Const
({epoch = 0, name = {Name = "NUMERAL", Thy = "arithmetic"},
uptodate = ref true},
GRND
(
Tyapp
(({epoch = 0, name = {Name = "fun", Thy = "min"}, uptodate =
ref true}, 2),
[Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"}, uptodate =
ref true}, 0), []),
Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"}, uptodate =
ref true}, 0), [])])
)),
Comb
(Const
({epoch = 0, name = {Name = "BIT2", Thy = "arithmetic"}, uptodate =
ref true},
GRND
(
Tyapp
(({epoch = 0, name = {Name = "fun", Thy = "min"}, uptodate =
ref true}, 2),
[Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"},
uptodate = ref true}, 0), []),
Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"},
uptodate = ref true}, 0), [])])
)),
Const
({epoch = 0, name = {Name = "ZERO", Thy = "arithmetic"}, uptodate =
ref true},
GRND
(
Tyapp
(({epoch = 0, name = {Name = "num", Thy = "num"}, uptodate =
ref true}, 0), [])
))))): lambda
See also
Term.dest_abs, Term.dest_comb,
Term.dest_const,
boolSyntax.dest_strip_comb,
Term.dest_thy_const,
Term.dest_var
dest_thy_const
dest_thy_const
Term.dest_thy_const : term -> {Thy:string, Name:string, Ty:hol_type}
Breaks apart a constant into name, theory, and type.
dest_thy_const is a term destructor for constants. If M is a
constant, declared in theory Thy with name Name, having type ty,
then dest_thy_const M returns {Thy, Name, Ty}, where Ty is equal
to ty.
Failure
Fails if M is not a constant.
Comments
A more precise alternative to dest_const.
See also
Term.mk_const,
Term.dest_thy_const,
Term.is_const, Term.dest_abs,
Term.dest_comb, Term.dest_var
dest_var
dest_var
Term.dest_var : term -> string * hol_type
Breaks apart a variable into name and type.
If M is a HOL variable, then dest_var M returns (v,ty), where v
is the name of the variable, an ty is its type.
Failure
Fails if M is not a variable.
See also
Term.mk_var, Term.is_var,
Term.dest_const,
Term.dest_comb, Term.dest_abs
empty_tmset
empty_tmset
Term.empty_tmset : term set
Empty set of terms.
The value empty_tmset represents an empty set of terms. The set has a
built-in ordering, which is given by Term.compare.
Comments
Used as a starting point for building sets of terms.
See also
Term.compare,
Term.empty_varset
empty_varset
empty_varset
Term.empty_varset : term set
Empty set of term variables.
The value empty_varset represents an empty set of term variables. The
set has a built-in ordering, which is given by Term.var_compare.
Comments
Used as a starting point for building sets of variables.
See also
Term.var_compare,
Term.empty_tmset
eta_conv
eta_conv
Term.eta_conv : term -> term
Performs one step of eta-reduction.
Eta-reduction is an important operation in the lambda calculus. A step
of eta-reduction may be performed by eta_conv M, where M is a lambda
abstraction of the following form: \v. (N v), i.e., a lambda
abstraction whose body is an application of a term N to the bound
variable v. Moreover, v must not occur free in M. If this proviso
is met, an invocation eta_conv (\v. (N v)) is equal to N.
Failure
If M is not of the specified form, or if v occurs free in N.
Example
> eta_conv (Term `\n. PRE n`);
val it = “PRE”: term
Comments
Eta-reduction embodies the principle of extensionality, which is basic to the HOL logic.
See also
Drule.ETA_CONV,
Drule.RIGHT_ETA
free_in
free_in
Term.free_in : term -> term -> bool
Tests if one term is free in another.
When applied to two terms t1 and t2, the function free_in returns
true if t1 is free in t2, and false otherwise. It is not
necessary that t1 be simply a variable. A term M occurs free in N
when there is some occurrence of M in N such that each free variable
of M in that occurrence is not bound by a binder in N.
Failure
Never fails.
Example
In the following example free_in returns false because the x in
SUC x in the second term is bound:
- free_in ``SUC x`` ``!x. SUC x = x + 1``;
> val it = false : bool
whereas the following call returns true because the first instance of
x in the second term is free, even though there is also a bound
instance:
- free_in ``x:bool`` ``!y. x /\ ?x. x = y``;
> val it = true : bool
See also
free_vars
free_vars
Term.free_vars : term -> term list
Returns the set of free variables in a term.
An invocation free_vars tm returns a list representing the set of term
variables occurring in tm.
Failure
Never fails.
Example
> free_vars (Term `x /\ y /\ y ==> x`);
val it = [“y”, “x”]: term list
Comments
Code should not depend on how elements are arranged in the result of
free_vars.
free_vars is not efficient for large terms with many free variables.
Demanding applications should be coded with FVL.
See also
Term.FVL, Term.free_vars_lr,
Term.free_varsl,
Term.empty_varset,
Type.type_vars
free_vars_lr
free_vars_lr
Term.free_vars_lr : term -> term list
Returns the set of free variables in a term, in order.
An invocation free_vars_lr ty returns a list representing the set of
type variables occurring in ty. The list will be in order of variable
occurrence when scanning the parse tree of the term from left to right.
This is usually, but need not be, the textual order when the term is
printed.
Failure
Never fails.
Example
> free_vars_lr (Term `x /\ y /\ y ==> z`);
val it = [“x”, “y”, “z”]: term list
Comments
free_vars_lr is not efficient for large terms with many free
variables. More strenuous applications should use high performance set
implementations available in the Standard ML Basis Library.
free_vars_lr can be used to build pleasing quantifier prefixes.
See also
Term.FVL, Term.free_vars,
Term.empty_varset,
Type.type_vars
free_varsl
free_varsl
Term.free_varsl : term list -> term list
Returns the set of free variables in a list of terms.
An invocation free_varsl [t1,...,tn] returns a list representing the
set of free term variables occurring in t1,...,tn.
Failure
Never fails.
Example
> free_varsl [Term `x /\ y /\ y ==> x`,
Term `!x. x ==> p ==> y`];
val it = [“x”, “y”, “p”]: term list
Comments
Code should not depend on how elements are arranged in the result of
free_varsl.
free_varsl is not efficient for large terms with many free variables.
Demanding applications should be coded with FVL.
See also
Term.FVL, Term.free_vars_lr,
Term.free_vars,
Term.empty_varset,
Type.type_vars
FVL
FVL
Term.FVL : term list -> term set -> term set
Efficient computation of the set of free variables in a list of terms.
An invocation FVL [t1,...,tn] V adds the set of free variables found
in t1,...,tn to the accumulator V.
Failure
Never fails.
Example
> FVL [Term `v1 /\ v2 ==> v2 \/ v3`] empty_varset;
val it = HOLset{“v1”, “v2”, “v3”}: term set
> HOLset.listItems it;
val it = [“v1”, “v2”, “v3”]: term list
Comments
Preferable to free_varsl when the number of free variables becomes
large.
See also
HOLset, Term.empty_varset,
Term.free_varsl,
Term.free_vars
genvar
genvar
Term.genvar : hol_type -> term
Returns a variable whose name has not been used previously.
When given a type, genvar returns a variable of that type whose name
has not been used for a variable or constant in the HOL session so far.
Failure
Never fails.
Example
The following indicates the typical stylized form of the names (this should not be relied on, of course):
- genvar bool;
> val it = `%%genvar%%1380` : term
- genvar (Type`:num`);
> val it = `%%genvar%%1381` : term
Note that one can anticipate genvar:
- mk_var("%%genvar%%1382",bool);
> val it = `%%genvar%%1382` : term
- genvar bool;
> val it = `%%genvar%%1382` : term
This shortcoming could be guarded against, but it doesn't seem worth it currently. It doesn't seem to affect the soundness of the implementation of HOL; at worst, a proof procedure may fail because it doesn't have a sufficiently fresh variable.
The unique variables are useful in writing derived rules, for
specializing terms without having to worry about such things as free
variable capture. If the names are to be visible to a typical user, the
function variant can provide rather more meaningful names.
See also
genvars
genvars
Term.genvars : hol_type -> int -> term list
Generate a specified number of fresh variables.
An invocation genvars ty n will invoke genvar n times and return
the resulting list of variables.
Failure
Never fails. If n is less-than-or-equal to zero, the empty list is
returned.
Example
> genvars alpha 3;
val it =
[“$var$(%%genvar%%1100)”, “$var$(%%genvar%%1101)”,
“$var$(%%genvar%%1102)”]: term list
See also
inst
inst
Term.inst : (hol_type,hol_type)subst -> term -> term
Performs type instantiations in a term.
The function inst should be used as follows:
inst [{redex_1, residue_1},...,{redex_n, residue_n}] tm
where each 'redex' is a hol_type variable, and each 'residue' is a
hol_type and tm a term to be type-instantiated. This call will
replace each occurrence of a redex in tm by its associated
residue. Replacement is done in parallel, i.e., once a redex has
been replaced by its residue, at some place in the term, that
residue at that place will not itself be replaced in the current call.
Bound term variables may be renamed in order to preserve the term
structure.
Failure
Never fails. A redex that is not a variable is simply ignored.
Example
> show_types := true;
val it = (): unit
> inst [alpha |-> Type`:num`] (Term`(x:'a) = (x:'a)`)
val it = “(x :num) = x”: term
> inst [bool |-> Type`:num`] (Term`x:bool`);
val it = “(x :bool)”: term
> inst [alpha |-> bool] (mk_abs(Term`x:bool`,Term`x:'a`))
val it = “λ(x' :bool). (x :bool)”: term
See also
is_abs
is_abs
Term.is_abs : (term -> bool)
Tests a term to see if it is an abstraction.
is_abs "\var. t" returns true. If the term is not an abstraction the
result is false.
Failure
Never fails.
See also
Term.mk_abs, Term.dest_abs,
Term.is_var, Term.is_const,
Term.is_comb
is_comb
is_comb
Term.is_comb : term -> bool
Tests a term to see if it is a combination (function application).
If term M has the form f x, then is_comb M equals true.
Otherwise, the result is false.
Failure
Never fails
See also
Term.mk_comb, Term.dest_comb,
Term.is_var, Term.is_const,
Term.is_abs
is_const
is_const
Term.is_const : term -> bool
Tests a term to see if it is a constant.
If c is an instance of a previously declared HOL constant, then
is_const c returns true; otherwise the result is false.
Failure
Never fails.
See also
Term.mk_const,
Term.dest_const, Term.is_var,
Term.is_comb, Term.is_abs
is_genvar
is_genvar
Term.is_genvar : term -> bool
Tells if a variable has been built by invoking genvar.
is_genvar v attempts to tell if v has been created by a call to
genvar.
Failure
Never fails.
Example
> is_genvar (genvar bool);
val it = true: bool
> is_genvar (mk_var ("%%genvar%%3",bool));
val it = true: bool
Comments
As the second example shows, it is possible to fool is_genvar.
However, it is useful for derived proof tools which use it as part of
their internal operations.
See also
Term.is_var, Term.genvar,
Type.is_gen_tyvar,
Type.gen_tyvar
is_var
is_var
Term.is_var : term -> bool
Tests a term to see if it is a variable.
If M is a HOL variable, then is_var M returns true. If the term is
not a variable the result is false.
Failure
Never fails.
See also
Term.mk_var, Term.dest_var,
Term.is_const, Term.is_comb,
Term.is_abs
list_mk_abs
list_mk_abs
Term.list_mk_abs : term list * term -> term
Also exported as boolSyntax.list_mk_abs.
Performs a sequence of lambda binding operations.
An application list_mk_abs ([v1,...,vn], M) yields the term
\v1 ... vn. M. Free occurrences of v1,...,vn in M become bound in
the result.
Failure
Fails if some vi (1 <= i <= n) is not a variable.
Example
> list_mk_abs ([mk_var("v1",bool),mk_var("v2",bool),mk_var("v3",bool)],
Term `v1 /\ v2 /\ v3`);
val it = “λv1 v2 v3. v1 ∧ v2 ∧ v3”: term
Comments
In the current implementation, list_mk_abs is more efficient than
iteration of mk_abs for larger tasks.
See also
Term.mk_abs,
boolSyntax.list_mk_forall,
boolSyntax.list_mk_exists
list_mk_binder
list_mk_binder
Term.list_mk_binder : term option -> term list * term -> term
Performs a sequence of variable binding operations on a term.
An application list_mk_binder (SOME c) ([v1,...,vn],M) builds the term
c (\v1. ... (c (\vn. M) ...)). The term c should be a binder, that
is, a constant that takes a lambda abstraction and returns a bound term.
Thus list_mk_binder implements Church's view that variable binding
operations should be reduced to lambda-binding.
An application list_mk_binder NONE ([v1,...,vn],M) builds the term
\v1...vn. M.
Failure
list_mk_binder opt ([v1,...,vn],M) fails if some vi 1 <= i <= n is
not a variable. It also fails if the constructed term
c (\v1. ... (c (\vn. M) ...)) is not well typed.
Example
Repeated existential quantification is easy to code up using
list_mk_binder. For testing, we make a list of boolean variables.
- fun upto b t acc = if b >= t then rev acc else upto (b+1) t (b::acc)
fun vlist n = map (C (curry mk_var) bool o concat "v" o int_to_string)
(upto 0 n []);
val vars = vlist 100;
> val vars =
[`v0`, `v1`, `v2`, `v3`, `v4`, `v5`, `v6`, `v7`, `v8`, `v9`, `v10`, `v11`,
`v12`, `v13`, `v14`, `v15`, `v16`, `v17`, `v18`, `v19`, `v20`, `v21`,
`v22`, `v23`, `v24`, `v25`, `v26`, `v27`, `v28`, `v29`, `v30`, `v31`,
`v32`, `v33`, `v34`, `v35`, `v36`, `v37`, `v38`, `v39`, `v40`, `v41`,
`v42`, `v43`, `v44`, `v45`, `v46`, `v47`, `v48`, `v49`, `v50`, `v51`,
`v52`, `v53`, `v54`, `v55`, `v56`, `v57`, `v58`, `v59`, `v60`, `v61`,
`v62`, `v63`, `v64`, `v65`, `v66`, `v67`, `v68`, `v69`, `v70`, `v71`,
`v72`, `v73`, `v74`, `v75`, `v76`, `v77`, `v78`, `v79`, `v80`, `v81`,
`v82`, `v83`, `v84`, `v85`, `v86`, `v87`, `v88`, `v89`, `v90`, `v91`,
`v92`, `v93`, `v94`, `v95`, `v96`, `v97`, `v98`, `v99`] : term list
Now we exercise list_mk_binder.
- val exl_tm = list_mk_binder (SOME boolSyntax.existential)
(vars, list_mk_conj vars);
> val exl_tm =
`?v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20
v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32 v33 v34 v35 v36 v37 v38
v39 v40 v41 v42 v43 v44 v45 v46 v47 v48 v49 v50 v51 v52 v53 v54 v55 v56
v57 v58 v59 v60 v61 v62 v63 v64 v65 v66 v67 v68 v69 v70 v71 v72 v73 v74
v75 v76 v77 v78 v79 v80 v81 v82 v83 v84 v85 v86 v87 v88 v89 v90 v91 v92
v93 v94 v95 v96 v97 v98 v99.
v0 /\ v1 /\ v2 /\ v3 /\ v4 /\ v5 /\ v6 /\ v7 /\ v8 /\ v9 /\ v10 /\
v11 /\ v12 /\ v13 /\ v14 /\ v15 /\ v16 /\ v17 /\ v18 /\ v19 /\ v20 /\
v21 /\ v22 /\ v23 /\ v24 /\ v25 /\ v26 /\ v27 /\ v28 /\ v29 /\ v30 /\
v31 /\ v32 /\ v33 /\ v34 /\ v35 /\ v36 /\ v37 /\ v38 /\ v39 /\ v40 /\
v41 /\ v42 /\ v43 /\ v44 /\ v45 /\ v46 /\ v47 /\ v48 /\ v49 /\ v50 /\
v51 /\ v52 /\ v53 /\ v54 /\ v55 /\ v56 /\ v57 /\ v58 /\ v59 /\ v60 /\
v61 /\ v62 /\ v63 /\ v64 /\ v65 /\ v66 /\ v67 /\ v68 /\ v69 /\ v70 /\
v71 /\ v72 /\ v73 /\ v74 /\ v75 /\ v76 /\ v77 /\ v78 /\ v79 /\ v80 /\
v81 /\ v82 /\ v83 /\ v84 /\ v85 /\ v86 /\ v87 /\ v88 /\ v89 /\ v90 /\
v91 /\ v92 /\ v93 /\ v94 /\ v95 /\ v96 /\ v97 /\ v98 /\ v99` : term
Comments
Terms with many consecutive binders should be constructed using
list_mk_binder and its instantiations list_mk_abs, list_mk_forall,
and list_mk_exists. In the current implementation of HOL, iterating
mk_abs, mk_forall, or mk_exists is far slower for terms with many
consecutive binders.
See also
Term.list_mk_abs,
boolSyntax.list_mk_forall,
boolSyntax.list_mk_exists,
Term.strip_binder
list_mk_comb
list_mk_comb
Term.list_mk_comb : term * term list -> term
Iteratively constructs combinations (function applications).
list_mk_comb(t,[t1,...,tn]) returns t t1 ... tn.
Failure
Fails if the types of t1,...,tn are not equal to the argument types
of t. It is not necessary for all the arguments of t to be given. In
particular the list of terms t1,...,tn may be empty.
Example
> list_mk_comb(conditional,[T, mk_var("one",alpha), mk_var("two",alpha)]);
val it = “if T then one else two”: term
> list_mk_comb(universal,[]);
val it = “$!”: term
> try list_mk_comb(universal,[F]);
Exception- Type error in function application.
Function: try list_mk_comb :
(term -> (term * term list) option) list -> term -> term
Argument: (universal, [F]) : term * term list
Reason:
Can't unify (term -> (term * term list) option) list to
term * term list (Incompatible types)
Fail "Static Errors" raised
See also
boolSyntax.strip_comb,
Term.mk_comb
match_term
match_term
Term.match_term : term -> term -> (term,term) subst * (hol_type,hol_type) subst
Finds instantiations to match one term to another.
An application match_term M N attempts to find a set of type and term
instantiations for M to make it alpha-convertible to N. If
match_term succeeds, it returns the instantiations in the form of a
pair containing a term substitution and a type substitution. In
particular, if match_term pat ob succeeds in returning a value
(S,T), then
aconv (subst S (inst T pat)) ob.
Failure
Fails if the term cannot be matched by one-way instantiation. If the pattern includes variables of the same name but different types, the resulting type instantiation may cause those variables to be identified and the term instantiation to be useless.
Example
The following shows how match_term could be used to match the
conclusion of a theorem to a term.
> val th = REFL “x:'a”;
val th = ⊢ x = x: thm
> match_term (concl th) “1 = 1”;
val it =
([{redex = “x”, residue = “1”}], [{redex = “:α”, residue = “:num”}]):
(term, term) Term.subst * (hol_type, hol_type) Term.subst
> INST_TY_TERM it th;
val it = ⊢ 1 = 1: thm
The following shows an attempt to use a bad pattern (the pattern term
t has two variables called x at different types):
> val _ = show_types := true;
> val t = list_mk_comb(``f:'a -> 'b -> 'c``, [``x:'a``, ``x:'b``]);
val t = “(f :α -> β -> γ) (x :α) (x :β)”: term
> val (tminst, tyinst) = match_term t ``(g: 'a -> 'a -> 'b) a b``;
val tminst =
[{redex = “(f :α -> α -> β)”, residue = “(g :α -> α -> β)”},
{redex = “(x :α)”, residue = “(a :α)”},
{redex = “(x :α)”, residue = “(b :α)”}]: (term, term) Term.subst
val tyinst =
[{redex = “:γ”, residue = “:β”}, {redex = “:β”, residue = “:α”}]:
(hol_type, hol_type) Term.subst
The tminst value is unusable as it seeks to instantiate two different
x variables (one with a, one with b) that are now actually the
same variable.
Comments
For instantiating theorems PART_MATCH is usually easier to use.
See also
Term.match_terml,
Type.match_type,
Drule.INST_TY_TERM,
Drule.PART_MATCH
match_terml
match_terml
Term.match_terml
: hol_type list -> term set -> term -> term
-> (term,term) subst * (hol_type,hol_type) subst
Match two terms while restricting some instantiations.
An invocation match_terml avoid_tys avoid_tms pat ob (tmS,tyS), if it
does not raise an exception, returns a pair of substitutions (S,T)
such that
aconv (subst S (inst T pat)) ob.
The arguments avoid_tys and avoid_tms specify type and term
variables in pat that are not allowed to become redexes in S and
T.
Failure
match_terml will fail if no S and T meeting the above requirements
can be found. If a match (S,T) between pat and ob can be found,
but elements of avoid_tys would appear as redexes in T or elements
of avoid_tms would appear as redexes in S, then match_terml will
also fail.
Example
> val (tmS,tyS) = match_terml [] empty_varset
(Term `\x:'a. x = f (y:'b)`)
(Term `\a. a = ~p`);
val tmS = [{redex = “f”, residue = “$¬”}, {redex = “y”, residue = “p”}]:
(term, term) Term.subst
val tyS =
[{redex = “:β”, residue = “:bool”}, {redex = “:α”, residue = “:bool”}]:
(hol_type, hol_type) Term.subst
> match_terml [alpha] empty_varset (* forbid instantiation of 'a *)
(Term `\x:'a. x = f (y:'b)`)
(Term `\a. a = ~p`);
Exception- HOL_ERR (at Type.raw_match_type: double bind on type variable 'a) raised
> match_terml [] (HOLset.add(empty_varset,mk_var("y",beta)))
(Term `\x:'a. x = f (y:'b)`)
(Term `\a. a = ~p`);
Exception- HOL_ERR (at Term.raw_match_term: double bind on variable "y") raised
See also
Term.match_term,
Term.raw_match, Term.subst,
Term.inst, Type.match_typel,
Type.type_subst
mk_abs
mk_abs
Term.mk_abs : term * term -> term
Constructs an abstraction.
mk_abs (v, t) returns the lambda abstraction \v. t. All free
occurrences of v in t thereby become bound.
Failure
Fails if v is not a variable.
See also
Term.dest_abs, Term.is_abs,
boolSyntax.list_mk_abs,
Term.mk_var, Term.mk_const,
Term.mk_comb
mk_comb
mk_comb
Term.mk_comb : term * term -> term
Constructs a combination (function application).
mk_comb (t1,t2) returns the combination t1 t2.
Failure
Fails if t1 does not have a function type, or if t1 has a function
type, but its domain does not equal the type of t2.
Example
- mk_comb (neg_tm,T);
> val it = `~T` : term
- mk_comb(T, T) handle e => Raise e;
Exception raised at Term.mk_comb:
incompatible types
See also
Term.dest_comb, Term.is_comb,
Term.list_mk_comb,
Term.mk_var, Term.mk_const,
Term.mk_abs
mk_const
mk_const
Term.mk_const : string * hol_type -> term
Constructs a constant.
If n is a string that has been previously declared to be a constant
with type ty and ty1 is an instance of ty, then mk_const(n,ty1)
returns the specified instance of the constant.
(A type ty1 is an 'instance' of a type ty2 when match_type ty2 ty1
does not fail.)
Note, however, that constants with the same name (and type) may be
declared in different theories. If two theories having constants with
the same name n are in the ancestry of the current theory, then
mk_const(n,ty) will issue a warning before arbitrarily selecting which
constant to construct. In such situations, mk_thy_const allows one to
specify exactly which constant to use.
Failure
Fails if n is not the name of a known constant, or if ty is not an
instance of the type that the constant has in the signature.
Example
- mk_const ("T", “:bool”);
> val it = `T` : term
- mk_const ("=", “:bool -> bool -> bool”);
> val it = `$=` : term
- try mk_const ("test", “:bool”);
Exception raised at Term.mk_const:
test not found
The following example shows a new constant being introduced that has the same name as the standard equality of HOL. Then we attempt to make an instance of that constant.
- new_constant ("=", “:bool -> bool -> bool”);
> val it = () : unit
- mk_const("=", “:bool -> bool -> bool”);
<<HOL warning: Term.mk_const: "=": more than one possibility>>
> val it = `$=` : term
See also
Term.mk_thy_const,
Term.dest_const,
Term.is_const, Term.mk_var,
Term.mk_comb, Term.mk_abs,
Type.match_type
mk_primed_var
mk_primed_var
Term.mk_primed_var : string * hol_type -> term
Primes a variable name sufficiently to make it distinct from all constants.
When applied to a record made from a string v and a type ty, the
function mk_primed_var constructs a variable whose name consists of
v followed by however many primes are necessary to make it distinct
from any constants in the current theory.
Failure
Never fails.
Example
> new_theory "wombat";
val it = (): unit
> mk_primed_var("x", bool);
val it = “x”: term
> new_constant("x", alpha);
val it = (): unit
> mk_primed_var("x", bool);
val it = “x'”: term
See also
mk_thy_const
mk_thy_const
Term.mk_thy_const : {Thy:string, Name:string, Ty:hol_type} -> term
Constructs a constant.
If n is a string that has been previously declared to be a constant
with type ty in theory thy, and ty1 is an instance of ty, then
mk_thy_const{Name=n, Thy=thy, Ty=ty1} returns the specified instance
of the constant.
(A type ty1 is an 'instance' of a type ty2 when match_type ty2 ty1
does not fail.)
Failure
Fails if n is not the name of a constant in theory thy, if thy is
not in the ancestry of the current theory, or if ty1 is not an
instance of ty.
Example
- mk_thy_const {Name="T", Thy="bool", Ty=bool};
> val it = `T` : term
- try mk_thy_const {Name = "bar", Thy="foo", Ty=bool};
Exception raised at Term.mk_thy_const:
"foo$bar" not found
See also
Term.dest_thy_const,
Term.mk_const,
Term.dest_const,
Term.is_const, Term.mk_var,
Term.mk_comb, Term.mk_abs,
Type.match_type
mk_var
mk_var
Term.mk_var : string * hol_type -> term
Constructs a variable of given name and type.
If v is a string and ty is a HOL type, then mk_var(v, ty) returns
a HOL variable.
Failure
Never fails.
Comments
mk_var can be used to construct variables with names which are not
acceptable to the term parser. In particular, a variable with the name
of a known constant can be constructed using mk_var.
See also
Term.dest_var, Term.is_var,
Term.mk_const, Term.mk_comb,
Term.mk_abs
norm_subst
norm_subst
Term.norm_subst : ((term, term) subst * term set) *
((hol_type, hol_type) subst * hol_type list) ->
(term, term) subst * (hol_type, hol_type) subst
Instantiate term substitution by a type substitution.
Given a term substitution and a type substitution, norm_subst applies
the type substitution to the redexes of the term substitution.
The substitutions coming from raw_match need to be normalized before
they can be applied by inference rules like INST_TY_TERM. An
invocation raw_match avoid_tys avoid_tms pat ob A returns a pair of
substitutions ((S,Ids),(T,Idt)). The Id components can be ignored.
The S component is a substitution for term variables, but it has to be
instantiated by the type substitution T in order to be suitable for
use by INST_TY_TERM. In this case, one uses
norm_subst ((S,Ids),(T,Idt)) as the first argument for INST_TY_TERM.
norm_subst ((S,Ids),(T,Idt)) ignores Ids and Idt, and returns T
unchanged. Where a type-substituted term redex becomes equal to the
corresponding residue, that term redex-residue pair is omitted from the
term substitution returned.
Failure
Never fails.
Example
> val ((tmS,Ids),(tyS,Idt)) = raw_match [] empty_varset
“\x:'a. x = f (y:'b)”
“\a. a = ~p” ([],[]);
val Ids = HOLset{}: term set
val Idt = []: hol_type list
val tmS = [{redex = “y”, residue = “p”}, {redex = “f”, residue = “$¬”}]:
(term, term) Term.subst
val tyS =
[{redex = “:β”, residue = “:bool”}, {redex = “:α”, residue = “:bool”}]:
(hol_type, hol_type) Term.subst
> val (tmS',_) = norm_subst ((tmS,Ids),(tyS,Idt)) ;
val tmS' = [{redex = “f”, residue = “$¬”}, {redex = “y”, residue = “p”}]:
(term, term) Term.subst
Comments
Higher level matching routines, like match_term and match_terml
already return normalized substitutions.
See also
Term.raw_match,
Term.match_term,
Term.match_terml,
Drule.INST_TY_TERM
prim_mk_const
prim_mk_const
Term.prim_mk_const : {Thy:string, Name:string} -> term
Build a constant.
If Name is the name of a previously declared constant in theory Thy,
then prim_mk_const {Thy,Name} will return the specified constant.
Failure
If Name is not the name of a constant declared in theory Thy.
Example
> prim_mk_const {Thy="min", Name="="};
val it = “$=”: term
> type_of it;
val it = “:α -> α -> bool”: hol_type
Comments
The difference between mk_thy_const (and mk_const) and
prim_mk_const is that mk_thy_const and mk_const will create type
instances of polymorphic constants, while prim_mk_const merely returns
the originally declared constant.
See also
prim_variant
prim_variant
Term.prim_variant : term list -> term -> term
Rename a variable to be different from any in a list.
The function prim_variant is exactly the same as variant, except
that it doesn't rename away from constants.
Failure
prim_variant l t fails if any term in the list l is not a variable
or if t is not a variable.
Example
> variant [] (mk_var("T",bool));
val it = “T'”: term
> prim_variant [] (mk_var("T",bool));
val it = “T”: term
Comments
The extra amount of renaming that variant does is useful when
generating new constant names (even though it returns a variable) inside
high-level definition mechanisms. Otherwise, prim_variant seems
preferable.
See also
Term.variant, Term.mk_var,
Term.genvar,
Term.mk_primed_var
rand
rand
Term.rand : term -> term
Returns the operand from a combination (function application).
If M is a combination, i.e., has the form (t1 t2), then rand M
returns t2.
Failure
Fails if M is not a combination.
See also
rator
rator
Term.rator : term -> term
Returns the operator from a combination (function application).
If M is a combination, i.e., has the form (t1 t2), then rator M
returns t1.
Failure
Fails if M is not a combination.
See also
raw_match
raw_match
Term.raw_match :
hol_type list -> term set ->
term -> term ->
(term,term) subst * (hol_type,hol_type) subst ->
((term,term) subst * term set) *
((hol_type,hol_type) subst * hol_type list)
Primitive term matcher.
The most primitive matching algorithm for HOL terms is raw_match. An
invocation raw_match avoid_tys avoid_tms pat ob (tmS,tyS), if it
succeeds, returns a substitution pair ((TmS,TmID),(TyS,TyID)) such
that
aconv (subst TmS' (inst TyS pat)) ob.
where TmS' is TmS instantiated by TyS. The arguments avoid_tys
and avoid_tms specify type and term variables in pat that are not
allowed to become redexes in S and T.
The pair (tmS,tyS) is an accumulator argument. This allows raw_match
to be folded through lists of terms to be matched. (TmS,TyS) must
agree with (tmS,tyS). This means that if there is a {redex,residue}
in TmS and also a {redex,residue} in tmS so that both redex
fields are equal, then the residue fields must be alpha-convertible.
Similarly for types: if there is a {redex,residue} in TyS and also a
{redex,residue} in tyS so that both redex fields are equal, then
the residue fields must also be equal. If these conditions hold, then
the result-pair (TmS,TyS) includes (tmS,tyS).
Finally, note that the result also includes a set (resp. a list) of term
and type variables, accompanying the substitutions. These represent
identity bindings that have occurred in the process of doing the match.
If raw_match is to be folded across multiple problems, these output
values will need to be merged with avoid_tms and avoid_tys
respectively on the next call so that they cannot be instantiated a
second time. Because they are identity bindings, they do not need to be
referred to in validating the central identity above.
Failure
raw_match will fail if no TmS and TyS meeting the above
requirements can be found. If a match (TmS,TyS) between pat and ob
can be found, but elements of avoid_tys would appear as redexes in
TyS or elements of avoid_tms would appear as redexes in TmS, then
raw_match will also fail.
Example
We first perform a match that requires type instantitations, and also alpha-convertibility.
> val ((tmS,_),(tyS,_)) =
raw_match [] empty_varset
“\x:'a. x = f (y:'b)”
“\a. a = ~p” ([],[]);
val tmS = [{redex = “y”, residue = “p”}, {redex = “f”, residue = “$¬”}]:
(term, term) Term.subst
val tyS =
[{redex = “:β”, residue = “:bool”}, {redex = “:α”, residue = “:bool”}]:
(hol_type, hol_type) Term.subst
One of the main differences between raw_match and more refined
derivatives of it, is that the returned substitutions are un-normalized
by raw_match. If one naively applied (tmS,tyS) to \x:'a. x = f (y:'b),
type instantiation with tyS would be applied first, yielding
\x:bool. x = f (y:bool). Then substitution with tmS would be applied,
unsuccessfully, since both f and y in the pattern term have been
type instantiated, but the corresponding elements of the substitution
haven't. Thus, higher level operations building on raw_match typically
instantiate tmS by tyS to get tmS' before applying (tmS',tyT) to the
pattern term. This can be achieved by using norm_subst. However,
raw_match exposes this level of detail to the programmer.
Comments
Higher level matchers are generally preferable, but raw_match is
occasionally useful when programming inference rules.
See also
Term.match_term,
Term.match_terml,
Term.norm_subst, Term.subst,
Term.inst,
Type.raw_match_type,
Type.match_type,
Type.match_typel,
Type.type_subst
rename_bvar
rename_bvar
Term.rename_bvar : string -> term -> term
Performs one step of alpha conversion.
If M is a lambda abstraction, i.e., has the form \v.N, an invocation
rename_bvar s M performs one step of alpha conversion to obtain
\s. N[s/v].
Failure
If M is not a lambda abstraction.
Example
> rename_bvar "x" (Term `\v. v ==> w`);
val it = “λx. x ⇒ w”: term
> rename_bvar "x" (Term `\y. y /\ x`);
val it = “λx'. x' ∧ x”: term
Comments
rename_bvar takes constant time in the current implementation.
See also
same_const
same_const
Term.same_const : term -> term -> bool
Constant time equality check for constants.
In many cases, one needs to check that a constant is an instance of the
generic constant originally introduced into the signature, or that two
constants are both type instantiations of another. This can be achieved
by taking the constants apart with dest_thy_const and comparing their
name and theory. However, this is relatively inefficient. Instead, one
can invoke same_const, which takes constant time.
Failure
Never fails.
Example
> same_const boolSyntax.universal (rator (concl BOOL_CASES_AX));
val it = true: bool
See also
Term.aconv,
Term.dest_thy_const,
Term.match_term
strip_abs
strip_abs
Term.strip_abs : term -> term list * term
Also exported as boolSyntax.strip_abs.
Break apart consecutive lambda abstractions.
If M is a term of the form \v1...vn.N, where N is not a lambda
abstraction, then strip_abs M equals ([v1,...,vn],N). Otherwise, the
result is ([],M).
Failure
Never fails.
Example
> strip_abs (Term `\x y z. x ==> y ==> z`);
val it = ([“x”, “y”, “z”], “x ⇒ y ⇒ z”): term list * term
> strip_abs T;
val it = ([], “T”): term list * term
Comments
In the current implementation of HOL, strip_abs is far faster than
iterating dest_abs for terms with many consecutive binders.
See also
Term.strip_binder,
Term.dest_abs,
boolSyntax.strip_forall,
boolSyntax.strip_exists
strip_binder
strip_binder
Term.strip_binder : term option -> term -> term list * term
Break apart consecutive binders.
An application strip_binder (SOME c) (c(\v1. ... (c(\vn.M))...))
returns ([v1,...,vn],M). The constant c should represent a term
binding operation.
An application strip_binder NONE (\v1...vn. M) returns
([v1,...,vn],M).
Failure
Never fails.
Example
strip_abs could be defined as follows.
- val strip_abs = strip_binder NONE;
> val strip_abs = fn : term -> term list * term
- strip_abs (Term `\x y z. x /\ y ==> z`);
> val it = ([`x`, `y`, `z`], `x /\ y ==> z`) : term list * term
Defining strip_forall is similar.
strip_binder (SOME boolSyntax.universal)
Comments
Terms with many consecutive binders should be taken apart using
strip_binder and its instantiations strip_abs, strip_forall, and
strip_exists. In the current implementation of HOL, iterating
dest_abs, dest_forall, or dest_exists is far slower for terms with
many consecutive binders.
See also
Term.list_mk_binder,
Term.strip_abs,
boolSyntax.strip_forall,
boolSyntax.strip_exists
subst
subst
Term.subst : (term,term) subst -> term -> term
Substitutes terms in a term.
Given a "(term,term) subst" (a list of {redex, residue} records) and a
term tm, subst attempts to replace each free occurrence of a redex
in tm by its associated residue. The substitution is done in
parallel, i.e., once a redex has been replaced by its residue, at some
place in the term, that residue at that place will not itself be
replaced in the current call. When necessary, renaming of bound
variables in tm is done to avoid capturing the free variables of an
incoming residue.
Failure
Failure occurs if there exists a {redex, residue} record in the
substitution such that the types of the redex and residue are not
equal.
Example
> load "arithmeticTheory";
val it = (): unit
> subst [Term`SUC 0` |-> Term`1`]
(Term`SUC(SUC 0)`);
val it = “SUC 1”: term
> subst [Term`SUC 0` |-> Term`1`,
Term`SUC 1` |-> Term`2`]
(Term`SUC(SUC 0)`);
val it = “SUC 1”: term
> subst [Term`SUC 0` |-> Term`1`,
Term`SUC 1` |-> Term`2`]
(Term`SUC(SUC 0) = SUC 1`);
val it = “SUC 1 = 2”: term
> subst [Term`b:num` |-> Term`a:num`]
(Term`\a:num. b:num`);
val it = “λa'. a”: term
> subst [Term`flip:'a` |-> Term`foo:'a`]
(Term`waddle:'a`);
Exception- HOL_ERR
(at Preterm.type-analysis: on line 1, characters 12-15:
Type constraint failure:
Term: flip :(α -> β -> γ) -> β -> α -> γ
Constraint: :α
) raised
See also
Term.inst, Thm.SUBST,
Drule.SUBS, Lib.|->
term
term
Term.eqtype term
ML datatype of HOL terms.
The ML abstract type term represents the set of HOL terms, which is
essentially the simply typed lambda calculus of Church. A term may be a
variable, a constant, an application of one term to another, or a lambda
abstraction.
Comments
Since term is an ML eqtype, any two terms tm1 and tm2 can be
tested for equality by tm1 = tm2. However, the fundamental notion of
equality for terms is implemented by aconv.
Since term is an abstract type, access to its representation is mediated
by the interface presented by the Term structure.
See also
type_of
type_of
Term.type_of : term -> hol_type
Returns the type of a term.
Failure
Never fails.
Example
> type_of boolSyntax.universal;
val it = “:(α -> bool) -> bool”: hol_type
type_vars_in_term
type_vars_in_term
Term.type_vars_in_term : term -> hol_type list
Return the type variables occurring in a term.
An invocation type_vars_in_term M returns the set of type variables
occurring in M.
Failure
Never fails.
Example
> type_vars_in_term (concl boolTheory.ONE_ONE_DEF);
val it = [“:β”, “:α”]: hol_type list
See also
Term.free_vars, Type.type_vars
var_compare
var_compare
Term.var_compare : term * term -> order
Total ordering on variables.
An invocation var_compare (v1,v2) will return one of
{LESS, EQUAL, GREATER}, according to an ordering on term variables.
The ordering is transitive and total.
Failure
If v1 and v2 are not both variables.
Example
> var_compare (mk_var("x",bool), mk_var("x",bool --> bool));
val it = LESS: order
Comments
Used to build high performance datastructures for dealing with sets having many variables.
See also
Term.empty_varset,
Term.compare
var_occurs
var_occurs
Term.var_occurs : term -> term -> bool
Check if a variable occurs in free in a term.
An invocation var_occurs v M returns true just in case v occurs
free in M.
Failure
If the first argument is not a variable.
Example
> var_occurs (Term`x:bool`) (Term `a /\ b ==> x`);
val it = true: bool
> var_occurs (Term`x:bool`) (Term `!x. a /\ b ==> x`);
val it = false: bool
Comments
Identical to free_in, except for the requirement that the first
argument be a variable.
See also
variant
variant
Term.variant : term list -> term -> term
Modifies a variable name to avoid clashes.
When applied to a list of variables to avoid clashing with, and a
variable to modify, variant returns a variant of the variable to
modify, that is, it changes the name as intuitively as possible to make
it distinct from any variables in the list, or any constants. This is
done by adding primes to the name.
The exact form of the variable name should not be relied on, except that the original variable will be returned unmodified unless it is itself in the list to avoid clashing with, or if it is the name of a constant.
Failure
variant l t fails if any term in the list l is not a variable or if
t is not a variable.
Example
The following shows a couple of typical cases:
> variant [“y:bool”, “z:bool”] “x:bool”;
val it = “x” : term
> variant [“x:bool”, “x':num”, “x'':num”] “x:bool”;
> val it = “x'''” : term
while the following shows that clashes with the names of constants are also avoided:
> variant [] (mk_var("T",bool));
val it = “T'” : term
The function variant is extremely useful for complicated derived rules
which need to rename variables to avoid free variable capture while
still making the role of the variable obvious to the user.
Comments
There is a Term.numvariant function that has the same type signature,
but which varies by adding and then incrementing a numeric suffix to the
variable's stem.
See also
Term.genvar, Term.prim_variant
clear_overloads
clear_overloads
term_grammar.clear_overloads : term_grammar.grammar -> term_grammar.grammar
Remove non-trivial overloading from a term grammar
For a term grammar tmG, clear_overloads tmG is the similar grammar,
changed to remove non-trivial overloading. (Each constant remains
overloaded with itself, which avoids the printing of the theory name for
every constant).
Sometimes overloading can be too helpful, when we would like to see the structure of a term (eg, in finding which theorems could simplify it).
Example
In this example we obtain the current type and term grammars tyG and
tmG, then reset the current grammars to be these, except with
overloading cleared from the term grammar. We print some theorems (eg,
to view their internal structure), and finally we reset the current
grammars to the original ones.
> ratTheory.RATND_RAT_OF_NUM;
val it =
⊢ rat$RATN (rat$rat_of_num n) = integer$int_of_num n ∧
rat$RATD (rat$rat_of_num n) = 1: thm
> rich_listTheory.MEM_TAKE;
val it = ⊢ ∀l m x. MEM x (TAKE m l) ⇒ MEM x l: thm
> ratTheory.RATND_RAT_OF_NUM;
val it =
⊢ rat$RATN (rat$rat_of_num n) = integer$int_of_num n ∧
rat$RATD (rat$rat_of_num n) = 1: thm
> rich_listTheory.MEM_TAKE;
val it = ⊢ ∀l m x. MEM x (TAKE m l) ⇒ MEM x l: thm
Comments
To print just a few terms without overloading, print_without_macros
may be easier.
See also
Parse.print_without_macros,
Parse.current_grammars,
Parse.temp_set_grammars
ancestry
ancestry
Theory.ancestry : string -> string list
Returns the (proper) ancestry of a theory in a list.
A call to ancestry thy returns a list of all the proper ancestors
(i.e. parents, parents of parents, etc.) of the theory thy. The
shorthand "-" may be used to denote the name of the current theory
segment.
Failure
Fails if thy is not an ancestor of the current theory.
Example
> load "bossLib";
val it = (): unit
> current_theory();
val it = "wombat": string
> ancestry "-";
val it =
["hrat", "hreal", "realax", "real_arith", "real", "sorting", "scratch",
"numeral_bit", "permutes", "iterate", "fcp", "sum_num", "logroot", "bit",
"numposrep", "ternaryComparisons", "string", "ASCIInumbers", "words",
"bitstring", "ConseqConv", "quantHeuristics", "patternMatches",
"ind_type", "divides", "While", "cv", "reduce", "one", "sum", "option",
"numeral", "basicSize", "numpair", "pred_set", "list", "rich_list",
"indexedLists", "hol", "quotient", "pair", "combin", "sat",
"normalForms", "relation", "min", "bool", "marker", "num", "prim_rec",
"arithmetic", "normalizer", "integer", "example"]: string list
See also
constants
constants
Theory.constants : string -> term list
Returns a list of the constants defined in a named theory.
The call
constants thy
where thy is an ancestor theory (the special string "-" means the
current theory), returns a list of all the constants in that theory.
Failure
Fails if the named theory does not exist, or is not an ancestor of the current theory.
Example
> load "combinTheory";
val it = (): unit
> constants "combin";
val it =
[“$o”, “W”, “UPDATE”, “S”, “RIGHT_ID”, “RESTRICTION”, “MONOID”, “LEFT_ID”,
“K”, “I”, “FCOMM”, “FAIL”, “EXTENSIONAL”, “COMM”, “flip”, “ASSOC”, “$:>”]:
term list
See also
Theory.types,
Theory.current_axioms,
Theory.current_definitions,
Theory.current_theorems
current_axioms
current_axioms
Theory.current_axioms : unit -> (string * thm) list
Return the axioms in the current theory segment.
An invocation current_axioms() returns a list of the axioms asserted
in the current theory segment.
Failure
Never fails. If no axioms have been asserted, the empty list is returned.
See also
Theory.current_theory,
Theory.new_theory,
Theory.current_definitions,
Theory.current_theorems,
Theory.constants,
Theory.types, Theory.parents
current_definitions
current_definitions
Theory.current_definitions : unit -> (string * thm) list
Return the definitions in the current theory segment.
An invocation current_definitions() returns the list of definitions
stored in the current theory segment. Every definition is automatically
stored in the current segment by the primitive definition principles.
Advanced definition principles are built in terms of the primitives, so they also store their results in the cuurent segment. However, the definitions may be quite far removed from the user input, and they may also store some consequences of the definition as theorems.
Failure
Never fails. If no definitions have been made, the empty list is returned.
See also
Theory.current_theory,
Theory.new_theory,
Theory.current_axioms,
Theory.current_theorems,
Theory.constants,
Theory.types, Theory.parents,
Definition.new_definition,
Definition.new_specification,
Definition.new_type_definition,
TotalDefn.Define,
IndDefLib.Hol_reln
current_theorems
current_theorems
Theory.current_theorems : unit -> (string * thm) list
Return the theorems stored in the current theory segment.
An invocation current_theorems () returns the list of theorems stored
in the current theory segment.
Failure
Never fails. If no theorems have been stored, the empty list is returned.
See also
Theory.current_theory,
Theory.new_theory,
Theory.current_definitions,
Theory.current_theorems,
Theory.constants,
Theory.types, Theory.parents
current_theory
current_theory
Theory.current_theory : unit -> string
Returns the name of the current theory segment.
A HOL session has a notion of 'current theory'. There are two senses to this phrase. First, the current theory denotes the totality of all loaded theories plus whatever definitions, axioms, and theorems have been stored in the current session. In this sense, the current theory is the full logical context being used at the moment. This logical context can be extended in two ways: (a) by loading in prebuilt theories residing on disk; and (b) by making a definition, asserting an axiom, or storing a theorem. Therefore, the current theory consists of a body of prebuilt theories that have been loaded from disk (a collection of static components) plus whatever has been stored in the current session.
This latter component --- what has been stored in the current session --- embodies the second sense of 'current theory'. It is more properly known as the 'current theory segment'. The current segment is dynamic in nature, for its contents can be augmented and overwritten. It functions as a kind of scratchpad used to help build a static theory segment.
In a HOL session, there is always a single current theory segment. Its
name is given by calling current_theory(). On startup, the current
theory segment is called "scratch", which is just a default name. If
one is just experimenting, or hacking about, then this segment can be
used.
On the other hand, if one intends to build a static theory segment, one
usually creates a new theory segment named thy by calling
new_theory thy. This changes the value of current_theory to thy.
Once such a theory segment has been built (which may take many
sessions), one calls export_theory, which exports the stored elements
to disk.
Example
> current_theory();
val it = "wombat": string
> new_theory "foo";
val it = (): unit
> current_theory();
val it = "foo": string
Failure
Never fails.
See also
Theory.new_theory,
Theory.export_theory
delete_binding
delete_binding
Theory.delete_binding : string -> unit
Remove a stored value from the current theory segment.
An invocation delete_binding s attempts to locate an axiom,
definition, or theorem that has been stored under name s in the
current theory segment. If such a binding can be found, it is deleted.
Failure
Never fails. If the binding can't be found, then nothing is removed from the current theory segment.
Example
> Define `fact x = if x=0 then 1 else x * fact (x-1)`;
val it = ⊢ ∀x. fact x = if x = 0 then 1 else x * fact (x − 1): thm
> current_theorems();
val it =
[("fact_ind", ⊢ ∀P. (∀x. (x ≠ 0 ⇒ P (x − 1)) ⇒ P x) ⇒ ∀v. P v),
("fact_def", ⊢ ∀x. fact x = if x = 0 then 1 else x * fact (x − 1))]:
(string * thm) list
> delete_binding "fact_ind";
val it = (): unit
> current_theorems();
val it =
[("fact_def", ⊢ ∀x. fact x = if x = 0 then 1 else x * fact (x − 1))]:
(string * thm) list
Comments
Removing a definition binding does not remove the constant(s) it
introduced from the signature. Use delete_const for that.
Removing an axiom has the consequence that all theorems proved from it become garbage.
See also
Theory.scrub,
Theory.delete_type,
Theory.delete_const
delete_const
delete_const
Theory.delete_const : string -> unit
Remove a term constant from the current signature.
An invocation delete_const s removes the constant denoted by s from
the current HOL segment. All types, terms, and theorems that depend on
that constant become garbage.
The implementation ensures that a deleted constant is never equal to a
subsequently declared constant, even if it has the same name and type.
Furthermore, although garbage types, terms, and theorems may exist in a
session, and may even have been stored in the current segment for
export, no theorem, definition, or axiom that is garbage is exported
when export_theory is invoked.
The prettyprinter highlights deleted constants.
Failure
If a constant named s has not been declared in the current segment, a
warning will be issued, but an exception will not be raised.
Example
> Define `foo x = if x=0 then 1 else x * foo (x-1)`;
val it = ⊢ ∀x. foo x = if x = 0 then 1 else x * foo (x − 1): thm
> val th = EVAL (Term `foo 4`);
val th = ⊢ foo 4 = 24: thm
> delete_const "foo";
val it = (): unit
> th;
val it = ⊢ foo$old45->foo<-old 4 = 24: thm
Comments
A type, term, or theorem that depends on a deleted constant may be detected by invoking the appropriate 'uptodate' entrypoint.
It may happen that a theorem th is proved with the use of another
theorem th1 that subsequently becomes garbage because a constant c
was deleted. If c does not occur in th, then th does not become
garbage, which may be contrary to expectation. The conservative
extension property of HOL says that th is still provable, even in the
absence of c.
See also
Theory.delete_type,
Theory.uptodate_type,
Theory.uptodate_term,
Theory.uptodate_thm,
Theory.scrub
delete_type
delete_type
Theory.delete_type : string -> unit
Remove a type operator from the signature.
An invocation delete_type s removes the type constant denoted by s
from the current HOL segment. All types, terms, and theorems that depend
on that type should therefore disappear, as though they hadn't been
constructed in the first place. Conceptually, they have become "garbage"
and need to be collected. However, because of the way that HOL is
implemented in ML, it is not possible to have them automatically
collected. Instead, HOL tracks the currency of type and term constants
and provides some consistency maintenance support.
In particular, the implementation ensures that a deleted type operator
is never equal to a subsequently declared type operator with the same
name (and arity). Furthermore, although garbage types, terms, and
theorems may exist in a session, no theorem, definition, or axiom that
is garbage is exported when export_theory is invoked.
The notion of garbage is hereditary. Any type, term, definition, or theorem is garbage if any of its constituents are. Furthermore, if a type operator or term constant had been defined, and its witness theorem later becomes garbage, then that type or term is garbage, as is anything built from it.
Failure
If a type constant named s has not been declared in the current
segment, a warning will be issued, but an exception will not be raised.
Example
> new_type ("foo", 2);
val it = (): unit
> val thm = REFL (Term `f:('a,'b)foo`);
val thm = ⊢ f = f: thm
> delete_type "foo";
val it = (): unit
> thm;
val it = ⊢ f = f: thm
> show_types := true;
val it = (): unit
> thm;
val it = ⊢ (f :(α, β) foo$old46->foo<-old) = f: thm
Comments
It's rather dodgy to withdraw constants from the HOL signature.
It is not possible to delete constants from ancestor theories.
See also
Theory.delete_const,
Theory.uptodate_type,
Theory.uptodate_term,
Theory.uptodate_thm,
Theory.scrub
export_theory
export_theory
Theory.export_theory : unit -> unit
Write a theory segment to disk.
If the Globals.interactive flag is false, an invocation
export_theory() saves the current theory segment to disk. All parents,
definitions, axioms, and stored theorems of the segment are saved in
such a way that, when the theory is loaded from disk in a later session,
the full theory in place at the time export_theory was called is
re-instated.
If the Globals.interactive flag is true, the call export_theory()
does nothing, returning unit () instantly.
If the current theory segment is named thy, then export_theory()
will create ML files thyTheory.sig and thyTheory.sml, in the current
directory at the time export_theory is invoked. These files need to be
compiled before they become usable. In the standard way of doing things,
the Holmake facility will handle this task.
Once a theory segment has been exported and compiled, it is available for use. It can be brought into an interactive proof session via
load "thyTheory";
When the segment is loaded, its parents, axioms, theorems, and definitions are incorporated into the current theory (recall that this notion is different than the current theory segment).
Failure
A call to export_theory may fail if the disk file cannot be opened. A
call to export_theory will also fail if some bindings are such that
the name of the binding is not a valid ML identifier. In that case,
export_theory will report all such bad names. These can be changed
with set_MLname, and then export_theory may be attempted again.
Example
save_thm("foo", REFL “x:bool”);
Globals.interactive := false;
export_theory();
(These calls are not evaluated by polyscripter when this entry is
rendered: actually running export_theory() freezes the
polyscripter session's current theory segment and breaks every
subsequent Definition / Theorem example.)
Comments
Note that export_theory exports the state of the theory (which can
include other user-definable data in addition to the logical content
(theorems, definitions, etc.), but not the state of the SML session.
When theories are developed interactively, the interactive flag will
typically be set to true; preventing export_theory() from doing
anything in this situation reserves special behaviours for when theories
are built with Holmake.
See also
Theory.new_theory,
Theory.adjoin_to_theory,
Theory.set_MLname
new_axiom
new_axiom
Theory.new_axiom : string * term -> thm
Install a new axiom in the current theory.
If M is a term of type bool, a call new_axiom(name,M) creates a
theorem
|- tm
and stores it away in the current theory segment under name.
Failure
Fails if the given term does not have type bool.
Example
> new_axiom("untrue", Term `!x. x = 1`);
val it = ⊢ ∀x. x = 1: thm
Comments
For most purposes, it is unnecessary to declare new axioms: all of classical mathematics can be derived by definitional extension alone. Proceeding by definition is not only more elegant, but also guarantees the consistency of the deductions made. However, there are certain entities which cannot be modelled in simple type theory without further axioms, such as higher transfinite ordinals.
See also
Thm.mk_thm,
Definition.new_definition,
Definition.new_specification
new_constant
new_constant
Theory.new_constant : string * hol_type -> unit
Declares a new constant in the current theory.
A call new_constant(n,ty) installs a new constant named n in the
current theory. Note that new_constant does not specify a value for
the constant, just a name and type. The constant may have a polymorphic
type, which can be used in arbitrary instantiations.
Failure
Never fails, but issues a warning if the name is not a valid constant name. It will overwrite an existing constant with the same name in the current theory.
See also
Theory.constants,
boolSyntax.new_infix,
boolSyntax.new_binder,
Definition.new_definition,
Definition.new_type_definition,
Definition.new_specification,
Theory.new_axiom,
boolSyntax.new_infixl_definition,
boolSyntax.new_infixr_definition,
boolSyntax.new_binder_definition
new_theory
new_theory
Theory.new_theory : string -> unit
Creates a new theory segment.
A theory consists of a hierarchy of named parts called 'theory segments'. All theory segments have a 'theory' of the same name associated with them consisting of the theory segment itself together with the contents of all its ancestors. Each axiom, definition, specification and theorem belongs to a particular theory segment.
Calling new_theory thy creates a new, and empty, theory segment having
name thy. The theory segment which was current before the call becomes
a parent of the new theory segment. The new theory therefore consists of
the current theory extended with the new theory segment. The new theory
segment replaces its parent as the current theory segment. The parent
segment is exported to disk.
In the interests of interactive usability, the behaviour of new_theory
has some special cases. First, if new_theory thy is called in a
situation where the current theory segment is already called thy, then
this is interpreted as the user wanting to restart the current segment.
In that case, the current segment is wiped clean (types and constants
declared in it are removed from the signature, and all definitions,
theorems and axioms are deleted) but is otherwise unchanged (it keeps
the same parents, for example).
Second, if the current theory segment is empty and named "scratch",
then new_theory thy creates a new theory segment the parents of which
are the parents of "scratch". (This situation is almost never visible
to users.)
Failure
A call new_theory thy fails if the name thy is unsuitable for use as
a filename. In particular, it should be an alphanumeric identifier.
Failure also occurs if thy is the name of a currently loaded theory
segment or if is in a set of reserved words that includes all SML and
HOL keywords (e.g., if, while, Definition). In general, all
theory names, whether loaded or not, should be distinct. Moreover, the
names should be distinct even when case distinctions are ignored.
Example
In the following, we follow a standard progression: start HOL up and declare a new theory segment.
- current_theory();
> val it = "scratch" : string
- parents "-";
> val it = ["list", "option"] : string list
- new_theory "foo";
<<HOL message: Created theory "foo">>
> val it = () : unit
- parents "-";
> val it = ["list", "option"] : string list
Next we make a definition, prove and store a theorem, and then change our mind about the name of the defined constant. Restarting the current theory keeps the static theory context fixed but clears the current segment so that we have a clean slate to work from.
- val def = new_definition("foo", Term `foo x = x + x`);
> val def = |- !x. foo x = x + x : thm
val thm = Q.store_thm("foo_thm", `foo x = 2 * x`,
RW_TAC arith_ss [def]);
> val thm = |- foo x = 2 * x : thm
- new_theory "foo";
<<HOL message: Restarting theory "foo">>
> val it = () : unit
val def = new_definition("twice", Term `twice x = x + x`);
> val def = |- !x. twice x = x + x : thm
- curr_defs();
> val it = [("twice", |- !x. twice x = x + x)]
: (string * thm) list
Comments
The theory file in which the data of the new theory segment is
ultimately stored will have name thyTheory in the directory in which
export_theory is called.
Modularizing large formalizations. By splitting a formalization effort
into theory segments by use of new_theory, the work required if
definitions, etc., need to be changed is minimized. Only the associated
segment and its descendants need be redefined.
See also
Theory.current_theory,
Theory.new_axiom,
Theory.parents,
boolSyntax.new_binder,
Theory.new_constant,
Definition.new_definition,
boolSyntax.new_infix,
Definition.new_specification,
Theory.new_type,
Theory.save_thm,
Theory.export_theory,
Hol_pp.print_theory
new_type
new_type
Theory.new_type : string * int -> unit
Declares a new type or type constructor.
A call new_type(t,n) declares a new n-ary type constructor called
t in the current theory segment. If n is zero, this is just a new
base type.
Failure
Never fails, but issues a warning if the name is not a valid type name. It will overwrite an existing type operator with the same name in the current theory.
Example
A non-definitional version of ZF set theory might declare a new type
set and start using it as follows:
- new_theory "ZF";
<<HOL message: Created theory "ZF">>
> val it = () : unit
- new_type ("set", 0);
> val it = () : unit
- new_constant ("mem", Type`:set->set->bool`);
> val it = () : unit
- new_axiom ("EXT", Term`(!z. mem z x = mem z y) ==> (x = y)`);
> val it = |- (!z. mem z x = mem z y) ==> (x = y) : thm
See also
Theory.types,
Theory.new_constant,
Theory.new_axiom
parents
parents
Theory.parents : string -> string list
Lists the parent theories of a named theory.
If s is the name of the current theory or an ancestor of the current
theory, the call parents s returns a list of strings that identify the
parent theories of s. The shorthand "-" may be used to denote the
name of the current theory segment.
Failure
Fails if the named theory is not an ancestor of the current theory.
Example
> parents "bool";
val it = ["min"]: string list
> parents "min";
val it = []: string list
> current_theory();
val it = "foo": string
> parents "-";
val it = ["wombat"]: string list
See also
Theory.ancestry,
Theory.current_theory
save_thm
save_thm
Theory.save_thm : string * thm -> thm
Stores a theorem in the current theory segment.
The call save_thm(name, th) adds the theorem th to the current
theory segment under the name name. The theorem is also the return
value of the call. When the current segment thy is exported, things
are arranged in such a way that, if thyTheory is loaded into a later
session, the ML variable thyTheory.name will have th as its value.
Failure
If th is out-of-date, then save_thm will fail. If name is not a
valid ML alphanumeric identifier, save_thm will not fail, but
export_theory will (printing an informative error message first).
Example
> val savethm_demo = save_thm("savethm_demo", REFL (Term `x:bool`));
val savethm_demo = ⊢ x ⇔ x: thm
> current_theorems();
val it =
[("savethm_demo", ⊢ x ⇔ x),
("foo_ind", ⊢ ∀P. (∀x. (x ≠ 0 ⇒ P (x − 1)) ⇒ P x) ⇒ ∀v. P v),
("foo_def",
⊢ ∀x. foo$old45->foo<-old x =
if x = 0 then 1 else x * foo$old45->foo<-old (x − 1)),
("fact_def",
⊢ ∀x. foo$fact x = if x = 0 then 1 else x * foo$fact (x − 1))]:
(string * thm) list
Comments
If a theorem is already saved under name in the current theory
segment, it will be overwritten.
The results of new_axiom, and definition principle (such as
new_definition, new_type_definition, and new_specification) are
automatically stored in the current theory: one does not have to call
save_thm on them.
Saving important theorems for eventual export. Binding the result of
save_thm to an ML variable makes it easy to access the theorem in the
remainder of the current session.
See also
Theory.new_theory,
Tactical.store_thm, DB.fetch,
DB.thy,
Theory.current_definitions,
Theory.current_theorems,
Theory.uptodate_thm,
Theory.new_axiom,
Definition.new_type_definition,
Definition.new_definition,
Definition.new_specification
scrub
scrub
Theory.scrub : unit -> unit
Remove all out-of-date elements from the current theory segment.
An invocation scrub() goes through the current theory segment and
removes all out-of-date elements.
Failure
Never fails.
Example
In the following, we define a concrete type and examine the current
theory segment to see what consequences of this definition have been
stored there. Then we delete the type, which turns all those
consequences into garbage. An query, like current_theorems, shows that
this garbage is not collected automatically. A manual invocation of
scrub is necessary to show the true state of play.
- Hol_datatype `foo = A | B of 'a`;
<<HOL message: Defined type: "foo">>
> val it = () : unit
- current_theorems();
> val it =
[("foo_induction", |- !P. P A /\ (!a. P (B a)) ==> !f. P f),
("foo_Axiom", |- !f0 f1. ?fn. (fn A = f0) /\ !a. fn (B a) = f1 a),
("foo_nchotomy", |- !f. (f = A) \/ ?a. f = B a),
("foo_case_cong",
|- !M M' v f.
(M = M') /\ ((M' = A) ==> (v = v')) /\
(!a. (M' = B a) ==> (f a = f' a)) ==>
(case v f M = case v' f' M')),
("foo_distinct", |- !a. ~(A = B a)),
("foo_11", |- !a a'. (B a = B a') = (a = a'))] : (string * thm) list
- delete_type "foo";
> val it = () : unit
- current_theorems();
> val it =
[("foo_induction", |- !P. P A /\ (!a. P (B a)) ==> !f. P f),
("foo_Axiom", |- !f0 f1. ?fn. (fn A = f0) /\ !a. fn (B a) = f1 a),
("foo_nchotomy", |- !f. (f = A) \/ ?a. f = B a),
("foo_case_cong",
|- !M M' v f.
(M = M') /\ ((M' = A) ==> (v = v')) /\
(!a. (M' = B a) ==> (f a = f' a)) ==>
(case v f M = case v' f' M')),
("foo_distinct", |- !a. ~(A = B a)),
("foo_11", |- !a a'. (B a = B a') = (a = a'))] : (string * thm) list
- scrub();
> val it = () : unit
- current_theorems();
> val it = [] : (string * thm) list
When export_theory is called, it uses scrub to prepare the current
segment for export. Users can also call scrub to find out what setting
they are really working in.
See also
Theory.uptodate_type,
Theory.uptodate_term,
Theory.uptodate_thm,
Theory.delete_type,
Theory.delete_const
set_MLname
set_MLname
Theory.set_MLname : string -> string -> unit
Change the name attached to an element of the current theory.
It can happen that an axiom, definition, or theorem gets stored in the current theory segment under a name that wouldn't be a suitable ML identifier. For example, some advanced definition mechanisms in HOL automatically construct names to bind the results of making a definition. In some cases, particularly when symbolic identifiers are involved, a binding name can be generated that is not a valid ML identifier.
In such cases, we don't want to fail and lose the work done by the
definition mechanism. Instead, when export_theory is invoked, all
names binding axioms, definitions, and theorems are examined to see if
they are valid ML identifiers. If not, an informative error message is
generated, and it is up to the user to change the names in the offending
bindings. The function set_MLname s1 s2 will replace a binding with
name s1 by one with name s2.
Failure
Never fails, although will give a warning if s1 is not the name of a
binding in the current theory segment.
Example
We inductively define a predicate telling if a number is odd in the following. The name is admittedly obscure, however it illustrates our point.
- Hol_reln `(%% 1) /\ (!n. %% n ==> %% (n+2))`;
> val it =
(|- %% 1 /\ !n. %% n ==> %% (n + 2),
|- !%%'. %%' 1 /\ (!n. %%' n ==> %%' (n + 2)) ==> !a0. %% a0 ==> %%' a0,
|- !a0. %% a0 = (a0 = 1) \/ ?n. (a0 = n + 2) /\ %% n) : thm * thm * thm
- export_theory();
<<HOL message: The following ML binding names in the theory to be exported:
"%%_rules", "%%_ind", "%%_cases"
are not acceptable ML identifiers.
Use `set_MLname <bad> <good>' to change each name.>>
! Uncaught exception:
! HOL_ERR
- (set_MLname "%%_rules" "odd_rules"; (* OK, do what it says *)
set_MLname "%%_ind" "odd_ind";
set_MLname "%%_cases" "odd_cases");
> val it = () : unit
- export_theory();
Exporting theory "scratch" ... done.
> val it = () : unit
Comments
The definition principles that currently have the potential to make
problematic bindings are Hol_datatype and Hol_reln.
It is slightly awkward to have to repair the names in a post-hoc fashion. It is probably simpler to proceed by using alphanumeric names when defining constants, and to use overloading to get the desired name.
See also
bossLib.Hol_reln,
bossLib.Hol_datatype,
Theory.export_theory,
Theory.current_definitions,
Theory.current_theorems,
Theory.current_axioms, DB.thy,
DB.dest_theory
thy_addon
thy_addon
Theory.type thy_addon
Type of theory additions.
The type abbreviation thy_addon, declared as
type thy_addon = {sig_ps : unit PP.pprinter option,
struct_ps : unit PP.pprinter option}
packages up the arguments to adjoin_to_theory. The sig_ps argument
is an optional prettyprinter, which will be invoked when the theory
signature file is written. The struct_ps argument is an optional
prettyprinter invoked when the theory structure file is written.
The unit type parameter in both cases simply means that the
pretty-printers won't be passed any extra information when invoked.
See also
types
types
Theory.types : string -> (string * int) list
Lists the types in the named theory.
The function types should be applied to a string which is the name of
an ancestor theory (including the current theory; the special string
"-" is always interpreted as the current theory). It returns a list of
all the type constructors declared in the named theory, in the form of
arity-name pairs.
Failure
Fails unless the named theory is an ancestor, or the current theory.
Example
> load "bossLib";
val it = (): unit
> itlist union (map types (ancestry "-")) [];
val it =
[("hrat", 0), ("hreal", 0), ("real", 0), ("bit0", 1), ("bit1", 1),
("cart", 2), ("finite_image", 1), ("ordering", 0), ("char", 0),
("recspace", 1), ("cv", 0), ("one", 0), ("sum", 2), ("option", 1),
("list", 1), ("prod", 2), ("bool", 0), ("fun", 2), ("ind", 0),
("itself", 1), ("num", 0), ("int", 0), ("example", 0), ("atree", 2)]:
(string * int) list
See also
Theory.constants,
Theory.current_axioms,
Theory.current_definitions,
Theory.current_theorems,
Theory.new_type,
Definition.new_type_definition,
Theory.parents,
Theory.ancestry
uptodate_term
uptodate_term
Theory.uptodate_term : term -> bool
Tells if a term is out of date.
Operations in the current theory segment of HOL allow one to redefine types and constants. This can cause theorems to become invalid. As a result, HOL has a rudimentary consistency maintenance system built around the notion of whether type operators and term constants are "up-to-date".
An invocation uptodate_term M checks M to see if it has been built
from any out-of-date components. The definition of out-of-date is
mutually recursive among types, terms, and theorems. If M is a
variable, it is out-of-date if its type is out-of-date. If M is a
constant, it is out-of-date if it has been redeclared, or if its type is
out-of-date, or if the witness theorem used to justify its existence is
out-of-date. If M is a combination, it is out-of-date if either of its
components are out-of-date. If M is an abstraction, it is out-of-date
if either the bound variable or the body is out-of-date.
All items from ancestor theories are fixed, and unable to be overwritten, thus are always up-to-date.
Failure
Never fails.
Example
> Define `utdtfact x = if x=0 then 1 else x * utdtfact (x-1)`;
val it = ⊢ ∀x. utdtfact x = if x = 0 then 1 else x * utdtfact (x − 1): thm
> val M = Term `!x. 0 < utdtfact x`;
val M = “∀x. 0 < utdtfact x”: term
> uptodate_term M;
val it = true: bool
> delete_const "utdtfact";
val it = (): unit
> uptodate_term M;
val it = false: bool
See also
Theory.uptodate_type,
Theory.uptodate_thm
uptodate_thm
uptodate_thm
Theory.uptodate_thm : thm -> bool
Tells if a theorem is out of date.
Operations in the current theory segment of HOL allow one to redefine types and constants. This can cause theorems to become invalid. As a result, HOL has a rudimentary consistency maintenance system built around the notion of whether type operators and term constants are "up-to-date".
An invocation uptodate_thm th should check th to see if it has
been proved from any out-of-date components. However, HOL does not
currently keep the proofs of theorems, so a simpler approach is taken.
Instead, th is checked to see if its hypotheses and conclusions are
up-to-date, and if any (locally asserted) axioms it depends on are
also up-to-date.
All items from ancestor theories are fixed, and unable to be overwritten, thus are always up-to-date.
Failure
Never fails.
Example
Definition fact_def:
fact (x:num) = if x=0 then 1 else x * fact (x-1)
End
Equations stored under "fact_def".
Induction stored under "fact_ind".
val fact_def = ⊢ ∀x. fact x = if x = 0 then 1 else x * fact (x − 1): thm
> val th = EVAL “fact 3”
val th = ⊢ fact 3 = fact 3: thm
> uptodate_thm th;
val it = true: bool
> delete_const "fact";
val it = (): unit
> uptodate_thm th;
val it = true: bool
Comments
It may happen that a theorem th is proved with the use of another
theorem th1 that subsequently becomes garbage because a constant c
was deleted. If c does not occur in th, then th does not become
garbage, which may be contrary to expectation. The conservative
extension property of HOL says that th is still provable, even in the
absence of c.
See also
Theory.uptodate_type,
Theory.uptodate_term,
Theory.delete_const,
Theory.delete_type
uptodate_type
uptodate_type
Theory.uptodate_type : hol_type -> bool
Tells if a type is out of date.
Operations in the current theory segment of HOL allow one to redefine types and constants. This can cause theorems to become invalid. As a result, HOL has a rudimentary consistency maintenance system built around the notion of whether type operators and term constants are "up-to-date".
An invocation uptodate_type ty, checks ty to see if it has been
built from any out of date components, returning false just in case it
has. The definition of out-of-date is mutually recursive among types,
terms, and theorems. A type variable never out-of-date. A compound type
is out-of-date if either (a) its type operator is out-of-date, or (b)
any of its argument types are out-of-date. A type operator is
out-of-date if it has been re-declared or if the witness theorem used to
justify the type in the call to new_type_definition is out-of-date.
Only a component of the current theory segment may be out-of-date. All
items from ancestor theories are fixed, and unable to be overwritten,
thus are always up-to-date.
Failure
Never fails.
Example
> Hol_datatype `foo = A | B of 'a`;
val it = (): unit
> val ty = Type `:'a foo list`;
val ty = “:α foo list”: hol_type
> uptodate_type ty;
val it = true: bool
> delete_type "foo";
val it = (): unit
> uptodate_type ty;
val it = false: bool
See also
Theory.uptodate_term,
Theory.uptodate_thm
ABS
ABS
Thm.ABS : term -> thm -> thm
Abstracts both sides of an equation.
A |- t1 = t2
------------------------ ABS x [Where x is not free in A]
A |- (\x.t1) = (\x.t2)
Failure
If the theorem is not an equation, or if the variable x is free in the
assumptions A.
Example
> let val m = “m:bool”
in
ABS m (REFL m)
end;
val it = ⊢ (λm. m) = (λm. m): thm
See also
Drule.ETA_CONV, Drule.EXT,
Drule.MK_ABS
add_tag
add_tag
Thm.add_tag : tag * thm -> thm
Adds oracle tags to a theorem.
A call to add_tag(tg,th) returns a th' such that calling
Thm.tag(th') returns the tag that is the merge of the tag associated
with th (if any) and tg.
Failure
Never fails.
Comments
If an oracle implementation wishes to record additional information about the oracle mechanisms that have contributed to the 'proof' of a theorem (perhaps the use of existing HOL theorems that will have their own tags), then this function can be used to add that record.
See also
ALPHA
ALPHA
Thm.ALPHA : term -> term -> thm
Proves equality of alpha-equivalent terms.
When applied to a pair of terms t1 and t1' which are
alpha-equivalent, ALPHA returns the theorem |- t1 = t1'.
------------- ALPHA t1 t1'
|- t1 = t1'
Failure
Fails unless the terms provided are alpha-equivalent.
See also
Term.aconv, Drule.ALPHA_CONV,
Drule.GEN_ALPHA_CONV
AP_TERM
AP_TERM
Thm.AP_TERM : term -> thm -> thm
Applies a function to both sides of an equational theorem.
When applied to a term f and a theorem A |- x = y, the inference
rule AP_TERM returns the theorem A |- f x = f y.
A |- x = y
---------------- AP_TERM f
A |- f x = f y
Failure
Fails unless the theorem is equational and the supplied term is a function whose domain type is the same as the type of both sides of the equation.
See also
Tactic.AP_TERM_TAC,
Thm.AP_THM, Tactic.AP_THM_TAC,
Thm.MK_COMB
AP_THM
AP_THM
Thm.AP_THM : thm -> term -> thm
Proves equality of equal functions applied to a term.
When applied to a theorem A |- f = g and a term x, the inference
rule AP_THM returns the theorem A |- f x = g x.
A |- f = g
---------------- AP_THM (A |- f = g) x
A |- f x = g x
Failure
Fails unless the conclusion of the theorem is an equation, both sides of which are functions whose domain type is the same as that of the supplied term.
See also
Tactic.AP_THM_TAC,
Thm.AP_TERM, Drule.ETA_CONV,
Drule.EXT, Conv.FUN_EQ_CONV,
Thm.MK_COMB
ASSUME
ASSUME
Thm.ASSUME : term -> thm
Introduces an assumption.
When applied to a term t, which must have type bool, the inference
rule ASSUME returns the theorem t |- t.
-------- ASSUME t
t |- t
Failure
Fails unless the term t has type bool.
See also
Beta
Beta
Thm.Beta : thm -> thm
Perform one step of beta-reduction on the right hand side of an equational theorem.
Beta performs a single beta-reduction step on the right-hand side of
an equational theorem.
A |- t = ((\x.M) N)
--------------------- Beta
A |- t = M [N/x]
Failure
If the theorem is not an equation, or if the right hand side of the equation is not a beta-redex.
Example
> val th = REFL “(K:'a ->'b->'a) x”;
val th = ⊢ K x = K x: thm
> SUBS_OCCS [([2],combinTheory.K_DEF)] th;
val it = ⊢ K x = (λx y. x) x: thm
> Beta it;
val it = ⊢ K x = (λy. x): thm
Comments
Beta is equivalent to RIGHT_BETA but faster.
See also
Drule.RIGHT_BETA,
Drule.ETA_CONV
BETA_CONV
BETA_CONV
Thm.BETA_CONV : conv
Performs a single step of beta-conversion.
The conversion BETA_CONV maps a beta-redex "(\x.u)v" to the theorem
|- (\x.u)v = u[v/x]
where u[v/x] denotes the result of substituting v for all free
occurrences of x in u, after renaming sufficient bound variables to
avoid variable capture. This conversion is one of the primitive
inference rules of the HOL system.
Failure
BETA_CONV tm fails if tm is not a beta-redex.
Example
> BETA_CONV (Term `(\x.x+1)y`);
val it = ⊢ (λx. x + 1) y = y + 1: thm
> BETA_CONV (Term `(\x y. x+y)y`);
val it = ⊢ (λx y. x + y) y = (λy'. y + y'): thm
See also
Conv.BETA_RULE,
Tactic.BETA_TAC,
Drule.LIST_BETA_CONV,
PairedLambda.PAIRED_BETA_CONV,
Drule.RIGHT_BETA,
Drule.RIGHT_LIST_BETA
CCONTR
CCONTR
Thm.CCONTR : term -> thm -> thm
Implements the classical contradiction rule.
When applied to a term t and a theorem A |- F, the inference rule
CCONTR returns the theorem A - {~t} |- t.
A |- F
--------------- CCONTR t
A - {~t} |- t
Failure
Fails unless the term has type bool and the theorem has F as its
conclusion.
Comments
The usual use will be when ~t exists in the assumption list; in this
case, CCONTR corresponds to the classical contradiction rule: if ~t
leads to a contradiction, then t must be true.
See also
Drule.CONTR, Drule.CONTRAPOS,
Tactic.CONTR_TAC, Thm.NOT_ELIM
CHOOSE
CHOOSE
Thm.CHOOSE : term * thm -> thm -> thm
Eliminates existential quantification using deduction from a particular witness.
When applied to a term-theorem pair (v,A1 |- ?x. s) and a second
theorem of the form A2 u {s[v/x]} |- t, the inference rule CHOOSE
produces the theorem A1 u A2 |- t.
A1 |- ?x. s A2 u {s[v/x]} |- t
--------------------------------------- CHOOSE (v,(A1 |- ?x. s))
A1 u A2 |- t
Where v is not free in A1, A2 or t.
Failure
Fails unless the terms and theorems correspond as indicated above; in
particular v must have the same type as the variable existentially
quantified over, and must not be free in A1, A2 or t.
See also
Tactic.CHOOSE_TAC, Thm.EXISTS,
Tactic.EXISTS_TAC,
Drule.SELECT_ELIM
concl
concl
Thm.concl : thm -> term
Returns the conclusion of a theorem.
When applied to a theorem A |- t, the function concl returns t.
Failure
Never fails.
See also
CONJ
CONJ
Thm.CONJ : thm -> thm -> thm
Introduces a conjunction.
A1 |- t1 A2 |- t2
------------------------ CONJ
A1 u A2 |- t1 /\ t2
Failure
Never fails.
Comments
The theorem AND_INTRO_THM can be instantiated to similar effect.
See also
Drule.BODY_CONJUNCTS,
Thm.CONJUNCT1, Thm.CONJUNCT2,
Drule.CONJ_PAIR,
Drule.LIST_CONJ,
Drule.CONJ_LIST,
Drule.CONJUNCTS
CONJUNCT1
CONJUNCT1
Thm.CONJUNCT1 : thm -> thm
Extracts left conjunct of theorem.
A |- t1 /\ t2
--------------- CONJUNCT1
A |- t1
Failure
Fails unless the input theorem is a conjunction.
Comments
The theorem AND1_THM can be instantiated to similar effect.
See also
Drule.BODY_CONJUNCTS,
Thm.CONJUNCT2,
Drule.CONJ_PAIR, Thm.CONJ,
Drule.LIST_CONJ,
Drule.CONJ_LIST,
Drule.CONJUNCTS
CONJUNCT2
CONJUNCT2
Thm.CONJUNCT2 : thm -> thm
Extracts right conjunct of theorem.
A |- t1 /\ t2
--------------- CONJUNCT2
A |- t2
Failure
Fails unless the input theorem is a conjunction.
Comments
The theorem AND2_THM can be instantiated to similar effect.
See also
Drule.BODY_CONJUNCTS,
Thm.CONJUNCT1,
Drule.CONJ_PAIR, Thm.CONJ,
Drule.LIST_CONJ,
Drule.CONJ_LIST,
Drule.CONJUNCTS
dest_thm
dest_thm
Thm.dest_thm : thm -> term list * term
Breaks a theorem into assumption list and conclusion.
dest_thm ([t1,...,tn] |- t) returns ([t1,...,tn],t).
Failure
Never fails.
Example
> dest_thm (ASSUME (Term `p=T`));
val it = ([“p ⇔ T”], “p ⇔ T”): term list * term
See also
DISCH
DISCH
Thm.DISCH : (term -> thm -> thm)
Discharges an assumption.
A |- t
-------------------- DISCH u
A - {u} |- u ==> t
Failure
DISCH will fail if u is not boolean.
Comments
The term u need not be a hypothesis. Discharging u will remove all
identical and alpha-equivalent hypotheses.
See also
Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Drule.NEG_DISCH,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
DISJ1
DISJ1
Thm.DISJ1 : thm -> term -> thm
Introduces a right disjunct into the conclusion of a theorem.
A |- t1
--------------- DISJ1 (A |- t1) t2
A |- t1 \/ t2
Failure
Fails unless the term argument is boolean.
Example
> DISJ1 TRUTH F;
val it = ⊢ T ∨ F: thm
See also
Tactic.DISJ1_TAC, Thm.DISJ2,
Tactic.DISJ2_TAC,
Thm.DISJ_CASES
DISJ2
DISJ2
Thm.DISJ2 : term -> thm -> thm
Introduces a left disjunct into the conclusion of a theorem.
A |- t2
--------------- DISJ2 "t1"
A |- t1 \/ t2
Failure
Fails if the term argument is not boolean.
Example
> DISJ2 F TRUTH;
val it = ⊢ F ∨ T: thm
See also
Thm.DISJ1, Tactic.DISJ1_TAC,
Tactic.DISJ2_TAC,
Thm.DISJ_CASES
DISJ_CASES
DISJ_CASES
Thm.DISJ_CASES : (thm -> thm -> thm -> thm)
Eliminates disjunction by cases.
The rule DISJ_CASES takes a disjunctive theorem, and two 'case'
theorems, each with one of the disjuncts as a hypothesis while sharing
alpha-equivalent conclusions. A new theorem is returned with the same
conclusion as the 'case' theorems, and the union of all assumptions
excepting the disjuncts.
A |- t1 \/ t2 A1 u {t1} |- t A2 u {t2} |- t
------------------------------------------------------ DISJ_CASES
A u A1 u A2 |- t
Failure
Fails if the first argument is not a disjunctive theorem, or if the conclusions of the other two theorems are not alpha-convertible.
Example
Specializing the built-in theorem num_CASES gives the theorem:
> val disj_th = SPEC “m:num” arithmeticTheory.num_CASES;
val disj_th = ⊢ m = 0 ∨ ∃n. m = SUC n: thm
Using two additional theorems, each having one disjunct as a hypothesis:
> show_assums := true;
val it = (): unit
> val th1 = EQT_ELIM $
REWRITE_CONV [ASSUME “m = 0”, prim_recTheory.PRE] “PRE m = m ⇔ m = 0”;
val th1 = [m = 0] ⊢ PRE m = m ⇔ m = 0: thm
> val th2_0 =
REWRITE_CONV [ASSUME “m = SUC n”, prim_recTheory.PRE,
arithmeticTheory.SUC_NOT_ZERO,
GSYM prim_recTheory.SUC_ID]
“PRE m = m ⇔ m = 0”;
val th2_0 = [m = SUC n] ⊢ (PRE m = m ⇔ m = 0) ⇔ T: thm
> val th2 = CHOOSE (“n:num”, ASSUME “∃n. m = SUC n”) (EQT_ELIM th2_0);
val th2 = [∃n. m = SUC n] ⊢ PRE m = m ⇔ m = 0: thm
a new theorem can be derived:
> DISJ_CASES disj_th th1 th2;
val it = [] ⊢ PRE m = m ⇔ m = 0: thm
Comments
Neither of the 'case' theorems is required to have either disjunct as a
hypothesis, but otherwise DISJ_CASES is pointless.
See also
Thm.CHOOSE,
Tactic.DISJ_CASES_TAC,
Thm_cont.DISJ_CASES_THEN,
Thm_cont.DISJ_CASES_THEN2,
Drule.DISJ_CASES_UNION,
Thm.DISJ1, Thm.DISJ2
EQ_IMP_RULE
EQ_IMP_RULE
Thm.EQ_IMP_RULE : thm -> thm * thm
Derives forward and backward implication from equality of boolean terms.
When applied to a theorem A |- t1 = t2, where t1 and t2 both have
type bool, the inference rule EQ_IMP_RULE returns the theorems
A |- t1 ==> t2 and A |- t2 ==> t1.
A |- t1 = t2
----------------------------------- EQ_IMP_RULE
A |- t1 ==> t2 A |- t2 ==> t1
Failure
Fails unless the conclusion of the given theorem is an equation between boolean terms.
See also
Thm.EQ_MP, Tactic.EQ_TAC,
Drule.IMP_ANTISYM_RULE
EQ_MP
EQ_MP
Thm.EQ_MP : thm -> thm -> thm
Equality version of the Modus Ponens rule.
When applied to theorems A1 |- t1 = t2 and A2 |- t1, the inference
rule EQ_MP returns the theorem A1 u A2 |- t2.
A1 |- t1 = t2 A2 |- t1
-------------------------- EQ_MP
A1 u A2 |- t2
Failure
Fails unless the first theorem is equational and its left side is the
same as the conclusion of the second theorem (and is therefore of type
bool), up to alpha-conversion.
See also
Thm.EQ_IMP_RULE,
Drule.IMP_ANTISYM_RULE, Thm.MP
EXISTS
EXISTS
Thm.EXISTS : term * term -> thm -> thm
Introduces existential quantification given a particular witness.
When applied to a pair of terms and a theorem, the first term an
existentially quantified pattern indicating the desired form of the
result, and the second a witness whose substitution for the quantified
variable gives a term which is the same as the conclusion of the
theorem, EXISTS gives the desired theorem.
A |- p[u/x]
------------- EXISTS (?x. p, u)
A |- ?x. p
Failure
Fails unless the substituted pattern is the same as the conclusion of the theorem.
Example
The following examples illustrate how it is possible to deduce different things from the same theorem:
- EXISTS (Term `?x. x=T`,T) (REFL T);
> val it = |- ?x. x = T : thm
- EXISTS (Term `?x:bool. x=x`,T) (REFL T);
> val it = |- ?x. x = x : thm
See also
Thm.CHOOSE,
Drule.SIMPLE_EXISTS,
Tactic.EXISTS_TAC
GEN
GEN
Thm.GEN : term -> thm -> thm
Generalizes the conclusion of a theorem.
When applied to a term x and a theorem A |- t, the inference rule
GEN returns the theorem A |- !x. t, provided x is a variable not
free in any of the assumptions. There is no compulsion that x should
be free in t.
A |- t
------------ GEN x [where x is not free in A]
A |- !x. t
Failure
Fails if x is not a variable, or if it is free in any of the
assumptions.
Example
The following example shows how the above side-condition prevents the
derivation of the theorem x=T |- !x. x=T, which is clearly invalid.
> show_types := true;
val it = (): unit
> val t = ASSUME “x=T”;
val t = [.] ⊢ (x :bool) ⇔ T: thm
> try (GEN “x:bool”) t;
Exception- HOL_ERR (at Thm.GEN: variable occurs free in hypotheses) raised
See also
Thm.GENL, Drule.GEN_ALL,
Tactic.GEN_TAC, Thm.SPEC,
Drule.SPECL, Drule.SPEC_ALL,
Tactic.SPEC_TAC,
ConseqConv.GEN_ASSUM,
ConseqConv.GEN_IMP,
ConseqConv.GEN_EQ
GEN_ABS
GEN_ABS
Thm.GEN_ABS : term option -> term list -> thm -> thm
Rule of inference for building binder-equations.
The GEN_ABS function is, semantically at least, a derived rule that
combines applications of the primitive rules ABS and MK_COMB. When
the first argument, a term option, is the value NONE, the effect is an
iterated application of the rule ABS (as per List.foldl. Thus,
G |- x = y
-------------------------------------------- GEN_ABS NONE [v1,v2,...,vn]
G |- (\v1 v2 .. vn. x) = (\v1 v2 .. vn. y)
If the first argument is SOME b for some term b, this term b is to
be a binder, usually of polymorphic type :('a -> bool) -> bool. Then
the effect is to interleave the effect of ABS and a call to AP_TERM.
For every variable v in the list, the following theorem transformation
will occur
G |- x = y
------------------------ ABS v
G |- (\v. x) = (\v. y)
---------------------------- AP_TERM b'
G |- b (\v. x) = b (\v. x)
where b' is a version of b that has been instantiated to match the
type of the term to which it is applied (AP_TERM doesn't do this).
Example
> val th = REWRITE_CONV [] ``t /\ u /\ u``
val th = ⊢ t ∧ u ∧ u ⇔ t ∧ u: thm
> GEN_ABS (SOME ``$!``) [``t:bool``, ``u:bool``] th;
val it = ⊢ (∀t u. t ∧ u ∧ u) ⇔ ∀t u. t ∧ u: thm
Failure
Fails if the theorem argument is not an equality. Fails if the second
argument (the list of terms) does not consist of variables. Fails if any
of the variables in the list appears in the hypotheses of the theorem.
Fails if the first argument is SOME b and the type of b is either
not of type :('a -> bool) -> bool, or some :(ty -> bool) -> bool
where all the variables have type ty.
Comments
Though semantically a derived rule, a HOL kernel may implement this as part of its core for reasons of efficiency.
See also
Thm.ABS, Thm.AP_TERM,
Thm.MK_COMB
GENL
GENL
Thm.GENL : term list -> thm -> thm
Generalizes zero or more variables in the conclusion of a theorem.
When applied to a term list [x1,...,xn] and a theorem A |- t, the
inference rule GENL returns the theorem A |- !x1...xn. t, provided
none of the variables xi are free in any of the assumptions. It is not
necessary that any or all of the xi should be free in t.
A |- t
------------------ GENL [x1,...,xn] [where no xi is free in A]
A |- !x1...xn. t
Failure
Fails unless all the terms in the list are variables, none of which are free in the assumption list.
See also
Thm.GEN, Drule.GEN_ALL,
Tactic.GEN_TAC, Thm.SPEC,
Drule.SPECL, Drule.SPEC_ALL,
Tactic.SPEC_TAC
hyp
hyp
Thm.hyp : thm -> term list
Returns the hypotheses of a theorem.
When applied to a theorem A |- t, the function hyp returns A, the
list of hypotheses of the theorem.
Failure
Never fails.
Comments
The order in which hypotheses are returned can not be relied on.
See also
INST
INST
Thm.INST : (term,term) subst -> thm -> thm
Instantiates free variables in a theorem.
INST is a rule for substituting arbitrary terms for free variables in
a theorem.
A |- t INST [x1 |-> t1,...,xn |-> tn]
-----------------------------
A[t1,...,tn/x1,...,xn]
|-
t[t1,...,tn/x1,...,xn]
Failure
Fails if, for 1 <= i <= n, some xi is not a variable, or if some
xi has a different type than its intended replacement ti.
Example
In the following example a theorem is instantiated for a specific term:
- load"arithmeticTheory";
- CONJUNCT1 arithmeticTheory.ADD_CLAUSES;
> val it = |- 0 + m = m : thm
- INST [``m:num`` |-> ``2*x``]
(CONJUNCT1 arithmeticTheory.ADD_CLAUSES);
val it = |- 0 + (2 * x) = 2 * x : thm
See also
Drule.INST_TY_TERM,
Thm.INST_TYPE, Drule.ISPEC,
Drule.ISPECL, Thm.SPEC,
Drule.SPECL, Drule.SUBS,
Term.subst, Thm.SUBST,
Lib.|->
INST_TYPE
INST_TYPE
Thm.INST_TYPE : (hol_type,hol_type) subst -> thm -> thm
Instantiates types in a theorem.
INST_TYPE is a primitive rule in the HOL logic, which allows
instantiation of type variables.
A |- t
----------------------------------- INST_TYPE[vty1|->ty1,..., vtyn|->tyn]
A[ty1,...,tyn/vty1,...,vtyn]
|-
t[ty1,...,tyn/vty1,...,vtyn]
Type substitution is performed throughout the hypotheses and the conclusion. Variables will be renamed if necessary to prevent distinct bound variables becoming identical after the instantiation.
Failure
Never fails.
INST_TYPE enables polymorphic theorems to be used at any type.
Example
Supposing one wanted to specialize the theorem EQ_SYM_EQ for
particular values, the first attempt could be to use SPECL as follows:
- SPECL [``a:num``, ``b:num``] EQ_SYM_EQ;
uncaught exception HOL_ERR
The failure occurred because EQ_SYM_EQ contains polymorphic types. The
desired specialization can be obtained by using INST_TYPE:
- load "numTheory";
- SPECL [Term `a:num`, Term`b:num`]
(INST_TYPE [alpha |-> Type`:num`] EQ_SYM_EQ);
> val it = |- (a = b) = (b = a) : thm
See also
Term.inst, Thm.INST,
Drule.INST_TY_TERM, Lib.|->
MK_COMB
MK_COMB
Thm.MK_COMB : thm * thm -> thm
Proves equality of combinations constructed from equal functions and operands.
When applied to theorems A1 |- f = g and A2 |- x = y, the inference
rule MK_COMB returns the theorem A1 u A2 |- f x = g y.
A1 |- f = g A2 |- x = y
--------------------------- MK_COMB
A1 u A2 |- f x = g y
Failure
Fails unless both theorems are equational and f and g are functions
whose domain types are the same as the types of x and y
respectively.
See also
Thm.AP_TERM, Thm.AP_THM,
Tactic.MK_COMB_TAC
mk_oracle_thm
mk_oracle_thm
Thm.mk_oracle_thm : string -> term list * term -> thm
Construct a theorem without proof, and tag it.
In principle, nearly every theorem of interest can be proved in HOL by using only the axioms and primitive rules of inference. The use of ML to orchestrate larger inference steps from the primitives, along with support in HOL for goal-directed proof, considerably eases the task of formal proof. Nearly every theorem of interest can therefore be produced as the end product of a chain of primitive inference steps, and HOL implementations strive to keep this purity.
However, it is occasionally useful to interface HOL with trusted external tools that also produce, in some sense, theorems that would be derivable in HOL. It is clearly a burden to require that HOL proofs accompany such theorems so that they can be (re-)derived in HOL. In order to support greater interoperation of proof tools, therefore, HOL provides the notion of a 'tagged' theorem.
A tagged theorem is manufactured by invoking mk_oracle_thm tag (A,w),
where A is a list of HOL terms of type bool, and w is also a HOL
term of boolean type. No proof is done; the sequent is merely injected
into the type of theorems, and the tag value is attached to it. The
result is the theorem A |- w.
The tag value stays with the theorem, and it propagates in a
hereditary fashion to any theorem derived from the tagged theorem. Thus,
if one examines a theorem with Thm.tag and finds that it has no tag,
then the theorem has been derived purely by proof steps in the HOL
logic. Otherwise, shortcuts have been taken, and the external tools,
also known as ‘oracles’, used to make the shortcuts are signified by the
tags.
Failure
If some element of A does not have type bool, or w does not have
type bool, or the tag string doesn't represent a valid tag (which
occurs if it is the string "DISK_THM", or if it is a string containing
unprintable characters).
Example
In the following, we construct a tag and then make a rogue rule of inference.
> val tag = "SimonSays";
val tag = "SimonSays": string
> val SimonThm = mk_oracle_thm tag;
val SimonThm = fn: term list * term -> thm
> val th = SimonThm ([], Term `!x. x`);
val th = ⊢ ∀x. x: thm
> val th1 = SPEC F th;
val th1 = ⊢ F: thm
> (show_tags := true; th1);
val it = [oracles: SimonSays] [axioms: ] [] ⊢ F: thm
Tags accumulate in a manner similar to logical hypotheses.
> CONJ th1 th1;
val it = [oracles: SimonSays] [axioms: ] [] ⊢ F ∧ F: thm
> val SerenaThm = mk_oracle_thm "Serena";
val SerenaThm = fn: term list * term -> thm
> CONJ th1 (SerenaThm ([],T));
val it = [oracles: Serena, SimonSays] [axioms: ] [] ⊢ F ∧ T: thm
Comments
It is impossible to detach a tag from a theorem.
See also
Thm.add_tag, Thm.mk_thm,
Tag.read, Thm.tag
mk_thm
mk_thm
Thm.mk_thm : term list * term -> thm
Creates an arbitrary theorem (dangerous!).
The function mk_thm can be used to construct an arbitrary theorem. It
is applied to a pair consisting of the desired assumption list (possibly
empty) and conclusion. All the terms therein should be of type bool.
mk_thm([a1,...,an],c) = ({a1,...,an} |- c)
mk_thm is an application of mk_oracle_thm, and every application of
it tags the resulting theorem with MK_THM.
Failure
Fails unless all the terms provided for assumptions and conclusion are
of type bool.
Example
The following shows how to create a simple contradiction:
> val falsity = mk_thm([],boolSyntax.F);
val falsity = ⊢ F: thm
> Globals.show_tags := true;
val it = (): unit
> falsity;
val it = [oracles: MK_THM] [axioms: ] [] ⊢ F: thm
Comments
Although mk_thm can be useful for experimentation or temporarily
plugging gaps, its use should be avoided if at all possible in important
proofs, because it can be used to create theorems leading to
contradictions. The example above is a trivial case, but it is all too
easy to create a contradiction by asserting 'obviously sound' theorems.
All theorems which are likely to be needed can be derived using only HOL's inbuilt axioms and primitive inference rules, which are provably sound (see the DESCRIPTION). Basing all proofs, normally via derived rules and tactics, on just these axioms and inference rules gives proofs which are (apart from bugs in HOL or the underlying system) completely secure. This is one of the great strengths of HOL, and it is foolish to sacrifice it to save a little work.
Because of the way tags are propagated during proof, a theorem proved
with the aid of mk_thm is detectable by examining its tag.
See also
Theory.new_axiom,
Thm.mk_oracle_thm, Thm.tag,
Globals.show_tags
MP
MP
Thm.MP : thm -> thm -> thm
Implements the Modus Ponens inference rule.
When applied to theorems A1 |- t1 ==> t2 and A2 |- t1, the inference
rule MP returns the theorem A1 u A2 |- t2.
A1 |- t1 ==> t2 A2 |- t1
---------------------------- MP
A1 u A2 |- t2
In common with the underlying dest_imp syntax function, MP treats
theorems with conclusions of the form ~p as implications p ==> F.
This means that MP also has the following behaviour:
A1 |- ~t1 A2 |- t1
------------------------ MP
A1 u A2 |- F
Failure
Fails unless the first theorem is an implication (in the sense of
dest_imp) whose antecedent is the same as the conclusion of the second
theorem (up to alpha-conversion)
See also
boolSyntax.dest_imp,
Thm.EQ_MP, Drule.LIST_MP,
Drule.MATCH_MP,
Tactic.MATCH_MP_TAC,
Tactic.MP_TAC
NOT_ELIM
NOT_ELIM
Thm.NOT_ELIM : thm -> thm
Transforms |- ~t into |- t ==> F.
When applied to a theorem A |- ~t, the inference rule NOT_ELIM
returns the theorem A |- t ==> F.
A |- ~t
-------------- NOT_ELIM
A |- t ==> F
Failure
Fails unless the theorem has a negated conclusion.
See also
NOT_INTRO
NOT_INTRO
Thm.NOT_INTRO : (thm -> thm)
Transforms |- t ==> F into |- ~t.
When applied to a theorem A |- t ==> F, the inference rule NOT_INTRO
returns the theorem A |- ~t.
A |- t ==> F
-------------- NOT_INTRO
A |- ~t
Failure
Fails unless the theorem has an implicative conclusion with F as the
consequent.
See also
REFL
REFL
Thm.REFL : conv
Returns theorem expressing reflexivity of equality.
REFL maps any term t to the corresponding theorem |- t = t.
Failure
Never fails.
See also
Conv.ALL_CONV, Tactic.REFL_TAC
SPEC
SPEC
Thm.SPEC : term -> thm -> thm
Specializes the conclusion of a theorem.
When applied to a term u and a theorem A |- !x. t, then SPEC
returns the theorem A |- t[u/x]. If necessary, variables will be
renamed prior to the specialization to ensure that u is free for x
in t, that is, no variables free in u become bound after
substitution.
A |- !x. t
-------------- SPEC u
A |- t[u/x]
Failure
Fails if the theorem's conclusion is not universally quantified, or if
x and u have different types.
Example
The following example shows how SPEC renames bound variables if
necessary, prior to substitution: a straightforward substitution would
result in the clearly invalid theorem |- ~y ==> (!y. y ==> ~y).
- let val xv = Term `x:bool`
and yv = Term `y:bool`
in
(GEN xv o DISCH xv o GEN yv o DISCH yv) (ASSUME xv)
end;
> val it = |- !x. x ==> !y. y ==> x : thm
- SPEC (Term `~y`) it;
> val it = |- ~y ==> !y'. y' ==> ~y : thm
See also
Drule.ISPEC, Drule.SPECL,
Drule.SPEC_ALL,
Drule.SPEC_VAR, Thm.GEN,
Thm.GENL, Drule.GEN_ALL
Specialize
Specialize
Thm.Specialize : term -> thm -> thm
Specializes the conclusion of a universal theorem.
When applied to a term u and a theorem A |- !x. t, Specialize
returns the theorem A |- t[u/x]. Care is taken to ensure that no
variables free in u become bound after this operation.
A |- !x. t
-------------- Specialize u
A |- t[u/x]
Failure
Fails if the theorem's conclusion is not universally quantified, or if
x and u have different types.
Comments
Specialize behaves identically to SPEC, but is faster.
See also
Thm.SPEC, Drule.ISPEC,
Drule.SPECL, Drule.SPEC_ALL,
Drule.SPEC_VAR, Thm.GEN,
Thm.GENL, Drule.GEN_ALL
SUBST
SUBST
Thm.SUBST : (term,thm) subst -> term -> thm -> thm
Makes a set of parallel substitutions in a theorem.
Implements the following rule of simultaneous substitution
A1 |- t1 = u1 , ... , An |- tn = un , A |- t[t1,...,tn]
-------------------------------------------------------------
A u A1 u ... u An |- t[u1,...,un]
Evaluating
SUBST [x1 |-> (A1 |- t1=u1) ,..., xn |-> (An |- tn=un)]
t[x1,...,xn]
(A |- t[t1,...,tn])
returns the theorem A u A1 u ... u An |- t[u1,...,un] (perhaps with
fewer assumptions, see paragraph below). The term argument
t[x1,...,xn] is a template which should match the conclusion of the
theorem being substituted into, with the variables x1, ... , xn
marking those places where occurrences of t1, ... , tn are to be
replaced by the terms u1, ... , un, respectively. The occurrence of
ti at the places marked by xi must be free (i.e. ti must not
contain any bound variables). SUBST automatically renames bound
variables to prevent free variables in ui becoming bound after
substitution.
The assumptions of the returned theorem may not contain all the
assumptions A1 u ... u An if some of them are not required. In
particular, if the theorem Ak |- tk = uk is unnecessary because xk
does not appear in the template, then Ak is not be added to the
assumptions of the returned theorem.
Failure
If the template does not match the conclusion of the hypothesis, or the
terms in the conclusion marked by the variables x1, ... , xn in the
template are not identical to the left hand sides of the supplied
equations (i.e. the terms t1, ... , tn).
Example
> val x = “x:num”
and y = “y:num”
and th0 = SPEC “0” arithmeticTheory.ADD1
and th1 = SPEC “1” arithmeticTheory.ADD1;
val th0 = ⊢ SUC 0 = 0 + 1: thm
val th1 = ⊢ SUC 1 = 1 + 1: thm
val x = “x”: term
val y = “y”: term
> SUBST [x |-> th0, y |-> th1]
“(x+y) > SUC 0”
(ASSUME “(SUC 0 + SUC 1) > SUC 0”);
val it = [.] ⊢ 0 + 1 + (1 + 1) > SUC 0: thm
> SUBST [x |-> th0, y |-> th1]
“(SUC 0 + y) > SUC 0”
(ASSUME “(SUC 0 + SUC 1) > SUC 0”);
val it = [.] ⊢ SUC 0 + (1 + 1) > SUC 0: thm
> SUBST [x |-> th0, y |-> th1]
“(x+y) > x”
(ASSUME “(SUC 0 + SUC 1) > SUC 0”);
val it = [.] ⊢ 0 + 1 + (1 + 1) > 0 + 1: thm
Comments
SUBST is perhaps overly complex for a primitive rule of inference.
For substituting at selected occurrences. Often useful for writing special purpose derived inference rules.
See also
Thm.INST, Drule.SUBS,
Drule.SUBST_CONV, Lib.|->
SYM
SYM
Thm.SYM : thm -> thm
Swaps left-hand and right-hand sides of an equation.
When applied to a theorem A |- t1 = t2, the inference rule SYM
returns A |- t2 = t1.
A |- t1 = t2
-------------- SYM
A |- t2 = t1
Failure
Fails unless the theorem is equational.
See also
Conv.GSYM, Drule.NOT_EQ_SYM,
Thm.REFL, Tacic.SYM_TAC
tag
tag
Thm.tag : thm -> tag
Extract the tag from a theorem.
An invocation tag th, where th has type thm, returns the tag of
the theorem. If derivation of the theorem has appealed at some point to
an oracle, the tag of that oracle will be embedded in the result.
Otherwise, an empty tag is returned.
Failure
Never fails.
Example
> Thm.tag (mk_thm([],F));
val it = [oracles: #] [axioms: ]: tag
> Thm.tag NOT_FORALL_THM;
val it = [oracles: #] [axioms: ]: tag
See also
Thm.mk_oracle_thm, Tag.read,
Tag.merge, Tag.pp_tag
thm
thm
Thm.type thm
Type of theorems of the HOL logic.
The abstract type thm represents the theorems derivable by inference
in the HOL logic. The type of theorems can be viewed as the inductive
closure of the axioms of the HOL logic by the primitive inference rules
of HOL. Robin Milner had the brilliant insight to implement this view by
encapsulating the primitive rules of inference for a logic as the
constructors for an abstract type of theorems. This implementation
technique is adopted in HOL.
See also
Thm.dest_thm, Thm.hyp,
Thm.concl, Thm.tag,
Thm.ASSUME, Thm.REFL,
Thm.BETA_CONV, Thm.ABS,
Thm.DISCH, Thm.MP,
Thm.SUBST, Thm.INST_TYPE
TRANS
TRANS
Thm.TRANS : (thm -> thm -> thm)
Uses transitivity of equality on two equational theorems.
When applied to a theorem A1 |- t1 = t2 and a theorem A2 |- t2 = t3,
the inference rule TRANS returns the theorem A1 u A2 |- t1 = t3.
A1 |- t1 = t2 A2 |- t2 = t3
------------------------------- TRANS
A1 u A2 |- t1 = t3
Failure
Fails unless the theorems are equational, with the right side of the first being the same as the left side of the second.
Example
- val t1 = ASSUME ``a:bool = b`` and t2 = ASSUME ``b:bool = c``;
val t1 = [.] |- a = b : thm
val t2 = [.] |- b = c : thm
- TRANS t1 t2;
val it = [..] |- a = c : thm
See also
Thm.EQ_MP, Drule.IMP_TRANS,
Thm.REFL, Thm.SYM
ALL_THEN
ALL_THEN
Thm_cont.ALL_THEN : thm_tactical
Passes a theorem unchanged to a theorem-tactic.
For any theorem-tactic ttac and theorem th, the application
ALL_THEN ttac th results simply in ttac th, that is, the theorem is
passed unchanged to the theorem-tactic. ALL_THEN is the identity
theorem-tactical.
Failure
The application of ALL_THEN to a theorem-tactic never fails. The
resulting theorem-tactic fails under exactly the same conditions as the
original one.
Writing compound tactics or tacticals, e.g. terminating list iterations of theorem-tacticals.
See also
Tactical.ALL_TAC,
Tactical.FAIL_TAC,
Tactical.NO_TAC,
Thm_cont.NO_THEN,
Thm_cont.THEN_TCL,
Thm_cont.ORELSE_TCL
ANTE_RES_THEN
ANTE_RES_THEN
Thm_cont.ANTE_RES_THEN : thm_tactical
Resolves implicative assumptions with an antecedent.
Given a theorem-tactic ttac and a theorem A |- t, the function
ANTE_RES_THEN produces a tactic that attempts to match t to the
antecedent of each implication
Ai |- !x1...xn. ui ==> vi
(where Ai is just !x1...xn. ui ==> vi) that occurs among the
assumptions of a goal. If the antecedent ui of any implication matches
t, then an instance of Ai u A |- vi is obtained by specialization of
the variables x1, ..., xn and type instantiation, followed by an
application of modus ponens. Because all implicative assumptions are
tried, this may result in several modus-ponens consequences of the
supplied theorem and the assumptions. Tactics are produced using ttac
from all these theorems, and these tactics are applied in sequence to
the goal. That is,
ANTE_RES_THEN ttac (A |- t) g
has the effect of:
MAP_EVERY ttac [A1 u A |- v1, ..., Am u A |- vm] g
where the theorems Ai u A |- vi are all the consequences that can be
drawn by a (single) matching modus-ponens inference from the
implications that occur among the assumptions of the goal g and the
supplied theorem A |- t. Any negation ~v that appears among the
assumptions of the goal is treated as an implication v ==> F. The
sequence in which the theorems Ai u A |- vi are generated and the
corresponding tactics applied is unspecified.
Failure
ANTE_RES_THEN ttac (A |- t) fails when applied to a goal g if any of
the tactics produced by ttac (Ai u A |- vi), where Ai u A |- vi is
the ith resolvent obtained from the theorem A |- t and the
assumptions of g, fails when applied in sequence to g.
Painfully detailed proof hacking.
See also
Tactic.IMP_RES_TAC,
Thm_cont.IMP_RES_THEN,
Drule.MATCH_MP,
Tactic.RES_TAC,
Thm_cont.RES_THEN
CASES_THENL
CASES_THENL
Thm_cont.CASES_THENL : (thm_tactic list -> thm_tactic)
Applies the theorem-tactics in a list to corresponding disjuncts in a theorem.
When given a list of theorem-tactics [ttac1;...;ttacn] and a theorem
whose conclusion is a top-level disjunction of n terms, CASES_THENL
splits a goal into n subgoals resulting from applying to the original
goal the result of applying the i'th theorem-tactic to the i'th
disjunct. This can be represented as follows, where the number of
existentially quantified variables in a disjunct may be zero. If the
theorem th has the form:
A' |- ?x11..x1m. t1 \/ ... \/ ?xn1..xnp. tn
where the number of existential quantifiers may be zero, and for all i
from 1 to n:
A ?- s
========== ttaci (|- ti[xi1'/xi1]..[xim'/xim])
Ai ?- si
where the primed variables have the same type as their unprimed counterparts, then:
A ?- s
========================= CASES_THENL [ttac1;...;ttacn] th
A1 ?- s1 ... An ?- sn
Unless A' is a subset of A, this is an invalid tactic.
Failure
Fails if the given theorem does not, at the top level, have the same number of (possibly multiply existentially quantified) disjuncts as the length of the theorem-tactic list (this includes the case where the theorem-tactic list is empty), or if any of the tactics generated as specified above fail when applied to the goal.
Performing very general disjunctive case splits.
See also
Thm_cont.DISJ_CASES_THENL,
Thm_cont.X_CASES_THENL
CHOOSE_THEN
CHOOSE_THEN
Thm_cont.CHOOSE_THEN : thm_tactical
Applies a tactic generated from the body of existentially quantified theorem.
When applied to a theorem-tactic ttac, an existentially quantified
theorem A' |- ?x. t, and a goal, CHOOSE_THEN applies the tactic
ttac (t[x'/x] |- t[x'/x]) to the goal, where x' is a variant of x
chosen not to be free in the assumption list of the goal. Thus if:
A ?- s1
========= ttac (t[x'/x] |- t[x'/x])
B ?- s2
then
A ?- s1
========== CHOOSE_THEN ttac (A' |- ?x. t)
B ?- s2
This is invalid unless A' is a subset of A.
Failure
Fails unless the given theorem is existentially quantified, or if the resulting tactic fails when applied to the goal.
Example
This theorem-tactical and its relatives are very useful for using existentially quantified theorems. For example one might use the inbuilt theorem
LESS_ADD_1 = |- !m n. n < m ==> (?p. m = n + (p + 1))
to help solve the goal
?- x < y ==> 0 < y * y
by starting with the following tactic
DISCH_THEN (CHOOSE_THEN SUBST1_TAC o MATCH_MP LESS_ADD_1)
which reduces the goal to
?- 0 < ((x + (p + 1)) * (x + (p + 1)))
which can then be finished off quite easily, by, for example:
REWRITE_TAC[ADD_ASSOC, SYM (SPEC_ALL ADD1),
MULT_CLAUSES, ADD_CLAUSES, LESS_0]
Comments
As CHOOSE_THEN scans a theorem’s hypotheses as it generates a fresh name to replace the existential, and then internally produces a fresh theorem with an additional hypothesis, this function can be inefficient if used repeatedly within code; in such cases, code should probably use X_CHOOSE_THEN instead.
See also
Tactic.CHOOSE_TAC,
Thm_cont.X_CHOOSE_THEN
CONJUNCTS_THEN
CONJUNCTS_THEN
Thm_cont.CONJUNCTS_THEN : thm_tactical
Applies a theorem-tactic to each conjunct of a theorem.
CONJUNCTS_THEN takes a theorem-tactic f, and a theorem t whose
conclusion must be a conjunction. CONJUNCTS_THEN breaks t into two
new theorems, t1 and t2 which are CONJUNCT1 and CONJUNCT2 of t
respectively, and then returns a new tactic: f t1 THEN f t2. That is,
CONJUNCTS_THEN f (A |- l /\ r) = f (A |- l) THEN f (A |- r)
so if
A1 ?- t1 A2 ?- t2
========== f (A |- l) ========== f (A |- r)
A2 ?- t2 A3 ?- t3
then
A1 ?- t1
========== CONJUNCTS_THEN f (A |- l /\ r)
A3 ?- t3
Failure
CONJUNCTS_THEN f will fail if applied to a theorem whose conclusion is
not a conjunction.
Comments
CONJUNCTS_THEN f (A |- u1 /\ ... /\ un) results in the tactic:
f (A |- u1) THEN f (A |- u2 /\ ... /\ un)
Unfortunately, it is more likely that the user had wanted the tactic:
f (A |- u1) THEN ... THEN f(A |- un)
Such a tactic could be defined as follows:
fun CONJUNCTS_THENL (f:thm_tactic) thm =
List.foldl (op THEN) ALL_TAC (map f (CONJUNCTS thm));
or by using REPEAT_TCL.
See also
Thm.CONJUNCT1, Thm.CONJUNCT2,
Drule.CONJUNCTS,
Tactic.CONJ_TAC,
Thm_cont.CONJUNCTS_THEN2,
Thm_cont.STRIP_THM_THEN
CONJUNCTS_THEN2
CONJUNCTS_THEN2
Thm_cont.CONJUNCTS_THEN2 : (thm_tactic -> thm_tactical)
Applies two theorem-tactics to the corresponding conjuncts of a theorem.
CONJUNCTS_THEN2 takes two theorem-tactics, f1 and f2, and a
theorem t whose conclusion must be a conjunction. CONJUNCTS_THEN2
breaks t into two new theorems, t1 and t2 which are CONJUNCT1
and CONJUNCT2 of t respectively, and then returns the tactic
f1 t1 THEN f2 t2. Thus
CONJUNCTS_THEN2 f1 f2 (A |- l /\ r) = f1 (A |- l) THEN f2 (A |- r)
so if
A1 ?- t1 A2 ?- t2
========== f1 (A |- l) ========== f2 (A |- r)
A2 ?- t2 A3 ?- t3
then
A1 ?- t1
========== CONJUNCTS_THEN2 f1 f2 (A |- l /\ r)
A3 ?- t3
Failure
CONJUNCTS_THEN f will fail if applied to a theorem whose conclusion is
not a conjunction.
Comments
The system shows the type as (thm_tactic -> thm_tactical).
The construction of complex tacticals like CONJUNCTS_THEN.
See also
Thm.CONJUNCT1, Thm.CONJUNCT2,
Drule.CONJUNCTS,
Tactic.CONJ_TAC,
Thm_cont.CONJUNCTS_THEN2,
Thm_cont.STRIP_THM_THEN
DISCH_THEN
DISCH_THEN
Thm_cont.DISCH_THEN : (thm_tactic -> tactic)
Undischarges an antecedent of an implication and passes it to a theorem-tactic.
DISCH_THEN removes the antecedent and then creates a theorem by
ASSUMEing it. This new theorem is passed to the theorem-tactic given
as DISCH_THEN's argument. The consequent tactic is then applied. Thus:
DISCH_THEN f (asl, t1 ==> t2) = f(ASSUME t1) (asl,t2)
For example, if
A ?- t
======== f (ASSUME u)
B ?- v
then
A ?- u ==> t
============== DISCH_THEN f
B ?- v
Note that DISCH_THEN treats ~u as u ==> F.
Failure
DISCH_THEN will fail for goals which are not implications or
negations.
Example
The following shows how DISCH_THEN can be used to preprocess an
antecedent before adding it to the assumptions.
A ?- (x = y) ==> t
==================== DISCH_THEN (ASSUME_TAC o SYM)
A u {y = x} ?- t
In many cases, it is possible to use an antecedent and then throw it away:
A ?- (x = y) ==> t x
====================== DISCH_THEN (\th. PURE_REWRITE_TAC [th])
A ?- t y
See also
Thm.DISCH, Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Drule.NEG_DISCH,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
DISJ_CASES_THEN
DISJ_CASES_THEN
Thm_cont.DISJ_CASES_THEN : thm_tactical
Applies a theorem-tactic to each disjunct of a disjunctive theorem.
If the theorem-tactic f:thm->tactic applied to either ASSUMEd
disjunct produces results as follows when applied to a goal (A ?- t):
A ?- t A ?- t
========= f (u |- u) and ========= f (v |- v)
A ?- t1 A ?- t2
then applying DISJ_CASES_THEN f (|- u \/ v) to the goal (A ?- t)
produces two subgoals.
A ?- t
====================== DISJ_CASES_THEN f (|- u \/ v)
A ?- t1 A ?- t2
Failure
Fails if the theorem is not a disjunction. An invalid tactic is produced if the theorem has any hypothesis which is not alpha-convertible to an assumption of the goal.
Example
Given the theorem
th = |- (m = 0) \/ (?n. m = SUC n)
and a goal of the form ?- (PRE m = m) = (m = 0), applying the tactic
DISJ_CASES_THEN ASSUME_TAC th
produces two subgoals, each with one disjunct as an added assumption:
?n. m = SUC n ?- (PRE m = m) = (m = 0)
m = 0 ?- (PRE m = m) = (m = 0)
Building cases tactics. For example, DISJ_CASES_TAC could be defined
by:
val DISJ_CASES_TAC = DISJ_CASES_THEN ASSUME_TAC
Comments
Use DISJ_CASES_THEN2 to apply different tactic generating functions to
each case.
See also
Thm_cont.CHOOSE_THEN,
Thm_cont.CONJUNCTS_THEN,
Thm_cont.CONJUNCTS_THEN2,
Thm.DISJ_CASES,
Tactic.DISJ_CASES_TAC,
Thm_cont.DISJ_CASES_THEN2,
Thm_cont.DISJ_CASES_THENL,
Thm_cont.STRIP_THM_THEN
DISJ_CASES_THEN2
DISJ_CASES_THEN2
Thm_cont.DISJ_CASES_THEN2 : (thm_tactic -> thm_tactical)
Applies separate theorem-tactics to the two disjuncts of a theorem.
If the theorem-tactics f1 and f2, applied to the ASSUMEd left and
right disjunct of a theorem |- u \/ v respectively, produce results as
follows when applied to a goal (A ?- t):
A ?- t A ?- t
========= f1 (u |- u) and ========= f2 (v |- v)
A ?- t1 A ?- t2
then applying DISJ_CASES_THEN2 f1 f2 (|- u \/ v) to the goal
(A ?- t) produces two subgoals.
A ?- t
====================== DISJ_CASES_THEN2 f1 f2 (|- u \/ v)
A ?- t1 A ?- t2
Failure
Fails if the theorem is not a disjunction. An invalid tactic is produced if the theorem has any hypothesis which is not alpha-convertible to an assumption of the goal.
Example
Given the theorem
th = |- (m = 0) \/ (?n. m = SUC n)
and a goal of the form ?- (PRE m = m) = (m = 0), applying the tactic
DISJ_CASES_THEN2 SUBST1_TAC ASSUME_TAC th
to the goal will produce two subgoals
?n. m = SUC n ?- (PRE m = m) = (m = 0)
?- (PRE 0 = 0) = (0 = 0)
The first subgoal has had the disjunct m = 0 used for a substitution,
and the second has added the disjunct to the assumption list.
Alternatively, applying the tactic
DISJ_CASES_THEN2 SUBST1_TAC (CHOOSE_THEN SUBST1_TAC) th
to the goal produces the subgoals:
?- (PRE(SUC n) = SUC n) = (SUC n = 0)
?- (PRE 0 = 0) = (0 = 0)
Building cases tacticals. For example, DISJ_CASES_THEN could be
defined by:
let DISJ_CASES_THEN f = DISJ_CASES_THEN2 f f
See also
Thm_cont.STRIP_THM_THEN,
Thm_cont.CHOOSE_THEN,
Thm_cont.CONJUNCTS_THEN,
Thm_cont.CONJUNCTS_THEN2,
Thm_cont.DISJ_CASES_THEN,
Thm_cont.DISJ_CASES_THENL
DISJ_CASES_THENL
DISJ_CASES_THENL
Thm_cont.DISJ_CASES_THENL : (thm_tactic list -> thm_tactic)
Applies theorem-tactics in a list to the corresponding disjuncts in a theorem.
If the theorem-tactics f1...fn applied to the ASSUMEd disjuncts of a
theorem
|- d1 \/ d2 \/...\/ dn
produce results as follows when applied to a goal (A ?- t):
A ?- t A ?- t
========= f1 (d1 |- d1) and ... and ========= fn (dn |- dn)
A ?- t1 A ?- tn
then applying DISJ_CASES_THENL [f1;...;fn] (|- d1 \/...\/ dn) to the
goal (A ?- t) produces n subgoals.
A ?- t
======================= DISJ_CASES_THENL [f1;...;fn] (|- d1 \/...\/ dn)
A ?- t1 ... A ?- tn
DISJ_CASES_THENL is defined using iteration, hence for theorems with
more than n disjuncts, dn would itself be disjunctive.
Failure
Fails if the number of tactic generating functions in the list exceeds the number of disjuncts in the theorem. An invalid tactic is produced if the theorem has any hypothesis which is not alpha-convertible to an assumption of the goal.
Used when the goal is to be split into several cases, where a different tactic-generating function is to be applied to each case.
See also
Thm_cont.CHOOSE_THEN,
Thm_cont.CONJUNCTS_THEN,
Thm_cont.CONJUNCTS_THEN2,
Thm_cont.DISJ_CASES_THEN,
Thm_cont.DISJ_CASES_THEN2,
Thm_cont.STRIP_THM_THEN
EVERY_TCL
EVERY_TCL
Thm_cont.EVERY_TCL : (thm_tactical list -> thm_tactical)
Composes a list of theorem-tacticals.
When given a list of theorem-tacticals and a theorem, EVERY_TCL simply
composes their effects on the theorem. The effect is:
EVERY_TCL [ttl1;...;ttln] = ttl1 THEN_TCL ... THEN_TCL ttln
In other words, if:
ttl1 ttac th1 = ttac th2 ... ttln ttac thn = ttac thn'
then:
EVERY_TCL [ttl1;...;ttln] ttac th1 = ttac thn'
If the theorem-tactical list is empty, the resulting theorem-tactical
behaves in the same way as ALL_THEN, the identity theorem-tactical.
Failure
The application to a list of theorem-tacticals never fails.
See also
Thm_cont.FIRST_TCL,
Thm_cont.ORELSE_TCL,
Thm_cont.REPEAT_TCL,
Thm_cont.THEN_TCL
FIRST_TCL
FIRST_TCL
Thm_cont.FIRST_TCL : (thm_tactical list -> thm_tactical)
Applies the first theorem-tactical in a list which succeeds.
When applied to a list of theorem-tacticals, a theorem-tactic and a
theorem, FIRST_TCL returns the tactic resulting from the application
of the first theorem-tactical to the theorem-tactic and theorem which
succeeds. The effect is the same as:
FIRST_TCL [ttl1;...;ttln] = ttl1 ORELSE_TCL ... ORELSE_TCL ttln
Failure
FIRST_TCL fails iff each tactic in the list fails when applied to the
theorem-tactic and theorem. This is trivially the case if the list is
empty.
See also
Thm_cont.EVERY_TCL,
Thm_cont.ORELSE_TCL,
Thm_cont.REPEAT_TCL,
Thm_cont.THEN_TCL
IMP_RES_THEN
IMP_RES_THEN
Thm_cont.IMP_RES_THEN : thm_tactical
Resolves an implication with the assumptions of a goal.
The function IMP_RES_THEN is the basic building block for resolution
in HOL. This is not full higher-order, or even first-order, resolution
with unification, but simply one way simultaneous pattern-matching
(resulting in term and type instantiation) of the antecedent of an
implicative theorem to the conclusion of another theorem (the candidate
antecedent).
Given a theorem-tactic ttac and a theorem th, the theorem-tactical
IMP_RES_THEN uses RES_CANON to derive a canonical list of
implications from th, each of which has the form:
Ai |- !x1...xn. ui ==> vi
IMP_RES_THEN then produces a tactic that, when applied to a goal
A ?- g attempts to match each antecedent ui to each assumption
aj |- aj in the assumptions A. If the antecedent ui of any
implication matches the conclusion aj of any assumption, then an
instance of the theorem Ai u {aj} |- vi, called a 'resolvent', is
obtained by specialization of the variables x1, ..., xn and type
instantiation, followed by an application of modus ponens. There may be
more than one canonical implication and each implication is tried
against every assumption of the goal, so there may be several resolvents
(or, indeed, none).
Tactics are produced using the theorem-tactic ttac from all these
resolvents (failures of ttac at this stage are filtered out) and these
tactics are then applied in an unspecified sequence to the goal. That
is,
IMP_RES_THEN ttac th (A ?- g)
has the effect of:
MAP_EVERY (mapfilter ttac [... , (Ai u {aj} |- vi) , ...]) (A ?- g)
where the theorems Ai u {aj} |- vi are all the consequences that can
be drawn by a (single) matching modus-ponens inference from the
assumptions of the goal A ?- g and the implications derived from the
supplied theorem th. The sequence in which the theorems
Ai u {aj} |- vi are generated and the corresponding tactics applied is
unspecified.
Failure
Evaluating IMP_RES_THEN ttac th fails if the supplied theorem th is
not an implication, or if no implications can be derived from th by
the transformation process described under the entry for RES_CANON.
Evaluating IMP_RES_THEN ttac th (A ?- g) fails if no assumption of the
goal A ?- g can be resolved with the implication or implications
derived from th. Evaluation also fails if there are resolvents, but
for every resolvent Ai u {aj} |- vi evaluating the application
ttac (Ai u {aj} |- vi) fails---that is, if for every resolvent ttac
fails to produce a tactic. Finally, failure is propagated if any of the
tactics that are produced from the resolvents by ttac fails when
applied in sequence to the goal.
Example
The following example shows a straightforward use of IMP_RES_THEN to
infer an equational consequence of the assumptions of a goal, use it
once as a substitution in the conclusion of goal, and then 'throw it
away'. Suppose the goal is:
a + n = a ?- !k. k - n = k
By the built-in theorem:
ADD_INV_0 = |- !m n. (m + n = m) ==> (n = 0)
the assumption of this goal implies that n equals 0. A single-step
resolution with this theorem followed by substitution:
IMP_RES_THEN SUBST1_TAC ADD_INV_0
can therefore be used to reduce the goal to:
a + n = a ?- !k. k - 0 = m
Here, a single resolvent a + n = a |- n = 0 is obtained by matching
the antecedent of ADD_INV_0 to the assumption of the goal. This is
then used to substitute 0 for n in the conclusion of the goal.
See also
Tactic.IMP_RES_TAC,
Drule.MATCH_MP,
Drule.RES_CANON,
Tactic.RES_TAC,
Thm_cont.RES_THEN
NO_THEN
NO_THEN
Thm_cont.NO_THEN : thm_tactical
Theorem-tactical which always fails.
When applied to a theorem-tactic and a theorem, the theorem-tactical
NO_THEN always fails with string `NO_THEN`.
Failure
Always fails when applied to a theorem-tactic and a theorem (note that it never gets as far as being applied to a goal!)
Writing compound tactics or tacticals.
See also
Tactical.ALL_TAC,
Thm_cont.ALL_THEN,
Tactical.FAIL_TAC,
Tactical.NO_TAC
ORELSE_TCL
ORELSE_TCL
Thm_cont.ORELSE_TCL : (thm_tactical * thm_tactical -> thm_tactical)
Applies a theorem-tactical, and if it fails, tries a second.
When applied to two theorem-tacticals, ttl1 and ttl2, a
theorem-tactic ttac, and a theorem th, if ttl1 ttac th succeeds,
that gives the result. If it fails, the result is ttl2 ttac th, which
may itself fail.
Failure
ORELSE_TCL fails if both the theorem-tacticals fail when applied to
the given theorem-tactic and theorem.
See also
Thm_cont.EVERY_TCL,
Thm_cont.FIRST_TCL,
Thm_cont.THEN_TCL
PROVEHYP_THEN
PROVEHYP_THEN
Thm_cont.PROVEHYP_THEN : (thm -> thm -> tactic) -> thm -> tactic
Makes antecedent of theorem as subgoal, continues with both parts as theorems.
An application of the tactic PROVEHYP_THEN th2tac th to a goal g
requires that th be an (universally quantified) implication (or a
negation, in which case ~p is treated as p ==> F). Given an
implication |- !x1..xn. l ==> r x1..xn, the result is a new sub-goal
requiring the user to prove l, and the application of th2tac to the
theorems with conclusion l and !x1..xn. r x1..xn.
Diagrammatically, one might see this as
A ?- g
============================================== PROVEHYP_THEN th2tac th
A ?- l ... th2tac (A |- l) (A |- r) (A ?- g)
Failure
Fails if the theorem argument is not an implication or negation.
Example
> FIRST_X_ASSUM (PROVEHYP_THEN (K MP_TAC)) ([“p”, “p ==> q”], “r”)
val it = ([([“p”], “p”), ([“p”], “q ==> r”)], fn):
goal list * validation
The use of FIRST_X_ASSUM pulls out the first implicational theorem,
and gives the user the requirement to prove p as a subgoal. In the
other subgoal, q has become a new antecedent in the goal (thanks to
the action of MP_TAC).
Comments
This function is also available under the name provehyp_then.
See also
Tactic.impl_keep_tac,
Tactic.impl_tac
REPEAT_GTCL
REPEAT_GTCL
Thm_cont.REPEAT_GTCL : (thm_tactical -> thm_tactical)
Applies a theorem-tactical until it fails when applied to a goal.
When applied to a theorem-tactical, a theorem-tactic, a theorem and a goal:
REPEAT_GTCL ttl ttac th goal
REPEAT_GTCL repeatedly modifies the theorem according to ttl till
the result of handing it to ttac and applying it to the goal fails
(this may be no times at all).
Failure
Fails iff the theorem-tactic fails immediately when applied to the theorem and the goal.
Example
The following tactic matches th's antecedents against the assumptions
of the goal until it can do so no longer, then puts the resolvents onto
the assumption list:
REPEAT_GTCL (IMP_RES_THEN ASSUME_TAC) th
See also
Thm_cont.REPEAT_TCL,
Thm_cont.THEN_TCL
REPEAT_TCL
REPEAT_TCL
Thm_cont.REPEAT_TCL : (thm_tactical -> thm_tactical)
Repeatedly applies a theorem-tactical until it fails when applied to the theorem.
When applied to a theorem-tactical, a theorem-tactic and a theorem:
REPEAT_TCL ttl ttac th
REPEAT_TCL repeatedly modifies the theorem according to ttl until it
fails when given to the theorem-tactic ttac.
Failure
Fails iff the theorem-tactic fails immediately when applied to the theorem.
Example
It is often desirable to repeat the action of basic theorem-tactics. For
example CHOOSE_THEN strips off a single existential quantification, so
one might use REPEAT_TCL CHOOSE_THEN to get rid of them all.
Alternatively, one might want to repeatedly break apart a theorem which is a nested conjunction and apply the same theorem-tactic to each conjunct. For example the following goal:
?- ((0 = w) /\ (0 = x)) /\ (0 = y) /\ (0 = z) ==> (w + x + y + z = 0)
might be solved by
DISCH_THEN (REPEAT_TCL CONJUNCTS_THEN (SUBST1_TAC o SYM)) THEN
REWRITE_TAC[ADD_CLAUSES]
See also
Thm_cont.REPEAT_GTCL,
Thm_cont.THEN_TCL
RES_THEN
RES_THEN
Thm_cont.RES_THEN : (thm_tactic -> tactic)
Resolves all implicative assumptions against the rest.
Like the basic resolution function IMP_RES_THEN, the resolution tactic
RES_THEN performs a single-step resolution of an implication and the
assumptions of a goal. RES_THEN differs from IMP_RES_THEN only in
that the implications used for resolution are taken from the assumptions
of the goal itself, rather than supplied as an argument.
When applied to a goal A ?- g, the tactic RES_THEN ttac uses
RES_CANON to obtain a set of implicative theorems in canonical form
from the assumptions A of the goal. Each of the resulting theorems (if
there are any) will have the form:
ai |- !x1...xn. ui ==> vi
where ai is one of the assumptions of the goal. Having obtained these
implications, RES_THEN then attempts to match each antecedent ui to
each assumption aj |- aj in the assumptions A. If the antecedent
ui of any implication matches the conclusion aj of any assumption,
then an instance of the theorem ai, aj |- vi, called a 'resolvent', is
obtained by specialization of the variables x1, ..., xn and type
instantiation, followed by an application of modus ponens. There may be
more than one canonical implication derivable from the assumptions of
the goal and each such implication is tried against every assumption, so
there may be several resolvents (or, indeed, none).
Tactics are produced using the theorem-tactic ttac from all these
resolvents (failures of ttac at this stage are filtered out) and these
tactics are then applied in an unspecified sequence to the goal. That
is,
RES_THEN ttac (A ?- g)
has the effect of:
MAP_EVERY (mapfilter ttac [... ; (ai,aj |- vi) ; ...]) (A ?- g)
where the theorems ai,aj |- vi are all the consequences that can be
drawn by a (single) matching modus-ponens inference from the assumptions
A and the implications derived using RES_CANON from the assumptions.
The sequence in which the theorems ai,aj |- vi are generated and the
corresponding tactics applied is unspecified.
Failure
Evaluating RES_THEN ttac th fails with 'no implication' if no
implication(s) can be derived from the assumptions of the goal by the
transformation process described under the entry for RES_CANON.
Evaluating RES_THEN ttac (A ?- g) fails with 'no resolvents' if no
assumption of the goal A ?- g can be resolved with the derived
implication or implications. Evaluation also fails, with 'no tactics',
if there are resolvents, but for every resolvent ai,aj |- vi
evaluating the application ttac (ai,aj |- vi) fails---that is, if for
every resolvent ttac fails to produce a tactic. Finally, failure is
propagated if any of the tactics that are produced from the resolvents
by ttac fails when applied in sequence to the goal.
See also
Tactic.IMP_RES_TAC,
Thm_cont.IMP_RES_THEN,
Drule.MATCH_MP,
Drule.RES_CANON,
Tactic.RES_TAC
STRIP_ALL_THEN
STRIP_ALL_THEN
Thm_cont.STRIP_ALL_THEN : thm_tactical
Splits a theorem into a list of theorems and then calls the resulting theorem tactic on it.
Given a theorem th STRIP_ALL_THEN ttac th splits th into a list of
theorems and then applies the ttac on the resulting theorems. This is
done by recursively applying STRIP_THM_THEN and then calling the ttac
if the theorem can't be split anymore.
Failure
STRIP_ALL_THEN ttac th fails if the any application of ttac fails,
which is applied with the stripped theorems from th.
Comments
STRIP_ALL_THEN behaves exactly like REPEAT_TCL STRIP_THM_THEN but is
faster.
See also
Thm_cont.REPEAT_TCL,
Thm_cont.STRIP_ALL_THEN,
Tactic.STRIP_ASSUME_TAC
STRIP_THM_THEN
STRIP_THM_THEN
Thm_cont.STRIP_THM_THEN : thm_tactical
STRIP_THM_THEN applies the given theorem-tactic using the result of
stripping off one outer connective from the given theorem.
Given a theorem-tactic ttac, a theorem th whose conclusion is a
conjunction, a disjunction or an existentially quantified term, and a
goal (A,t), STRIP_THM_THEN ttac th first strips apart the conclusion
of th, next applies ttac to the theorem(s) resulting from the
stripping and then applies the resulting tactic to the goal.
In particular, when stripping a conjunctive theorem A'|- u /\ v, the
tactic
ttac(u|-u) THEN ttac(v|-v)
resulting from applying ttac to the conjuncts, is applied to the goal.
When stripping a disjunctive theorem A'|- u \/ v, the tactics
resulting from applying ttac to the disjuncts, are applied to split
the goal into two cases. That is, if
A ?- t A ?- t
========= ttac (u|-u) and ========= ttac (v|-v)
A ?- t1 A ?- t2
then:
A ?- t
================== STRIP_THM_THEN ttac (A'|- u \/ v)
A ?- t1 A ?- t2
When stripping an existentially quantified theorem A'|- ?x.u, the
tactic ttac(u|-u), resulting from applying ttac to the body of the
existential quantification, is applied to the goal. That is, if:
A ?- t
========= ttac (u|-u)
A ?- t1
then:
A ?- t
============= STRIP_THM_THEN ttac (A'|- ?x. u)
A ?- t1
The assumptions of the theorem being split are not added to the
assumptions of the goal(s) but are recorded in the proof. If A' is not
a subset of the assumptions A of the goal (up to alpha-conversion),
STRIP_THM_THEN ttac th results in an invalid tactic.
Failure
STRIP_THM_THEN ttac th fails if the conclusion of th is not a
conjunction, a disjunction or an existentially quantified term. Failure
also occurs if the application of ttac fails, after stripping the
outer connective from the conclusion of th.
STRIP_THM_THEN is used enrich the assumptions of a goal with a
stripped version of a previously-proved theorem.
See also
Thm_cont.CHOOSE_THEN,
Thm_cont.CONJUNCTS_THEN,
Thm_cont.DISJ_CASES_THEN,
Tactic.STRIP_ASSUME_TAC
THEN_TCL
THEN_TCL
Thm_cont.THEN_TCL : (thm_tactical * thm_tactical -> thm_tactical)
Composes two theorem-tacticals.
If ttl1 and ttl2 are two theorem-tacticals, ttl1 THEN_TCL ttl2 is
a theorem-tactical which composes their effect; that is, if:
ttl1 ttac th1 = ttac th2
and
ttl2 ttac th2 = ttac th3
then
(ttl1 THEN_TCL ttl2) ttac th1 = ttac th3
Failure
The application of THEN_TCL to a pair of theorem-tacticals never
fails.
See also
Thm_cont.EVERY_TCL,
Thm_cont.FIRST_TCL,
Thm_cont.ORELSE_TCL
UNDISCH_THEN
UNDISCH_THEN
Thm_cont.UNDISCH_THEN : term -> thm_tactic -> tactic
Discharges the assumption given and passes it to a theorem-tactic.
UNDISCH_THEN finds the first assumption equal to the term given,
removes it from the assumption list, ASSUMEs it, passes it to the
theorem-tactic and then applies the consequent tactic. Thus:
UNDISCH_THEN t f ([a1,... ai, t, aj, ... an], goal) =
f (ASSUME t) ([a1,... ai, aj,... an], goal)
For example, if
A ?- t
======== f (ASSUME t1)
B ?- v
then
A u {t1} ?- t
=============== UNDISCH_THEN t1 f
B ?- v
Failure
UNDISCH_THEN will fail on goals where the given term is not in the
assumption list.
See also
Tactical.PRED_ASSUM,
Tactical.PAT_ASSUM, Thm.DISCH,
Drule.DISCH_ALL,
Tactic.DISCH_TAC,
Thm_cont.DISCH_THEN,
Drule.NEG_DISCH,
Tactic.FILTER_DISCH_TAC,
Tactic.FILTER_DISCH_THEN,
Tactic.STRIP_TAC,
Drule.UNDISCH,
Drule.UNDISCH_ALL,
Tactic.UNDISCH_TAC
X_CASES_THEN
X_CASES_THEN
Thm_cont.X_CASES_THEN : term list list -> thm_tactical
Applies a theorem-tactic to all disjuncts of a theorem, choosing witnesses.
Let [yl1,...,yln] represent a list of variable lists, each of length
zero or more, and xl1,...,xln each represent a vector of zero or more
variables, so that the variables in each of yl1...yln have the same
types as the corresponding xli. X_CASES_THEN expects such a list of
variable lists, [yl1,...,yln], a tactic generating function
f:thm->tactic, and a disjunctive theorem, where each disjunct may be
existentially quantified:
th = |-(?xl1.B1) \/...\/ (?xln.Bn)
each disjunct having the form (?xi1 ... xim. Bi). If applying f to
the theorem obtained by introducing witness variables yli for the
objects xli whose existence is asserted by each disjunct, typically
({Bi[yli/xli]} |- Bi[yli/xli]), produce the following results when
applied to a goal (A ?- t):
A ?- t
========= f ({B1[yl1/xl1]} |- B1[yl1/xl1])
A ?- t1
...
A ?- t
========= f ({Bn[yln/xln]} |- Bn[yln/xln])
A ?- tn
then applying (X_CHOOSE_THEN [yl1,...,yln] f th) to the goal
(A ?- t) produces n subgoals.
A ?- t
======================= X_CHOOSE_THEN [yl1,...,yln] f th
A ?- t1 ... A ?- tn
Failure
Fails (with X_CHOOSE_THEN) if any yli has more variables than the
corresponding xli, or (with SUBST) if corresponding variables have
different types. Failures may arise in the tactic-generating function.
An invalid tactic is produced if any variable in any of the yli is
free in the corresponding Bi or in t, or if the theorem has any
hypothesis which is not alpha-convertible to an assumption of the goal.
Example
Given the goal ?- (x MOD 2) <= 1, the following theorem may be used to
split into 2 cases:
th = |- (?m. x = 2 * m) \/ (?m. x = (2 * m) + 1)
by the tactic
X_CASES_THEN [[Term`n:num`],[Term`n:num]] ASSUME_TAC th
to produce the subgoals:
{x = (2 * n) + 1} ?- (x MOD 2) <= 1
{x = 2 * n} ?- (x MOD 2) <= 1
See also
Thm_cont.DISJ_CASES_THENL,
Thm_cont.X_CASES_THENL,
Thm_cont.X_CHOOSE_THEN
X_CASES_THENL
X_CASES_THENL
Thm_cont.X_CASES_THENL : term list list -> thm_tactic list -> thm_tactic
Applies theorem-tactics to corresponding disjuncts of a theorem, choosing witnesses.
Let [yl1,...,yln] represent a list of variable lists, each of length
zero or more, and xl1,...,xln each represent a vector of zero or more
variables, so that the variables in each of yl1...yln have the same
types as the corresponding xli. The function X_CASES_THENL expects a
list of variable lists, [yl1,...,yln], a list of tactic-generating
functions [f1,...,fn]:(thm->tactic)list, and a disjunctive theorem,
where each disjunct may be existentially quantified:
th = |-(?xl1.B1) \/...\/ (?xln.Bn)
each disjunct having the form (?xi1 ... xim. Bi). If applying each
fi to the theorem obtained by introducing witness variables yli for
the objects xli whose existence is asserted by the ith disjunct,
({Bi[yli/xli]} |- Bi[yli/xli]), produces the following results when
applied to a goal (A ?- t):
A ?- t
========= f1 ({B1[yl1/xl1]} |- B1[yl1/xl1])
A ?- t1
...
A ?- t
========= fn ({Bn[yln/xln]} |- Bn[yln/xln])
A ?- tn
then applying X_CASES_THENL [yl1,...,yln] [f1,...,fn] th to the goal
(A ?- t) produces n subgoals.
A ?- t
======================= X_CASES_THENL [yl1,...,yln] [f1,...,fn] th
A ?- t1 ... A ?- tn
Failure
Fails (with X_CASES_THENL) if any yli has more variables than the
corresponding xli, or (with SUBST) if corresponding variables have
different types, or (with combine) if the number of theorem tactics
differs from the number of disjuncts. Failures may arise in the
tactic-generating function. An invalid tactic is produced if any
variable in any of the yli is free in the corresponding Bi or in
t, or if the theorem has any hypothesis which is not alpha-convertible
to an assumption of the goal.
Example
Given the goal ?- (x MOD 2) <= 1, the following theorem may be used to
split into 2 cases:
th = |- (?m. x = 2 * m) \/ (?m. x = (2 * m) + 1)
by the tactic
X_CASES_THENL [[Term`n:num`], [Term`n:num`]] [ASSUME_TAC, SUBST1_TAC] th
to produce the subgoals:
?- (((2 * n) + 1) MOD 2) <= 1
{x = 2 * n} ?- (x MOD 2) <= 1
See also
Thm_cont.DISJ_CASES_THEN,
Thm_cont.X_CASES_THEN,
Thm_cont.X_CHOOSE_THEN
X_CHOOSE_THEN
X_CHOOSE_THEN
Thm_cont.X_CHOOSE_THEN : (term -> thm_tactical)
Replaces existentially quantified variable with given witness, and passes it to a theorem-tactic.
X_CHOOSE_THEN expects a variable y, a tactic-generating function
f:thm->tactic, and a theorem of the form (A1 |- ?x. w) as arguments.
A new theorem is created by introducing the given variable y as a
witness for the object x whose existence is asserted in the original
theorem, (w[y/x] |- w[y/x]). If the tactic-generating function f
applied to this theorem produces results as follows when applied to a
goal (A ?- t):
A ?- t
========= f ({w[y/x]} |- w[y/x])
A ?- t1
then applying (X_CHOOSE_THEN “y” f (A1 |- ?x. w)) to the goal
(A ?- t) produces the subgoal:
A ?- t
========= X_CHOOSE_THEN “y” f (A1 |- ?x. w)
A ?- t1 (y not free anywhere)
Failure
Fails if the theorem's conclusion is not existentially quantified, or if
the first argument is not a variable. Failures may arise in the
tactic-generating function. An invalid tactic is produced if the
introduced variable is free in w, t or A, or if the theorem has
any hypothesis which is not alpha-convertible to an assumption of the
goal.
Example
Given a goal of the form
{n < m} ?- ?x. m = n + (x + 1)
the following theorem may be applied:
th = [n < m] |- ?p. m = n + p
by the tactic X_CHOOSE_THEN “q:num” SUBST1_TAC th giving
the subgoal:
{n < m} ?- ?x. n + q = n + (x + 1)
See also
Thm.CHOOSE,
Thm_cont.CHOOSE_THEN,
Thm_cont.CONJUNCTS_THEN,
Thm_cont.CONJUNCTS_THEN2,
Thm_cont.DISJ_CASES_THEN,
Thm_cont.DISJ_CASES_THEN2,
Thm_cont.DISJ_CASES_THENL,
Thm_cont.STRIP_THM_THEN,
Tactic.X_CHOOSE_TAC
define_abbreviation
define_abbreviation
ThmAttribute.define_abbreviation : {
abbrev : string,
expansion : (string * string list) list
} -> unit
Defines an abbreviation expanding to multiple attributes
A call to define_abbreviation{abbrev=a,expansion=e} modifies the
handling of theorem attributes so that when attributes attached to
theorem names are parsed, the string a will be replaced by the
expansion e. If the abbreviation string is accompanied by arguments,
these are silently dropped.
Failure
A call to define_abbreviation{abbrev,expansion} will fail if the
abbrev name is already in use as an attribute or reserved word.
Comments
These abbreviations do not persist; they are meant to be a transient convenience.
See also
ThmAttribute.register_attribute
Define
Define
TotalDefn.Define : term quotation -> thm
Re-exported from bossLib.Define. See that
entry for full documentation.
DefineSchema
DefineSchema
TotalDefn.DefineSchema : term quotation -> thm
Defines a recursion schema.
DefineSchema may be used to declare so-called 'schematic' definitions,
or 'recursion schemas'. These are just recursive functions with extra
free variables (also called 'parameters') on the right-hand side of some
clauses. Such schemas have been used as a basis for program
transformation systems.
DefineSchema takes its input in exactly the same format as Define.
The termination constraints of a schematic definition are collected on the hypotheses of the definition, and also on the hypotheses of the automatically proved induction theorem, but a termination proof is only attempted when the termination conditions have no occurrences of parameters. This is because, in general, termination can only be proved after some of the parameters of the schema have been instantiated.
Failure
DefineSchema fails in many of the same ways as Define. However, it
will not fail if it cannot prove termination.
Example
The following defines a schema for binary recursion.
- DefineSchema
`binRec (x:'a) =
if atomic x then (A x:'b)
else join (binRec (left x))
(binRec (right x))`;
<<HOL message: Definition is schematic in the following variables:
"A", "atomic", "join", "left", "right">>
Equations stored under "binRec_def".
Induction stored under "binRec_ind".
> val it =
[!x. ~atomic x ==> R (left x) x,
!x. ~atomic x ==> R (right x) x, WF R]
|- binRec A atomic join left right x =
if atomic x then A x
else
join (binRec A atomic join left right (left x))
(binRec A atomic join left right (right x)) : thm
The following defines a schema in which a termination proof is attempted successfully.
- DefineSchema `(map [] = []) /\ (map (h::t) = f h :: map t)`;
<<HOL message: inventing new type variable names: 'a, 'b>>
<<HOL message: Definition is schematic in the following variables:
"f">>
Equations stored under "map_def".
Induction stored under "map_ind".
> val it = [] |- (map f [] = []) /\ (map f (h::t) = f h::map f t) : thm
The easy termination proof is attempted because the schematic variable
f doesn't occur in the termination conditions.
Comments
The original recursion equations, in which parameters only occur on right hand sides, is transformed into one in which the parameters become arguments to the function being defined. This is the expected behaviour. If an argument intended as a parameter occurs on the left hand side in the original recursion equations, it becomes universally quantified in the termination conditions, which is not desirable for a schema.
See also
TotalDefn.Define,
Defn.Hol_defn
WF_REL_TAC
WF_REL_TAC
TotalDefn.WF_REL_TAC : term quotation -> tactic
Re-exported from bossLib.WF_REL_TAC. See that
entry for full documentation.
xDefine
xDefine
TotalDefn.xDefine : string -> term quotation -> thm
Re-exported from bossLib.xDefine. See that
entry for full documentation.
-->
-->
op Type.--> : hol_type * hol_type -> hol_type
Right associative infix operator for building a function type.
If ty1 and ty2 are HOL types, then ty1 --> ty2 builds the HOL type
ty1 -> ty2.
Failure
Never fails.
Example
> bool --> alpha;
val it = “:bool -> α”: hol_type
Comments
This operator associates to the right, that is, ty1 --> ty2 --> ty3 is
identical to ty1 --> (ty2 --> ty3).
See also
Type.dom_rng, Type.mk_type,
Type.mk_thy_type
alpha
alpha
Type.alpha : hol_type
Common type variable.
The ML variable Type.alpha is bound to the type variable 'a.
See also
Type.beta, Type.gamma,
Type.delta, Type.bool
beta
beta
Type.beta : hol_type
Common type variable.
The ML variable Type.beta is bound to the type variable 'b.
See also
Type.alpha, Type.gamma,
Type.delta, Type.bool
bool
bool
Type.bool : hol_type
Basic type constant.
The ML variable Type.bool is bound to the type constant bool.
See also
alpha, Type.beta,
Type.gamma, Type.delta
compare
compare
Type.compare : hol_type * hol_type -> order
An ordering on HOL types.
An invocation compare (ty1,ty2) returns one of
{LESS, EQUAL, GREATER}. This is a total and transitive order.
Failure
Never fails.
Example
> Type.compare (bool, alpha --> alpha);
val it = LESS: order
Comments
One use of compare is to build efficient set or dictionary
datastructures involving HOL types in the keys.
There is also a Term.compare.
See also
decls
decls
Type.decls : string -> {Thy : string, Tyop : string} list
Lists all theories a named type operator is declared in.
An invocation Type.decls s finds all theories in the ancestry of the
current theory with a type constant having the given name.
Failure
Never fails.
Example
> Type.decls "prod";
val it = [{Thy = "pair", Tyop = "prod"}]: {Thy: string, Tyop: string} list
Comments
There is also a function Term.decls that performs a similar operation
on term constants.
See also
Theory.ancestry, Term.decls,
Theory.constants
delta
delta
Type.delta : hol_type
Common type variable.
The ML variable Type.delta is bound to the type variable 'd.
See also
Type.alpha, Type.beta,
Type.gamma, Type.bool
dest_thy_type
dest_thy_type
Type.dest_thy_type
: hol_type -> {Thy:string, Tyop:string,
Args:hol_type list}
Breaks apart a type (other than a variable type).
If ty is an application of a type operator Tyop, which was declared
in theory Thy, to a list of types Args, then dest_thy_type ty
returns {Tyop,Thy,Args}.
Failure
Fails if ty is a type variable.
Example
> dest_thy_type “:'a -> bool”;
val it = {Args = [“:α”, “:bool”], Thy = "min", Tyop = "fun"}:
{Args: hol_type list, Thy: string, Tyop: string}
> try dest_thy_type alpha;
Exception- HOL_ERR at Type.dest_thy_type: raised
See also
Type.mk_thy_type,
Type.dest_type, Type.mk_type,
Term.mk_thy_const
dest_type
dest_type
Type.dest_type : hol_type -> string * hol_type list
Breaks apart a non-variable type.
If ty is a type constant, then dest_type ty returns (ty,[]). If
ty is a compound type (ty1,...,tyn)tyop, then dest_type ty returns
(tyop,[ty1,...,tyn]).
Failure
Fails if ty is a type variable.
Example
> dest_type bool;
val it = ("bool", []): string * hol_type list
> dest_type (alpha --> bool);
val it = ("fun", [“:α”, “:bool”]): string * hol_type list
Comments
A more precise alternative is dest_thy_type, which tells which theory
the type operator was declared in.
See also
Type.mk_type,
Type.dest_thy_type,
Type.dest_vartype
dest_vartype
dest_vartype
Type.dest_vartype : hol_type -> string
Breaks a type variable down to its name.
Failure
Fails with dest_vartype if the type is not a type variable.
Example
> dest_vartype alpha;
val it = "'a": string
> try dest_vartype bool;
Exception- HOL_ERR (at Type.dest_vartype: not a type variable) raised
See also
Type.mk_vartype,
Type.is_vartype,
Type.dest_type
dom_rng
dom_rng
Type.dom_rng : hol_type -> hol_type * hol_type
Breaks a function type into domain and range types.
If ty has the form ty1 -> ty2, then dom_rng ty yields (ty1,ty2).
Failure
Fails if ty is not a function type.
Example
> dom_rng (bool --> alpha);
val it = (“:bool”, “:α”): hol_type * hol_type
> try dom_rng bool;
Exception- HOL_ERR (at Type.dom_rng: not a function type) raised
See also
Type.-->, Type.dest_type,
Type.dest_thy_type
etyvar
etyvar
Type.etyvar : hol_type
Common type variable.
The ML variable Type.etyvar is bound to the type variable 'e.
See also
Type.alpha, Type.beta,
Type.gamma, Type.delta,
Type.ftyvar, Type.bool
exists_tyvar
exists_tyvar
Type.exists_tyvar : (hol_type -> bool) -> hol_type -> bool
Checks if a type variable satisfying a given condition exists in a type.
An invocation exists_tyvar P ty searches ty for a type variable
satisfying the predicate P. The value true is returned if the search
is successful; otherwise false is the result.
Failure
If P fails when applied to a type variable encountered in the course
of searching ty.
Example
> exists_tyvar (equal beta) (alpha --> beta --> bool);
val it = true: bool
Comments
This function is more efficient, in some cases, than
exists P o type_vars.
ftyvar
ftyvar
Type.ftyvar : hol_type
Common type variable.
The ML variable Type.ftyvar is bound to the type variable 'f.
See also
Type.alpha, Type.beta,
Type.gamma, Type.delta,
Type.etyvar, Type.bool
gamma
gamma
Type.gamma : hol_type
Common type variable.
The ML variable Type.gamma is bound to the type variable 'c.
See also
Type.alpha, Type.beta,
Type.delta, Type.bool
gen_tyvar
gen_tyvar
Type.gen_tyvar : unit -> hol_type
Generate a fresh type variable.
An invocation gen_tyvar() generates a type variable tyv not seen in
the current session. Furthermore, the concrete syntax of tyv is such
that tyv is not obtainable by mk_vartype, or by parsing.
Failure
Never fails.
Example
> gen_tyvar();
val it = “:%%gen_tyvar%%30”: hol_type
> try Type `:%%gen_tyvar%%1`;
Exception- HOL_ERR
(at Parse.parse_type: on line 1, characters 11-12:
Type parsing failure with remaining input: %%gen_tyvar%%1) raised
> try mk_vartype "%%gen_tyvar%%1";
val it = “:%%gen_tyvar%%1”: hol_type
Comments
In general, the actual name returned by gen_tyvar should not be relied
on.
Useful for coding some proof procedures.
See also
hol_type
hol_type
Type.eqtype hol_type
Type of HOL types.
The ML type hol_type represents the type of HOL types.
Comments
Since hol_type is an ML eqtype, any two hol_types ty1 and ty2
can be tested for equality by ty1 = ty2.
See also
ind
ind
Type.ind : hol_type
Basic type constant.
The ML variable Type.ind is bound to the HOL type constant ind. The
axiom INFINITY_AX in boolTheory states that ind represents an
infinite set of individuals.
See also
is_gen_tyvar
is_gen_tyvar
Type.is_gen_tyvar : hol_type -> bool
Checks if a type variable has been created by gen_tyvar.
Failure
Never fails.
Example
> is_gen_tyvar (gen_tyvar());
val it = true: bool
> is_gen_tyvar bool;
val it = false: bool
See also
is_type
is_type
Type.is_type : hol_type -> bool
Tests whether a HOL type is not a type variable.
is_type ty returns true if ty is an application of a type operator
and false otherwise.
Failure
Never fails.
See also
Type.op_arity, Type.mk_type,
Type.mk_thy_type,
Type.dest_type,
Type.dest_thy_type
is_vartype
is_vartype
Type.is_vartype : hol_type -> bool
Tests a type to see if it is a type variable.
Failure
Never fails.
Example
> is_vartype Type.alpha;
val it = true: bool
> is_vartype bool;
val it = false: bool
> is_vartype (Type `:'a -> bool`);
val it = false: bool
See also
Type.mk_vartype,
Type.dest_vartype
match_type
match_type
Type.match_type : hol_type -> hol_type -> (hol_type,hol_type) subst
Calculates a substitution theta such that instantiating the first
argument with theta equals the second argument.
If match_type ty1 ty2 succeeds, then
type_subst (match_type ty1 ty2) ty1 = ty2
Failure
If no such substitution can be found.
Example
> match_type alpha (Type`:num`);
val it = [{redex = “:α”, residue = “:num”}]: (hol_type, hol_type) Lib.subst
> let val patt = Type`:('a -> bool) -> 'b`
val ty = Type`:(num -> bool) -> bool`
in
type_subst (match_type patt ty) patt = ty
end;
val it = true: bool
> match_type (alpha --> alpha)
(ind --> bool);
Exception- HOL_ERR (at Type.raw_match_type: double bind on type variable 'a) raised
See also
Term.match_term,
Type.type_subst
mk_thy_type
mk_thy_type
Type.mk_thy_type
: {Thy:string, Tyop:string, Args:hol_type list} -> hol_type
Constructs a type.
If s is a string that has been previously declared to be a type with
arity type n in theory thy, and the length of tyl is equal to n,
then mk_thy_type{Tyop=s, Thy=thy, Args=tyl} returns the requested
compound type.
Failure
Fails if s is not the name of a type in theory thy, if thy is not
in the ancestry of the current theory, or if n is not the length of
tyl.
Example
> mk_thy_type {Tyop="fun", Thy="min", Args = [alpha,bool]};
val it = “:α -> bool”: hol_type
> try mk_thy_type {Tyop="bar", Thy="foo", Args = []};
Exception- HOL_ERR
(at Type.mk_thy_type:
the type operator "bar" has not been declared in theory "foo".) raised
Comments
In general, mk_thy_type is to be preferred over mk_type because HOL
provides a fresh namespace for each theory (mk_type is a holdover from
a time when there was only one namespace shared by all theories).
See also
Type.mk_type,
Type.dest_thy_type,
Term.mk_const,
Term.mk_thy_const
mk_type
mk_type
Type.mk_type : string * hol_type list -> hol_type
Constructs a compound type.
mk_type(tyop,[ty1,...,tyn]) returns the HOL type (ty1,...,tyn)tyop,
provided tyop is the name of a known n-ary type constructor.
Failure
Fails if tyop is not the name of a known type, or if tyop is known,
but the length of the list of argument types is not equal to the arity
of tyop.
Example
> mk_type ("bool",[]);
val it = “:bool”: hol_type
> mk_type ("fun",[alpha,it]);
val it = “:α -> bool”: hol_type
Comments
Note that type operators with the same name (and arity) may be declared
in different theories. If two theories having type operators with the
same name s are in the ancestry of the current theory, then
mk_type(s,tyl) will issue a warning before arbitrarily selecting which
type operator to use. In such situations, it is preferable to use
mk_thy_type since it allows one to specify exactly which type operator
to use.
See also
Type.mk_thy_type,
Type.dest_type,
Type.mk_vartype, Type.-->
mk_vartype
mk_vartype
Type.mk_vartype : string -> hol_type
Constructs a type variable of the given name.
Failure
Fails if the string does not begin with '.
Example
> mk_vartype "'giraffe";
val it = “:'giraffe”: hol_type
> try mk_vartype "test";
val it = “:test”: hol_type
See also
Type.dest_vartype,
Type.is_vartype, Type.mk_type
op_arity
op_arity
Type.op_arity : {Thy:string, Tyop:string} -> int option
Return the arity of a type operator.
An invocation op_arity{Tyop,Thy} returns NONE if the given record
does not identify a type operator in the current type signature.
Otherwise, it returns SOME n, where n identifies the number of
arguments the specified type operator takes.
Failure
Never fails.
Example
> op_arity{Tyop="fun", Thy="min"};
val it = SOME 2: int option
> op_arity{Tyop="foo", Thy="min"};
val it = NONE: int option
See also
polymorphic
polymorphic
Type.polymorphic : hol_type -> bool
Checks if there is a type variable in a type.
An invocation polymorphic ty checks to see if ty has an occurrence
of any type variable. It is equivalent in functionality to
not o null o type_vars, but may be more efficient in some situations,
since it can stop processing once it finds one type variable.
Failure
Never fails.
Example
> polymorphic (bool --> alpha --> ind);
val it = true: bool
Comments
polymorphic is also equivalent to exists_tyvar (K true), and no
faster.
See also
Type.type_vars,
Type.type_var_in,
Type.exists_tyvar
raw_match_type
raw_match_type
Type.raw_match_type
: hol_type -> hol_type ->
(hol_type,hol_type) subst * hol_type list ->
(hol_type,hol_type) subst * hol_type list
Primitive type matching algorithm.
An invocation raw_match_type pat ty (S,Id) performs matching, just as
match_type, except that it takes an extra accumulating parameter
(S,Id), which represents a 'raw' substitution that the match
(theta,id) of pat and ty must be compatible with. If matching is
successful, (theta,id) is merged with (S,Id) to yield the result.
Failure
A call to raw_match_type pat ty (S,Id) will fail when
match_type pat ty would. It will also fail when a {redex,residue}
calculated in the course of matching pat and ty is such that there
is a {redex_i,residue_i} in S and redex equals redex_i but
residue does not equal residue_i.
Example
> val res1 = raw_match_type alpha “:'a -> bool” ([],[]);
val res1 = ([{redex = “:α”, residue = “:α -> bool”}], []):
(hol_type, hol_type) Lib.subst * hol_type list
> raw_match_type “:'a -> 'b -> 'c”
“:('a -> bool) -> 'b -> ind” res1;
val it =
([{redex = “:γ”, residue = “:ind”},
{redex = “:α”, residue = “:α -> bool”}], [“:β”]):
(hol_type, hol_type) Lib.subst * hol_type list
Comments
Probably exposes too much internal state of the matching algorithm.
See also
type_subst
type_subst
Type.type_subst : (hol_type,hol_type) subst -> hol_type -> hol_type
Instantiates types in a type.
If theta = [{redex_1,residue_1},...,{redex_n,residue_n}] is a
(hol_type,hol_type) subst, where the redex_i are the types to be
substituted for, and the residue_i the replacements, and ty is a
type to instantiate, the call type_subst theta ty will replace each
occurrence of a redex_i by the corresponding residue_i throughout
ty. The replacements will be performed in parallel. If several of the
type instantiations are applicable, the choice is undefined. Each
redex_i ought to be a type variable, but if it isn't, it will never be
replaced in ty. Also, it is not necessary that any or all of the types
redex_1...redex_n should in fact appear in ty.
Failure
Never fails.
Example
> type_subst [alpha |-> bool] (Type `:'a # 'b`);
val it = “:bool # β”: hol_type
> type_subst [Type`:'a # 'b` |-> Type `:num`, alpha |-> bool]
(Type`:'a # 'b`);
val it = “:bool # β”: hol_type
See also
Term.inst, Thm.INST_TYPE,
Lib.|->, Term.subst
type_var_in
type_var_in
Type.type_var_in : hol_type -> hol_type -> bool
Checks if a type variable occurs in a type.
An invocation type_var_in tyv ty returns true if tyv occurs in
ty. Otherwise, it returns false.
Failure
Fails if tyv is not a type variable.
Example
> type_var_in alpha (bool --> alpha);
val it = true: bool
> type_var_in alpha bool;
val it = false: bool
Comments
Can be useful in enforcing side conditions on inference rules.
See also
Type.type_vars,
Type.type_varsl,
Type.exists_tyvar
type_vars
type_vars
Type.type_vars : hol_type -> hol_type list
Returns the set of type variables in a type.
An invocation type_vars ty returns a list representing the set of type
variables occurring in ty.
Failure
Never fails.
Example
> type_vars ((alpha --> beta) --> bool --> beta);
val it = [“:β”, “:α”]: hol_type list
Comments
Code should not depend on how elements are arranged in the result of
type_vars.
See also
Type.type_vars_acc,
Type.type_varsl,
Type.type_var_in,
Type.exists_tyvar,
Type.polymorphic,
Term.free_vars
type_vars_acc
type_vars_acc
Type.type_vars_acc : hol_type -> hol_type list -> hol_type list
Returns the set of type variables in a type.
An invocation type_vars_acc ty A returns a list representing the
set-theoretic union of the type variables occurring in ty and A.
Failure
Never fails.
Example
> type_vars_acc ((alpha --> beta) --> bool --> beta) [];
val it = [“:β”, “:α”]: hol_type list
Comments
Code should not depend on how elements are arranged in the result of
type_vars_acc.
See also
Type.type_vars,
Type.type_varsl,
Type.type_var_in,
Type.exists_tyvar,
Type.polymorphic,
Term.free_vars
type_varsl
type_varsl
Type.type_varsl : hol_type list -> hol_type list
Returns the set of type variables in a list of types.
An invocation type_varsl [ty1,...,tyn] returns a list representing the
set-theoretic union of the type variables occurring in ty1,...,tyn.
Failure
Never fails.
Example
> type_varsl [alpha, beta, bool, ((alpha --> beta) --> bool --> beta)];
val it = [“:β”, “:α”]: hol_type list
Comments
Code should not depend on how elements are arranged in the result of
type_varsl.
See also
Type.type_vars,
Type.type_vars_acc,
Type.type_var_in,
Type.exists_tyvar,
Type.polymorphic,
Term.free_vars
TypeBase
TypeBase
structure TypeBase
A database of facts stemming from datatype declarations.
The structure TypeBase provides an interface to a database that is
updated when a new datatype is introduced with Hol_datatype. When a
new datatype is declared, a collection of theorems "about" the type can
be automatically derived. These are indeed proved, and are stored in the
current theory segment. They are also automatically stored in
TypeBase.
The interface to TypeBase is intended to provide support for writers
of high-level tools for reasoning about datatypes.
Example
> Datatype `tree = Leaf | Node 'a tree tree`;
<<HOL message: Defined type: "tree">>
val it = () : unit
> TypeBase.read {Thy = current_theory(), Tyop = "tree"};
val it =
SOME
-----------------------
-----------------------
HOL datatype: "scratch$tree"
Primitive recursion:
|- !f0 f1.
?fn.
(fn Leaf = f0) /\
!a0 a1 a2. fn (Node a0 a1 a2) = f1 a0 a1 a2 (fn a1) (fn a2)
Case analysis:
|- (!v f. tree_CASE Leaf v f = v) /\
!a0 a1 a2 v f. tree_CASE (Node a0 a1 a2) v f = f a0 a1 a2
Size:
|- (!f. tree_size f Leaf = 0) /\
!f a0 a1 a2.
tree_size f (Node a0 a1 a2) =
1 + (f a0 + (tree_size f a1 + tree_size f a2))
Induction:
|- !P.
P Leaf /\ (!t t0. P t /\ P t0 ==> !a. P (Node a t t0)) ==>
!t. P t
Case completeness: |- !tt. (tt = Leaf) \/ ?a t t0. tt = Node a t t0
Case-const equality split:
|- (tree_CASE x v f = v') <=>
(x = Leaf) /\ (v = v') \/
?a t t0. (x = Node a t t0) /\ (f a t t0 = v')
Extras: [ ]
One-to-one:
|- !a0 a1 a2 a0' a1' a2'.
(Node a0 a1 a2 = Node a0' a1' a2') <=>
(a0 = a0') /\ (a1 = a1') /\ (a2 = a2')
Distinctness: |- !a2 a1 a0. Leaf <> Node a0 a1 a2: tyinfo option
See also
CONJ_FORALL_CONV
CONJ_FORALL_CONV
unwindLib.CONJ_FORALL_CONV : conv
Moves universal quantifiers up through a tree of conjunctions.
CONJ_FORALL_CONV "(!x1 ... xm. t1) /\ ... /\ (!x1 ... xm. tn)" returns
the following theorem:
|- (!x1 ... xm. t1) /\ ... /\ (!x1 ... xm. tn) =
!x1 ... xm. t1 /\ ... /\ tn
where the original term can be an arbitrary tree of conjunctions. The structure of the tree is retained in both sides of the equation.
Failure
Never fails.
Example
#CONJ_FORALL_CONV "((!(x:*) (y:*) (z:*). a) /\ (!(x:*) (y:*) (z:*). b)) /\
# (!(x:*) (y:*) (z:*). c)";;
|- ((!x y z. a) /\ (!x y z. b)) /\ (!x y z. c) = (!x y z. (a /\ b) /\ c)
#CONJ_FORALL_CONV "T";;
|- T = T
#CONJ_FORALL_CONV "((!(x:*) (y:*) (z:*). a) /\ (!(x:*) (w:*) (z:*). b)) /\
# (!(x:*) (y:*) (z:*). c)";;
|- ((!x y z. a) /\ (!x w z. b)) /\ (!x y z. c) =
(!x. ((!y z. a) /\ (!w z. b)) /\ (!y z. c))
See also
unwindLib.FORALL_CONJ_CONV,
unwindLib.CONJ_FORALL_ONCE_CONV,
unwindLib.FORALL_CONJ_ONCE_CONV,
unwindLib.CONJ_FORALL_RIGHT_RULE,
unwindLib.FORALL_CONJ_RIGHT_RULE
CONJ_FORALL_ONCE_CONV
CONJ_FORALL_ONCE_CONV
unwindLib.CONJ_FORALL_ONCE_CONV : conv
Moves a single universal quantifier up through a tree of conjunctions.
CONJ_FORALL_ONCE_CONV "(!x. t1) /\ ... /\ (!x. tn)" returns the
theorem:
|- (!x. t1) /\ ... /\ (!x. tn) = !x. t1 /\ ... /\ tn
where the original term can be an arbitrary tree of conjunctions. The structure of the tree is retained in both sides of the equation.
Failure
Fails if the argument term is not of the required form. The term need not be a conjunction, but if it is every conjunct must be universally quantified with the same variable.
Example
#CONJ_FORALL_ONCE_CONV "((!x. x \/ a) /\ (!x. x \/ b)) /\ (!x. x \/ c)";;
|- ((!x. x \/ a) /\ (!x. x \/ b)) /\ (!x. x \/ c) =
(!x. ((x \/ a) /\ (x \/ b)) /\ (x \/ c))
#CONJ_FORALL_ONCE_CONV "!x. x \/ a";;
|- (!x. x \/ a) = (!x. x \/ a)
#CONJ_FORALL_ONCE_CONV "((!x. x \/ a) /\ (!y. y \/ b)) /\ (!x. x \/ c)";;
evaluation failed CONJ_FORALL_ONCE_CONV
See also
unwindLib.FORALL_CONJ_ONCE_CONV,
unwindLib.CONJ_FORALL_CONV,
unwindLib.FORALL_CONJ_CONV,
unwindLib.CONJ_FORALL_RIGHT_RULE,
unwindLib.FORALL_CONJ_RIGHT_RULE
CONJ_FORALL_RIGHT_RULE
CONJ_FORALL_RIGHT_RULE
unwindLib.CONJ_FORALL_RIGHT_RULE : (thm -> thm)
Moves universal quantifiers up through a tree of conjunctions.
A |- !z1 ... zr.
t = ?y1 ... yp. (!x1 ... xm. t1) /\ ... /\ (!x1 ... xm. tn)
-------------------------------------------------------------------
A |- !z1 ... zr. t = ?y1 ... yp. !x1 ... xm. t1 /\ ... /\ tn
Failure
Fails if the argument theorem is not of the required form, though either
or both of r and p may be zero.
See also
unwindLib.FORALL_CONJ_RIGHT_RULE,
unwindLib.CONJ_FORALL_CONV,
unwindLib.FORALL_CONJ_CONV,
unwindLib.CONJ_FORALL_ONCE_CONV,
unwindLib.FORALL_CONJ_ONCE_CONV
DEPTH_EXISTS_CONV
DEPTH_EXISTS_CONV
unwindLib.DEPTH_EXISTS_CONV : (conv -> conv)
Applies a conversion to the body of nested existential quantifications.
DEPTH_EXISTS_CONV conv "?x1 ... xn. body" applies conv to "body"
and returns a theorem of the form:
|- (?x1 ... xn. body) = (?x1 ... xn. body')
Failure
Fails if the application of conv fails.
Example
#DEPTH_EXISTS_CONV BETA_CONV "?x y z. (\w. x /\ y /\ z /\ w) T";;
|- (?x y z. (\w. x /\ y /\ z /\ w)T) = (?x y z. x /\ y /\ z /\ T)
See also
DEPTH_FORALL_CONV
DEPTH_FORALL_CONV
unwindLib.DEPTH_FORALL_CONV : (conv -> conv)
Applies a conversion to the body of nested universal quantifications.
DEPTH_FORALL_CONV conv "!x1 ... xn. body" applies conv to "body"
and returns a theorem of the form:
|- (!x1 ... xn. body) = (!x1 ... xn. body')
Failure
Fails if the application of conv fails.
Example
#DEPTH_FORALL_CONV BETA_CONV "!x y z. (\w. x /\ y /\ z /\ w) T";;
|- (!x y z. (\w. x /\ y /\ z /\ w)T) = (!x y z. x /\ y /\ z /\ T)
See also
EXISTS_DEL1_CONV
EXISTS_DEL1_CONV
unwindLib.EXISTS_DEL1_CONV : conv
Deletes one existential quantifier.
EXISTS_DEL1_CONV "?x. t" returns the theorem:
|- (?x. t) = t
provided x is not free in t.
Failure
Fails if the argument term is not an existential quantification or if
x is free in t.
See also
unwindLib.EXISTS_DEL_CONV,
unwindLib.PRUNE_ONCE_CONV
EXISTS_DEL_CONV
EXISTS_DEL_CONV
unwindLib.EXISTS_DEL_CONV : conv
Deletes existential quantifiers.
EXISTS_DEL_CONV "?x1 ... xn. t" returns the theorem:
|- (?x1 ... xn. t) = t
provided x1,...,xn are not free in t.
Failure
Fails if any of the x's appear free in t. The function does not
perform a partial deletion; for example, if x1 and x2 do not appear
free in t but x3 does, the function will fail; it will not return:
|- ?x1 ... xn. t = ?x3 ... xn. t
See also
unwindLib.EXISTS_DEL1_CONV,
unwindLib.PRUNE_CONV
EXISTS_EQN_CONV
EXISTS_EQN_CONV
unwindLib.EXISTS_EQN_CONV : conv
Proves the existence of a line that has a non-recursive equation.
EXISTS_EQN_CONV "?l. !y1 ... ym. l x1 ... xn = t" returns the theorem:
|- (?l. !y1 ... ym. l x1 ... xn = t) = T
provided l is not free in t. Both m and n may be zero.
Failure
Fails if the argument term is not of the specified form or if l
appears free in t.
See also
EXPAND_ALL_BUT_CONV
EXPAND_ALL_BUT_CONV
unwindLib.EXPAND_ALL_BUT_CONV : (string list -> thm list -> conv)
Unfolds, then unwinds all lines (except those specified) as much as possible, then prunes the unwound lines.
EXPAND_ALL_BUT_CONV [`li(k+1)`;...;`lim`] thl when applied to the
following term:
"?l1 ... lm. t1 /\ ... /\ ui1 /\ ... /\ uik /\ ... /\ tn"
returns a theorem of the form:
B |- (?l1 ... lm. t1 /\ ... /\ ui1 /\ ... /\ uik /\ ... /\ tn) =
(?li(k+1) ... lim. t1' /\ ... /\ tn')
where each ti' is the result of rewriting ti with the theorems in
thl. The set of assumptions B is the union of the instantiated
assumptions of the theorems used for rewriting. If none of the rewrites
are applicable to a conjunct, it is unchanged. Those conjuncts that
after rewriting are equations for the lines li1,...,lik (they are
denoted by ui1,...,uik) are used to unwind and the lines li1,...,lik
are then pruned.
The li's are related by the equation:
{{li1,...,lik}} u {{li(k+1),...,lim}} = {{l1,...,lm}}
Failure
The function may fail if the argument term is not of the specified form. It will also fail if the unwound lines cannot be pruned. It is possible for the function to attempt unwinding indefinitely (to loop).
Example
#EXPAND_ALL_BUT_CONV [`l1`]
# [ASSUME "!in out. INV (in,out) = !(t:num). out t = ~(in t)"]
# "?l1 l2.
# INV (l1,l2) /\ INV (l2,out) /\ (!(t:num). l1 t = l2 (t-1) \/ out (t-1))";;
. |- (?l1 l2.
INV(l1,l2) /\ INV(l2,out) /\ (!t. l1 t = l2(t - 1) \/ out(t - 1))) =
(?l1.
(!t. out t = ~~l1 t) /\ (!t. l1 t = ~l1(t - 1) \/ ~~l1(t - 1)))
See also
unwindLib.EXPAND_AUTO_CONV,
unwindLib.EXPAND_ALL_BUT_RIGHT_RULE,
unwindLib.EXPAND_AUTO_RIGHT_RULE,
unwindLib.UNFOLD_CONV,
unwindLib.UNWIND_ALL_BUT_CONV,
unwindLib.PRUNE_SOME_CONV
EXPAND_ALL_BUT_RIGHT_RULE
EXPAND_ALL_BUT_RIGHT_RULE
unwindLib.EXPAND_ALL_BUT_RIGHT_RULE : (string list -> thm list -> thm -> thm)
Unfolds, then unwinds all lines (except those specified) as much as possible, then prunes the unwound lines.
EXPAND_ALL_BUT_RIGHT_RULE [`li(k+1)`;...;`lim`] thl behaves as
follows:
A |- !z1 ... zr.
t = ?l1 ... lm. t1 /\ ... /\ ui1 /\ ... /\ uik /\ ... /\ tn
-------------------------------------------------------------------
B u A |- !z1 ... zr. t = ?li(k+1) ... lim. t1' /\ ... /\ tn'
where each ti' is the result of rewriting ti with the theorems in
thl. The set of assumptions B is the union of the instantiated
assumptions of the theorems used for rewriting. If none of the rewrites
are applicable to a conjunct, it is unchanged. Those conjuncts that
after rewriting are equations for the lines li1,...,lik (they are
denoted by ui1,...,uik) are used to unwind and the lines li1,...,lik
are then pruned.
The li's are related by the equation:
{{li1,...,lik}} u {{li(k+1),...,lim}} = {{l1,...,lm}}
Failure
The function may fail if the argument theorem is not of the specified form. It will also fail if the unwound lines cannot be pruned. It is possible for the function to attempt unwinding indefinitely (to loop).
Example
#EXPAND_ALL_BUT_RIGHT_RULE [`l1`]
# [ASSUME "!in out. INV (in,out) = !(t:num). out t = ~(in t)"]
# (ASSUME
# "!(in:num->bool) out.
# DEV(in,out) =
# ?l1 l2.
# INV (l1,l2) /\ INV (l2,out) /\ (!(t:num). l1 t = in t \/ out (t-1))");;
.. |- !in out.
DEV(in,out) =
(?l1. (!t. out t = ~~l1 t) /\ (!t. l1 t = in t \/ ~~l1(t - 1)))
See also
unwindLib.EXPAND_AUTO_RIGHT_RULE,
unwindLib.EXPAND_ALL_BUT_CONV,
unwindLib.EXPAND_AUTO_CONV,
unwindLib.UNFOLD_RIGHT_RULE,
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE,
unwindLib.PRUNE_SOME_RIGHT_RULE
EXPAND_AUTO_CONV
EXPAND_AUTO_CONV
unwindLib.EXPAND_AUTO_CONV : (thm list -> conv)
Unfolds, then unwinds as much as possible, then prunes the unwound lines.
EXPAND_AUTO_CONV thl when applied to the following term:
"?l1 ... lm. t1 /\ ... /\ ui1 /\ ... /\ uik /\ ... /\ tn"
returns a theorem of the form:
B |- (?l1 ... lm. t1 /\ ... /\ ui1 /\ ... /\ uik /\ ... /\ tn) =
(?li(k+1) ... lim. t1' /\ ... /\ tn')
where each ti' is the result of rewriting ti with the theorems in
thl. The set of assumptions B is the union of the instantiated
assumptions of the theorems used for rewriting. If none of the rewrites
are applicable to a conjunct, it is unchanged. After rewriting, the
function decides which of the resulting terms to use for unwinding, by
performing a loop analysis on the graph representing the dependencies of
the lines.
Suppose the function decides to unwind li1,...,lik using the terms
ui1',...,uik' respectively. Then, after unwinding, the lines
li1,...,lik are pruned (provided they have been eliminated from the
right-hand sides of the conjuncts that are equations, and from the whole
of any other conjuncts) resulting in the elimination of ui1',...,uik'.
The li's are related by the equation:
{{li1,...,lik}} u {{li(k+1),...,lim}} = {{l1,...,lm}}
The loop analysis allows the term to be unwound as much as possible without the risk of looping. The user is left to deal with the recursive equations.
Failure
The function may fail if the argument term is not of the specified form. It also fails if there is more than one equation for any line variable.
Example
#EXPAND_AUTO_CONV
# [ASSUME "!in out. INV (in,out) = !(t:num). out t = ~(in t)"]
# "?l1 l2.
# INV (l1,l2) /\ INV (l2,out) /\ (!(t:num). l1 t = l2 (t-1) \/ out (t-1))";;
. |- (?l1 l2.
INV(l1,l2) /\ INV(l2,out) /\ (!t. l1 t = l2(t - 1) \/ out(t - 1))) =
(?l2.
(!t. l2 t = ~(l2(t - 1) \/ ~l2(t - 1))) /\ (!t. out t = ~l2 t))
See also
unwindLib.EXPAND_ALL_BUT_CONV,
unwindLib.EXPAND_AUTO_RIGHT_RULE,
unwindLib.EXPAND_ALL_BUT_RIGHT_RULE,
unwindLib.UNFOLD_CONV,
unwindLib.UNWIND_AUTO_CONV,
unwindLib.PRUNE_SOME_CONV
EXPAND_AUTO_RIGHT_RULE
EXPAND_AUTO_RIGHT_RULE
unwindLib.EXPAND_AUTO_RIGHT_RULE : (thm list -> thm -> thm)
Unfolds, then unwinds as much as possible, then prunes the unwound lines.
EXPAND_AUTO_RIGHT_RULE thl behaves as follows:
A |- !z1 ... zr.
t = ?l1 ... lm. t1 /\ ... /\ ui1 /\ ... /\ uik /\ ... /\ tn
-------------------------------------------------------------------
B u A |- !z1 ... zr. t = ?li(k+1) ... lim. t1' /\ ... /\ tn'
where each ti' is the result of rewriting ti with the theorems in
thl. The set of assumptions B is the union of the instantiated
assumptions of the theorems used for rewriting. If none of the rewrites
are applicable to a conjunct, it is unchanged. After rewriting, the
function decides which of the resulting terms to use for unwinding, by
performing a loop analysis on the graph representing the dependencies of
the lines.
Suppose the function decides to unwind li1,...,lik using the terms
ui1',...,uik' respectively. Then, after unwinding, the lines
li1,...,lik are pruned (provided they have been eliminated from the
right-hand sides of the conjuncts that are equations, and from the whole
of any other conjuncts) resulting in the elimination of ui1',...,uik'.
The li's are related by the equation:
{{li1,...,lik}} u {{li(k+1),...,lim}} = {{l1,...,lm}}
The loop analysis allows the term to be unwound as much as possible without the risk of looping. The user is left to deal with the recursive equations.
Failure
The function may fail if the argument theorem is not of the specified form. It also fails if there is more than one equation for any line variable.
Example
#EXPAND_AUTO_RIGHT_RULE
# [ASSUME "!in out. INV (in,out) = !(t:num). out t = ~(in t)"]
# (ASSUME
# "!(in:num->bool) out.
# DEV(in,out) =
# ?l1 l2.
# INV (l1,l2) /\ INV (l2,out) /\ (!(t:num). l1 t = in t \/ out (t-1))");;
.. |- !in out. DEV(in,out) = (!t. out t = ~~(in t \/ out(t - 1)))
See also
unwindLib.EXPAND_ALL_BUT_RIGHT_RULE,
unwindLib.EXPAND_AUTO_CONV,
unwindLib.EXPAND_ALL_BUT_CONV,
unwindLib.UNFOLD_RIGHT_RULE,
unwindLib.UNWIND_AUTO_RIGHT_RULE,
unwindLib.PRUNE_SOME_RIGHT_RULE
FLATTEN_CONJ_CONV
FLATTEN_CONJ_CONV
unwindLib.FLATTEN_CONJ_CONV : conv
Flattens a 'tree' of conjunctions.
FLATTEN_CONJ_CONV "t1 /\ ... /\ tn" returns a theorem of the form:
|- t1 /\ ... /\ tn = u1 /\ ... /\ un
where the right-hand side of the equation is a flattened version of the left-hand side.
Failure
Never fails.
Example
#FLATTEN_CONJ_CONV "(a /\ (b /\ c)) /\ ((d /\ e) /\ f)";;
|- (a /\ b /\ c) /\ (d /\ e) /\ f = a /\ b /\ c /\ d /\ e /\ f
FORALL_CONJ_CONV
FORALL_CONJ_CONV
unwindLib.FORALL_CONJ_CONV : conv
Moves universal quantifiers down through a tree of conjunctions.
FORALL_CONJ_CONV "!x1 ... xm. t1 /\ ... /\ tn" returns the theorem:
|- !x1 ... xm. t1 /\ ... /\ tn =
(!x1 ... xm. t1) /\ ... /\ (!x1 ... xm. tn)
where the original term can be an arbitrary tree of conjunctions. The structure of the tree is retained in both sides of the equation.
Failure
Never fails.
Example
#FORALL_CONJ_CONV "!(x:*) (y:*) (z:*). (a /\ b) /\ c";;
|- (!x y z. (a /\ b) /\ c) = ((!x y z. a) /\ (!x y z. b)) /\ (!x y z. c)
#FORALL_CONJ_CONV "T";;
|- T = T
#FORALL_CONJ_CONV "!(x:*) (y:*) (z:*). T";;
|- (!x y z. T) = (!x y z. T)
See also
unwindLib.CONJ_FORALL_CONV,
unwindLib.FORALL_CONJ_ONCE_CONV,
unwindLib.CONJ_FORALL_ONCE_CONV,
unwindLib.FORALL_CONJ_RIGHT_RULE,
unwindLib.CONJ_FORALL_RIGHT_RULE
FORALL_CONJ_ONCE_CONV
FORALL_CONJ_ONCE_CONV
unwindLib.FORALL_CONJ_ONCE_CONV : conv
Moves a single universal quantifier down through a tree of conjunctions.
FORALL_CONJ_ONCE_CONV "!x. t1 /\ ... /\ tn" returns the theorem:
|- !x. t1 /\ ... /\ tn = (!x. t1) /\ ... /\ (!x. tn)
where the original term can be an arbitrary tree of conjunctions. The structure of the tree is retained in both sides of the equation.
Failure
Fails if the argument term is not of the required form. The body of the term need not be a conjunction.
Example
#FORALL_CONJ_ONCE_CONV "!x. ((x \/ a) /\ (x \/ b)) /\ (x \/ c)";;
|- (!x. ((x \/ a) /\ (x \/ b)) /\ (x \/ c)) =
((!x. x \/ a) /\ (!x. x \/ b)) /\ (!x. x \/ c)
#FORALL_CONJ_ONCE_CONV "!x. x \/ a";;
|- (!x. x \/ a) = (!x. x \/ a)
#FORALL_CONJ_ONCE_CONV "!x. ((x \/ a) /\ (y \/ b)) /\ (x \/ c)";;
|- (!x. ((x \/ a) /\ (y \/ b)) /\ (x \/ c)) =
((!x. x \/ a) /\ (!x. y \/ b)) /\ (!x. x \/ c)
See also
unwindLib.CONJ_FORALL_ONCE_CONV,
unwindLib.FORALL_CONJ_CONV,
unwindLib.CONJ_FORALL_CONV,
unwindLib.FORALL_CONJ_RIGHT_RULE,
unwindLib.CONJ_FORALL_RIGHT_RULE
FORALL_CONJ_RIGHT_RULE
FORALL_CONJ_RIGHT_RULE
unwindLib.FORALL_CONJ_RIGHT_RULE : (thm -> thm)
Moves universal quantifiers down through a tree of conjunctions.
A |- !z1 ... zr. t = ?y1 ... yp. !x1 ... xm. t1 /\ ... /\ tn
-------------------------------------------------------------------
A |- !z1 ... zr.
t = ?y1 ... yp. (!x1 ... xm. t1) /\ ... /\ (!x1 ... xm. tn)
Failure
Fails if the argument theorem is not of the required form, though either
or both of r and p may be zero.
See also
unwindLib.CONJ_FORALL_RIGHT_RULE,
unwindLib.FORALL_CONJ_CONV,
unwindLib.CONJ_FORALL_CONV,
unwindLib.FORALL_CONJ_ONCE_CONV,
unwindLib.CONJ_FORALL_ONCE_CONV
line_name
line_name
unwindLib.line_name : (term -> string)
Computes the line name of an equation.
line_name "!y1 ... ym. f x1 ... xn = t" returns the string `f`.
Failure
Fails if the argument term is not of the specified form.
See also
line_var
line_var
unwindLib.line_var : (term -> term)
Computes the line variable of an equation.
line_var "!y1 ... ym. f x1 ... xn = t" returns the variable "f".
Failure
Fails if the argument term is not of the specified form.
See also
PRUNE_CONV
PRUNE_CONV
unwindLib.PRUNE_CONV : conv
Prunes all hidden variables.
PRUNE_CONV "?l1 ... lr. t1 /\ ... /\ eqn1 /\ ... /\ eqnr /\ ... /\ tp"
returns a theorem of the form:
|- (?l1 ... lr. t1 /\ ... /\ eqn1 /\ ... /\ eqnr /\ ... /\ tp) =
(t1 /\ ... /\ tp)
where each eqni has the form "!y1 ... ym. li x1 ... xn = b" and li
does not appear free in any of the other conjuncts or in b. The
conversion works if one or more of the eqni's are not present, that is
if li is not free in any of the conjuncts, but does not work if li
appears free in more than one of the conjuncts. p may be zero, that
is, all the conjuncts may be eqni's. In this case the result will be
simply T (true). Also, for each eqni, m and n may be zero.
Failure
Fails if the argument term is not of the specified form or if any of the
li's are free in more than one of the conjuncts or if the equation for
any li is recursive.
Example
#PRUNE_CONV
# "?l2 l1.
# (!(x:num). l1 x = F) /\ (!x. l2 x = ~(out x)) /\ (!(x:num). out x = T)";;
|- (?l2 l1. (!x. l1 x = F) /\ (!x. l2 x = ~out x) /\ (!x. out x = T)) =
(!x. out x = T)
See also
unwindLib.PRUNE_ONCE_CONV,
unwindLib.PRUNE_ONE_CONV,
unwindLib.PRUNE_SOME_CONV,
unwindLib.PRUNE_SOME_RIGHT_RULE,
unwindLib.PRUNE_RIGHT_RULE
PRUNE_ONCE_CONV
PRUNE_ONCE_CONV
unwindLib.PRUNE_ONCE_CONV : conv
Prunes one hidden variable.
PRUNE_ONCE_CONV "?l. t1 /\ ... /\ ti /\ eq /\ t(i+1) /\ ... /\ tp"
returns a theorem of the form:
|- (?l. t1 /\ ... /\ ti /\ eq /\ t(i+1) /\ ... /\ tp) =
(t1 /\ ... /\ ti /\ t(i+1) /\ ... /\ tp)
where eq has the form "!y1 ... ym. l x1 ... xn = b" and l does not
appear free in the ti's or in b. The conversion works if eq is not
present, that is if l is not free in any of the conjuncts, but does
not work if l appears free in more than one of the conjuncts. Each of
m, n and p may be zero.
Failure
Fails if the argument term is not of the specified form or if l is
free in more than one of the conjuncts or if the equation for l is
recursive.
Example
#PRUNE_ONCE_CONV "?l2. (!(x:num). l1 x = F) /\ (!x. l2 x = ~(l1 x))";;
|- (?l2. (!x. l1 x = F) /\ (!x. l2 x = ~l1 x)) = (!x. l1 x = F)
See also
unwindLib.PRUNE_ONE_CONV,
unwindLib.PRUNE_SOME_CONV,
unwindLib.PRUNE_CONV,
unwindLib.PRUNE_SOME_RIGHT_RULE,
unwindLib.PRUNE_RIGHT_RULE
PRUNE_ONE_CONV
PRUNE_ONE_CONV
unwindLib.PRUNE_ONE_CONV : (string -> conv)
Prunes a specified hidden variable.
PRUNE_ONE_CONV `lj` when applied to the term:
"?l1 ... lj ... lr. t1 /\ ... /\ ti /\ eq /\ t(i+1) /\ ... /\ tp"
returns a theorem of the form:
|- (?l1 ... lj ... lr. t1 /\ ... /\ ti /\ eq /\ t(i+1) /\ ... /\ tp) =
(?l1 ... l(j-1) l(j+1) ... lr. t1 /\ ... /\ ti /\ t(i+1) /\ ... /\ tp)
where eq has the form "!y1 ... ym. lj x1 ... xn = b" and lj does
not appear free in the ti's or in b. The conversion works if eq is
not present, that is if lj is not free in any of the conjuncts, but
does not work if lj appears free in more than one of the conjuncts.
Each of m, n and p may be zero.
If there is more than one line with the specified name (but with different types), the one that appears outermost in the existential quantifications is pruned.
Failure
Fails if the argument term is not of the specified form or if lj is
free in more than one of the conjuncts or if the equation for lj is
recursive. The function also fails if the specified line is not one of
the existentially quantified lines.
Example
#PRUNE_ONE_CONV `l2` "?l2 l1. (!(x:num). l1 x = F) /\ (!x. l2 x = ~(l1 x))";;
|- (?l2 l1. (!x. l1 x = F) /\ (!x. l2 x = ~l1 x)) = (?l1. !x. l1 x = F)
#PRUNE_ONE_CONV `l1` "?l2 l1. (!(x:num). l1 x = F) /\ (!x. l2 x = ~(l1 x))";;
evaluation failed PRUNE_ONE_CONV
See also
unwindLib.PRUNE_ONCE_CONV,
unwindLib.PRUNE_SOME_CONV,
unwindLib.PRUNE_CONV,
unwindLib.PRUNE_SOME_RIGHT_RULE,
unwindLib.PRUNE_RIGHT_RULE
PRUNE_RIGHT_RULE
PRUNE_RIGHT_RULE
unwindLib.PRUNE_RIGHT_RULE : (thm -> thm)
Prunes all hidden variables.
PRUNE_RIGHT_RULE behaves as follows:
A |- !z1 ... zr.
t = ?l1 ... lr. t1 /\ ... /\ eqn1 /\ ... /\ eqnr /\ ... /\ tp
---------------------------------------------------------------------
A |- !z1 ... zr. t = t1 /\ ... /\ tp
where each eqni has the form "!y1 ... ym. li x1 ... xn = b" and li
does not appear free in any of the other conjuncts or in b. The rule
works if one or more of the eqni's are not present, that is if li is
not free in any of the conjuncts, but does not work if li appears free
in more than one of the conjuncts. p may be zero, that is, all the
conjuncts may be eqni's. In this case the result will be simply T
(true). Also, for each eqni, m and n may be zero.
Failure
Fails if the argument theorem is not of the specified form or if any of
the li's are free in more than one of the conjuncts or if the equation
for any li is recursive.
Example
#PRUNE_RIGHT_RULE
# (ASSUME
# "!(in:num->bool) (out:num->bool).
# DEV (in,out) =
# ?(l1:num->bool) l2.
# (!x. l1 x = F) /\ (!x. l2 x = ~(in x)) /\ (!x. out x = ~(in x))");;
. |- !in out. DEV(in,out) = (!x. out x = ~in x)
See also
unwindLib.PRUNE_SOME_RIGHT_RULE,
unwindLib.PRUNE_ONCE_CONV,
unwindLib.PRUNE_ONE_CONV,
unwindLib.PRUNE_SOME_CONV,
unwindLib.PRUNE_CONV
PRUNE_SOME_CONV
PRUNE_SOME_CONV
unwindLib.PRUNE_SOME_CONV : (string list -> conv)
Prunes several hidden variables.
PRUNE_SOME_CONV [`li1`;...;`lik`] when applied to the term:
"?l1 ... lr. t1 /\ ... /\ eqni1 /\ ... /\ eqnik /\ ... /\ tp"
returns a theorem of the form:
|- (?l1 ... lr. t1 /\ ... /\ eqni1 /\ ... /\ eqnik /\ ... /\ tp) =
(?li(k+1) ... lir. t1 /\ ... /\ tp)
where for 1 <= j <= k, each eqnij has the form:
"!y1 ... ym. lij x1 ... xn = b"
and lij does not appear free in any of the other conjuncts or in b.
The li's are related by the equation:
{{li1,...,lik}} u {{li(k+1),...,lir}} = {{l1,...,lr}}
The conversion works if one or more of the eqnij's are not present,
that is if lij is not free in any of the conjuncts, but does not work
if lij appears free in more than one of the conjuncts. p may be
zero, that is, all the conjuncts may be eqnij's. In this case the body
of the result will be T (true). Also, for each eqnij, m and n
may be zero.
If there is more than one line with a specified name (but with different types), the one that appears outermost in the existential quantifications is pruned. If such a line name is mentioned twice in the list, the two outermost occurrences of lines with that name will be pruned, and so on.
Failure
Fails if the argument term is not of the specified form or if any of the
lij's are free in more than one of the conjuncts or if the equation
for any lij is recursive. The function also fails if any of the
specified lines are not one of the existentially quantified lines.
Example
#PRUNE_SOME_CONV [`l1`;`l2`]
# "?l3 l2 l1.
# (!(x:num). l1 x = F) /\ (!x. l2 x = ~(l3 x)) /\ (!(x:num). l3 x = T)";;
|- (?l3 l2 l1. (!x. l1 x = F) /\ (!x. l2 x = ~l3 x) /\ (!x. l3 x = T)) =
(?l3. !x. l3 x = T)
See also
unwindLib.PRUNE_ONCE_CONV,
unwindLib.PRUNE_ONE_CONV,
unwindLib.PRUNE_CONV,
unwindLib.PRUNE_SOME_RIGHT_RULE,
unwindLib.PRUNE_RIGHT_RULE
PRUNE_SOME_RIGHT_RULE
PRUNE_SOME_RIGHT_RULE
unwindLib.PRUNE_SOME_RIGHT_RULE : (string list -> thm -> thm)
Prunes several hidden variables.
PRUNE_SOME_RIGHT_RULE [`li1`;...;`lik`] behaves as follows:
A |- !z1 ... zr.
t = ?l1 ... lr. t1 /\ ... /\ eqni1 /\ ... /\ eqnik /\ ... /\ tp
-----------------------------------------------------------------------
A |- !z1 ... zr. t = ?li(k+1) ... lir. t1 /\ ... /\ tp
where for 1 <= j <= k, each eqnij has the form:
"!y1 ... ym. lij x1 ... xn = b"
and lij does not appear free in any of the other conjuncts or in b.
The li's are related by the equation:
{{li1,...,lik}} u {{li(k+1),...,lir}} = {{l1,...,lr}}
The rule works if one or more of the eqnij's are not present, that is
if lij is not free in any of the conjuncts, but does not work if lij
appears free in more than one of the conjuncts. p may be zero, that
is, all the conjuncts may be eqnij's. In this case the conjunction
will be transformed to T (true). Also, for each eqnij, m and n
may be zero.
If there is more than one line with a specified name (but with different types), the one that appears outermost in the existential quantifications is pruned. If such a line name is mentioned twice in the list, the two outermost occurrences of lines with that name will be pruned, and so on.
Failure
Fails if the argument theorem is not of the specified form or if any of
the lij's are free in more than one of the conjuncts or if the
equation for any lij is recursive. The function also fails if any of
the specified lines are not one of the existentially quantified lines.
Example
#PRUNE_SOME_RIGHT_RULE [`l1`;`l2`]
# (ASSUME
# "!(in:num->bool) (out:num->bool).
# DEV (in,out) =
# ?(l1:num->bool) l2.
# (!x. l1 x = F) /\ (!x. l2 x = ~(in x)) /\ (!x. out x = ~(in x))");;
. |- !in out. DEV(in,out) = (!x. out x = ~in x)
See also
unwindLib.PRUNE_RIGHT_RULE,
unwindLib.PRUNE_ONCE_CONV,
unwindLib.PRUNE_ONE_CONV,
unwindLib.PRUNE_SOME_CONV,
unwindLib.PRUNE_CONV
UNFOLD_CONV
UNFOLD_CONV
unwindLib.UNFOLD_CONV : (thm list -> conv)
Expands sub-components of a hardware description using their definitions.
UNFOLD_CONV thl "t1 /\ ... /\ tn" returns a theorem of the form:
B |- t1 /\ ... /\ tn = t1' /\ ... /\ tn'
where each ti' is the result of rewriting ti with the theorems in
thl. The set of assumptions B is the union of the instantiated
assumptions of the theorems used for rewriting. If none of the rewrites
are applicable to a ti, it is unchanged.
Failure
Never fails.
Example
#UNFOLD_CONV [ASSUME "!in out. INV (in,out) = !(t:num). out t = ~(in t)"]
# "INV (l1,l2) /\ INV (l2,l3) /\ (!(t:num). l1 t = l2 (t-1) \/ l3 (t-1))";;
. |- INV(l1,l2) /\ INV(l2,l3) /\ (!t. l1 t = l2(t - 1) \/ l3(t - 1)) =
(!t. l2 t = ~l1 t) /\
(!t. l3 t = ~l2 t) /\
(!t. l1 t = l2(t - 1) \/ l3(t - 1))
See also
UNFOLD_RIGHT_RULE
UNFOLD_RIGHT_RULE
unwindLib.UNFOLD_RIGHT_RULE : (thm list -> thm -> thm)
Expands sub-components of a hardware description using their definitions.
UNFOLD_RIGHT_RULE thl behaves as follows:
A |- !z1 ... zr. t = ?y1 ... yp. t1 /\ ... /\ tn
--------------------------------------------------------
B u A |- !z1 ... zr. t = ?y1 ... yp. t1' /\ ... /\ tn'
where each ti' is the result of rewriting ti with the theorems in
thl. The set of assumptions B is the union of the instantiated
assumptions of the theorems used for rewriting. If none of the rewrites
are applicable to a ti, it is unchanged.
Failure
Fails if the second argument is not of the required form, though either
or both of r and p may be zero.
Example
#UNFOLD_RIGHT_RULE [ASSUME "!in out. INV(in,out) = !(t:num). out t = ~(in t)"]
# (ASSUME "!(in:num->bool) out. BUF(in,out) = ?l. INV(in,l) /\ INV(l,out)");;
.. |- !in out.
BUF(in,out) = (?l. (!t. l t = ~in t) /\ (!t. out t = ~l t))
See also
UNWIND_ALL_BUT_CONV
UNWIND_ALL_BUT_CONV
unwindLib.UNWIND_ALL_BUT_CONV : (string list -> conv)
Unwinds all lines of a device (except those in the argument list) as much as possible.
UNWIND_ALL_BUT_CONV l when applied to the following term:
"t1 /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn"
returns a theorem of the form:
|- t1 /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn =
t1' /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn'
where ti' (for 1 <= i <= n) is ti rewritten with the equations
eqni (1 <= i <= m). These equations are those conjuncts with line
name not in l (and which are equations).
Failure
Never fails but may loop indefinitely.
Example
#UNWIND_ALL_BUT_CONV [`l2`]
# "(!(x:num). l1 x = (l2 x) - 1) /\
# (!x. f x = (l2 (x+1)) + (l1 (x+2))) /\
# (!x. l2 x = 7)";;
|- (!x. l1 x = (l2 x) - 1) /\
(!x. f x = (l2(x + 1)) + (l1(x + 2))) /\
(!x. l2 x = 7) =
(!x. l1 x = (l2 x) - 1) /\
(!x. f x = (l2(x + 1)) + ((l2(x + 2)) - 1)) /\
(!x. l2 x = 7)
See also
unwindLib.UNWIND_ONCE_CONV,
unwindLib.UNWIND_CONV,
unwindLib.UNWIND_AUTO_CONV,
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE,
unwindLib.UNWIND_AUTO_RIGHT_RULE
UNWIND_ALL_BUT_RIGHT_RULE
UNWIND_ALL_BUT_RIGHT_RULE
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE : (string list -> thm -> thm)
Unwinds all lines of a device (except those in the argument list) as much as possible.
UNWIND_ALL_BUT_RIGHT_RULE l behaves as follows:
A |- !z1 ... zr.
t =
(?l1 ... lp. t1 /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn)
---------------------------------------------------------------------
A |- !z1 ... zr.
t =
(?l1 ... lp. t1' /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn')
where ti' (for 1 <= i <= n) is ti rewritten with the equations
eqni (1 <= i <= m). These equations are those conjuncts with line
name not in l (and which are equations).
Failure
Fails if the argument theorem is not of the required form, though either
or both of p and r may be zero. May loop indefinitely.
Example
#UNWIND_ALL_BUT_RIGHT_RULE [`l2`]
# (ASSUME
# "!f. IMP(f) =
# ?l2 l1.
# (!(x:num). l1 x = (l2 x) - 1) /\
# (!x. f x = (l2 (x+1)) + (l1 (x+2))) /\
# (!x. l2 x = 7)");;
. |- !f.
IMP f =
(?l2 l1.
(!x. l1 x = (l2 x) - 1) /\
(!x. f x = (l2(x + 1)) + ((l2(x + 2)) - 1)) /\
(!x. l2 x = 7))
See also
unwindLib.UNWIND_AUTO_RIGHT_RULE,
unwindLib.UNWIND_ALL_BUT_CONV,
unwindLib.UNWIND_AUTO_CONV,
unwindLib.UNWIND_ONCE_CONV,
unwindLib.UNWIND_CONV
UNWIND_AUTO_CONV
UNWIND_AUTO_CONV
unwindLib.UNWIND_AUTO_CONV : conv
Automatic unwinding of equations defining wire values in a standard device specification.
UNWIND_AUTO_CONV "?l1 ... lm. t1 /\ ... /\ tn" returns a theorem of
the form:
|- (?l1 ... lm. t1 /\ ... /\ tn) = (?l1 ... lm. t1' /\ ... /\ tn')
where tj' is tj rewritten with equations selected from the ti's.
The function decides which equations to use for rewriting by performing a loop analysis on the graph representing the dependencies of the lines. By this means the term can be unwound as much as possible without the risk of looping. The user is left to deal with the recursive equations.
Failure
Fails if there is more than one equation for any line variable.
Example
#UNWIND_AUTO_CONV
# "(!(x:num). l1 x = (l2 x) - 1) /\
# (!x. f x = (l2 (x+1)) + (l1 (x+2))) /\
# (!x. l2 x = 7)";;
|- (!x. l1 x = (l2 x) - 1) /\
(!x. f x = (l2(x + 1)) + (l1(x + 2))) /\
(!x. l2 x = 7) =
(!x. l1 x = 7 - 1) /\ (!x. f x = 7 + (7 - 1)) /\ (!x. l2 x = 7)
See also
unwindLib.UNWIND_ONCE_CONV,
unwindLib.UNWIND_CONV,
unwindLib.UNWIND_ALL_BUT_CONV,
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE,
unwindLib.UNWIND_AUTO_RIGHT_RULE
UNWIND_AUTO_RIGHT_RULE
UNWIND_AUTO_RIGHT_RULE
unwindLib.UNWIND_AUTO_RIGHT_RULE : (thm -> thm)
Automatic unwinding of equations defining wire values in a standard device specification.
UNWIND_AUTO_RIGHT_RULE behaves as follows:
A |- !z1 ... zr. t = ?l1 ... lm. t1 /\ ... /\ tn
----------------------------------------------------
A |- !z1 ... zr. t = ?l1 ... lm. t1' /\ ... /\ tn'
where tj' is tj rewritten with equations selected from the ti's.
The function decides which equations to use for rewriting by performing a loop analysis on the graph representing the dependencies of the lines. By this means the term can be unwound as much as possible without the risk of looping. The user is left to deal with the recursive equations.
Failure
Fails if there is more than one equation for any line variable, or if
the argument theorem is not of the required form, though either or both
of m and r may be zero.
Example
#UNWIND_AUTO_RIGHT_RULE
# (ASSUME
# "!f. IMP(f) =
# ?l2 l1.
# (!(x:num). l1 x = (l2 x) - 1) /\
# (!x. f x = (l2 (x+1)) + (l1 (x+2))) /\
# (!x. l2 x = 7)");;
. |- !f.
IMP f =
(?l2 l1.
(!x. l1 x = 7 - 1) /\ (!x. f x = 7 + (7 - 1)) /\ (!x. l2 x = 7))
See also
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE,
unwindLib.UNWIND_AUTO_CONV,
unwindLib.UNWIND_ALL_BUT_CONV,
unwindLib.UNWIND_ONCE_CONV,
unwindLib.UNWIND_CONV
UNWIND_CONV
UNWIND_CONV
unwindLib.UNWIND_CONV : ((term -> bool) -> conv)
Unwinds device behaviour using selected line equations until no change.
UNWIND_CONV p "t1 /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn" returns
a theorem of the form:
|- t1 /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn =
t1' /\ ... /\ eqn1 /\ ... /\ eqnm /\ ... /\ tn'
where ti' (for 1 <= i <= n) is ti rewritten with the equations
eqni (1 <= i <= m). These equations are the conjuncts for which the
predicate p is true. The ti terms are the conjuncts for which p is
false. The rewriting is repeated until no changes take place.
Failure
Never fails but may loop indefinitely.
Example
#UNWIND_CONV (\tm. mem (line_name tm) [`l1`;`l2`])
# "(!(x:num). l1 x = (l2 x) - 1) /\
# (!x. f x = (l2 (x+1)) + (l1 (x+2))) /\
# (!x. l2 x = 7)";;
|- (!x. l1 x = (l2 x) - 1) /\
(!x. f x = (l2(x + 1)) + (l1(x + 2))) /\
(!x. l2 x = 7) =
(!x. l1 x = (l2 x) - 1) /\ (!x. f x = 7 + (7 - 1)) /\ (!x. l2 x = 7)
See also
unwindLib.UNWIND_ONCE_CONV,
unwindLib.UNWIND_ALL_BUT_CONV,
unwindLib.UNWIND_AUTO_CONV,
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE,
unwindLib.UNWIND_AUTO_RIGHT_RULE
UNWIND_ONCE_CONV
UNWIND_ONCE_CONV
unwindLib.UNWIND_ONCE_CONV : ((term -> bool) -> conv)
Basic conversion for parallel unwinding of equations defining wire values in a standard device specification.
UNWIND_ONCE_CONV p tm unwinds the conjunction tm using the equations
selected by the predicate p. tm should be a conjunction, equivalent
under associative-commutative reordering to:
t1 /\ t2 /\ ... /\ tn
p is used to partition the terms ti for 1 <= i <= n into two
disjoint sets:
REW = {{ti | p ti}}
OBJ = {{ti | ~p ti}}
The terms ti for which p is true are then used as a set of rewrite
rules (thus they should be equations) to do a single top-down parallel
rewrite of the remaining terms. The rewritten terms take the place of
the original terms in the input conjunction. For example, if tm is:
t1 /\ t2 /\ t3 /\ t4
and REW = {{t1,t3}} then the result is:
|- t1 /\ t2 /\ t3 /\ t4 = t1 /\ t2' /\ t3 /\ t4'
where ti' is ti rewritten with the equations REW.
Failure
Never fails.
Example
> unwindLib.UNWIND_ONCE_CONV (fn tm => mem (unwindLib.line_name tm) [`l1`,`l2`])
“(!(x:num). l1 x = (l2 x) - 1) /\
(!x. f x = (l2 (x+1)) + (l1 (x+2))) /\
(!x. l2 x = 7)”;
Exception- Type error in function application.
Function: mem (unwindLib.line_name tm) : string list -> bool
Argument: [[QUOTE " (*#loc 1 69*)l1"], [QUOTE " (*#loc 1 74*)l2"]]
: 'a frag list list
Reason:
Can't unify string (*In Basis*) with 'a frag list (*In Basis*)
(Different type constructors)
Fail "Static Errors" raised
See also
unwindLib.UNWIND_CONV,
unwindLib.UNWIND_ALL_BUT_CONV,
unwindLib.UNWIND_AUTO_CONV,
unwindLib.UNWIND_ALL_BUT_RIGHT_RULE,
unwindLib.UNWIND_AUTO_RIGHT_RULE
wlog_tac
wlog_tac
wlogLib.wlog_tac : term quotation -> term quotation list -> tactic
Re-exported from bossLib.wlog_tac. See that
entry for full documentation.
wlog_then
wlog_then
wlogLib.wlog_then : term quotation -> term quotation list -> thm_tactic -> tactic
Re-exported from bossLib.wlog_then. See that
entry for full documentation.
BIT_ss
BIT_ss
wordsLib.BIT_ss : ssfrag
Simplification fragment for words.
The fragment BIT_ss rewrites the term “BIT i n” for ground n.
Example
> SIMP_CONV (std_ss++wordsLib.BIT_ss) [] “BIT i 33”;
val it = ⊢ BIT i 33 ⇔ i ∈ {0; 5}: thm
> SIMP_CONV (std_ss++wordsLib.BIT_ss) [] “BIT 5 33”;
val it = ⊢ BIT 5 33 ⇔ T: thm
See also
wordsLib.WORD_CONV,
fcpLib.FCP_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
BITS_INTRO_CONV
BITS_INTRO_CONV
wordsLib.BITS_INTRO_CONV : conv
Tries to convert terms of the form n MOD p, n MOD p DIV q and
(n DIV q) MOD p into a terms of the form BITS h l n. This will
succeed when p and q are powers of two.
Example
> wordsLib.BITS_INTRO_CONV “(n DIV 16) MOD 4”;
val it = ⊢ n DIV 16 MOD 4 = BITS 5 4 n: thm
> wordsLib.BITS_INTRO_CONV “n MOD 16 DIV 4”;
val it = ⊢ n MOD 16 DIV 4 = BITS 3 2 n: thm
> wordsLib.BITS_INTRO_CONV “n MOD 16”;
val it = ⊢ n MOD 16 = BITS 3 0 n: thm
> wordsLib.BITS_INTRO_CONV “n MOD dimword(:'a)”;
val it = ⊢ n MOD dimword (:α) = BITS (dimindex (:α) − 1) 0 n: thm
See also
BITS_INTRO_ss
BITS_INTRO_ss
wordsLib.BITS_INTRO_ss : ssfrag
Simplification fragment that applies the conversion BITS_INTRO_CONV.
See also
EXPAND_REDUCE_CONV
EXPAND_REDUCE_CONV
wordsLib.EXPAND_REDUCE_CONV : conv
The conversion EXPAND_REDUCE_CONV expands out applications of
reduce_and, reduce_or, reduce_xor, reduce_nand, reduce_nor and
reduce_xnor.
Example
> wordsLib.EXPAND_REDUCE_CONV “reduce_and (w: word4)”;
val it =
⊢ reduce_and w = (((3 >< 3) w && (2 >< 2) w) && (1 >< 1) w) && (0 >< 0) w:
thm
See also
guess_lengths
guess_lengths
wordsLib.guess_lengths : unit -> unit
Turns on word length guessing.
A call to guess_lengths adds a post-prcessing stage to the term
parser: the function inst_word_lengths is used to instantiate type
variables that are the return type of word_concat and word_extract.
Example
> show_types := true;
val it = (): unit
> val t1 = “(7 >< 5) a @@ (4 >< 0) a”;
val t1 =
“(((((7 :num) >< (5 :num)) (a :δ word) :α word) @@
(((4 :num) >< (0 :num)) a :β word))
:γ word)”: term
> wordsLib.guess_lengths();
val it = (): unit
> val t2 = “(7 >< 5) a @@ (4 >< 0) a”;
val t2 =
“(((((7 :num) >< (5 :num)) (a :δ word) :word3) @@
(((4 :num) >< (0 :num)) a :word5))
:word8)”: term
> type_of t2;
val it = “:word8”: hol_type
See also
wordsLib.inst_word_lengths,
wordsLib.notify_on_word_length_guess
Induct_word
Induct_word
wordsLib.Induct_word : tactic
Initiate an induction on the value of a word.
The tactic Induct_word makes use of the tactic
bossLib.recInduct wordsTheory.WORD_INDUCT.
Example
Given the goal
?- !w:word8. P w
one can apply Induct_word to begin a proof by induction.
> e wordsLib.Induct_word
Exception- OK..
HOL_ERR (at Induction.ndest_forall: too few quantified variables in goal) raised
This results in the base and step cases of the induction as new goals.
?- P 0w
[SUC n < 256, P (n2w n)] ?- P (n2w (SUC n))
See also
inst_word_lengths
inst_word_lengths
wordsLib.inst_word_lengths : term -> term
Guess and instantiate word index type variables in a term.
The function inst_word_lengths tries to instantiate type variables
that correspond with the return type of word_concat and
word_extract.
Example
> load "wordsLib";
val it = (): unit
> wordsLib.inst_word_lengths “(7 >< 5) a @@ (4 >< 0) a”;
val it = “(7 >< 5) a @@ (4 >< 0) a”: term
> type_of it;
val it = “:word8”: hol_type
Comments
The function guess_lengths adds inst_word_lengths as a
post-processing stage to the term parser.
See also
wordsLib.guess_lengths,
wordsLib.notify_on_word_length_guess
LESS_CONV
LESS_CONV
wordsLib.LESS_CONV : conv
Converts terms of the form n < m into
(n = m - 1) \/ ... \/ (n = 1) \/ (n = 0), provided that m is a
natural number literal.
Example
> wordsLib.LESS_CONV “n < 4n”;
val it = ⊢ n < 4 ⇔ n = 3 ∨ n = 2 ∨ n = 1 ∨ n = 0: thm
mk_word_size
mk_word_size
wordsLib.mk_word_size : int -> unit
Adds a type abbreviation and theorems for a given word length.
An invocation of mk_word_size n introduces a type abbreviation for
words of length n. Theorems for dimindex(:n), dimword(:n) and
INT_MIN(:n) are generated and stored.
Example
> wordsLib.mk_word_size 128
val it = (): unit
> “:word128”
val it = “:word128”: hol_type
> theorem "dimword_128"
val it = ⊢ dimword (:128) = 340282366920938463463374607431768211456: thm
Comments
The type abbreviation will only print when type_pp.pp_array_types is
set to false.
See also
Parse.type_abbrev,
wordsLib.SIZES_CONV,
wordsLib.SIZES_ss
n2w_INTRO_TAC
n2w_INTRO_TAC
wordsLib.n2w_INTRO_TAC : int -> tactic
The tactic n2w_INTRO_TAC i attempts to recast finite problems (over
num) of the form m = n, m < n and m <= n into problems over
bit-vectors of size i.
Example
Given the goal:
?- w2n (a: word4) + w2n (b: word4) < 32
applying
e (wordsLib.n2w_INTRO_TAC 6)
gives the new goal
[ w2n a < 16, w2n b < 16 ] ?- w2w a + w2w b <+ 32w
This goal can be solved using blastLib.BBLAST_TAC. Any word length
strictly greater than five would have sufficed here; it is generally
best to pick as small a word size as is necessary.
See also
notify_on_word_length_guess
notify_on_word_length_guess
wordsLib.notify_on_word_length_guess : bool ref
Controls notification of word length guesses.
When the reference notify_on_word_length_guess is true a HOL message
is printed (in interactive sessions) when the function
inst_word_lengths instantiates types in a term.
Example
> load "wordsLib";
val it = (): unit
> wordsLib.notify_on_word_length_guess := false;
val it = (): unit
> wordsLib.inst_word_lengths “(7 >< 5) a @@ (4 >< 0) a”;
val it = “(7 >< 5) a @@ (4 >< 0) a”: term
> type_of it;
val it = “:word8”: hol_type
Comments
By default notify_on_word_length_guess is true.
See also
wordsLib.guess_lengths,
wordsLib.inst_word_lengths
output_words_as_bin
output_words_as_bin
wordsLib.output_words_as_bin : unit -> unit
Makes word literals pretty-print as binary.
A call to output_words_as_bin will make word literals output in binary
format.
Example
> wordsLib.output_words_as_bin();
val it = (): unit
> EVAL “$FCP ODD : word8”;
val it = ⊢ $FCP ODD = 0b10101010w: thm
See also
wordsLib.remove_word_printer,
wordsLib.output_words_as_dec,
wordsLib.output_words_as_oct,
wordsLib.output_words_as_hex
output_words_as_dec
output_words_as_dec
wordsLib.output_words_as_dec : unit -> unit
Makes word literals pretty-print as decimal.
A call to output_words_as_dec will make word literals output in
decimal format.
Example
> “0x100000w”;
val it = “0b100000000000000000000w”: term
> wordsLib.output_words_as_dec();
val it = (): unit
> “0x100000w”;
val it = “1048576w”: term
See also
wordsLib.remove_word_printer,
wordsLib.output_words_as_hex,
wordsLib.output_words_as_bin,
wordsLib.output_words_as_oct
output_words_as_hex
output_words_as_hex
wordsLib.output_words_as_hex : unit -> unit
Makes word literals pretty-print as hexadecimal.
A call to output_words_as_hex will make word literals output in
hexadecimal format.
Example
> wordsLib.output_words_as_hex();
val it = (): unit
> EVAL “44w : word32 << 3”
val it = ⊢ 0x2Cw ≪ 3 = 0x160w: thm
See also
wordsLib.remove_word_printer,
wordsLib.output_words_as_dec,
wordsLib.output_words_as_bin,
wordsLib.output_words_as_oct
output_words_as_oct
output_words_as_oct
wordsLib.output_words_as_oct : unit -> unit
Makes word literals pretty-print as octal.
A call to output_words_as_oct will make word literals output in octal
format.
Example
> “032w:word5”;
val it = “0x20w”: term
> wordsLib.output_words_as_oct();
val it = (): unit
> “032w:word5”;
val it = “032w”: term
> wordsLib.output_words_as_dec();
val it = (): unit
> “032w:word5”;
val it = “26w”: term
Comments
Printing and parsing in octal is controlled by the reference
base_tokens.allow_octal_input. A call to output_words_as_oct sets
this value to true.
See also
wordsLib.remove_word_printer,
wordsLib.output_words_as_dec,
wordsLib.output_words_as_bin,
wordsLib.output_words_as_hex
remove_word_printer
remove_word_printer
wordsLib.remove_word_printer : unit -> unit
Turns off custom pretty-printing for word literals.
The function remove_word_printer calls Parse.remove_user_printer to
remove pretty-printing for ground instances of "n2w n". This will
normally mean that words output in decimal format.
Example
> load "wordsLib";
val it = (): unit
> “0x10000000w”;
val it = “268435456w”: term
> wordsLib.remove_word_printer();
val it = (): unit
> “0x10000000w”;
val it = “0x10000000w”: term
See also
Parse.remove_user_printer,
wordsLib.output_words_as,
wordsLib.output_words_as_dec,
wordsLib.output_words_as_bin,
wordsLib.output_words_as_oct,
wordsLib.output_words_as_hex
SIZES_CONV
SIZES_CONV
wordsLib.SIZES_CONV : conv
Evaluates dimindex, dimword and INT_MIN.
Example
> wordsLib.SIZES_CONV “dimword(:32)”
val it = ⊢ dimword (:32) = 4294967296: thm
Comments
Evaluations are stored and so will be slightly faster when repeated.
See also
SIZES_ss
SIZES_ss
wordsLib.SIZES_ss : ssfrag
Simplification fragment for words.
The fragment SIZES_ss evaluates terms “dimindex(:'a)”,
“dimword(:'a)”, “INT_MIN(:'a)”, and “FINITE (UNIV : 'a set)” for
numeric types.
Example
> SIMP_CONV (pure_ss++wordsLib.SIZES_ss) [] “dimindex(:32) + INT_MIN(:32) + dimword(:32)”
val it =
⊢ dimindex (:32) + INT_MIN (:32) + dimword (:32) =
32 + 2147483648 + 4294967296: thm
See also
wordsLib.SIZES_CONV,
wordsLib.WORD_CONV,
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_ARITH_CONV
WORD_ARITH_CONV
wordsLib.WORD_ARITH_CONV : conv
Conversion based on WORD_ARITH_ss and WORD_ARITH_EQ_ss.
The conversion WORD_ARITH_CONV converts word arithmetic expressions
into a canonical form.
Example
WORD_ARITH_CONV fixes the sign of equalities.
> SIMP_CONV (std_ss++wordsLib.WORD_ARITH_ss++wordsLib.WORD_ARITH_EQ_ss) [] “$- a = b : 'a word”
Exception- HOL_ERR
(at Preterm.type-analysis: at line 1, character 83:
Type error in function application.
Function: $= ($- a) :(α word -> α word) -> bool
Argument: b :α word
Reason: Attempt to unify different type operators: min$fun and fcp$cart
) raised
> wordsLib.WORD_ARITH_CONV “$- a = b : 'a word”
Exception- HOL_ERR
(at Preterm.type-analysis: at line 1, character 35:
Type error in function application.
Function: $= ($- a) :(α word -> α word) -> bool
Argument: b :α word
Reason: Attempt to unify different type operators: min$fun and fcp$cart
) raised
Comments
The fragment WORD_ARITH_EQ_ss and conversion WORD_CONV do not adjust
the sign of equalities.
See also
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_CONV,
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_EVAL_CONV
WORD_ARITH_EQ_ss
WORD_ARITH_EQ_ss
wordsLib.WORD_ARITH_EQ_ss : ssfrag
Simplification fragment for words.
The fragment WORD_ARITH_EQ_ss simplifies “a = b : 'a word” to
“a - b = 0w”. It also simplifies using the theorems
WORD_LEFT_ADD_DISTRIB, WORD_RIGHT_ADD_DISTRIB, WORD_MUL_LSL and
WORD_NOT. When combined with wordsLib.WORD_ARITH_ss this fragment
can be used to test for the arithmetic equality of words.
Example
> SIMP_CONV (pure_ss++wordsLib.WORD_ARITH_ss++wordsLib.WORD_ARITH_EQ_ss) [] “3w * (a + b) = b + 3w * a”
val it = ⊢ 3w * (a + b) = b + 3w * a ⇔ 2w * b = 0w: thm
Comments
This fragment is not included in WORDS_ss.
See also
wordsLib.WORD_ARITH_CONV,
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_ARITH_ss
WORD_ARITH_ss
wordsLib.WORD_ARITH_ss : ssfrag
Simplification fragment for words.
The fragment WORD_ARITH_ss does AC simplification for word
multiplication, addition and subtraction. It also simplifies INT_MINw,
INT_MAXw and UINT_MAXw. If the word length is known then further
simplification may occur, in particular for $- (n2w n) and
w2n (n2w n).
Example
> SIMP_CONV (pure_ss++wordsLib.WORD_ARITH_ss) [] “3w * b + a + 2w * b - a * 4w”
val it = ⊢ 3w * b + a + 2w * b − a * 4w = -3w * a + 5w * b: thm
> SIMP_CONV (pure_ss++wordsLib.WORD_ARITH_ss) [] “INT_MINw + INT_MAXw + UINT_MAXw”
val it = ⊢ INT_MINw + INT_MAXw + UINT_MAXw = -2w: thm
More simplification occurs when the word length is known.
> SIMP_CONV (pure_ss++wordsLib.WORD_ARITH_ss) [] “3w * b + a + 2w * b - a * 4w:word2”
val it = ⊢ 3w * b + a + 2w * b − a * 4w = a + b: thm
> SIMP_CONV (pure_ss++wordsLib.WORD_ARITH_ss) [] “w2n (33w:word4)”;
val it = ⊢ w2n 33w = 1: thm
Comments
Any term of value UINT_MAXw simplifies to $- 1w even when the word
length is known - this helps when simplifying bitwise operations. If the
word length is not known then INT_MAXw becomes INT_MINw + $- 1w.
See also
wordsLib.WORD_ARITH_CONV,
wordsLib.WORD_CONV,
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_BIT_EQ_CONV
WORD_BIT_EQ_CONV
wordsLib.WORD_BIT_EQ_CONV : conv
Conversion based on WORD_BIT_EQ_ss.
The conversion WORD_BIT_EQ_CONV performs simplification using
fcpLib.FCP_ss.
Example
> wordsLib.WORD_BIT_EQ_CONV “a << 2 >>> 1 = ((5 -- 0) a << 1) :word8”
val it = ⊢ a ≪ 2 ⋙ 1 = (5 -- 0) a ≪ 1 ⇔ T: thm
See also
wordsLib.WORD_BIT_EQ_ss,
blastLib.BBLAST_CONV,
wordsLib.WORD_ARITH_CONV,
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_CONV,
wordsLib.WORD_EVAL_CONV
WORD_BIT_EQ_ss
WORD_BIT_EQ_ss
wordsLib.WORD_BIT_EQ_ss : ssfrag
Simplification fragment for words.
The fragment WORD_BIT_EQ_ss simplifies using fcpLib.FCP_ss and the
definitions of "bitwise" operations, e.g., conjunction, disjunction, 1's
complement, shifts, concatenation and sub-word extraction. Can be used
in combination with decision procedures to test for the bitwise equality
of words.
Example
> SIMP_CONV (std_ss++wordsLib.WORD_BIT_EQ_ss) [] “a = b : 'a word”
val it = ⊢ a = b ⇔ ∀i. i < dimindex (:α) ⇒ (a ' i ⇔ b ' i): thm
Further simplification occurs when the word length is known.
> SIMP_CONV (std_ss++wordsLib.WORD_BIT_EQ_ss) [] “a = b : word2”
val it = ⊢ a = b ⇔ (a ' 1 ⇔ b ' 1) ∧ (a ' 0 ⇔ b ' 0): thm
Best used in combination with decision procedures.
> (SIMP_CONV (std_ss++wordsLib.WORD_BIT_EQ_ss) [] THENC tautLib.TAUT_CONV) “a && b && a = a && b”
val it = ⊢ a && b && a = a && b ⇔ T: thm
Comments
This fragment is not included in WORDS_ss.
See also
wordsLib.WORD_BIT_EQ_CONV,
fcpLib.FCP_ss,
blastLib.BBLAST_CONV,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_CANCEL_CONV
WORD_CANCEL_CONV
wordsLib.WORD_CANCEL_CONV : conv
Conversion that forms the basis of wordsLib.WORD_CANCEL_ss.
See also
WORD_CANCEL_ss
WORD_CANCEL_ss
wordsLib.WORD_CANCEL_ss : ssfrag
Simplification fragment for words.
The fragment WORD_CANCEL_ss helps simplify linear equations over
bit-vectors. This fragment is designed to work in concert with
wordsLib.WORD_ARITH_ss. The procedure will endeavour to ensure that
all coefficients appear in positive form. Furthermore, the leftmost
coefficient will be highest on the left-hand side of equations.
Example
> SIMP_CONV (pure_ss++wordsLib.WORD_ARITH_ss++wordsLib.WORD_CANCEL_ss) []
“-3w * b + a = -2w * a + b: word32”;
val it = ⊢ -3w * b + a = -2w * a + b ⇔ 4w * b = 3w * a: thm
Comments
This fragment can be viewed as a superior version of
wordsLib.WORD_ARITH_EQ_ss.
See also
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_ARITH_EQ_ss
WORD_CONV
WORD_CONV
wordsLib.WORD_CONV : conv
Conversion for words.
The conversion WORD_CONV applies the simpset fragment WORD_ss.
Example
> wordsLib.WORD_CONV “c * (a + b) !! (b + a) * c”
val it = ⊢ c * (a + b) ‖ (b + a) * c = a * c + b * c: thm
See also
wordsLib.WORD_ss,
wordsLib.WORD_ARITH_CONV,
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_EVAL_CONV
WORD_DECIDE
WORD_DECIDE
wordsLib.WORD_DECIDE : conv
A decision procedure for words.
The conversion WORD_DECIDE is the same as
WORD_DP WORD_CONV bossLib.DECIDE.
Example
> wordsLib.WORD_DECIDE “a && (b !! a) = a !! a && b”
val it = ⊢ a && (b ‖ a) = a ‖ a && b: thm
> wordsLib.WORD_DECIDE “a + 2w <+ 4w = a <+ 2w \/ 13w <+ a :word4”
Exception- Don't expect to find a = in this position after a <+
at line 1, character 37 and on line 1, characters 31-32.
HOL_ERR
(at Absyn.Absyn: on line 1, characters 31-32:
Don't expect to find a = in this position after a <+
at line 1, character 37 and on line 1, characters 31-32.
) raised
> wordsLib.WORD_DECIDE “a < 0w = 1w <+ a : word2”
Exception- Don't expect to find a = in this position after a <
at line 1, character 31 and at line 1, character 26.
HOL_ERR
(at Absyn.Absyn: at line 1, character 26:
Don't expect to find a = in this position after a <
at line 1, character 31 and at line 1, character 26.
) raised
> wordsLib.WORD_DECIDE “(?w:word4. 14w <+ w) /\ ~(?w:word4. 15w <+ w)”
val it = ⊢ (∃w. 14w <₊ w) ∧ ¬∃w. 15w <₊ w: thm
See also
WORD_DECIDE_TAC
WORD_DECIDE_TAC
wordsLib.WORD_DECIDE_TAC : tactic
A decision procedure tactic for words.
WORD_DECIDE_TAC is a tactical verion of WORD_DECIDE.
Failure
As for WORD_DECIDE.
See also
WORD_DIV_LSR_CONV
WORD_DIV_LSR_CONV
wordsLib.WORD_DIV_LSR_CONV : conv
The conversion WORD_DIV_LSR_CONV replaces instances of unsigned
division by a power of two with applications of logical right-shift.
Example
> wordsLib.WORD_DIV_LSR_CONV “w // 8w : word8”;
val it = ⊢ w // 8w = w ⋙ 3: thm
Comments
This conversion requires the word length to be known.
See also
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_MOD_BITS_CONV
WORD_DP
WORD_DP
wordsLib.WORD_DP : conv -> conv -> conv
Constructs a decision procedure for words.
The conversion WORD_DP conv dp is a decision procedure for words that
makes use of the supplied conversion conv and decision procedure dp.
Suitable decision procedures include tautLib.TAUT_PROVE,
bossLib.DECIDE, intLib.ARITH_PROVE and intLib.COOPER_PROVE. The
procedure will first apply conv and then WORD_BIT_EQ_CONV. If this
is not sufficient then an attempt is made to solve the problem by
applying an arithmetic decision procedure dp,
e.g. “(a = 0w) \/ (a = 1w :1 word)” is mapped to the goal
“w2n a < 2 ==> (w2n a = 0) \/ (w2n a = 1)”.
Failure
The invocation will fail when the decision procedure dp fails.
Example
> wordsLib.WORD_DP ALL_CONV tautLib.TAUT_PROVE “a && b && a = a && b”
val it = ⊢ a && b && a = a && b: thm
> wordsLib.WORD_DP ALL_CONV DECIDE “a < b /\ b < c ==> a < c : 'a word”
val it = ⊢ a < b ∧ b < c ⇒ a < c: thm
> wordsLib.WORD_DP ALL_CONV intLib.ARITH_PROVE “a <+ 3w:word16 ==> (a = 0w) \/ (a = 1w) \/ (a = 2w)”
val it = ⊢ a <₊ 3w ⇒ a = 0w ∨ a = 1w ∨ a = 2w: thm
Comments
On large problems intLib.ARITH_PROVE will perform much better than
bossLib.DECIDE.
See also
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_DECIDE
WORD_EVAL_CONV
WORD_EVAL_CONV
wordsLib.WORD_EVAL_CONV : conv
Evaluation for words.
The conversion WORD_EVAL_CONV provides efficient evaluation for word
operations. It uses wordsLib.words_compset.
Example
> wordsLib.WORD_EVAL_CONV “word_log2 (word_reverse (3w * (33w #<< 4))) : word32”
val it = ⊢ word_log2 (word_reverse (3w * 33w ⇆ 4)) = 27w: thm
Comments
This conversion is best suited to evaluating ground terms with known
word lengths. The conversion wordsLib.WORD_CONV is a suitable
alternative.
See also
bossLib.EVAL,
computeLib.CBV_CONV,
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_CONV,
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_EVAL_CONV
WORD_EXTRACT_ss
WORD_EXTRACT_ss
wordsLib.WORD_EXTRACT_ss : ssfrag
Simplification fragment for words.
The fragment WORD_EXTRACT_ss simplifies the operations w2w, sw2sw
(signed word-to-word conversion), word_lsb, word_msb, word_bit,
>> (arithmetic right shift), >>> (logical right shift), #>>
(rotate right), #<< (rotate left), @@ (concatenation), -- (word
bits) and '' (word slice). The result is expressed in terms of !!
(disjunction), << (left shift) and >< (word extract).
Example
> SIMP_CONV (std_ss++wordsLib.WORD_ss++wordsLib.WORD_EXTRACT_ss) [] “(((7 >< 5) (a:word8)):3 word @@ ((4 >< 0) a):5 word) : word8”
val it = ⊢ (7 >< 5) a @@ (4 >< 0) a = a: thm
> SIMP_CONV (std_ss++wordsLib.WORD_ss++wordsLib.WORD_EXTRACT_ss) [] “(4 -- 2) ((a:word8) #>> 4)”
val it = ⊢ (4 -- 2) (a ⇄ 4) = (0 >< 0) a ≪ 2 ‖ (7 >< 6) a: thm
> SIMP_CONV (std_ss++wordsLib.WORD_ss++wordsLib.WORD_EXTRACT_ss) [] “w2w (sw2sw (a:word4):word8):word4”
val it = ⊢ w2w (sw2sw a) = a: thm
Comments
Best used in combination with WORD_ss.
See also
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_LOGIC_CONV
WORD_LOGIC_CONV
wordsLib.WORD_LOGIC_CONV : conv
Conversion based on WORD_LOGIC_ss.
The conversion WORD_LOGIC_CONV converts word logic expressions into a
canonical form.
Example
> wordsLib.WORD_LOGIC_CONV “a && (b !! ~a !! c)”
val it = ⊢ a && (b ‖ ¬a ‖ c) = a && b ‖ a && c: thm
See also
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_ARITH_CONV,
wordsLib.WORD_MUL_LSL_CONV,
wordsLib.WORD_CONV,
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_EVAL_CONV
WORD_LOGIC_ss
WORD_LOGIC_ss
wordsLib.WORD_LOGIC_ss : ssfrag
Simplification fragment for words.
The fragment WORD_LOGIC_ss does AC simplification for word
conjunction, disjunction and 1's complement (negation). If the word
length is known then further simplification occurs, in particular for
~(n2w n).
Example
> SIMP_CONV (pure_ss++wordsLib.WORD_LOGIC_ss) [] “3w !! 12w && a !! ~4w !! a && 16w”
val it = ⊢ 3w ‖ 12w && a ‖ ¬4w ‖ a && 16w = 28w && a ‖ -5w: thm
More simplification occurs when the word length is known.
> SIMP_CONV (pure_ss++wordsLib.WORD_LOGIC_ss) [] “~12w !! ~14w : word8”
val it = ⊢ ¬12w ‖ ¬14w = 243w: thm
Comments
The term $- 1w represents UINT_MAXw, which is the supremum in
bitwise operations.
See also
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_CONV,
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_MOD_BITS_CONV
WORD_MOD_BITS_CONV
wordsLib.WORD_MOD_BITS_CONV : conv
The conversion WORD_MOD_BITS_CONV replaces instances of word_mod by
a power of two with applications of word_bits.
Example
> wordsLib.WORD_MOD_BITS_CONV “word_mod w 8w : word16”;
val it = ⊢ word_mod w 8w = (2 -- 0) w: thm
Comments
This conversion requires the word length to be known.
See also
wordsLib.WORD_DIV_LSR_CONV,
wordsLib.BITS_INTRO_CONV
WORD_MUL_LSL_CONV
WORD_MUL_LSL_CONV
wordsLib.WORD_MUL_LSL_CONV : conv
Conversion based on WORD_MUL_LSL_ss.
The conversion WORD_MUL_LSL_CONV converts a multiplication by a word
literal into a sum of left shifts.
Example
> wordsLib.WORD_MUL_LSL_CONV “49w * a”
val it = ⊢ 49w * a = a ≪ 5 + a ≪ 4 + a: thm
See also
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_DIV_LSR_CONV,
wordsLib.WORD_ARITH_CONV,
wordsLib.WORD_LOGIC_CONV,
wordsLib.WORD_CONV,
wordsLib.WORD_BIT_EQ_CONV,
wordsLib.WORD_EVAL_CONV
WORD_MUL_LSL_ss
WORD_MUL_LSL_ss
wordsLib.WORD_MUL_LSL_ss : ssfrag
Simplification fragment for words.
The fragment WORD_MUL_LSL_ss simplifies a multiplication by a word
literal into a sum of left shifts.
Example
> SIMP_CONV (std_ss++wordsLib.WORD_MUL_LSL_ss) [] “49w * a”
val it = ⊢ 49w * a = a ≪ 5 + a ≪ 4 + a: thm
> SIMP_CONV (std_ss++wordsLib.WORD_ss++wordsLib.WORD_MUL_LSL_ss) [] “2w * a + a << 1”
val it = ⊢ 2w * a + a ≪ 1 = a ≪ 2: thm
Comments
This fragment is not included in WORDS_ss. It should not be used in
combination with WORD_ARITH_EQ_ss or wordsLib.WORD_ARITH_CONV, since
these convert left shifts into multiplications.
See also
wordsLib.WORD_MUL_LSL_CONV,
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_ss
WORD_SHIFT_ss
WORD_SHIFT_ss
wordsLib.WORD_SHIFT_ss : ssfrag
Simplification fragment for words.
The fragment WORD_SHIFT_ss does some basic simplifications for the
operations: << (left shift), >> (arithmetic right shift), >>>
(logical right shift), #>> (rotate right) and #<< (rotate left).
More simplification is possible when used in combination with
wordsLib.SIZES_ss.
Example
> SIMP_CONV (std_ss++wordsLib.WORD_SHIFT_ss) [] “a << 2 << 3 + a >> 3 >> 2 + a >>> 1 >>> 2 + a #<< 1 #<< 2”
val it =
⊢ a ≪ 2 ≪ 3 + a ≫ 3 ≫ 2 + a ⋙ 1 ⋙ 2 + a ⇆ 1 ⇆ 2 =
a ≪ 5 + a ≫ 5 + a ⋙ 3 + a ⇆ 3: thm
> SIMP_CONV (std_ss++wordsLib.WORD_SHIFT_ss) [] “a >> 0 + 0w << n + a #<< 2 #>> 2”
val it = ⊢ a ≫ 0 + 0w ≪ n + a ⇆ 2 ⇄ 2 = a + 0w + a: thm
More simplification is possible when the word length is known.
> SIMP_CONV (std_ss++wordsLib.SIZES_ss++wordsLib.WORD_SHIFT_ss) [] “a << 4 + (a #<< 6) : word4”
val it = ⊢ a ≪ 4 + a ⇆ 6 = 0w + a ⇆ 2: thm
Comments
When the word length is known the fragment WORD_ss simplifies #<< to
#>>.
See also
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss,
wordsLib.WORD_ss
WORD_ss
WORD_ss
wordsLib.WORD_ss : ssfrag
Simplification fragment for words.
The fragment WORD_ss contains BIT_ss, SIZES_ss, WORD_LOGIC_ss,
WORD_ARITH_ss and WORD_SHIFT_ss. It also performs ground term
evaluation.
Example
> SIMP_CONV (pure_ss++wordsLib.WORD_ss) [] “BIT i 42”
val it = ⊢ BIT i 42 ⇔ i ∈ {1; 3; 5}: thm
> SIMP_CONV (pure_ss++wordsLib.WORD_ss) [] “dimword(:42)”
val it = ⊢ dimword (:42) = 4398046511104: thm
> SIMP_CONV (pure_ss++wordsLib.WORD_ss) [] “((a #<< 2 #>> 2 + a) && $- 1w) - a”
Exception- HOL_ERR
(at Preterm.type-analysis: on line 1, characters 69-72:
Type error in function application.
Function: $&& (a ⇆ 2 ⇄ 2 + a) :α word -> α word
Argument: $- 1w :α word -> α word
Reason: Attempt to unify different type operators: fcp$cart and min$fun
) raised
> SIMP_CONV (pure_ss++wordsLib.WORD_ss) [] “(4 -- 2) ($- 1w : word8)”
Exception- HOL_ERR
(at Preterm.type-analysis: on line 1, characters 55-58:
Type constraint failure:
Term: $- 1w :α word -> α word
Constraint: :word8
) raised
Comments
The WORD_ss fragment does not include WORD_ARITH_EQ_ss,
WORD_BIT_EQ_ss, WORD_EXTRACT_ss or WORD_MUL_LSL_ss. These extra
fragments have more specialised applications.
See also
wordsLib.WORD_CONV,
fcpLib.FCP_ss,
wordsLib.BIT_ss,
wordsLib.SIZES_ss,
wordsLib.WORD_ARITH_ss,
wordsLib.WORD_LOGIC_ss,
wordsLib.WORD_ARITH_EQ_ss,
wordsLib.WORD_BIT_EQ_ss,
wordsLib.WORD_SHIFT_ss,
wordsLib.WORD_EXTRACT_ss,
wordsLib.WORD_MUL_LSL_ss
WORD_SUB_CONV
WORD_SUB_CONV
wordsLib.WORD_SUB_CONV : conv
The conversion WORD_SUB_CONV is designed to eliminate occurrences of
multiplication by a negative coefficient, introducing unary-minus (2's
complement) and subtraction wherever possible.
Example
> wordsLib.WORD_SUB_CONV “a + -3w * b + -1w * c = -1w * d + e: 'a word”;
val it = ⊢ a + -3w * b + -1w * c = -1w * d + e ⇔ a − 3w * b − c = e − d: thm
> wordsLib.WORD_SUB_CONV “-1w * a: 'a word”;
val it = ⊢ -1w * a = -a: thm
Comments
This conversion forms the basis of wordsLib.WORD_SUB_ss. Care should
be taken when using this conversion in combination with other bit-vector
tools. For example, wordsLib.WORD_ARITH_CONV will undo all of the work
of WORD_SUB_CONV.
See also
WORD_SUB_ss
WORD_SUB_ss
wordsLib.WORD_SUB_ss : ssfrag
Simplification fragment for words.
The fragment WORD_SUB_ss applies the conversion
wordsLib.WORD_SUB_CONV.
Comments
This fragment should not be used in combination with
wordsLib.WORD_ARITH_ss, which also excludes use with
wordsLib.WORD_ss and srw_ss.