I trying to use coq as a programming language with dependent type. I created the following small program:
Inductive Good : list nat -> Set :=
| GoodNonEmpty : forall h t, Good (h :: t).
Definition get_first(l : list nat)(good : Good l) : nat :=
match l with
| h :: t => h
| nil =>
match good with
end
end.
I defined a type for non empty list and create a function which gets the first element of such a list provided there's a proof that it's not empty. I handle well the case where head items consists of two items, but I can't handle the impossible case of empty list. How can I do this in coq?
One way to do it that is simpler than your try is:
Definition get_first (l : list nat) (good : Good l) : nat :=
match good with
| GoodNonEmpty h _ => h
end.
Here is a way to do it in the way you wanted to do it. You'll notice it is very verbose to prove that "Good nil" does not exist, inlined.
Definition get_first (l : list nat) (good : Good l) : nat :=
(
match l as l' return (Good l' -> nat) with
| nil =>
fun (goodnil : Good nil) =>
(
match goodnil in (Good l'') return (nil = l'' -> nat) with
| GoodNonEmpty h t =>
fun H => False_rect _ (nil_cons H)
end
)
(#eq_refl _ nil)
| h :: _ => fun _ => h
end
) good.
You can surely define some of that outside and reuse it. I am not aware of the best practices though. Maybe someone can come with a shorter way to do the same thing.
EDIT:
By the way, you can get to pretty much the same result, in a much easier way, in proof mode:
Definition get_first' (l : list nat) (good : Good l) : nat.
Proof.
destruct l. inversion good. exact n.
Defined.
You can then:
Print get_first'.
To see how Coq defines it. However, for more involved things, you might be better off following what gdsfhl from the #coq IRC channel proposed as a solution:
http://paste.in.ua/4782/
You can see that he uses the refine tactic to provide part of the skeleton of the term to write, and defer the missing proofs.
Related
Coq seems to assume ex falso quodlibet / the principle of explosion (PEP).
The induction principle generated from a data type definition with no constructors is PEP:
False_ind =
fun (P : Prop) (f : False) => match f return P with
end
: forall P : Prop, False -> P
This principal seems to be necessary for proving things like disjunctive syllogism:
Lemma disj_syll : forall (A B: Prop), A \/ B -> (not B) -> A.
Proof.
intros.
destruct H.
- (* prove A from A *) assumption.
- (* prove A from B and ~B *) contradiction.
Qed.
So that's what PEP buys us in terms of proving. But what about programming?
I can't figure out what it would mean to drop PEP and am really confused by the program extraction output.
As far as I can tell:
the extractions are the same for all proofs that rely on PEP, including the one above
the extractions for Scheme and Haskell seem to do completely different things
Scheme:
(load "macros_extr.scm")
(define __ (lambda (_) __))
(define disj_syll __)
Haskell:
module Disj_syll where
import qualified Prelude
__ :: any
__ = Prelude.error "Logical or arity value used"
disj_syll :: ()
disj_syll = __
What is going on?
I'm asking this question because the connection between proofs and programs (Propositions-as-Types / Curry-Howard Isomorphism) seems well-understood for the logical connectives generally, but PEP is an axiom in Heyting and Kolmogorov's formalizations of intuitionistic logic (Kolmogorov and Brouwer on constructive implication and
the Ex Falso rule, Van Dalen 2004). It's hard for me to see what the computational content of such an axiom is, especially when it says "Given that you have constructed the unconstructable, you now get (for free!) a construction of anything you choose to imagine)." I don't know how to write a program to do such a thing, and Coq's program extraction doesn't seem to have a consistent perspective on the matter either.
The standard computational interpretation for PEP is just the program crashing, since it requires a logically impossible premise. In the Scheme code, crashing is represented by the program looping, and in Haskell, this is a toplevel exception. But in both cases we know this is dead code and should never be reached, except if Coq is inconsistent itself.
Note that Coq is consistent with alternative computational interpretations of PEP, though. One can apply a variant of Friedman's A-translation to Coq to replace crashing by raising recoverable exceptions. See the Exceptional model for more details.
Would giving up on 'ex falso' change anything w.r.t. dependently-typed programming in Coq?
Yes, it would. Let us consider the hello-world of dependently typed programming, namely length-indexed lists (a.k.a. vectors). It is defined in the standard library, but let me give it here for context.
Inductive vec (A : Type) : nat -> Type :=
| vnil : vec A 0
| vcons n : A -> vec A n -> vec A (S n).
Now, we might want to provide the analogue of the head function on regular (non-indexed) lists. There is many approaches to deal with the case of the empty list as the input of head for lists. But for vectors it is especially easy to ask for non-empty input: we put this restriction in the type of the input v : vec A (S n), where S n ensures that the length of the input vector is not zero.
Here is a stub for this function:
Fixpoint head {A n} (v : vec A (S n)) : A :=
match v with
| vnil _ => _
| vcons _ n hd tl => hd
end.
But what do we return in case of the empty input? Coq won't let us simply omit vnil constructor in the pattern-matching expression. Here we can use the principle of explosion to solve the issue. Here is one possible way to fill in the blank above:
Fixpoint head {A n} (v : vec A (S n)) : A :=
match v in vec _ len
return (len = S n -> A)
with
| vnil _ => fun contra => False_rect _ (O_S _ contra)
| vcons _ n hd tl => fun _ => hd
end eq_refl.
This solution uses the so-called "convoy pattern" which is described in several Stackoverflow answers and in the CPDT book by Adam Chlipala. It also uses the standard O_S lemma (of type forall n : nat, 0 <> S n), so (O_S _ contra) has type type False.
I'd like to create a dependent function, but I am running into a type mismatch error on the False_rec term. I'm trying to do something similar to the following:
Definition env A := list A.
Fixpoint zip (xs ys : env nat) (H : length xs = length ys) : env (nat * nat).
Proof.
refine
(match xs, ys with
| [], [] => []
| x :: xs, y :: ys =>
(x, y) :: zip xs ys _
| _, _ => False_rec _ _
end).
...
However, I receive the following error:
The term "False_rec ?P ?f" has type "?P" while it is expected to have type
"env (nat * nat)" (unable to find a well-typed instantiation for
"?P": cannot ensure that "Type" is a subtype of "Set").
The standard list, when it is given a Set, becomes a set itself, but it seems that it does not do so when aliased in this way. For example:
Check (list nat). (* list nat : Set *)
Check (env nat). (* env nat : Type *)
Is there a reason for this mismatch? And is there a way to work around it? (For example, can I convince Coq that (env nat) is a Set? Or can I use a more general False_rec function that operates on Type instead of Set?)
Is there a reason for this mismatch?
Yes. Type is an entity that can contain (big) things that won't fit into Set. E.g. nat fits into Set, but Set does not fit into itself. I think there should be more than one excellent answers on SO explaining this issue.
(For example, can I convince Coq that (env nat) is a Set?
You can use explicit type annotations:
Definition env (A : Set) : Set := list A.
Or can I use a more general False_rec function that operates on Type instead of Set?
Yes, you can. It's called False_rect.
Observe that simple match-expression won't work in your case (regardless of Set/Type business), you will need to use dependent pattern matching. Another possibility is to use proof mode to define your function.
I've began learning Coq, and am trying to prove something that seems fairly simple: if a list contains x, then the number of instances of x in that list will be > 0.
I've defined the contains and count functions as follows:
Fixpoint contains (n: nat) (l: list nat) : Prop :=
match l with
| nil => False
| h :: t => if beq_nat h n then True else contains n t
end.
Fixpoint count (n acc: nat) (l: list nat) : nat :=
match l with
| nil => acc
| h :: t => if beq_nat h n then count n (acc + 1) t else count n acc t
end.
I'm trying to prove:
Lemma contains_count_ge1 : forall (n: nat) (l: list nat), contains n l -> (count n 0 l > 0).
I understand the proof will involve unfolding the definitions of count and contains, but then I'd like to say "the list cannot be nil, as contains is true, so there must be an element x in l such that beq_nat h x is true", and I've played around a bit but can't figure out how to use tactics to do this. Any guidance would be greatly appreciated.
ejgallego already gave a great solution to your problem in his answer. I would still like to single out an important point that he left out: in Coq, you must always argue from first principles, and be very pedantic and precise about your proofs.
You argued that the proof should proceed as follows:
The list cannot be nil, as contains is true, so there must be an element x in l such that beq_nat h x is true.
Even though this makes intuitive sense for humans, it is not precise enough for Coq to understand. The problem, as ejgallego's answer shows, is that your informal reasoning conceals a use of induction. Indeed, it is useful to try to expand out your argument in more details even before translating it into tactics. We could proceed like this, for instance:
Let us prove that, for every n : nat and ns : list nat, contains n ns implies count n 0 ns > 0. We proceed by induction on the list ns. If ns = nil, the definition of contains implies that False holds; a contradiction. We are thus left with the case ns = n' :: ns', where we can use the following induction hypothesis: contains n ns' -> count n 0 ns' > 0. There are two sub-cases to consider: whether beq_nat n n' is true or not.
If beq_nat n n' is true, by the definition of count, we see that we just have to show that count n (0 + 1) ns' > 0. Note there isn't a direct way to proceed here. This is because you wrote count tail-recursively, using an accumulator. While this is perfectly reasonable in functional programming, it can making proving properties about count more difficult. In this case, we would need the following auxiliary lemma, also proved by induction: forall n acc ns, count n acc ns = acc + count n 0 ns. I'll let you figure out how to prove this one. But assuming that we have already established it, the goal would reduce to showing that 1 + count n 0 ns' > 0. This is true by simple arithmetic. (There is an even simpler way that does not require an auxiliary lemma, but it would require slightly generalizing the statement you're proving.)
If beq_nat n n' is false, by the definitions of contains and count, we would need to show that contains n ns' implies count n 0 ns' > 0. This is exactly what the induction hypothesis gives us, and we are done.
There are two lessons to be learned here. The first one is that doing formal proofs often requires translating your intuition in formal terms that the system can understand. We know intuitively what it means to have some element occur inside of a list. But if we were to explain what that means more formally, we would resort to some kind of recursive traversal of the list, which would probably turn out to be the very definition of count that you wrote in Coq. And in order to reason about recursion, we need induction. The second lesson is that the way you define things in Coq has important consequences for the proofs you write. ejgallego's solution did not require any auxiliary lemmas beyond those in the standard library, precisely because his definition of count was not tail-recursive.
Well, you pose many questions about basic Coq beyond what is IMO possible to address here. For this particular problem, I would proceed this way (in reality I would use the already provided lemmas in MathComp):
From Coq Require Import PeanoNat Bool List.
Fixpoint contains (n: nat) (l: list nat) : bool :=
match l with
| nil => false
| h :: t => if Nat.eqb h n then true else contains n t
end.
Fixpoint count (n : nat) (l: list nat) : nat :=
match l with
| nil => 0
| h :: t => if Nat.eqb h n then S (count n t) else count n t
end.
Lemma contains_count_ge1 n l : contains n l = true -> count n l > 0.
Proof.
induction l as [|x l IHl]; simpl; [now congruence|].
now destruct (Nat.eqb_spec x n); auto with arith.
Qed.
My "standard" solution:
Lemma test n (l : list nat) : n \in l -> 0 < count_mem n l.
Proof. by rewrite lt0n => /count_memPn/eqP. Qed.
and different definitions of count and contains that may prove useful:
Fixpoint contains (n: nat) (l: list nat) : bool :=
match l with
| nil => false
| h :: t => Nat.eqb h n || contains n t
end.
Fixpoint count (n : nat) (l: list nat) : nat :=
match l with
| nil => 0
| h :: t => Nat.b2n (Nat.eqb h n) + (count n t)
end.
1) I believe that it is possible to use inductive types without pattern matching. (using _rec,_rect,_ind only). It is opaque, complicated, but possible.
2) Is it possible to use coinductive types withous pattern matching?
There exist a function from coinductive type to union of constructors' domains of coinductive type.
Does Coq generate it explicitly?
If yes, how to rewrite 'hd' ?
Section stream.
Variable A : Type.
CoInductive stream : Type :=
| Cons : A -> stream -> stream.
End stream.
Definition hd A (s : stream A) : A :=
match s with
| Cons x _ => x
end.
Although it is possible to use inductive types without directly resorting to pattern matching, this is only superficially true: the _rec, _rect and _ind combinators generated by Coq are all defined in terms of match. For instance:
Print nat_rect.
nat_rect =
fun (P : nat -> Type) (f : P 0) (f0 : forall n : nat, P n -> P (S n)) =>
fix F (n : nat) : P n :=
match n as n0 return (P n0) with
| 0 => f
| S n0 => f0 n0 (F n0)
end
: forall P : nat -> Type,
P 0 -> (forall n : nat, P n -> P (S n)) -> forall n : nat, P n
Furthermore, there are many cases where replacing pattern matching by an eliminator would result in a term with different computational behavior. Consider the following function, which divides a nat by two:
Fixpoint div2 (n : nat) :=
match n with
| 0 | 1 => 0
| S (S n') => S (div2 n')
end.
It is possible to rewrite this function using nat_rec, but the recursive call on n - 2 makes it a bit complicated (try it!).
Now, back to your main question, Coq does not automatically generate similar elimination principles for coinductive types. The Paco library helps deriving more useful principles for reasoning about coinductive data. But as far as I am aware, there is nothing similar for writing plain functions.
It is worth pointing out that your proposed approach is different from what Coq does for inductive data types, in that nat_rect and friends allow writing recursive functions and proofs by induction. One of the reasons providing these combinators is that they are used by the induction tactic. Something of type nat -> unit + nat, which more or less corresponds to what you proposed, wouldn't suffice.
This is one of the exercise given to me, I got stuck almost immediately after doing an induction on l. I dont know what other assertion to make here.
I'm not allowed to use advanced tactics like auto, intuition etc.
Fixpoint snoc {A : Type} l a : list A :=
match l with
| nil => a :: nil
| h :: t => h :: (snoc t a)
end.
Fixpoint rev {A : Type} l : list A :=
match l with
| nil => nil
| h :: t => snoc (rev t) h
end.
(Prove the following)
Theorem rev_rev : forall A (l : list A),
rev (rev l) = l.
We have all been new to this, and in the beginning it is useful to get help to not get stuck an lose courage when trying to master a new subject. I'll try to give you a hint without giving away too much.
The reason why this is trickier than earlier exercises may be because this proof involves doing two inductive reasoning steps. You probably did the first one just fine and got the second goal like
...
IHl : rev (rev l) = l
============================
rev (snoc (rev l) a) = a :: l
Unfortunately you can't use your inductive hypothesis IHl immediately, because the argument to rev is not in the right shape.
So, here you could try to prove another lemma about rev (snoc l a) = ... that would turn the goal into something which you could rewrite with IHl.
If you can figure that out, and prove that in a lemma, then you should be fine.
We won't do your homework for you, you should first prove it on pen & paper as #gallais said.
A tip: you might need to generalize your property a little (use an intermediate lemma) to be able to prove rev_rev. You should have a look at rev_append.