Understanding how pattern matching works in Coq

Question

I'm currently following the Software Foundations book, I am currently on the Lists chapter. However, I'm having a hard time wrapping my head around a specific case of pattern matching and, due to being a beginner in Coq, I'm not sure about how to find the answer of this question.

So, the exercise was to create a Fixpoint to calculate how many nat v we have in a list s (a bag, more specifically).

I decided to use pattern matching for this, but if I tried to define a function like this:

Fixpoint count' (v : nat) (s : bag) : nat :=
  match s with
  | nil => O
  | h :: t => match h with
              | v => S (count' v t)
              end
  end.

and tried to apply this function to, let's say,


count' 1 [1; 2; 3; 1; 4; 1] = 3

I would end up with 6 = 3. My understanding is that matching h with v is always "true", so it ends up counting every element of the list.

But why does it happen? How could we compare, using pattern matching, the values of both h and v?

PS: I have already solved this exercise using an auxiliary function that compares if h and v are equal, but I'm wondering if this can be achieved only using built-in pattern matching.

Answer (Li-yao Xia)

The pattern

match h with
| v => S (count' v t)
end

introduces a new variable v bound to h, shadowing the existing v. It is equivalent to a let expression:

let v := h in S (count' v t)
(* or, without shadowing *)
let v1 := h in S (count' v1 t)

Instead, to compare h and v, use a comparison function:

if h =? v then ... else ...

Answer (Ana Borges)

Pattern matching is useful when you want to make case distinctions on constructors. Perhaps the name is misleading in this sense, since

match h with
| v => ...
end

will not compare h and the specific v from above. Instead, the match checks to see if the shape of h matches the shape exemplified by v. Like Li-yao Xia mentioned, here v has no shape, it is a universal placeholder. On the other hand something like

match h with
| O => ...
| S k => ...
end

exposes two different shapes that a nat can have, namely being O or the successor of some k. The latter is the kind of situation where we do want to use match. Comparing values is best done through _ =? _.