Define a polymorphic type in coq - coq

So i was doing an exercise for learning coq. and I was trying to defind a type according to this encoding:
forall X.(X -> X) -> X -> X;`and this is from Alonzo Church(he proposed an encoding for natural number) as below:
0 , f:x:x
1 , f:x:fx
2 , f:x:f(fx)
3 , f:x:f(f(fx))
.....
n , f:x:fnx:
My code is like below:
Definition nat := forall X : Type, (X -> X) -> X -> X.
And the exercise require me to define expressions zero,one,two and three that encode the corresponding numbers as elements of nat:
Below is what I thought it will be
Definition zero : nat :=
fun (X : Type) (f : X -> X) (x : X) => x.
Definition one : nat :=
fun (X : Type) (f : X -> X) (x : X) => f x.
Definition two : nat :=
fun (X : Type) (f : X -> X) (x : X) => f (f x).
Definition three : nat :=
fun (X:Type)(f: X -> X)(x: X) => f ( f ( f x )).
My question is I need to prove that the plus n one = succ n. and the n is my defined type Nat
I have a succ function defined as below:
Definition succ (n : nat) : nat :=
fun (X : Type) (f : X -> X) (x : X) => f (n X f x).
my plus function defined as below:
Definition plus (n m : nat) : nat :=
fun (X : Type) (f : X -> X) (x : X) => (n X f (m X f x)).
The thing is when I tried to prove plus n one = succ n, I stuck in the middle and have no idea how to prove.
code as below:
Theorem plus_succ: forall (n : nat),
plus n one = succ n.
Proof.
intros.
1 subgoal
n : nat
______________________________________(1/1)
plus n one = succ n
and there's no way I can do inversion or any other tactic...(I am new to Coq, I've learnt list,poly,induction and tactics so far)
So that brings me to the thought that probably one, two or maybe all of my definition I defined above are not accurate.
Tons of appreciation if anyone can help me or give me some hints! Thankssss!

Using Church encodings in Coq is not a bad idea per-se, but you won't be able to say much about the inhabitants of this type (beside constructing some of them as you did).
The first issue is that inhabitants of this Church encoding are functions, and you will be able to show that two functions are equal in pure Coq only if they compute to the same value (up to unfolding, beta-reductions, reductions of match and fixes).
This is not the case for plus n one and succ n: you have on the lhs fun X f x => f (n X f x) and on the rhs fun X f x => n X f (f x). What you could hope to prove is forall (X : type) (f : X -> X) (x : X), f (n X f x) = n X f (f x), and you would then need to use functional extensionality, an axiom stating that the equality between functions is determined by the value of the functions at each point of their domain (see Coq.Logic.FunctionalExtensionality in the stdlib for more details on that point). This axiom is frequently assumed, but it is not innocent either (e.g. it does block computations).
The second issue you will run into is that you expect the inhabitants of nat = forall X, (X -> X) -> X -> X to be functions parametric in their first argument X : Type, but there is nothing actually enforcing that. Indeed, you can construct non-parametric inhabitants if you assume additional axioms, for instance excluded-middle. In pure Coq (without any axiom), there are results due to Bernardy and Lasson that show that indeed all inhabitants of your type nat are parametric, however you cannot internalize this result. And without parametricity, you have no bullets to prove equations such as f (n X f x) = n X f (f x).
So your troubles come from these two issues:
in absence of functional extensionality, the equalities that you can prove between functions are quite limited, and
you are not able in pure Coq to express internally that a quantification over types is parametric.
If you want to learn more about these issues on parametricity and what can still be achieved using Church encodings (or variants of these), I would recommend having a look at Chlipala's Parametric Higher-Order Abstract Syntax.

Related

Check cnat. and got Type return

All
I am trying to understand the Church numerals, mentioned in the SF-LF book, chp4.
Definition cnat := forall X : Type, (X -> X) -> X -> X.
Definition one : cnat :=
fun (X : Type) (f : X -> X) (x : X) => f x.
Check cnat.
Check one.
And I get
cnat
: Type
one
: cnat
It seems cnat is some kind of type, and function at the same time. How can it be both type and function? Anyone can help explain a little more about this?
The "forall (X : Type)," syntax is a way to form a type, from a type parameterized by X. forall (X : Type), (X -> X) -> X -> X is a type of functions, which given a type X produce a value of type (X -> X) -> X -> X (which is itself a function).
The "fun (X : Type) =>" syntax is a way to form a function, from a term parameterized by X. fun (X : Type) (f : X -> X) (x : X) => f x is a function, which given a type X produce the function fun (f : X -> X) (x : X) => f x (which is itself a function).
What fun and forall have in common is that they involve binders, like (X : Type) (also like (f : X -> X), (x : X)). fun is a construct that involves binders to form functions, but not all constructs that involve binders form functions: forall is a construct that involves binders to form types.

How to define exp for Church Numerals in coq?

I am currently learning coq thanks to the Software Fondation's ebook.
I successfully wrote the addition as follow:
Definition cnat := forall X : Type, (X -> X) -> X -> X.
Definition plus (n m : cnat) : cnat :=
fun (X : Type) (f : X -> X) (x : X) => n X f (m X f x).
But I'm stuck with exp because of the following error:
Definition exp (n m : cnat) : cnat :=
m cnat (mult n) n.
(*
In environment
n : cnat
m : cnat
The term "cnat" has type "Type#{cnat.u0+1}"
while it is expected to have type "Type#{cnat.u0}"
(universe inconsistency).
*)
Since they wrote:
If you hit a "Universe inconsistency" error, try iterating over a different type. Iterating over cnat itself is usually problematic.
I tried using the definition of cnat:
Definition exp (n m : cnat) : cnat :=
m (forall X : Type, (X -> X) -> X) (mult n) n.
But then I have:
In environment
n : cnat
m : cnat
The term "mult n" has type "cnat -> cnat"
while it is expected to have type
"(forall X : Type, (X -> X) -> X) -> forall X : Type, (X -> X) -> X"
(universe inconsistency).
I do not ask for a solution, but I'd really like to understand these errors.
Thanks for your lights !
Just post the solution for others who got stuck on this problem.
Definition exp (n m : cnat) : cnat :=
fun X => (m (X->X)) (n X).
The key is to understand m (X->X). The figure below might be helpful.
An example of 2 ^ 2

Induction on a datatype with non-uniform type parameters produces ill-typed terms

I'm working towards formalising Free Selective Applicative Functors in Coq, but struggling with proofs by induction for inductive data types with non-uniform type parameters.
Let me give a bit of an introduction on the datatype I'm dealing with.
In Haskell, we encode Free Selective Functors as a GADT:
data Select f a where
Pure :: a -> Select f a
Select :: Select f (Either a b) -> f (a -> b) -> Select f b
The crucial thing here is the existential type variable b in the second data constructor.
We can translate this definition to Coq:
Inductive Select (F : Type -> Type) (A : Set) : Set :=
Pure : A -> Select F A
| MkSelect : forall (B : Set), Select F (B + A) -> F (B -> A) -> Select F A.
As a side note, I use the -impredicative-set option to encode it.
Coq generates the following induction principle for this datatype:
Select_ind :
forall (F : Type -> Type) (P : forall A : Set, Select F A -> Prop),
(forall (A : Set) (a : A), P A (Pure a)) ->
(forall (A B : Set) (s : Select F (B + A)), P (B + A)%type s ->
forall f0 : F (B -> A), P A (MkSelect s f0)) ->
forall (A : Set) (s : Select F A), P A s
Here, the interesting bit is the predicate P : forall A : Set, Select F A -> Prop which is parametrised not only in the expression, but also in the expressions type parameter. As I understand, the induction principle has this particular form because of the first argument of the MkSelect constructor of type Select F (B + A).
Now, I would like to prove statements like the third Applicative law for the defined datatype:
Theorem Select_Applicative_law3
`{FunctorLaws F} :
forall (A B : Set) (u : Select F (A -> B)) (y : A),
u <*> pure y = pure (fun f => f y) <*> u.
Which involve values of type Select F (A -> B), i.e. expressions containing functions. However,
calling induction on variables of such types produces ill-typed terms. Consider an oversimplified example of an equality that can be trivially proved by reflexivity, but can't be proved using induction:
Lemma Select_induction_fail `{Functor F} :
forall (A B : Set) (a : A) (x : Select F (A -> B)),
Select_map (fun f => f a) x = Select_map (fun f => f a) x.
Proof.
induction x.
Coq complains with the error:
Error: Abstracting over the terms "P" and "x" leads to a term
fun (P0 : Set) (x0 : Select F P0) =>
Select_map (fun f : P0 => f a) x0 = Select_map (fun f : P0 => f a) x0
which is ill-typed.
Reason is: Illegal application (Non-functional construction):
The expression "f" of type "P0" cannot be applied to the term
"a" : "A"
Here, Coq can't construct the predicate abstracted over the type variable because the reversed function application from the statement becomes ill-typed.
My question is, how do I use induction on my datatype? I can't see a way how to modify the induction principle in such a way so the predicate would not abstract the type. I tried to use dependent induction, but it has been producing inductive hypothesis constrained by equalities similar to (A -> B -> C) = (X + (A -> B -> C)) which I think would not be possible to instantiate.
Please see the complete example on GitHub: https://github.com/tuura/selective-theory-coq/blob/impredicative-set/src/Control/Selective/RigidImpredSetMinimal.v
UPDATE:
Following the discussio in the gist I have tried to carry out proofs by induction on depth of expression. Unfortunately, this path was not very fruitful since the induction hypothesis I get in theorems similar to Select_Applicative_law3 appear to be unusable. I will leave this problem for now and will give it a try later.
Li-yao, many thanks again for helping me to improve my understanding!
Proofs by induction are motivated by recursive definitions. So to know what to apply induction to, look for Fixpoints.
Your Fixpoints most likely work on terms indexed by single type variables Select F A, that's exactly where you want to use induction, not at the toplevel of the goal.
A Fixpoint on terms indexed by function types A -> B is useless since no subterms of any Select term are indexed by function types. For the same reason, induction is useless on such terms.
Here I think the strong type discipline actually forces you to work everything out on paper before trying to do anything in Coq (which is a good thing in my opinion). Try to do the proof on paper, without even worrying about types; explicitly write down the predicate(s) you want to prove by induction. Here's a template to see what I mean:
By induction on u, we will show
u <*> pure x = pure (fun f => f x) <*> u
(* Dummy induction predicate for the sake of example. *)
(* Find the right one. *)
(* It may use quantifiers... *)
Base case (set u = Pure f). Prove:
Pure f <*> pure x = pure (fun f => f x) <*> Pure f
Induction step (set u = MkSelect v h). Prove:
MkSelect v h <*> pure x = pure (fun f => f x) <*> MkSelect v h
assuming the induction hypothesis for the subterm v (set u = v):
v <*> pure x = pure (fun f => f x) <*> v
Notice in particular that the last equation is ill-typed, but you can still run along with it to do equational reasoning. Regardless, it will likely turn out that there is no way to apply that hypothesis after simplifying the goal.
If you really need to use Coq to do some exploration, there is a trick, consisting in erasing the problematic type parameter (and all terms that depend on it). Depending on your familiarity with Coq, this tip may turn out to be more confusing than anything. So be careful.
The terms will still have the same recursive structure. Keep in mind that the proof should also follow the same structure, because the point is to add more types on top afterwards, so you should avoid shortcuts that rely on the lack of types if you can.
(* Replace all A and B by unit. *)
Inductive Select_ (F : unit -> Type) : Set :=
| Pure_ : unit -> Select_ F
| MkSelect_ : Select_ F -> F tt -> Select_ F
.
Arguments Pure_ {F}.
Arguments MkSelect_ {F}.
(* Example translating Select_map. The Functor f constraint gets replaced with a dummy function argument. *)
(* forall A B, (A -> B) -> (F A -> F B) *)
Fixpoint Select_map_ {F : unit -> Type} (fmap : forall t, unit -> (F t -> F t)) (f : unit -> unit) (v : Select_ F) : Select_ F :=
match v with
| Pure_ a => Pure_ (f a)
| MkSelect_ w h => MkSelect_ (Select_map_ fmap f w) (fmap _ tt h)
end.
With that, you can try to prove this trimmed down version of the functor laws for example:
Select_map_ fmap f (Select_map_ fmap g v) = Select_map_ fmap (fun x => f (g x)) v
(* Original theorem:
Select_map f (Select_map g v) = Select_map (fun x => f (g x)) v
*)
The point is that removing the parameter avoids the associated typing problems, so you can try to use induction naively to see how things (don't) work out.

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.

Incorrect elimination of X in the inductive type "or":

I am trying to define a relatively simple function on Coq:
(* Preliminaries *)
Require Import Vector.
Definition Vnth {A:Type} {n} (v : Vector.t A n) : forall i, i < n -> A. admit. Defined.
(* Problematic definition below *)
Definition VnthIndexMapped {A:Type}
{i o:nat}
(x: Vector.t (option A) i)
(f': nat -> option nat)
(f'_spec: forall x, x<o ->
(forall z,(((f' x) = Some z) -> z < i)) \/
(f' x = None))
(n:nat) (np: n<o)
: option A
:=
match (f' n) as fn, (f'_spec n np) return f' n = fn -> option A with
| None, _ => fun _ => None
| Some z, or_introl zc1 => fun p => Vnth x z (zc1 z p)
| Some z, or_intror _ => fun _ => None (* impossible case *)
end.
And getting the following error:
Error:
Incorrect elimination of "f'_spec n np" in the inductive type "or":
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.
I think I understand the reason for this limitation, but I am having difficulty coming up with a workaround. How something like this could be implemented? Basically I have a function f' for which I have a separate proof that values less than 'o' it either returns None or a (Some z) where z is less than i and I am trying to use it in my definition.
There are two approaches to a problem like this: the easy way and the hard way.
The easy way is to think whether you're doing anything more complicated than you have to. In this case, if you look carefully, you will see that your f'_spec is equivalent to the following statement, which avoids \/:
Lemma f'_spec_equiv i o (f': nat -> option nat) :
(forall x, x<o ->
(forall z,(((f' x) = Some z) -> z < i)) \/
(f' x = None))
<-> (forall x, x<o -> forall z,(((f' x) = Some z) -> z < i)).
Proof.
split.
- intros f'_spec x Hx z Hf.
destruct (f'_spec _ Hx); eauto; congruence.
- intros f'_spec x Hx.
left. eauto.
Qed.
Thus, you could have rephrased the type of f'_spec in VnthIndexedMapped and used the proof directly.
Of course, sometimes there's no way of making things simpler. Then you need to follow the hard way, and try to understand the nitty-gritty details of Coq to make it accept what you want.
As Vinz pointed out, you usually (there are exceptions) can't eliminate the proof of proposition to construct something computational. However, you can eliminate a proof to construct another proof, and maybe that proof gives you what need. For instance, you can write this:
Definition VnthIndexMapped {A:Type}
{i o:nat}
(x: Vector.t (option A) i)
(f': nat -> option nat)
(f'_spec: forall x, x<o ->
(forall z,(((f' x) = Some z) -> z < i)) \/
(f' x = None))
(n:nat) (np: n<o)
: option A
:=
match (f' n) as fn return f' n = fn -> option A with
| None => fun _ => None
| Some z => fun p =>
let p' := proj1 (f'_spec_equiv i o f') f'_spec n np z p in
Vnth x z p'
end eq_refl.
This definition uses the proof that both formulations of f'_spec are equivalent, but the same idea would apply if they weren't, and you had some lemma allowing you to go from one to the other.
I personally don't like this style very much, as it is hard to use and lends itself to programs that are complicated to read. But it can have its uses...
The issue is that you want to build a term by inspecting the content of f'_spec. This disjunction lives in Prop, so it can only build other Prop. You want to build more, something in Type. Therefore you need a version of disjunction that lives at least in Set (more generally in Type). I advise you replace your Foo \/ Bar statement with the usage of sumbool, which uses the notation {Foo}+{Bar}.