How does one print the entire contents of a proof object or Gallina terms in Coq? - coq

How does one print and expand everything in a Coq term (e.g. implicits, notations, definition, everything)? I want to print absolutely everything (including the contents of the identifiers).
For example with a term, I tried a modest example with Set Printing All. but it didn't work as I expect. My script is:
Module print_everything.
Definition id {A:Type} (x:A) := x.
Print id.
Definition id2 := #id.
Print id2.
Set Printing All.
Print id2.
Print All.
End.
but when I sent it to coq I got:
id2 = #id
: forall (A : Type) (_ : A), A
but I expect the body of the function, something like this:
id2 = fun (A : Type) (x : A) => x
: forall (A : Type) (_ : A), A
or
id = fun (A : Type) (x : A) => x
: forall (A : Type) (_ : A), A
How does one remove all "abstractions", including notation, implicit and even identifiers
so that I can see the entire lambda term (ideally when passing a Gallina term to Print_everything)?
If possible I'd like to control the scopes of which definitions are unpacked for me too. e.g. global variables qualid . qualid.
How does one print and expand everything in a Coq term (e.g. implicits, notations, definition, everything)?
It would also be nice to be able to expand and simplify as much as possible.
Related:
How to temporarily disable notations in Coq
https://coq.discourse.group/t/how-to-unset-printing-everything-e-g-implicits-notations-etc/1364/4
it seems Show Proof. works in the middle of a proof: https://www.seas.upenn.edu/~cis500/cis500-f14/sf/ProofObjects.html and https://softwarefoundations.cis.upenn.edu/lf-current/ProofObjects.html

Related

Why is my definition not allowed because of strict positivity?

I have the following two definitions that result in two different error messages.
The first definition is declined because of strict positivity and the second one because of a universe inconsistency.
(* non-strictly positive *)
Inductive SwitchNSP (A : Type) : Type :=
| switchNSP : SwitchNSP bool -> SwitchNSP A.
Fail Inductive UseSwitchNSP :=
| useSwitchNSP : SwitchNSP UseSwitchNSP -> UseSwitchNSP.
(* universe inconsistency *)
Inductive SwitchNSPI : Type -> Type :=
| switchNSPI : forall A, SwitchNSPI bool -> SwitchNSPI A.
Fail Inductive UseSwitchNSPI :=
| useSwitchNSPI : SwitchNSPI UseSwitchNSPI -> UseSwitchNSPI.
Chatting on gitter revealed that universe (in)consistencies are checked first, that is, the first definition adheres this check, but then fails because of a strict positivity issue.
As far as I understand the strict positivity restriction, if Coq allows non-strictly positivity data type definitions, I could construct non-terminating functions without using fix (which is pretty bad).
In order to make it even more confusing, the first definition is accepted in Agda and the second one gives a strict positivity error.
data Bool : Set where
True : Bool
False : Bool
data SwitchNSP (A : Set) : Set where
switchNSP : SwitchNSP Bool -> SwitchNSP A
data UseSwitchNSP : Set where
useSwitchNSP : SwitchNSP UseSwitchNSP -> UseSwitchNSP
data SwitchNSPI : Set -> Set where
switchNSPI : forall A -> SwitchNSPI Bool -> SwitchNSPI A
data UseSwitchNSPI : Set where
useSwitchNSP : SwitchNSPI UseSwitchNSPI -> UseSwitchNSPI
Now my question is two-folded: first, what is the "evil example" I could construct with the above definition? Second, which of the rules applies to the above definition?
Some notes:
To clarify, I think that I do understand why the second definition is not allowed type-checking-wise, but still feel that there is nothing "evil" happening here, when the definition is allowed.
I first thought that my example is an instance of this question, but enabling universe polymorphism does not help for the second definition.
Can I use some "trick" do adapt my definition such that it is accepted by Coq?
Unfortunately, there's nothing super deep about this example. As you noted Agda accepts it, and what trips Coq is the lack of uniformity in the parameters. For example, it accepts this:
Inductive SwitchNSPA (A : Type) : Type :=
| switchNSPA : SwitchNSPA A -> SwitchNSPA A.
Inductive UseSwitchNSPA :=
| useSwitchNSPA : SwitchNSPA UseSwitchNSPA -> UseSwitchNSPA.
Positivity criteria like the one used by Coq are not complete, so they will reject harmless types; the problem with supporting more types is that it often makes the positivity checker more complex, and that's already one of the most complex pieces of the kernel.
As for the concrete details of why it rejects it, well, I'm not 100% sure. Going by the rules in the manual, I think it should be accepted?
EDIT: The manual is being updated.
Specifically, using the following shorter names to simplify the following:
Inductive Inner (A : Type) : Type := inner : Inner bool -> Inner A.
Inductive Outer := outer : Inner Outer -> Outer.
Correctness rules
Positivity condition
Here,
X = Outer
T = forall x: Inner X, X
So we're in the second case with
U = Inner X
V = X
V is easy, so let's do that first:
V = (X) falls in the first case, with no t_i, hence is positive for X
For U: is U = Inner X strictly positive wrt X?
Here,
T = Inner X
Hence we're in the last case: T converts to (I a1) (no t_i) with
I = Inner
a1 = X
and X does not occur in the t_i, since there are no t_i.
Do the instantiated types of the constructors satisfy the nested positivity condition?
There is only one constructor:
inner : Inner bool -> Inner X.
Does this satisfy the nested positivity condition?
Here,
T = forall x: Inner bool, Inner X.
So we're in the second case with
U = Inner bool
V = Inner X
X does not occur in U, so X is strictly positive in U.
Does V satisfy the nested positivity condition for X?
Here,
T = Inner X
Hence we're in the first case: T converts to (I b1) (no u_i) with
I = Inner
b1 = X
There are no u_i, so V satisfies the nested positivity condition.
I have opened a bug report. The manual is being fixed.
Two more small things:
I can't resist pointing that your type is empty:
Theorem Inner_empty: forall A, Inner A -> False.
Proof. induction 1; assumption. Qed.
You wrote:
if Coq allows non-strictly positivity data type definitions, I could construct non-terminating functions without using fix (which is pretty bad).
That's almost correct, but not exactly: if Coq didn't enforce strict positivity, you could construct non-terminating functions period, which is bad. It doesn't matter whether they use fix or not: having non-termination in the logic basically makes it unsound (and hence Coq prevents you from writing fixpoints that do not terminate by lazy reduction).

