Defining a function that returns one element satisfying the condition
Question
I want to declare a function that yeilds the element (b, n) that the b is equal to true.
Require Export List. Import Coq.Lists.List.ListNotations. Definition lstest := list (bool * nat). Fixpoint existbool (l : lstest) : option (bool * nat) := match l with | [] => None | (b, n) :: l' => if b then Some (b, n) else existbool l' end.
The function always get the first element satisfyting b = true. I want to express that there exists an element satisfyting b = true and returns the element. How can I define such a function?
Answer
You could write a function get_number that requires a proof that the list has a true value somewhere.
Definition has_true (l : lstest) := exists n, In (true, n) l.
get_number is defined with the help of refine which lets us leave 'holes' (written _) in the proof term to fill in later. Here we have two holes; one for the absurd case when the list is [], and one where we construct the proof term for the recursive call.
get_number: forall l : lstest, has_true l -> nat
l: lstest
H: has_true lnatget_number: forall l : lstest, has_true l -> nat
l: lstest
H: has_true l
L: l = []natget_number: forall l : lstest, has_true l -> nat
l: lstest
H: has_true l
p: (bool * nat)%type
l': list (bool * nat)
b: bool
n: nat
L: l = (false, n) :: l'has_true l'get_number: forall l : lstest, has_true l -> nat
l: lstest
H: has_true l
L: l = []natget_number: forall l : lstest, has_true l -> nat
l: lstest
H: has_true l
L: l = []Falsenow inversion H.get_number: forall l : lstest, has_true l -> nat
H: has_true []Falseget_number: forall l : lstest, has_true l -> nat
l: lstest
H: has_true l
p: (bool * nat)%type
l': list (bool * nat)
b: bool
n: nat
L: l = (false, n) :: l'has_true l'get_number: forall l : lstest, has_true l -> nat
l': list (bool * nat)
n: nat
H: has_true ((false, n) :: l')
p: (bool * nat)%type
b: boolhas_true l'inversion H0; [inversion H1 | now (exists x)]. Defined.get_number: forall l : lstest, has_true l -> nat
l': list (bool * nat)
n: nat
H: has_true ((false, n) :: l')
p: (bool * nat)%type
b: bool
x: nat
H0: In (true, x) ((false, n) :: l')has_true l'
The function uses the convoy pattern so that the match statement does not forget the shape of l in the different branches.
If you want to, you can prove rewriting lemmas to make it easier to use.
l: list (bool * nat)
m: nat
H: has_true ((false, m) :: l)exists H' : has_true l, get_number ((false, m) :: l) H = get_number l H'eexists; reflexivity. Qed.l: list (bool * nat)
m: nat
H: has_true ((false, m) :: l)exists H' : has_true l, get_number ((false, m) :: l) H = get_number l H'l: list (bool * nat)
m: nat
H: has_true ((true, m) :: l)get_number ((true, m) :: l) H = mreflexivity. Qed.l: list (bool * nat)
m: nat
H: has_true ((true, m) :: l)get_number ((true, m) :: l) H = mH: has_true []
m: natget_number [] H <> mnow inversion H. Qed.H: has_true []
m: natget_number [] H <> ml: lstest
H1, H2: has_true lget_number l H1 = get_number l H2induction l as [ | [[|] ?] l']; eauto; now inversion H1. Qed.l: lstest
H1, H2: has_true lget_number l H1 = get_number l H2