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.