how to figure out what "=" means in different types in coq

Given a type (like List) in Coq, how do I figure out what the equality symbol "=" mean in that type? What commands should I type to figure out the definition?
The equality symbol is just special infix syntax for the eq predicate. Perhaps surprisingly, it is defined the same way for every type, and we can even ask Coq to print it for us:
Print eq.
(* Answer: *)
Inductive eq (A : Type) (x : A) : Prop :=
| eq_refl : eq x x.
This definition is so minimal that it might be hard to understand what is going on. Roughly speaking, it says that the most basic way to show that two expressions are equal is by reflexivity -- that is, when they are exactly the same. For instance, we can use eq_refl to prove that 5 = 5 or [4] = [4]:
Check eq_refl : 5 = 5.
Check eq_refl : [4] = [4].
There is more to this definition than meets the eye. First, Coq considers any two expressions that are equalivalent up to simplification to be equal. In these cases, we can use eq_refl to show that they are equal as well. For instance:
Check eq_refl : 2 + 2 = 4.
This works because Coq knows the definition of addition on the natural numbers and is able to mechanically simplify the expression 2 + 2 until it arrives at 4.
Furthermore, the above definition tells us how to use an equality to prove other facts. Because of the way inductive types work in Coq, we can show the following result:
eq_elim :
forall (A : Type) (x y : A),
x = y ->
forall (P : A -> Prop), P x -> P y
Paraphrasing, when two things are equal, any fact that holds of the first one also holds of the second one. This principle is roughly what Coq uses under the hood when you invoke the rewrite tactic.
Finally, equality interacts with other types in interesting ways. You asked what the definition of equality for list was. We can show that the following lemmas are valid:
forall A (x1 x2 : A) (l1 l2 : list A),
x1 :: l1 = x2 :: l2 -> x1 = x2 /\ l1 = l2
forall A (x : A) (l : list A),
x :: l <> nil.
In words:
if two nonempty lists are equal, then their heads and tails are equal;
a nonempty list is different from nil.
More generally, if T is an inductive type, we can show that:
if two expressions starting with the same constructor are equal, then their arguments are equal (that is, constructors are injective); and
two expressions starting with different constructors are always different (that is, different constructors are disjoint).
These facts are not, strictly speaking, part of the definition of equality, but rather consequences of the way inductive types work in Coq. Unfortunately, it doesn't work as well for other kinds of types in Coq; in particular, the notion of equality for functions in Coq is not very useful, unless you are willing to add extra axioms into the theory.

(How) can I define partial coercions in Coq?

