I can define the following inductive type:
Inductive T : Type -> Type :=
| c1 : forall (A : Type), A -> T A
| c2 : T unit.
But then the command Check (c1 (T nat)) fails with the message: The term T nat has type Type#{max(Set, Top.3+1)} while it is expected to have type Type#{Top.3} (universe inconsistency).
How can I tweak the above inductive definition so that c1 (T nat) does not cause a universe inconsistency, and without setting universe polymorphism on?
The following works, but I would prefer a solution without adding equality:
Inductive T (A : Type) : Type :=
| c1 : A -> T A
| c2' : A = unit -> T A.
Definition c2 : T unit := c2' unit eq_refl.
Check (c1 (T nat)).
(*
c1 (T nat)
: T nat -> T (T nat)
*)
Let me first answer the question of why we get the universe inconsistency in the first place.
Universe inconsistencies are the errors that Coq reports to avoid proofs of False via Russell's paradox, which results from considering the set of all sets which do not contain themselves.
There's a variant which is more convenient to formalize in type theory called Hurken's Paradox; see Coq.Logic.Hurkens for more details. There is a specialization of Hurken's paradox which proves that no type can retract to a smaller type. That is, given
U := Type#{u}
A : U
down : U -> A
up : A -> U
up_down : forall (X:U), up (down X) = X
we can prove False.
This is almost exactly the setup of your Inductive type. Annotating your type with universes, you start with
Inductive T : Type#{i} -> Type#{j} :=
| c1 : forall (A : Type#{i}), A -> T A
| c2 : T unit.
Note that we can invert this inductive; we may write
Definition c1' (A : Type#{i}) (v : T A) : A
:= match v with
| c1 A x => x
| c2 => tt
end.
Lemma c1'_c1 (A : Type#{i}) : forall v, c1' A (c1 A v) = v.
Proof. reflexivity. Qed.
Suppose, for a moment, that c1 (T nat) typechecked. Since T nat : Type#{j}, this would require j <= i. If it gave us that j < i, then we would be set. We could write c1 Type#{j}. And this is exactly the setup for the variant of Hurken's that I mentioned above! We could define
u = j
U := Type#{j}
A := T Type#{j}
down : U -> A := c1 Type#{j}
up : A -> U := c1' Type#{j}
up_down := c1'_c1 Type#{j}
and hence prove False.
Coq needs to implement a rule for avoiding this paradox. As described here, the rule is that for each (non-parameter) argument to a constructor of an inductive, if the type of the argument has a sort in universe u, then the universe of the inductive is constrained to be >= u. In this case, this is stricter than Coq needs to be. As mentioned by SkySkimmer here, Coq could recognize arguments which appear directly in locations which are indices of the inductive, and disregard those in the same way that it disregards parameters.
So, to finally answer your question, I believe the following are your only options:
You can Set Universe Polymorphism so that in T (T nat), your two Ts take different universe arguments. (Equivalently, you can write Polymorphic Inductive.)
You can take advantage of how Coq treats parameters of inductive types specially, which mandates using equality in your case. (The requirement of using equality is a general property of going from indexed inductive types to parameterized inductives types---from moving arguments from after the : to before it.)
You can pass Coq the flag -type-in-type to entirely disable universe checking.
You can fix bug #7929, which I reported as part of digging into this question, to make Coq handle arguments of constructors which appear in index-position in the inductive in the same way it handles parameters of inductive types.
(You can find another edge case of the system, and manage to trick Coq into ignoring the universes you want to slip past it, and probably find a proof of False in the process. (Possibly involving module subtyping, see, e.g., this recent bug in modules with universes.))
Related
I have a function whose second argument depends on its first argument, like this:
Definition is_nice (f : Formula) (pf : FProof f) : bool := true.
And I have a unification goal, like this
is_nice (some_formula ?u) (some_proof ?u) =^= is_nice f pf
.
which fails to unify when the unification starts from left to right,
but it would be unifiable when we first unify (some_proof ?u =^= pf),
infer the value for u during this unification, and then proceed to unify
some_formula ?u =^= f with the knowledge of u.
How do I make Coq solve such unification problem? I have the following ideas:
Change is_nice so that the order of parameters is different. However, I do not know how to achieve this because of the dependency between the parameters. We would need to somehow break this dependency...
Change is_nice so that it uses some canonical structure trickery to reorder the unification problems. There is some trick like that described in the extended version of Gonthier's 'How to make ad hoc proof automation less ad hoc' paper, but it does not seem to be directly applicable.
Somehow infer ?u even before the unification of that goal starts. But again, I am not sure how.
I may use UniCoq, but it is not a requirement.
As an example, consider the following piece of code:
Inductive Formula : Set :=
| f_atomic : nat -> Formula
| f_imp : Formula -> Formula -> Formula.
Inductive FProof : Formula -> Set :=
| P1 : forall (f1 f2 : Formula), FProof (f_imp f1 (f_imp f2 f1))
| MP : forall (f1 f2 : Formula), FProof f1 -> FProof (f_imp f1 f2) -> FProof f2
.
Definition is_nice (f : Formula) (pf : FProof f) : bool := true.
Lemma impl_5_is_nice': forall (n1 : nat), is_nice _ (P1 (f_atomic (n1 + 0)) (f_atomic 5)) = true.
Proof. intros. unfold is_nice. reflexivity. Qed.
Lemma impl_3_5_is_nice: is_nice _ (P1 (f_atomic 3) (f_atomic 5) ) = true.
Proof. intros.
Fail apply impl_5_is_nice'.
apply (impl_5_is_nice' 3).
Qed.
The types Formula and FProof represent formulas and proofs in a deeply-embedded logic. The proof script of Lemma impl_3_5_is_nice demostrates the problem: the first apply does not go through, because the unification of f_atomic (?n1 + 0) with f_atomic 3 fails. However, when we manually compare the goal and Lemma impl_5_is_nice', we can realize that n1 has to be 3, and so we can specialize the lemma.
Another solution would be to inspect the goal using match goal, but then the problem is that I have quite a lot of lemmas similar impl_5_is_nice', and the tactic that would do the inspection would need to understand each one of these lemmas. Ideally, this would be unified using type classes or canonical structures, but this is really a 'backup plan'.
Definitions
I'm working on formalizing a typed lambda calculus in Coq, and to keep the notation manageable I've come to rely a lot on coercions. However, I've been running into some difficulties which seem odd.
Right now I'm trying to work with the following types:
type: A descriptor of an allowable type in the language (like function, Unit, etc...)
var: A variable type, defined as nat
VarSets: set of vars
Judgement: a var/my_type pair
ty_ctx: Lists of judgements.
ctx_join: Pairs of ty_ctx's describing disjoint sets of variables
The actual definitions are all given below, except for ctx_join which is given in the next block
(* Imports *)
Require Import lang_spec.
From Coq Require Import MSets.
Require Import List.
Import ListNotations.
Module VarSet := Make(Nat_as_OT).
Inductive Judgement : Type :=
| judge (v : var) (t : type)
.
Definition ty_ctx := (list Judgement).
Definition disj_vars (s1 s2 : VarSet.t) := VarSet.Empty (VarSet.inter s1 s2).
Often I'd like to make statements like "this var does not appear in the set of vars bound by ty_ctx", and to that end I've set up a bunch of coercions between these types below.
(* Functions to convert between the different types listed above *)
Fixpoint var_to_varset (v : var) : VarSet.t :=
VarSet.singleton v.
Coercion var_to_varset : var >-> VarSet.t.
Fixpoint bound_variables (g : ty_ctx) : VarSet.t :=
match g with
| nil => VarSet.empty
| cons (judge v _) g' =>VarSet.union (VarSet.singleton v) (bound_variables g')
end.
Coercion bound_variables : ty_ctx >-> VarSet.t.
Inductive ctx_join :=
| join_single (g : ty_ctx)
| join_double (g1 g2 : ty_ctx)
(disjoint_proof : disj_vars g1 g2)
.
Fixpoint coerce_ctx_join (dj : ctx_join) : ty_ctx :=
match dj with
| join_single g => g
| join_double g1 g2 _ => g1 ++ g2
end.
Coercion coerce_ctx_join : ctx_join >-> ty_ctx.
Fixpoint coerce_judgement_to_ty_ctx (j : Judgement) : ty_ctx :=
cons j nil.
Coercion coerce_judgement_to_ty_ctx : Judgement >-> ty_ctx.
You'll notice that the definition of ctx_join relies on coercing its arguments from ty_ctx to VarSet.
I've drawn up the conversion hierarchy just to make things clear
The Problem
I'd like to define an inductive type with the following constructor
Inductive expr_has_type : ty_ctx -> nat -> type -> Prop :=
(* General Expressions *)
| ty_var (g : ty_ctx) (x : var) (t : type) (xfree : disj_vars x g)
: expr_has_type (join_double (judge x t) g xfree) x t
.
The problem is that when I do, I get the following error:
Error:
In environment
expr_has_type : ty_ctx -> nat -> type -> Prop
g : ty_ctx
x : var
t : type
xfree : disj_vars x g
The term "xfree" has type "disj_vars x g" while it is expected to have type
"disj_vars (judge x t) g" (cannot unify "VarSet.In a (VarSet.inter (judge x t) g)" and
"VarSet.In a (VarSet.inter x g)").
However, if I change the type of xfree to disj_vars (VarSet.singleton x) g, then the definition works fine! This seems very odd, as disj_vars is defined only on VarSets, and so it seems like x should automatically be converted toVarSet.singleton x since that's how the coercion is set up.
Even weirder is the fact that if I don't set up the coercion from vars to varsets, then Coq correctly complains about applying dis_vars to a var instead of a VarSet. So the coercion is definitely doing something
Can someone explain to me why the first definition fails? Given the coercions I've set up, to me it like all the definitions above should be equivalent
Note
Changing the type of xfree to disj_vars (judge x t) g also fixes the error. This seems odd too, since to be able to apply disj_vars to j := (judge x t), it first needs to be coerced to a ty_ctx via cons j nil, then to a VarSet via bound_variables, which should produce a VarSet containing only x (which is equivalent to VarSet.singleton x?). So this coercion chain seems to go off without a hitch, while the other one fails even though it's simpler
If you use Set Printing Coercions., the error message will be much more informative about the problem:
The term "xfree" has type "disj_vars (var_to_varset x) (bound_variables g)"
while it is expected to have type
"disj_vars (bound_variables (coerce_judgement_to_ty_ctx (judge x t)))
(bound_variables g)"
The problem is that the coercion of x into a VarSet.t is equal to Var.singleton x, while the coercion in judge reduces to VarSet.union (VarSet.singleton x) VarSet.empty. While these two are propositionally equal, they are not judgmentally equal, so as far as Coq is concerned, the term it came up with is ill-typed.
I was going through IndProp in software foundations and Adam Chlipala's chapter 4 book and I was having difficulties understanding inductive propositions.
For the sake of a running example, lets use:
Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall n : nat, ev n -> ev (S (S n)).
I think I do understand "normal" types using Set like:
Inductive nat : Set :=
| O : nat
| S : nat -> nat.
and things like O just return the single object of type nat and S O is taking an object of type nat and returning another different one of the same type nat. By different object I guess I mean they have different values.
What I am confused is on how exactly the constructors for inductive props differ from inductive types Set. For Set it seems they just behave as function, a function that take values and return more values of that type. But for Inductive Propositions I am having a hard time figuring out what they do.
For example take ev_0 as a simple example. I assume that is the name for the propositional object (value) ev 0. Since it's by itself ev 0 must be a Prop a proposition. But what exactly makes it true? If its a proposition it could be false I assume. I guess the induction is confusing me. ev is the "function that returns objects of some type (proposition)", so ev 0 is just a proposition, but we have not said what ev 0 should mean (unlike in my definition of natural number the base case is clear what its doing). In python I would expect to see
n == 0: return True
or something for the base case. But in this case it seems circular pointing to itself and not to something like True. I know there is a foundational misconception I have but I don't know what exactly what I am not understanding.
Also whats confusing me is the naming. In the nat the name O was crucial for building/constructing objects. But in the inductive definition ev_0 seems to be more like a label/pointer to the real value ev 0. So I'd assume ev_SS == ev_0 -? ev 2 doesn't really make sense but I don't know why. How are the labels here acting differently from the labels in the inductive types using set?
For ev_SS thats even more confusing. Since I don't know what labels are doing of course thats confusing me but look how this is pointing:
forall n : nat, ev n -> ev (S (S n))
so given a natural number n I assume it returns the proposition ev n -> ev (S (S n)) (I am assuming forall n : nat is not part of the proposition object and its just there to indicate when the constructer that returns propositions works). So forall n : nat, ev n -> ev (S (S n)) isn't really a proposition but ev n -> ev (S (S n)).
Can someone help me clarify how inductive proposition type really work in Coq?
Note I don't truly understand the difference between Set vs Type but I believe that would be a whole other post by itself.
Some more comments:
I was playing around with this some more and did:
Check ev_SS
and to my surprise got:
ev_SS
: forall n : nat, ev n -> ev (S (S n))
I think this is unexpected because I didn't expect that the type of ev_SS (unless I am misunderstanding what Check is suppose to do) would be the definition of the function itself. I thought that ev_SS was a constructor so in my mind I thought that would do a mapping in this case nat -> Prop so of course thats the type I expected.
So, first, it is normal for you to be confused by this, but it might be simpler than what you think!
There are two distinct concepts you are confused about, so let's take them one at a time. First, you mention that ev 0 is a proposition, and wonder what makes it true. You will learn at some point that propositions and types are the same things, and the distinction between Prop and Set and Type is not that those things are different inherently.
So, when you define the type (or proposition) nat, you are creating a new type, and describing what values exist within it. You declare that there is a value O, that is a nat. And you declare that there is a parameterized value S, that is a nat, when passed a nat.
In the same way, when you define the type (or proposition) ev, you are creating a new type (well, it's actually a family of types indexed by values of type nat), and describing what values exist within those ev types. You declare that there is a value ev_0, that is an ev 0. And you declare that there is a parameterized value ev_SS, that is an ev (S (S n)), when passed a n : nat and an ev n.
So you made the proposition be true by having ways of creating values within it. You can also define a false proposition by having no constructors, or having constructors that can never be called:
Inductive MyFalse1 := . (* no constructor! *)
Inductive MyFalse2 :=
| TryToConstructMe : False -> MyFalse2
| ThisWontWorkEither : 0 = 1 -> MyFalse2
.
I have declared two now types (or proposition), but there's no way to witness them because they either have no constructors, or no way to ever call those constructors.
Now regarding the naming of things, ev_0, ev_SS, O, and S are all the same kind of entity: a constructor. I'm not sure why you think that ev_0 is a pointer to a value ev 0.
There is no meaning to assign to ev n as a proposition, other than it's a proposition that may be true if there is a way to construct a value with type ev n, and may be false if there is no way to construct a value with type ev n.
However, note that ev n has been carefully crafted to be inhabited for exactly those ns that are even, and to be uninhabited for exactly those ns that are odd. It's in this sense that ev captures a proposition. If you receive a value of type ev n, it essentially asserts that n is an even number, because the type ev n only contains inhabitants for even values:
ev 0 contains 1 inhabitant (ev_0)
ev 1 contains 0 inhabitant
ev 2 contains 1 inhabitant (ev_SS 0 ev_0)
ev 3 contains 0 inhabitant
ev 4 contains 1 inhabitant (ev_SS 2 (ev_SS 0 ev_0))
etc.
Finally, for the difference between Set, Prop, and Type, these are all universes within which you can create inductive types, but they come with certain restrictions.
Prop enables an optimization for code generation. It's essentially a way for you, the programmer, to mark some type as being only used for verification purposes, never used for computation purposes. As a result, the type-checker will force you to never compute on proofs within the Prop universe, and the code generation will know that it can throw away those proofs as they don't participate in computational behavior.
Set is just a restriction of Prop to avoid dealing with universe levels. You don't really need to understand this until later in your learning process.
You should really try to not think of Prop as being a magical thing different than Set.
The following might help you: we could rewrite the definitions of nat and ev, in a completely equivalent way, as:
Inductive nat1 : Set :=
| O : nat1
| S : nat1 -> nat1
.
(* is the same as *)
Inductive nat1 : Set :=
| O : nat1
| S : forall (n : nat1), nat1
.
(* and *)
Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall (n : nat), ev n -> ev (S (S n))
.
(* is the same as *)
Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall (n : nat) (e : ev n), ev (S (S n))
.
Any time you see a type looking like a -> b, it's really a short-hand for forall (_ : a), b, that is, we expect an input of type a, and return an output of type b.
The reason why we write forall (n : nat) in ev_SS is that we have to give a name to the first argument, because the type of the second argument will depend on it (the second argument has type ev n).
If you replace Prop with Set then you say you understand the definition:
Inductive ev' : nat -> Set :=
| ev_0' : ev' 0
| ev_SS' : forall n : nat, ev' n -> ev' (S (S n)).
For every n : nat we think of ev' n as a type which has some elements, or perhaps none. Because this is an inductive definition, we can tell what the elements of ev' 0 are: the only element is ev_0' (or to be more precise, every closed term of type ev' 0 computes to ev_0;). There are no elements of ev_0 1, but there is an element of ev 2', namely ev_SS' 0 ev_0'. In fact, a little bit of thinking shows that ev n is either empty or a singleton, depending on whether n is even or odd.
It's exactly the same when we switch from Set to Prop, except that the reading is different: Set is a (large) type of types, Prop is also a type of types (they are universes). Each element of Prop is a type (but we prefer to call it a "proposition") which has some elements (but we prefer to call them "proofs"). So consider this:
Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall n : nat, ev n -> ev (S (S n)).
For every n : nat, we think of ev n as the statement that n has the property ev, whatever that property might be. For any give n, there may be a proof of ev n, in which case n has the property ev, or there may be no such proof, in which case n does not have the property ev. Because this is an inductive definition, we can tell what the proofs of ev_0 are: they all compute to ev_0'. There are no proofs of ev_0 1, but there is a proof of ev 2, namely ev_SS 0 ev_0. In fact, a little bit of thinking shows that ev n has a proof if, and only if, n is even. We now understand that ev is the property of being "even".
This is knows as "propositions as types".
We observed that ev' 0 contains just one element ev_0'. The type unit also contains just one element tt. Does this mean that ev' 0 and unit are equal? No, but they are equivalent because we can provide functions ev' 0 -> unit and unit -> ev' 0 which are inverses of each other.
We can ask the same question about ev 0: is it equal to True? No, but they are equivalent because we can prove the implications ev 0 -> True and True -> ev' 0.
One starts to wonder what the difference between Prop and Set is. For a type P : Prop all of its elements are considered equal, i.e., Coq does not allow us to distinguish between them. (This is a bit of a pedagocical lie, because in reality Coq is agnostic about whether all the element of P are considered equal, but perhaps it's better not to get into this right now.)
Exercise 6.7 in Coq'Art, or the final exercise of the Logic chapter in Software Foundations: show that the following are equivalent.
Definition peirce := forall P Q:Prop, ((P->Q)->P)->P.
Definition classic := forall P:Prop, ~~P -> P.
Definition excluded_middle := forall P:Prop, P\/~P.
Definition de_morgan_not_and_not := forall P Q:Prop, ~(~P/\~Q)->P\/Q.
Definition implies_to_or := forall P Q:Prop, (P->Q)->(~P\/Q).
The solution set expresses this by a circular chain of implications, using five separate lemmas. But "TFAE" proofs are common enough in mathematics that I'd like to have an idiom to express them. Is there one in Coq?
This type of pattern is very easy to express in Coq, although setting up the infrastructure to do so might take some effort.
First, we define a proposition that expresses that all propositions in a list are equivalent:
Require Import Coq.Lists.List. Import ListNotations.
Definition all_equivalent (Ps : list Prop) : Prop :=
forall n m : nat, nth n Ps False -> nth m Ps True.
Next, we want to capture the standard pattern for proving this kind of result: if each proposition in the list implies the next one, and the last implies the first, we know they are all equivalent. (We could also have a more general pattern, where we replace a straight list of implications with a graph of implications between the propositions, whose transitive closure generates a complete graph. We'll avoid that in the interest of simplicity.) The premise of this pattern is easy to express; it is just a code transcription of the English explanation above.
Fixpoint all_equivalent'_aux
(first current : Prop) (rest : list Prop) : Prop :=
match rest with
| [] => current -> first
| P :: rest' => (current -> P) /\ all_equivalent'_aux first P rest'
end.
Definition all_equivalent' (Ps : list Prop) : Prop :=
match Ps with
| first :: second :: rest =>
(first -> second) /\ all_equivalent' first second rest
| _ => True
end.
The difficult part is showing that this premise implies the conclusion we want:
Lemma all_equivalentP Ps : all_equivalent' Ps -> all_equivalent Ps.
Showing that this lemma holds probably requires some ingenuity to find a strong enough inductive generalization. I can't quite prove it right now, but might add a solution later to the answer if you want.
I have been struggling on this for a while now. I have an inductive type:
Definition char := nat.
Definition string := list char.
Inductive Exp : Set :=
| Lit : char -> Exp
| And : Exp -> Exp -> Exp
| Or : Exp -> Exp -> Exp
| Many: Exp -> Exp
from which I define a family of types inductively:
Inductive Language : Exp -> Set :=
| LangLit : forall c:char, Language (Lit c)
| LangAnd : forall r1 r2: Exp, Language(r1) -> Language(r2) -> Language(And r1 r2)
| LangOrLeft : forall r1 r2: Exp, Language(r1) -> Language(Or r1 r2)
| LangOrRight : forall r1 r2: Exp, Language(r2) -> Language(Or r1 r2)
| LangEmpty : forall r: Exp, Language (Many r)
| LangMany : forall r: Exp, Language (Many r) -> Language r -> Language (Many r).
The rational here is that given a regular expression r:Exp I am attempting to represent the language associated with r as a type Language r, and I am doing so with a single inductive definition.
I would like to prove:
Lemma L1 : forall (c:char)(x:Language (Lit c)),
x = LangLit c.
(In other words, the type Language (Lit c) has only one element, i.e. the language of the regular expression 'c' is made of the single string "c". Of course I need to define some semantics converting elements of Language r to string)
Now the specifics of this problem are not important and simply serve to motivate my question: let us use nat instead of Exp and let us define a type List n which represents the lists of length n:
Parameter A:Set.
Inductive List : nat -> Set :=
| ListNil : List 0
| ListCons : forall (n:nat), A -> List n -> List (S n).
Here again I am using a single inductive definition to define a family of types List n.
I would like to prove:
Lemma L2: forall (x: List 0),
x = ListNil.
(in other words, the type List 0 has only one element).
I have run out of ideas on this one.
Normally when attempting to prove (negative) results with inductive types (or predicates), I would use the elim tactic (having made sure all the relevant hypothesis are inside my goal (generalize) and only variables occur in the type constructors). But elim is no good in this case.
If you are willing to accept more than just the basic logic of Coq, you can just use the dependent destruction tactic, available in the Program library (I've taken the liberty of rephrasing your last example in terms of standard-library vectors):
Require Coq.Vectors.Vector.
Require Import Program.
Lemma l0 A (v : Vector.t A 0) : v = #Vector.nil A.
Proof.
now dependent destruction v.
Qed.
If you inspect the term, you'll see that this tactic relied on the JMeq_eq axiom to get the proof to go through:
Print Assumptions l0.
Axioms:
JMeq_eq : forall (A : Type) (x y : A), x ~= y -> x = y
Fortunately, it is possible to prove l0 without having to resort to features outside of Coq's basic logic, by making a small change to the statement of the previous lemma.
Lemma l0_gen A n (v : Vector.t A n) :
match n return Vector.t A n -> Prop with
| 0 => fun v => v = #Vector.nil A
| _ => fun _ => True
end v.
Proof.
now destruct v.
Qed.
Lemma l0' A (v : Vector.t A 0) : v = #Vector.nil A.
Proof.
exact (l0_gen A 0 v).
Qed.
We can see that this new proof does not require any additional axioms:
Print Assumptions l0'.
Closed under the global context
What happened here? The problem, roughly speaking, is that in Coq we cannot perform case analysis on terms of dependent types whose indices have a specific shape (such as 0, in your case) directly. Instead, we must prove a more general statement where the problematic indices are replaced by variables. This is exactly what the l0_gen lemma is doing. Notice how we had to make the match on n return a function that abstracts on v. This is another instance of what is known as "convoy pattern". Had we written
match n with
| 0 => v = #Vector.nil A
| _ => True
end.
Coq would see the v in the 0 branch as having type Vector.t A n, making that branch ill-typed.
Coming up with such generalizations is one of the big pains of doing dependently typed programming in Coq. Other systems, such as Agda, make it possible to write this kind of code with much less effort, but it was only recently shown that this can be done without relying on the extra axioms that Coq wanted to avoid including in its basic theory. We can only hope that this will be simplified in future versions.