Purescript treats class as circular type synonym - purescript

I'm trying to define instances that only work on type level natural numbers. When I compile this file:
module Main where
data NatZero
data NatSucc n
class NatClass n where
switch :: f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n
it tells me:
Error found:
at src/Main.purs:6:1 - 7:73 (line 6, column 1 - line 7, column 73)
A cycle appears in the definition of type synonym NatClass
Cycles are disallowed because they can lead to loops in the type checker.
Consider using a 'newtype' instead.
Why did NatClass become a type synonym? I thought it was a type class. And where is there a loop? What should I change to make this work like in Haskell? It's telling me to newtype, what do I newtype?

The error message is misleading and unfortunate - it's not anything you're doing wrong with the code here, it's happening due to how the compiler desugars type classes.
Currently a dictionary is represented as a record, so the synonym mentioned in the error here is because the compiler creates something like this for the class:
type NatClass n =
{ switch :: forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n }
So that it can do a fairly direct replacement of constraints with dictionary arguments.
I think right now this class (or any that uses itself as a constraint in a member) will have the same problem.
I've been wanting to change the representation for type classes for a while, and have a WIP PR for it, I think after that this kind of thing will be allowed. After this classes will be desugared into a data type rather than a synonym, so the reference should be allowed.

You can work around the Purescript limitation pretty easily by reifying the dictionary yourself. Something like -
data NatZero
data NatSucc n
newtype NatClassDict n = NatClassDict (forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n)
getSwitch :: NatClassDict n -> (forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n)
getSwitch (NatClassDict f) = f
class NatClass n where
natClassDict :: NatClassDict n
switch :: NatClass n => forall f. f NatZero -> (forall m. NatClass m => f (NatSucc m)) -> f n
switch = getSwitch natClassDict

Related

Define a polymorphic type in 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.

Looking for some help on the Sin_domain proof from Software Foundations Color.v

Here is the full module: https://softwarefoundations.cis.upenn.edu/vfa-current/Color.html
The theorem at hand:
Exercise: 3 stars (Sin_domain)
Lemma Sin_domain: ∀ A n (g: M.t A), S.In n (Mdomain g) ↔ M.In n g.
Usually, 3 stars indicates hard but not too hard, but I'm struggling to figure out how to attack this. If you unfold Mdomain it becomes a fold which then becomes M.xfoldi, which is fairly low level. I have a sense of how I could prove a bunch of low level lemmas about how xfoldi acts on various indices but...I feel like there has got to be a better way? That said it does have this disclaimer
This seems so obvious! But I didn't find a really simple proof of it.
My first instinct with this sort of thing is always try try and prove some sort of distribution principle about the thing at hand, such as
Mdomain (M.Node s1 o s2)
But since Mdomain is implemented in terms of a fold, it gets complicated pretty quickly. Again, probably not insurmountable but...I'm wondering if there is a better way (given I just spent many, many hours on Sremove_cardinal_less and Mremove_cardinal_less!)
Hint: Use WP.fold_rec_bis to prove a relation P between a map and the result of folding it (with M.fold). It is a form of induction principle:
Base case: the relation must hold between the empty map and the initial accumulator;
Induction step: if the relation holds of some map (and accumulator), then it holds after inserting a new key-value pair (and updating the accumulator accordingly).
As a technicality, it also requires a "compatibility" assumption (which is an explicit proof that your relation P is independent from the order of insertion).
Theorem fold_rec_bis :
forall (A:Type)(P : t elt -> A -> Type)(f : key -> elt -> A -> A),
forall (i:A)(m:t elt),
(forall m m' a, Equal m m' -> P m a -> P m' a) -> (* Compatibility *)
(P (empty _) i) -> (* Base case *)
(forall k e a m', MapsTo k e m -> ~In k m' -> (* Induction step *)
P m' a -> P (add k e m') (f k e a)) ->
P m (fold f m i).

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 rewrite inside a lambda?

Basically, I want to prove the following lemma, but I'm having trouble since I can't seem to directly rewrite inside of the lambdas.
However I feel like this should be possible, because if I were "inside" the lambda, I could easily prove it for any given x.
Lemma lemma :
forall {A B : Type} (f : A -> B) (g : A -> B),
(forall (x : A), f x = g x) -> (fun x => f x) = (fun x => g x).
The statement you're trying to prove is (essentially) functional extentionality, which is well-known to not be provable in Coq without extra axioms. Basically, the idea is that f and g can be intentionally very different (their definitions can look different), but still take on the same values. Equality of functions (fun x => f x) = (fun x => g x) would (without any additional axioms) imply that the two functions are syntactically the same.
For example, take f(n) = 0 and g(n) = 1 if x^(3 + n) + y^(3 + n) = z^(3 + n) has a non-trivial solution in integers, otherwise 0 (both functions from natural numbers to natural numbers). Then f and g are intentionally different - one doesn't syntactically reduce to the other. However, thanks to Andrew Wiles, we know that f and g are extentionally the same since g(n) = 0 for all n.
You can freely add your lemma (or various strengthenings) as an axiom to Coq without worrying about inconsistency.

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}.