I want to set Coq up, without redefining the : with a notation (and without a plugin, and without replacing the standard library or redefining the constants I'm using---no cheating like that), so that I have something like a partial coercion from option nat to nat, which is defined only on Some _. In particular, I want
Eval compute in Some 0 : nat.
to evaluate to 0, and I want
Check None : nat.
to raise an error.
The closest I've managed is the ability to do this with two :s:
Definition dummy {A} (x : option A) := A.
Definition inverted_option {A} (x : option A)
:= match x with Some _ => A | _ => True end.
Definition invert_Some {A} (x : option A) : inverted_option x
:= match x with Some v => v | None => I end.
Coercion invert_Some : option >-> inverted_option.
Notation nat' := (inverted_option (A:=nat) (Some _)).
Eval compute in (Some 0 : nat') : nat.
Check (None : nat') : nat.
(* The term "None" has type "option ?A" while it is expected to have type
"nat'". *)
However, this only works when nat' is a notation, and I can't define a coercion out of a notation. (And trying to define a coercion from inverted_option (Some _) to nat violated the uniform inheritance condition.) I thought I might be able to get around this issue by using canonical structures, but I haven't managed to figure out how to interleave canonical structure resolution with coercion insertion (see also Can canonical structure resolution be interleaved with coercion insertion?).
(I ran into this issue when attempting to answer Coq: Defining a subtype.)

Idiomatically expressing "The Following Are Equivalent" in Coq

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.

Decoupling the data to be manipulated from the proofs that the manipulations are justified

I have a type of lists whose heads and tails must be in a certain sense "compatible":
Inductive tag := A | B. (* Just an example *)
Inductive element : tag -> tag -> Set :=
| AA : element A A
| AB : element A B
| BB : element B B. (* Also just an example *)
Inductive estack : tag -> tag -> Set :=
| ENil : forall t, estack t t
| ECons : forall r s t, element r s -> estack s t -> estack r t.
However, I do not like this code very much, for the following reasons:
It is not modular: The ad-hoc list data constructors are intrinsically coupled with the proofs that the heads and tails are compatible - the tags.
It does not favor code reuse: I am forced to redefine the usual list functions (such as list concatenation) and re-prove the usual list theorems (such as the associativity of list concatenation).
I have a different approach in mind, which consists of three steps:
Defining a single type of tagged elements (as opposed to a family of tagged types of elements):
Inductive taggedElement := Tagged : forall t1 t2, element t1 t2 -> taggedElement.
Defining the type of arbitrary (that is, either valid or invalid) lists of tagged elements:
Definition taggedElementStack := list taggedElement.
Defining a valid list of tagged elements as a tuple whose elements are an arbitrary list of tagged elements and a proof that the elements are compatible with the adjacent ones.
(* I have no idea how to do this in Coq, hence the question!
*
* I am going to use pseudomathematical notation. I am not well versed in either
* mathematics or theoretical computer science, so please do not beat me with a
* stick if I say something that is completely bogus!
*
* I want to construct the type
*
* (tes : taggedElementStack, b : proof that P(tes) holds)
*
* where P(tes) is a predicate that is only true when, for every sublist of tes,
* including tes itself, the heads and tails are compatible.
*)
How would I perform the third step in Coq?
Look at your estack, what does it do? Generalize! element is just a relation (A -> A -> Set), tag is just a Set. What do you get?
Inductive RTList {I : Set} (X : Rel I) : Rel I :=
| RTNil : forall {i : I}, RTList X i i
| RTCons : forall {i j k : I}, X i j -> RTList X j k -> RTList X i k.
(Rel ist just a Definition with Rel I = I -> I -> Set.)
Reflexive-transitive closure! That is common, reusable and modular. Or so you'd think.
The only implementation I found in Coq's libs is in Coq.Relations.Relation_Operators, named clos_refl_trans, differently structured and locked into Prop (all according to the docs, didn't try it).
You'll probably have to re-implement that or find a library somewhere. At least, you'll only have to do this once (or up to three times for Set, Prop and Type).
Your other idea will probably be harder to manage. Look at NoDup for something that's similar to your description, you might be able to reuse the pattern. If you really want that. NoDup uses In, which is a function that checks if an element is in a list. The last time I tried using it, I found it considerably harder to solve proofs involving In. You can't just destruct but have to apply helper lemmas, you have to carefully unfold exactly $n levels, folding back is hard etc. etc. I'd suggest that unless it's truly necessary, you'd better stick with data types for Props.