Declarations consist of
- Signature
- Set of clauses forming a covering of this signature
with
: an implicit sub-programwhere
: an explicit sub-program
- Rewrite rules generated by
Equations
are automatically registered in a hint database namedf
.- Usable with
autorewrite
. - Format:
f_clause_n_equation_k
- Usable with
An inductive graph will be generated (by default. Can be changed).
For example, here:
From Equations Require Import Equations.
Equations neg (b : bool) : bool :=
neg true := false;
neg false := true.
(* Equations generate this automatically *)
Print neg_graph.
(*
Inductive neg_graph : bool -> bool -> Set :=
neg_graph_equation_1 : neg_graph true false
| neg_graph_equation_2 : neg_graph false true.
Arguments neg_graph (b _)%bool_scope
*)
—
Signature pack a value with its index. —
Dependent types are also useful to turn partial functions into total functions by restricting their domain.
- Equations coq plugin manual
General
- Apparently, each case must have same number of arguments.
- Looks like arguments in
Context
doesn't agree withequations
. Equations?
: Use interactive proof mode to fill in holes instead ofProgram
obligations.- Axiom K
- Implicit arguments can be omitted from definition clauses
- But can also be given explicitly like
(A := B)
.
- But can also be given explicitly like
- Autogenerated stuff:
- nameind
- namegraph
- FunctionalEliminationname.
- Stuff for pattern matching:
|
,{ ... }
,with
,:=
,=>
Transparency/opacity
- Definitions made with
Equations
are opaque by default. - Can be changed globally for all definitions with
Set Equations Transparent
- Change for a single definition
- globally:
Global Transparent <name>
- locally:
Transparent <name>
- globally:
Empty pattern
!
is the empty pattern in Equations
Note: When writing { |!}
, make sure there is a space after {
. Otherwise it's syntax of a Coq record.
An example:
Equations hd {A: Type} (l: list A) (pf: l <> []): A :=
hd [] pf with pf eq_refl := { |!};
hd (a::l) _ := a.
Have not yet figured out how pf eq_refl
is appropriate here.
- pf would be a proof of a
x ≠ x
. Its proof cannot beeq_refl
. It would be like a function returningFalse
, I guess.
Holes
We can leave holes in the definition if needed. Each hole would generate a proof obligation. If Coq cannot resolve the obligations, we need to fulfill them. It would like in Program
-Next Obligation
.
—
An example where Coq can figure out all obligations by itself:
Equations equal (n m: nat): {n=m} + {n<>m} :=
equal O O := left eq_refl;
equal (S n) (S m) with equal n m := {
equal (S n) (S ?(n)) (left eq_refl) := left eq_refl;
equal (S n) (S m) (right _) := right _;
};
equal n m := right _.
?(n)
Syntax to allow for unification.
Equations eqt' {A: Type} (x y z: A) (pf1: x=y) (pf2: y=z): x=z :=
eqt' x ?(x) ?(x) eq_refl eq_refl := eq_refl.
Here the two ?(x)
-s gets values from y
and z
, and are unified with the value of x
.
From the manual:
The
?(x)
notation is essentially denoting that the pattern is not a candidate for refinement, as it is determined by another pattern. This particular patterns are called "inaccessible". When they are variables the inaccessibility annotation is optional.
–
Although this particular example could also have been just:
Equations eqt {A: Type} {x y z: A} (pf1: x=y) (pf2: y=z): x=z :=
eqt eq_refl eq_refl := eq_refl.
with
An example:
Equations unzip {A: Type} (l: list (A * A)): list A * list A :=
unzip [] := ([], []);
unzip (x :: l) with unzip l => {
unzip ((a,b)::l) (la, lb) := (a::la, b::lb)}.
Vectors
From Equations Require Import Equations.
Require Import Vector.
Import VectorNotations.
Arguments Vector.nil {A}.
Arguments Vector.cons {A} a {n} v: rename.
Equations vtail {A: Type} {n: nat}
(v: Vector.t A (S n))
: Vector.t A n :=
vtail (x::v) := v.
We didn't have to mention the case of empty vector because it was able to infer it.
Recursion
Following example to find diagonal vector a square matrix won't go through because Coq cannot see which argument is getting smaller:
(* Diagonal of a square matrix *)
Fail Equations diag {A: Type} {n: nat}
(v: Vector.t (Vector.t A n) n)
: Vector.t A n :=
diag [] := [];
diag ((x::v) :: v') :=
x :: (diag (vmap vtail v')).
(*
The command has indeed failed with message:
Cannot guess decreasing argument of fix.
*)
But if we use n
explicitly, somehow Equations
help Coq figure it out (unification is involved??):
Equations diag {A: Type} {n: nat}
(v: Vector.t (Vector.t A n) n)
: Vector.t A n :=
diag (n:=O) [] := [];
diag (n:=S _) ((x::v) :: v') :=
x :: (diag (vmap vtail v')).
Making primitive recursion explicit
Make well-foundedness explicit with wf
.
Instead of letting coq's default way to figure out decreasing argument in a recursive definition.
wf
allows Coq to have something more than just syntactic check to figure out decreasing argument in the definition.
Example (just for illustrative purposes. wf
is not needed here):
Equations id' (n: nat): nat by wf n lt :=
id' O := O;
id' (S n') := id n'.
This says that successive values of n
are related by the relation lt
.
Obligations are automatically inserted to show that lt next curr
holds all the way till the base case.
In this example, Coq can solve all obligations (n' < S n'
) automatically.
If the relation is heterogenous (ie, relates values of two different types, like (x: Vector.t A n) < (y: Vector.t A (S n))
, obligations would be less simple.
Derive
command of Equations
can be used to generate types that can help provide structure in such cases.
Derive NoConfusion for Vector.t.
(* NoConfusionPackage_t is defined *)
Derive Subterm for Vector.t.
(*
t_direct_subterm is defined
t_direct_subterm_ind is defined
t_direct_subterm_sind is defined
t_direct_subterm_sig is defined
t_direct_subterm_sig_pack is defined
t_direct_subterm_Signature is defined
t_subterm is defined
*)
From Equations Require Import Equations.
Derive NoConfusion for sort.
Derive Signature NoConfusion NoConfusionHom for t.
Derive Subterm for t.
Check well_founded_t_subterm : forall A, WellFounded (t_subterm A).
(* by wf (signature_pack f) (@t_subterm f) := *)
Attributes
- derive
- eliminator
- equations
- tactic: default tactic to solve proof obligations, if any
- universes
Note: eliminator=yes
implicitly sets equations=yes
Example:
#[derive(eliminator=no),
tactic=simpl]
Equations hd {A: Type} (l: list A) (pf: l <> []): A :=
hd [] pf with pf eq_refl := { |!};
hd (a::l) _ := a.
Tactics
depelim
anddependent elimination
funelim
Errors
'cannot find covering'
Try Set Equations Debug.
and see.
Will show where it went off track.
Settings
Set Equations Transparent.
Global Transparent
Misc
- Induction-recursion
- Fiber
Leibniz substitution principle
A: Type
P: A -> Type
x, y: A
P x: Type
x = y: Prop
-----------------
P y: Type
Essentially says that given a P x
, if x=y
, then we can get a P y
.