At this point, we have defined the operators for the first-order logic. To complete the constructive version of the logic, we still need two structural rules: weakening and cut. Weakening provides thinning of hypotheses, and the cut rule allows lemma introduction.
The interface for the structural rules declares the tactics for the module. We need three tactics,
1. Declare the tactics in the interface fol_struct.mli:
open Refiner.Refiner.TermType open Tacticals val nthHypT : int -> tactic val thinT : int -> tactic val assertT : term -> tactic
The module Refiner.Refiner.TermType defines the term type, and the Tacticals module defines the tactic type.
The hypothesis rule proves a goal by assumption.
2. Define the hypothesis rule in the fol_struct.ml file:
prim hypothesis 'H 'J 'x : : sequent ['ext] { 'H; x: 'T; 'J['x] >- 'T } = 'x
The hypothesis rule illustrates the use of equality patterns. When this rule is applied, the two terms matched by the variable 'T must be alpha-equal.
The tactic for hypothesis is just a wrapper for computing the hypothesis indices.
3. Define the nthHypT tactic:
let nthHypT i p = let v, _ = Sequent.nth_hyp p i in let j, k = Sequent.hyp_indices p i in hypothesis j k v p
Reasoning with nthHypT occurs at the leaves of most proofs in FOL, and it is useful to add this tactic to trivialT reasoning.
4. Add the nthHypT tactic to the trivial resource:
let trivial_resource = trivial_resource.resource_improve trivial_resource (**) { auto_name = "nthHypT"; auto_prec = trivial_prec; auto_tac = onSomeHypT nthHypT }
The thinning rule thins a hypothesis (weakening the goal). The rule for thinning produces arbitrary thinning--application of the rule may produce a free variable.
5. Define the rule for thinning in the file fol_struct.ml:
prim thin 'H 'J : ('t : sequent ['ext] { 'H; 'J['x] >- 'C['x] }) --> sequent ['ext] { 'H; x: 'T; 'J['x] >- 'C['x] } = 't
The introduction of a free variable by the thinning rule is logically valid. The semantics of the logic provides no specific interpretation of free variables, and there are no rules for reasoning about free variables. Still, introduction of free variables with the thinning rule is usually a mistake. The tactic for thinning should check before apply the rule.
6. Define the tactic for thinning:
let thinT i p = let x, _ = Sequent.nth_hyp p i in if Sequent.is_free_seq_var i x p then raise (RefineError ("thinT", StringStringError ("free variable: ", x))) else let i, j = Sequent.hyp_indices p i in thin i j p
The cut rule introduces a lemma, provided as an argument to the cut rule. The proof term for the rule substitutes the lemma proof for the lemma assumption.
7. Define the cut rule:
prim cut 'H 'T 'x : ('a : sequent ['ext] { 'H >- 'T }) --> ('b['x] : sequent ['ext] { 'H; x: 'T >- 'C }) --> sequent ['ext] { 'H >- 'C } = 'b['a]
The tactic for the cut rule is just a wrapper for producing a new variable for the hypothesis.
8. Define the assertT tactic:
let assertT t p = let v = Var.maybe_new_vars1 p "v" in cut (Sequent.hyp_count_addr p) t v p