Yes, these inductive type definitions can be hard to read.
First part:
Inductive ex (A:Type) (P:A -> Prop) : Prop :=
This is what is associated with the type itself. Therefore, at any time when you see ex , it will have A and P , and ex will be of type Prop . Skipping A for the moment, focus on P , which is a predicate. So, if we use “there is a natural number that is prime” as our example, P can be is_prime , where is_prime takes a nat (a natural number) as an argument and there can be proof of it if nat is prime.
In this example, A will be nat . Textbook A not mentioned because Coq can always infer it. Given a predicate, Coq can get type A by looking at the type of the predicate argument.
To summarize, here in our example the type will be ex nat is_prime . This suggests that there is a nat that is simple, but it does not say which nat. When we build a ex nat is_prime , we will need to say which one - we need a “witness”. And this leads us to the definition of a constructor:
ex_intro : forall x:A, P x -> ex (A:=A) P.
The constructor is named ex_intro . What a complication here is that the constructor has all the parameters for the type. So, before we move on to those listed after ex_intro , we must include those that are of type: A and P
After these parameters, those appearing after ex_intro : x , which is the witness, and P x , which is proof that the predicate holds for the witness. Using our example, x may be 2, and P x will be the proof (is_prime 2) .
The constructor must specify parameters for the ex type that it creates. This is what happens after the arrow ( -> ). They do not have to match the parameters used when calling the constructor, but they usually do. For this, argument A not output - it is passed explicitly. (A:=A) says that parameter A in ex should be equal to A in the constructor call. Similarly, the parameters P of ex are set to P from the constructor call.
So, if we had proof_that_2_is_prime with type (prime 2) , we can call ex_intro is_prime 2 proof_that_2_is_prime and it would have type ex nat is_prime . This is our proof that there is a natural number that is prime.
To answer your question directly: in the expression forall x:A, P x -> ex (A:=A) , x:A is the witness, and P x is the evidence of the truth of the witness. The expression does not contain a predicate, because it is part of the type parameters that must be passed to the ex_intro constructor. The parameter list does not include A because it is derived by Coq.
I hope you understand why I thought this discussion was too detailed for my tutorial! Thanks for the question.