Ltac-tically abstracting over a subterm of the goal type - coq

As a rough and untutored background, in HoTT, one deduces the heck out of the inductively defined type
Inductive paths {X : Type } : X -> X -> Type :=
| idpath : forall x: X, paths x x.
which allows the very general construction
Lemma transport {X : Type } (P : X -> Type ){ x y : X} (γ : paths x y):
P x -> P y.
Proof.
induction γ.
exact (fun a => a).
Defined.
The Lemma transport would be at the heart of HoTT "replace" or "rewrite" tactics; the trick, so far as I understand it, would be, supposing a goal which you or I can abstractly recognize as
...
H : paths x y
[ Q : (G x) ]
_____________
(G y)
to figure out what is the necessary dependent type G, so that we can apply (transport G H). So far, all I've figured out is that
Ltac transport_along γ :=
match (type of γ) with
| ?a ~~> ?b =>
match goal with
|- ?F b => apply (transport F γ)
| _ => idtac "apparently couldn't abstract" b "from the goal." end
| _ => idtac "Are you sure" γ "is a path?" end.
isn't general enough. That is, the first idtac gets used rather often.
The question is
[Is there a | what is the] Right Thing to Do?

There is a bug about using rewrite for relations in type, which would allow you to just say rewrite <- y.
In the mean time,
Ltac transport_along γ :=
match (type of γ) with
| ?a ~~> ?b => pattern b; apply (transport _ y)
| _ => idtac "Are you sure" γ "is a path?"
end.
probably does what you want.

