10.2 Semantic

10.2.1 Values

Values are given by table 10.3. All these values are tactic values, i.e. to be applied to a goal, except Fun, Rec and arg values.


6in
vexpr
::=
vexpr ; vexpr
 
|
vexpr ; [ (vexpr |)* vexpr ]
 
|
vatom
 
vatom
::=
Fun input_fun+ -> expr
 
|
Rec rec_clause
 
|
Rec (rec_clause And)* rec_clause In expr
 
|
Match Context With (context_rule |)* context_rule
 
|
( vexpr )
 
|
vatom Orelse vatom
 
|
Do (int | ident) vatom
 
|
Repeat vatom
 
|
Try vatom
 
|
First [ (vexpr |)* vexpr ]
 
|
Solve [ (vexpr |)* vexpr ]
 
|
Idtac
 
|
Fail
 
|
primitive_tactic
 
|
arg

Table 10.3: Values of Ltac


10.2.2 Evaluation

Local definitions

Local definitions can be done as follows:





Let ident1 = expr1
And ident2 = expr2
...
And identn = exprn In
expr

expri is evaluated to vi, then, expr is evaluated by subsituting vi to each occurrence of identi, for i=1,...,n. There is no dependencies between the expri and the identi.

Pattern matching on terms

We can carry out pattern matching on terms with:



Match term With
   term1 -> expr1
 | term2 -> expr2
 ...
 | termn -> exprn
 | _ -> exprn+1

if term is matched (non-linear first order unification) by term1 then expr1 is evaluated by substituting the pattern matching instantiations to the metavariables. Else, term2 is tried and so on. If no termi, with i=1,...,n, matches term then the last clause is used and exprn+1 is evaluated.
Error message:
No matching clauses for Match

    No pattern can be used and, in particular, there is no _ pattern.

Application

An application is an expression of the following form:
( expr expr1 ... exprn )
expr is evaluated to v and expri is evaluated to vi, for i=1,...,n. If expr is a Fun or Rec value then the body is evaluated by substituting vi to the formal parameters, for i=1,...,n. For recursive clauses, the bodies are lazily substituted (when an identifier to be evaluated is the name of a recursive clause).

10.2.3 Application of tactic values

Sequence

A sequence is an expression of the following form:
expr1 ; expr2
expr1 and expr2 are evaluated to v1 and v2. v1 and v2 must be tactic values. v1 is then applied and v2 is applied to the subgoals generated by the application of v1. Sequence is left associating.

General sequence

We can generalize the previous sequence operator by:
expr0 ; [ expr1 | ... | exprn ]
expri is evaluated to vi, for i=0,...,n. v0 is applied and vi is applied to the i-th generated subgoal by the application of v0, for =1,...,n. It fails if the application of v0 does not generate exactly n subgoals.

Branching

We can easily branch with the following structure:
expr1 Orelse expr2
expr1 and expr2 are evaluated to v1 and v2. v1 and v2 must be tactic values. v1 is applied and if it fails then v2 is applied. Branching is left associating.

For loop

We have a for loop with:
Do n expr
expr is evaluated to v. v must be a tactic value. v is applied n times. Supposing n>1, after the first application of v, v is applied, at least once, to the generated subgoals and so on. It fails if the application of v fails before the n applications have been completed.

Repeat loop

We have a repeat loop with:
Repeat expr
expr is evaluated to v. v must be a tactic value. v is applied until it fails. Supposing n>1, after the first application of v, v is applied, at least once, to the generated subgoals and so on. It stops when it fails for all the generated subgoals. It never fails.

Error catching

We can catch the tactic errors with:
Try expr
expr is evaluated to v. v must be a tactic value. v is applied. If the application of v fails, it catches the error and leaves the goal unchanged. It never fails.

First tactic to work

We may consider the first tactic to work (i.e. which does not fail) among a panel of tactics:
First [ expr1 | ... | exprn ]
expri are evaluated to vi and vi must be tactic values, for i=1,...,n. Supposing n>1, it applies v1, if it works, it stops else it tries to apply v2 and so on. It fails when there is no applicable tactic.
Error message:
No applicable tactic

Solving

We may consider the first to solve (i.e. which generates no subgoal) among a panel of tactics:
Solve [ expr1 | ... | exprn ]
expri are evaluated to vi and vi must be tactic values, for i=1,...,n. Supposing n>1, it applies v1, if it solves, it stops else it tries to apply v2 and so on. It fails if there is no solving tactic.
Error message:
Cannot solve the goal

Identity

We have the identity tactic:
Idtac
It leaves the goal unchanged but it appears in the proof script.

Failing

We have the failing tactic:
Fail
It always fails and leaves the goal unchanged. It does not appear in the proof script and can be catched by Try.

Error message:
Fail tactic always fails (level n).

Pattern matching on proof contexts

We can make pattern matching on proof contexts using the following expression:

Match Context With
   [context_hyps1,1;...;context_hyps1,m1   |-term1] -> expr1
  |[context_hyps2,1;...;context_hyps2,m2   |-term2] -> expr2
  ...
  |[context_hypsn,1;...;context_hypsn,mn   |-termn] -> exprn
  |_    -> exprn+1

If each hypothesis pattern context_hyps1,i, with i=1,...,m1 is matched (non-linear first order unification) by an hypothesis of the goal and if term1 is matched by the conclusion of the goal, then expr1 is evaluated to v1 by substituting the pattern matching to the metavariables and the real hypothesis names bound to the possible hypothesis names occurring in the hypothesis patterns. If v1 is a tactic value, then it is applied to the goal. If this application fails, then another combination of hypotheses is tried with the same proof context pattern. If there is no other combination of hypotheses then the second proof context pattern is tried and so on. If the next to last proof context pattern fails then exprn+1 is evaluated to vn+1 and vn+1 is applied.
Error message:
No matching clauses for Match Context

    No proof context pattern can be used and, in particular, there is no _ proof

    context pattern.

10.2.4 Tactic toplevel definitions

Basically, tactics toplevel definitions are made as follows:
Tactic Definition ident := expr
expr is evaluated to v and v is associated to ident. Next, every script is evaluated by substituting v to ident.

We can define functional definitions by:
Tactic Definition ident input_fun1 ... input_funn := expr
This definition is nothing else than syntactical sugar for:
Tactic Definition ident := Fun input_fun1 ... input_funn -> expr
Then, this definition is treated as above.

Finally, mutal recursive function definitions are possible with:

Recursive Tactic Definition
   ident1 input_fun1,1 ... input_fun1,m1  := expr1
And ident2 input_fun2,1 ... input_fun2,m2  := expr2
...
And identn input_funn,1 ... input_funn,mn  := exprn

This definition bloc is a set of simultaneous functional definitions (use of the same previous syntactical sugar) and the other scripts are evaluated as usual except that the substitutions are lazily carried out (when an identifier to be evaluated is the name of a recursive definition).