Very basic question about coq. How do I define the following two inductive types?
Type 1 containing:
o fo, ffo, fffo...
k, sk, ssk, sssk...
Note that the f here could alternatively be characterized as the natural number index for o.
Type 2 containing the same but now we can also have terms like fsffsk and sfsfso.
If I understand your first type correctly, you can represent it by combining simpler types defined in the Coq standard library:
Definition t1 : Type := nat + nat.
The + operator on types is the disjoint union of two types. The idea is that the element inl n, which is injected on the left of the union, represents the string fff...o, with n occurrences of f, whereas the element inr n, which is injected on the right of the union, represents the string sss...k, with n occurrences of s.
I do not understand the patterns on the second type. Did you really mean to write fsffsk instead of fsfsfsk?
Do you actually need to base type2's definition on type1 ? Because actually just a simple definition :
Inductive type2 : Type :=
| o : type2
| k : type2
| f : type2 -> type2
| s : type2 -> type2
.
And then define examples like :
Definition typeExample : type2 := f (s (f (s (s (f (s (k))))))).
Related
Consider this type that has X as an implicit type.
Inductive list' {X:Type} : Type :=
| nil'
| cons' (x : X) (l : list').
Coq deduced that type of the second argument of cons' is #list' A:
Fail Check cons' a (cons' b nil'). (* "cons' b nil'" expected to have type "#list' A"*)
But how was this type deduced unambiguously?
We can create another type:
Inductive list'' {X:Type} : Type :=
| nil''
| cons'' (x : X) (l : #list'' B).
Check cons'' a (cons'' b nil'').
It shows that l could also be #list' B.
To be precise, Coq inferred the type of cons' to be forall {X}, X -> #list' X -> #list' X. Then when you write cons a, Coq works out that you must be building a #list' A, and fills in X with A, thus constraining the second argument to be again of type #list' A.
However, the choice of X over some other type is not the only possible choice, as you noticed. In your second example, cons'' gets type forall {X}, X -> #list'' B -> #list'' X. However, when it is left unspecified, most people most of the time intend their parameters (things on the left side of the colon) to be uniform, that is, the same in the arguments as in the conclusion, which heuristic leads to the choice of X here. In general, Coq doesn't worry too much about making sure it's solutions are unique for things the user left unspecified.
In recent enough versions of Coq, you can use the option Uniform Inductive Parameters to specify that all parameters are uniform, or use a | to separate the uniform from the non-uniform parameters. In the case of lists, that would look like
Inductive list' (X:Type) | : Type :=
| nil'
| cons' (x : X) (l : list').
Note that with the |, in the declaration of constructors list' has type Type, while without the |, list' has type Type -> Type, and there is a constraint that the conclusion of the constructor has to be list X (while the arguments can use list other_type freely).
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.)
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.))
Coq would let me define this :
Definition teenagers : Set := { x : nat | x >= 13 /\ x <= 19 }.
and also :
Variable Julia:teenagers.
but not :
Example minus_20 : forall x:teenagers, x<20.
or :
Example Julia_fact1 : Julia > 12.
This is because Julia (of type teenagers) cannot be compared to 12 (nat).
Q: How should I inform Coq that Julia's support type is nat so that I can write anything useful about her ?
Q': My definition of teenagers seems like a dead end ; it is more declarative than constructive and I seem to have lost inductive properties of nat. How can I show up its inhabitants ? If there is no way, I can still stick to nat and work with Prop and functions. (newbie here, less than one week self learning with Pierce's SF).
The pattern you are using in teenagers is an instance of the "subType" pattern. As you have noted, a { x : nat | P x } is different from nat. Currently, Coq provides little support to handle these kind of types effectively, but if you restrict to "well-behaved" classes of P, you can actually work in a reasonable way. [This should really become a Coq FAQ BTW]
In the long term, you may want to use special support for this pattern. A good example of such support is provided by the math-comp library subType interface.
Describing this interface is beyond your original question, so I will end with a few comments:
In your minus_20 example, you want to use the first projection of your teenagers datatype. Try forall x : teenagers, proj1_sig x < 20. Coq can try to insert such projection automatically if you declare the projection as a Coercion:
Require Import Omega.
Definition teenagers : Set :=
{ x : nat | x >= 13 /\ x <= 19 }.
Coercion teen_to_nat := fun x : teenagers => proj1_sig x.
Implicit Type t : teenagers.
Lemma u t : t < 20.
Proof. now destruct t; simpl; omega. Qed.
As you have correctly observed, { x : T | P x } is not the same in Coq than x. In principle, you cannot transfer reasoning from objects of type T to objects of type { x : T | P x } as you must also reason in addition about objects of type P x. But for a wide class of P, you can show that the teen_to_nat projection is injective, that is:
forall t1 t2, teen_to_nat t1 = teen_to_nat t2 -> t1 = t2.
Then, reasoning over the base type can be transferred to the subtype. See also: Inductive subset of an inductive set in Coq
[edit]: I've added a couple typical examples of subTypes in math-comp, as I think they illustrate well the concept:
Sized lists or n.-tuples. A list of length n is represented in math-comp as a pair of a single list plus a proof of size, that is to say n.-tuple T = { s : seq T | size s == n}. Thanks to injectivity and coertions, you can use all the regular list functions over tuples and they work fine.
Bounded natural or ordinals: similarly, the type 'I_n = { x : nat | x < n } works almost the same than a natural number, but with a bound.
I would like to somehow limit what kind of inputs constructors are allowed to take in an inductive definition. Say I want to say define binary numbers as follows:
Inductive bin : Type :=
| O : bin
| D : bin -> bin
| S : bin -> bin.
The idea here is that D doubles up a nonzero number by adding a zero at the end and S takes a number with zero as the last digit and turns the last digit into a one. This means that the following are legal numbers:
S 0
D (S 0)
D (D (S 0))
while the following would not be:
S (S 0)
D 0
Is there a way to enforce such restrictions in an inductive definition in a clean way?
You could define what it means for a bin to be legal with a predicate, and then give a name to the subset of bins that obey that predicate. Then you write functions with Program Definition and Program Fixpoint instead of Definition and Fixpoint. For recursive functions you'll also need a measure to prove the arguments of your functions decrease in size since the functions are not structurally recursive anymore.
Require Import Coq.Program.Program.
Fixpoint Legal (b1 : bin) : Prop :=
match b1 with
| O => True
| D O => False
| D b2 => Legal b2
| S (S _) => False
| S b2 => Legal b2
end.
Definition lbin : Type := {b1 : bin | Legal b1}.
Fixpoint to_un (b1 : bin) : nat :=
match b1 with
| O => 0
| D b2 => to_un b2 + to_un b2
| S b2 => Coq.Init.Datatypes.S (to_un b2)
end.
Program Definition zer (b1 : lbin) := O.
Program Fixpoint succ (b1 : lbin) {measure (to_un b1)} : lbin :=
But this simply-typed approach would probably be easier.
This could be done with inductive-recursive definitions - but unfortunately Coq doesn't support those.
From an object-oriented programming perspective, O, D and S are subtypes of bin, and their constructor types are then definable without resorting to logical predicates, but Coq doesn't support object-oriented programming natively either.
However, Coq does have typeclasses. So what I might do is make bin a typeclass, and make each of the constructors a separate inductive type, each of which has an instance of the bin typeclass. I'm not sure what the method(s) of the typeclass would be though.