The feature request mentioned by Tom Prince in his answer has been granted:
Require Import Coq.Setoids.Setoid Coq.Classes.CMorphisms.
Inductive paths {X : Type } : X -> X -> Type :=
| idpath : forall x: X, paths x x.
Lemma transport {X : Type } (P : X -> Type ){ x y : X} (γ : paths x y):
P x -> P y.
Proof.
induction γ.
exact (fun a => a).
Defined.
Global Instance paths_Reflexive {A} : Reflexive (#paths A) := idpath.
Global Instance paths_Symmetric {A} : Symmetric (#paths A).
Proof. intros ?? []; constructor. Defined.
Global Instance proper_paths {A} (x : A) : Proper paths x := idpath x.
Global Instance paths_subrelation
(A : Type) (R : crelation A)
{RR : Reflexive R}
: subrelation paths R.
Proof.
intros ?? p.
apply (transport _ p), RR.
Defined.
Global Instance reflexive_paths_dom_reflexive
{B} {R' : crelation B} {RR' : Reflexive R'}
{A : Type}
: Reflexive (#paths A ==> R')%signature.
Proof. intros ??? []; apply RR'. Defined.
Goal forall (x y : nat) G, paths x y -> G x -> G y.
intros x y G H Q.
rewrite <- H.
exact Q.
Qed.
I found the required instances by comparing the logs I got with Set Typeclasses Debug from setoid_rewrite <- H when H : paths x y and when H : eq x y.

Related

How to implement remove with a membership proof as an argument in Coq?

data _∈_ {X : Set} (x : X) : (xs : List X) → Set where
here! : {xs : List X} → x ∈ x ∷ xs
there : {xs : List X} {y : X} (pr : x ∈ xs) → x ∈ y ∷ xs
remove : {X : Set} {x : X} (xs : List X) (pr : x ∈ xs) → List X
remove (_ ∷ xs) here! = xs
remove (y ∷ xs) (there pr) = y ∷ remove xs pr
I am trying to translate the above definition from Agda to Coq and am running into difficulties.
Inductive Any {A : Type} (P : A -> Type) : list A -> Prop :=
| here : forall {x : A} {xs : list A}, P x -> Any P (x :: xs)
| there : forall {x : A} {xs : list A}, Any P xs -> Any P (x :: xs).
Definition In' {A : Type} (x : A) xs := Any (fun x' => x = x') xs.
Fixpoint remove {A : Type} {x : A} {l : list A} (pr : In' x l) : list A :=
match l, pr with
| [], _ => []
| _ :: ls, here _ _ => ls
| x :: ls, there _ pr => x :: remove pr
end.
Incorrect elimination of "pr0" in the inductive type "#Any":
the return type has sort "Type" while it should be "Prop".
Elimination of an inductive object of sort Prop
is not allowed on a predicate in sort Type
because proofs can be eliminated only to build proofs.
In addition to this error, if I leave the [] case out Coq is asks me to provide it despite it being absurd.
Up to this point, I've thought that Agda and Coq were the same languages with a different front end, but now I am starting to think they are different under the hood. Is there a way to replicate the remove function in Coq and if not, what alternative would you recommend?
Edit: I also want to keep the proof between In and In'. Originally I made In' a Type rather than a Prop, but that made the following proof fail with a type error.
Fixpoint In {A : Type} (x : A) (l : list A) : Prop :=
match l with
| [] ⇒ False
| x' :: l' ⇒ x' = x ∨ In x l'
end.
Theorem In_iff_In' :
forall {A : Type} (x : A) (l : list A),
In x l <-> In' x l.
Proof.
intros.
split.
- intros.
induction l.
+ inversion H.
+ simpl in H.
destruct H; subst.
* apply here. reflexivity.
* apply there. apply IHl. assumption.
- intros.
induction H.
+ left. subst. reflexivity.
+ right. assumption.
Qed.
In environment
A : Type
x : A
l : list A
The term "In' x l" has type "Type" while it is expected to have type
"Prop" (universe inconsistency).
The In here is from the Logic chapter of SF. I have a solution of the pigeonhole principle in Agda, so I want this bijection in order to convert to the form that the exercise asks.
Edit2:
Theorem remove_lemma :
forall {A} {x} {y} {l : list A} (pr : In' x l) (pr' : In' y l),
x = y \/ In' y (remove pr).
I also outright run into universe inconsistency in this definition even when using Type when defining In'.
You need to use an informative proof of membership. Right now, your Any takes values in Prop, which, due to its limitations on elimination (see the error message you got), is consistent with the axiom forall (P: Prop) (x y: P), x = y. This means that if you have some term that depends on a term whose type is in Prop (as is the case with remove), it has to only use the fact that such a term exists, not what term it is specifically. Generally, you can't use elimination (usually pattern matching) on a Prop to produce anything other than something that's also a Prop.
There are three essentially different proofs of In' 1 [1; 2; 1; 3; 1; 4], and, depending which proof is used, remove p might be [2; 1; 4; 1; 4], [1; 2; 3; 1; 4] or [1; 2; 1; 3; 4]. So the output depends on the specific proof in an essential way.
To fix this, you can simply replace the Prop in Inductive Any {A : Type} (P : A -> Type) : list A -> Prop with Type.1 Now we can eliminate into non-Prop types and your definition of remove works as written.
To answer your edits, I think the biggest issue is that some of your theorems/definitions need In' to be a Prop (because they depend on uninformative proofs) and others need the informative proof.
I think your best bet is to keep In' as a Type, but then prove uninformative versions of the theorems. In the standard libary, in Coq.Init.Logic, there is an inductive type inhabited.
Inductive inhabited (A: Type): Prop :=
| inhabits: A -> inhabited A.
This takes a type and essentially forgets anything specific about its terms, only remembering if it's inhabited or not. I think your theorem and lemma are provable if you simply replace In' x l with inhabited (In' x l). I was able to prove a variant of your theorem whose conclusion is simply In x l <-> inhabited (In' x l). Your proof mostly worked, but I had to use the following simple lemma in one step:
Lemma inhabited_there {A: Type} {P: A -> Type} {x: A} {xs: list A}:
inhabited (Any P xs) -> inhabited (Any P (x :: xs)).
Note: even though inhabited A is basically just a Prop version of A and we have A -> inhabited A, we can't prove inhabited A -> A in general because that would involve choosing an arbitrary element of A.2
I also suggested Set here before, but this doesn't work since the inductive type depends on A, which is in Type.
In fact, I believe that the proof assistant Lean uses something very similar to this for its axiom of choice.

Coq: How to produce a strong polymorphic dependent type hypothesis

I have been having some problems with dependent induction because a "weak hypothesis".
For example :
I have a dependent complete foldable list :
Inductive list (A : Type) (f : A -> A -> A) : A -> Type :=
|Acons : forall {x x'' : A} (y' : A) (cons' : list f (f x x'')), list f (f (f x x'') y')
|Anil : forall (x: A) (y : A), list f (f x y).
And a function that a return the applied fold value from inductive type list and other function that forces a computation of these values through a matching.
Definition v'_list {X} {f : X -> X -> X} {y : X} (A : list f y) := y.
Fixpoint fold {A : Type} {Y : A} (z : A -> A -> A) (d' : list z Y) :=
match d' return A with
|Acons x y => z x (#fold _ _ z y)
|Anil _ x y => z x y
end.
Clearly, that's function return the same value if have the same dependent typed list and prove this don't should be so hard.
Theorem listFold_eq : forall {A : Type} {Y : A} (z : A -> A -> A) (d' : list z Y), fold d' = v'_list d'.
intros.
generalize dependent Y.
dependent induction d'.
(.. so ..)
Qed.
My problem is that dependent definition generates for me a weak hypothesis.
Because i have something like that in the most proof that i use dependent definitions, the problem of proof above:
A : Type
z : A -> A -> A
x, x'', y' : A
d' : list z (z x x'')
IHd' : fold d' = v'_list d'
______________________________________(1/2)
fold (Acons y' d') = v'_list (Acons y' d')
Even i have a polymorphic definition in (z x x'') i can't apply IHd' in my goal.
My question if have a way of define more "powerful" and polymorphic induction, instead of working crazy rewriting terms that sometimes struggling me.
If you do
simpl.
unfold v'_list.
You can see that you're almost there (you can finish with rewriting), but the arguments of z are in the wrong order, because list and fold don't agree on the way the fold should go.
On an unrelated note, Acons could quantify over a single x, replacing f x x'' with just x.

Error: The reference fst was not found in the current environment

I am writing a small program so that I can work some proofs of deMorgans laws using the type introduction/elimination rules from the HoTT book (et. al.). My model/example code is all here, https://mdnahas.github.io/doc/Reading_HoTT_in_Coq.pdf. So far I have,
Definition idmap {A:Type} (x:A) : A := x.
Inductive prod (A B:Type) : Type := pair : A -> B -> #prod A B.
Notation "x * y" := (prod x y) : type_scope.
Notation "x , y" := (pair _ _ x y) (at level 10).
Section projections.
Context {A : Type} {B : Type}.
Definition fst (p: A * B ) :=
match p with
| (x , y) => x
end.
Definition snd (p:A * B ) :=
match p with
| (x , y) => y
end.
End projections.
Inductive sum (A B : Type ) : Type :=
| inl : A -> sum A B
| inr : B -> sum A B.
Arguments inl {A B} _ , [A] B _.
Arguments inr {A B} _ , A [B].
Notation "x + y" := (sum x y) : type_scope.
Inductive Empty_set:Set :=.
Inductive unit:Set := tt:unit.
Definition Empty := Empty_set.
Definition Unit := unit.
Definition not (A:Type) : Type := A -> Empty.
Notation "~ x" := (not x) : type_scope.
Variables X:Type.
Variables Y:Type.
Goal (X * Y) -> (not X + not Y).
intro h. fst h.
Now I don't really know what the problem is. I've examples of people using definitions, but they always involve "Compute" commands, and I want to apply the rule fst to h to get x:X, so they are not helpful.
I tried "apply fst." which got me
Error: Cannot infer the implicit parameter B of fst whose type is
"Type" in environment:
h : A * B
In a proof context, Coq expects to get tactics to execute, not expressions to evaluate. Since fst is not defined as a tactic, it will give Error: The reference fst was not found in the current environment.
One possible tactic to execute along the lines of what you seem to be trying to do is set:
set (x := fst h).
I want to apply the rule fst to h to get x:X
I believe you can do
apply fst in h.
If you just write apply fst, Coq will apply the fst rule to the goal, rather than to h. If you write fst h, as Daniel says in his answer, Coq will attempt to run the fst tactic, which does not exist. In addition to Daniel's set solution, which will change the goal if fst h appears in it (and this may or may not be what you want), the following also work:
pose (fst h) as x. (* adds x := fst h to the context *)
pose proof (fst h) as x. (* adds opaque x : X to the context, justified by the term fst h *)
destruct h as [x y]. (* adds x : X and y : Y to the context, and replaces h with pair x y everywhere *)

Problems with dependent types in Coq proof assistant

Consider the following simple expression language:
Inductive Exp : Set :=
| EConst : nat -> Exp
| EVar : nat -> Exp
| EFun : nat -> list Exp -> Exp.
and its wellformedness predicate:
Definition Env := list nat.
Inductive WF (env : Env) : Exp -> Prop :=
| WFConst : forall n, WF env (EConst n)
| WFVar : forall n, In n env -> WF env (EVar n)
| WFFun : forall n es, In n env ->
Forall (WF env) es ->
WF env (EFun n es).
which basically states that every variable and function symbols must be defined in the environment. Now, I want to define a function that states the decidability of WF predicate:
Definition WFDec (env : Env) : forall e, {WF env e} + {~ WF env e}.
refine (fix wfdec e : {WF env e} + {~ WF env e} :=
match e as e' return e = e' -> {WF env e'} + {~ WF env e'} with
| EConst n => fun _ => left _ _
| EVar n => fun _ =>
match in_dec eq_nat_dec n env with
| left _ _ => left _ _
| right _ _ => right _ _
end
| EFun n es => fun _ =>
match in_dec eq_nat_dec n env with
| left _ _ => _
| right _ _ => right _ _
end
end (eq_refl e)) ; clear wfdec ; subst ; eauto.
The trouble is how to state that WF predicate holds or not for a list of expressions in the EFun case. My obvious guess was:
...
match Forall_dec (WF env) wfdec es with
...
But Coq refuses it, arguing that the recursive call wfdec is ill-formed. My question is: Is it possible to define decidability of such wellformedness predicate without changing the expression representation?
The complete working code is at the following gist.
The problem is that Forall_dec is defined as opaque in the standard library (that is, with Qed instead of Defined). Because of that, Coq does not know that the use of wfdec is valid.
The immediate solution to your problem is to redefine Forall_dec so that it is transparent. You can do this by printing the proof term that Coq generates and pasting it in your source file. I've added a gist here with a complete solution.
Needless to say, this approach lends itself to bloated, hard to read, and hard to maintain code. As ejgallego was pointing out in his answer, your best bet in this case is probably to define a Boolean function that decides WF, and use that instead of WFDec. The only problem with his approach, as he said, is that you will need to write your own induction principle to Exp in order to prove that the Boolean version indeed decides the inductive definition. Adam Chlipala's CPDT has a chapter on inductive types that gives an example of such an induction principle; just look for "nested inductive types".
As a temporal workaround you can define wf as:
Definition wf (env : Env) := fix wf (e : Exp) : bool :=
match e with
| EConst _ => true
| EVar v => v \in env
| EFun v l => [&& v \in env & all wf l]
end.
which is usually way more convenient to use. However, this definition will be pretty useless due to Coq generating the wrong induction principle for exp, as it doesn't detect the list. What I usually do is to fix the induction principle manually, but this is costly. Example:
From Coq Require Import List.
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Printing Implicit Defensive.
Import Prenex Implicits.
Section ReflectMorph.
Lemma and_MR P Q b c : reflect P b -> reflect Q c -> reflect (P /\ Q) (b && c).
Proof. by move=> h1 h2; apply: (iffP andP) => -[/h1 ? /h2 ?]. Qed.
Lemma or_MR P Q b c : reflect P b -> reflect Q c -> reflect (P \/ Q) (b || c).
Proof. by move=> h1 h2; apply: (iffP orP) => -[/h1|/h2]; auto. Qed.
End ReflectMorph.
Section IN.
Variables (X : eqType).
Lemma InP (x : X) l : reflect (In x l) (x \in l).
Proof.
elim: l => [|y l ihl]; first by constructor 2.
by apply: or_MR; rewrite // eq_sym; exact: eqP.
Qed.
End IN.
Section FORALL.
Variables (X : Type) (P : X -> Prop).
Variables (p : X -> bool).
Lemma Forall_inv x l : Forall P (x :: l) -> P x /\ Forall P l.
Proof. by move=> U; inversion U. Qed.
Lemma ForallP l : (forall x, In x l -> reflect (P x) (p x)) -> reflect (Forall P l) (all p l).
Proof.
elim: l => [|x l hp ihl /= ]; first by constructor.
have/hp {hp}hp : forall x : X, In x l -> reflect (P x) (p x).
by move=> y y_in; apply: ihl; right.
have {ihl} ihl := ihl _ (or_introl erefl).
by apply: (iffP andP) => [|/Forall_inv] [] /ihl hx /hp hall; constructor.
Qed.
End FORALL.
Inductive Exp : Type :=
| EConst : nat -> Exp
| EVar : nat -> Exp
| EFun : nat -> list Exp -> Exp.
Lemma Exp_rect_list (P : Exp -> Type) :
(forall n : nat, P (EConst n)) ->
(forall n : nat, P (EVar n)) ->
(forall (n : nat) (l : seq Exp), (forall x, In x l -> P x) -> P (EFun n l)) ->
forall e : Exp, P e.
Admitted.
Definition Env := list nat.
Definition wf (env : Env) := fix wf (e : Exp) : bool :=
match e with
| EConst _ => true
| EVar v => v \in env
| EFun v l => [&& v \in env & all wf l]
end.
Inductive WF (env : Env) : Exp -> Prop :=
| WFConst : forall n, WF env (EConst n)
| WFVar : forall n, In n env -> WF env (EVar n)
| WFFun : forall n es, In n env ->
Forall (WF env) es ->
WF env (EFun n es).
Lemma WF_inv env e (wf : WF env e ) :
match e with
| EConst n => True
| EVar n => In n env
| EFun n es => In n env /\ Forall (WF env) es
end.
Proof. by case: e wf => // [n|n l] H; inversion H. Qed.
Lemma wfP env e : reflect (WF env e) (wf env e).
Proof.
elim/Exp_rect_list: e => [n|n|n l ihe] /=; try repeat constructor.
by apply: (iffP idP) => [/InP|/WF_inv/InP //]; constructor.
apply: (iffP andP) => [[/InP ? /ForallP H]|/WF_inv[/InP ? /ForallP]].
by constructor => //; exact: H.
by auto.
Qed.

Dependent pattern matching in coq

The following code (which is of course not a complete proof) tries to do pattern matching on a dependent product:
Record fail : Set :=
mkFail {
i : nat ;
f : forall x, x < i -> nat
}.
Definition failomat : forall (m : nat) (f : forall x, x < m -> nat), nat.
Proof.
intros.
apply 0.
Qed.
Function fail_hard_omat fl : nat := failomat (i fl) (f fl).
Definition failhard fl : fail_hard_omat fl = 0.
refine ((fun fl =>
match fl with
| mkFail 0 _ => _
| mkFail (S n) _ => _
end) fl).
The error I get when trying to execute this is
Toplevel input, characters 0-125:
Error: Illegal application (Type Error):
The term "mkFail" of type
"forall i : nat, (forall x : nat, x < i -> nat) -> fail"
cannot be applied to the terms
"i" : "nat"
"f0" : "forall x : nat, x < i0 -> nat"
The 2nd term has type "forall x : nat, x < i0 -> nat"
which should be coercible to "forall x : nat, x < i -> nat".
It seems that the substitution somehow does not reach the inner type parameters.
After playing with the Program command I managed to build a refine that might suites you, but I don't understand everything I did. The main idea is to help Coq with the substitution by introducing intermediate equalities that will serve as brige within the substitution
refine ((fun fl =>
match fl as fl0 return (fl0 = fl -> fail_hard_omat fl0 = 0) with
| mkFail n bar =>
match n as n0 return (forall foo: (forall x:nat, x < n0 -> nat),
mkFail n0 foo = fl -> fail_hard_omat (mkFail n0 foo) = 0) with
| O => _
| S p => _
end bar
end (eq_refl fl) ) fl).
Anyway, I don't know what your purpose here is, but I advise never write dependent match "by hand" and rely on Coq's tactics. In your case, if you define your Definition failomat with Defined. instead of Qed, you will be able to unfold it and you won't need dependent matching.
Hope it helps,
V.
Note: both occurences of bar can be replaced by an underscore.
Another, slightly less involved, alternative is to use nat and fail's induction combinators.
Print nat_rect.
Print fail_rect.
Definition failhard : forall fl, fail_hard_omat fl = 0.
Proof.
refine (fail_rect _ _). (* Performs induction (projection) on fl. *)
refine (nat_rect _ _ _). (* Performs induction on fl's first component. *)
Show Proof.