I'm quite new to Coq, and I have an error when I try to use not_iff_compat theorem in a proof. For instance, given the following mwe:
Require Import Coq.Init.Logic.
Lemma dummy: forall A B, (A <-> B) -> (~A <-> ~B).
Proof.
apply not_iff_compat.
Qed.
Coq tells me: "Error: The reference not_iff_compat was not found in the current environment."
(As far as I now, Coq.Init.Logic is automatically loaded so not necessary here, but the problem is the same without).
Remarks: I use CoqIde 8.6, if that matters.
Your link starts with https://coq.inria.fr/distrib/current/, but the current version is 8.7.0 as of now and Coq v8.6 does not have the lemma in that module.
You can browse the standard libraries of different Coq versions by replacing 'current' with the version of your choice, e.g. like so: https://coq.inria.fr/distrib/8.6.1/stdlib/Coq.Init.Logic.html.
Just a tip: usually you can append #lemma to the file path to get a more precise link: https://coq.inria.fr/distrib/current/stdlib/Coq.Init.Logic.html#not_iff_compat.
Related
Suppose I write the following lemma and proof in Coq:
Lemma foo : forall A, A -> A.
Proof.
- simpl.
- auto.
Qed.
The simpl here doesn't do anything, and this is a bad use of bullet points (-). When I try to compile this with coqc, I get the following complaint:
Error: [Focus] Wrong bullet -: Current bullet - is not finished.
It's clear to me why this error happens. When I open the second bullet point for auto, it complains that I didn't finish the first bullet point. However, what doesn't make sense to me is that this code compiles fine:
From Coquelicot Require Import Complex.
Lemma foo : forall A, A -> A.
Proof.
- simpl.
- auto.
Qed.
It seems that the act of importing from Coquelicot makes it so that bullet points are completely ignored. A couple questions:
Why does this happen? Is this some sort of bug?
Is there a way to disable this behavior? I would like to use Coquelicot and still have proper bullet point usage be checked.
I'm currently using Coq 8.13.2 compiled with OCaml 4.10.2, and Coquelicot 3.2.0.
Coquelicot depends on MathComp and MathComp disables the conventional meaning of bullets (because they use them differently). However, instead of doing this locally to the MathComp project, they set an option globally, and that's why you get this behavior.
To retrieve the expected behavior, you need to reset the option to the default value like this:
Set Bullet Behavior "Strict Subproofs".
(cf. https://coq.inria.fr/refman/proofs/writing-proofs/proof-mode.html#coq:opt.Bullet-Behavior)
I like using the move=> tactic from the ssreflect library in cases when the goal is an implication (e.g. A -> B), to make the premise a hypothesis, and make the conclusion the new goal. However, I don't always want to use ssreflect.
Is there another Coq tactic that does the same thing without using ssreflect?
You can always use intros: intros pat is roughly equivalent to move=> pat. Unfortunately, Coq and ssreflect use a different syntax for introduction patterns, so the two are not interchangeable.
Note that nowadays ssreflect is part of the Coq distribution, so you can use the tactic language by simply doing From Coq Require Import ssreflect., without the need for installing a separate library.
I'd like to view the definition of a Standard Library theorem which I found through Search. I think seeing the definition will help me complete a similar theorem.
Doing Print Rdiv_lt_0_compat. yields:
Rdiv_lt_0_compat =
fun (a b : R) (H : (0 < a)%R) (H0 : (0 < b)%R) =>
Rmult_lt_0_compat a (/ b) H (Rinv_0_lt_compat b H0)
: forall a b : R, (0 < a)%R -> (0 < b)%R -> (0 < a / b)%R
Argument scopes are [R_scope R_scope _ _]
Setting Set Printing All. doesn't help. There's nothing extra available in the docs page.
The whole Coq system is based on the idea Proofs are programs, logical formulas are types. When you consider a theorem, it is a proof (a program) and its statement is a logical formula (the type of a program). In the very
first years of Coq, there was no tactic language, every proof was defined using the same keywords as when defining a program.
After a few years, it was recognized that writing the programs entirely by hand was long and tiresome, so a tactic language was invented to explain how to construct the proof-programs in a shorter and less difficult way. But what is recorded and eventually checked are still the programs that you see using Print.
When building a proof-program, the tactic intros constructs anonymous function expressions (also known as lambdas, usually written with the keyword fun, and apply constructs an application of a function to a certain number arguments, which apply infers or leaves to the user as goals. The tactics induction and rewrite are similar, but they apply theorems that are not
given by the user. The tactic destruct essentially produces a piece of programs that is a pattern-matching construct.
With Rdiv_lt_0_compat, you are lucky that the proof built by the tactic is quite short. Often, proofs written using tactics produce programs that are much longer.
If instead of the program, you want to see the sequence of tactics that generated it, you need to find it in the sources of the system, because this
is not kept in the memory of the proof assistant. Here are the clues.
Require Import Reals.
Locate Rdiv_lt_0_compat.
the answer is Constant Coq.Reals.RIneq.Rdiv_lt_0_compat
This sequence of names indicates the hierarchy of modules in which the theorem is kept. The first name Coq expresses that this theorem is in the Coq sources, essentially in directory ...theories/, the second name Reals, indicates that you should look in tge sub directory ...theories/Reals.
The fourth name should not be used as a directory name, but as file name. So you should look in the file RIneq.v
So go an look in https://github.com/coq/coq/tree/v8.12/theories/Reals/RIneq.v and you will probably find the script fragment that was used to generate your theorem (for the 8.12 version of Coq). I just checked, the theorem appears at line https://github.com/coq/coq/blob/c95bd4cf015a3084a8bddf6d3640458c9c25b455/theories/Reals/RIneq.v#L2106
The sequence of names provided by Locate is not a sure way to find the file where the script for a theorem is stored. The correspondence between the long name and the file path is broken when the theorem is defined using modules and functor instantiation. In that case, you have to rely on stronger knowledge of how the Coq system works.
In the current version of the Software Foundations, the relevant explanation is formulated with intentional leeway.
First, we've used the keyword Theorem instead of Example.
This difference is mostly a matter of style; the keywords
Example and Theorem (and a few others, including Lemma,
Fact, and Remark) mean pretty much the same thing to Coq.
(I put the wording used to introduce uncertainty in bold.)
In an earlier version of, evidently, the same writing, it was put strongly:
The form of this theorem and proof are almost exactly the same as the examples above: the only differences are that we've added the quantifier ∀ n:nat and that we've used the keyword Theorem instead of Example. Indeed, the latter difference is purely a matter of style; the keywords Example and Theorem (and a few others, including Lemma, Fact, and Remark) mean exactly the same thing to Coq.
(I put words introducing strength in bold.)
Looking at the official documentation, all of these words, and more, belong to the same grammatical category «assertion keyword»:
assertion_keyword ::= Theorem | Lemma
Remark | Fact
Corollary | Property | Proposition
Definition | Example
There are further two sections explaining how these keywords work: «Definitions» and «Assertions and proofs». In short:
Definitions extend the environment with associations of names to terms.
— And:
An assertion states a proposition (or a type) of which the proof (or an inhabitant of the type) is interactively built using tactics.
But, as far as I see, a theorem also extends the environment, and an example can be built with tactics. So, I am not seeing where these things are different. But the Software Foundation is a clever book. If they chose to be uncertain, there must be a reason?
As of today the differences are minimal, and could be summarized as:
Theorem/Example/Definition/... do produce different entries in the documentation; this is the most relevant difference.
Some forms such as Theorem don't support the syntactical form Theorem foo := nat. for non-interactive mode, which is supported by Definition for example.
Another non-trivial difference is whether you use the interactive mode or not. That is to say:
Definition foo : Type := nat.
and
Definition foo : Type. Proof. apply nat. Qed.
will take slightly different code paths due to the second creating an interactive proof; the codepath when the definition gets sent to the kernel is a bit different, but Coq 8.12 should unify them for all practical purposes, just marking the second proof as opaque.
One difference I've seen is that Definitions can give an immediate definition, whereas Lemma and Theorem can't.
Definition one := 1.
Lemma two := 2. (* syntax error *)
Theorem three := 3. (* syntax error *)
Out of the rest, only Example works.
Remark four := 4. (* syntax error *)
Fact five := 5. (* syntax error *)
Corollary six := 6. (* syntax error *)
Property seven := 7. (* syntax error *)
Proposition eight := 8. (* syntax error *)
Example nine := 9. (* works! *)
So, I've got a proof that looks like this:
induction t; intros; inversion H ; crush.
It solves all my goals, but when I do Qed, I get the following error:
Cannot guess decreasing argument of fix.
So somewhere in the generated proof term, there's non-well-founded recursion. The problem is, I have no idea where.
Is there a way to debug this kind of error, or to see the (possibly non halting) proof term that the tactics script generates?
You can use Show Proof. to view the proof term so far.
Another command that can help with seeing where the recursion went wrong is Guarded., which runs the termination checker on the proof term so far. You'll need to break apart the tactic script into independent sentences to use it, though. Here's an example:
Fixpoint f (n:nat) : nat.
Proof.
apply plus.
exact (f n).
Guarded.
(* fails with:
Error:
Recursive definition of f is ill-formed.
...
*)
Defined.
You can use the Show Proof. command inside proof mode to print the proof term produced so far.
In addition to the other excellent answers, I also want to point out that using induction inside an interactive-mode Fixpoint is usually a mistake, because you're recursing twice. Writing fixpoints in interactive mode is often tricky because most automation tools will happily make a recursive call at every possible opportunity, even when it would be ill-founded.
I would advise to use Definition instead of Fixpoint and use induction in the proof script. This invokes the explicit recursor, which allows for much better control of automation. The disadvantage is decreased flexibility since fixpoints have fewer restrictions than recursors - but as we've seen, that is both a blessing and a curse.