Proof using.
intros l; elim l; simpl in |- *; auto.
intros H; case H; auto.
intros a l0; case l0.
intros H H0; exists a; exists (nil (A:=nat)); exists (nil (A:=nat));
repeat (split; simpl in |- *; auto with datatypes).
intros n1 H1; case H1.
intros n1 H1; case H1.
intros n l1 H H0; case H; clear H; auto.
red in |- *; intros H1; discriminate; auto.
intros a1 (l2, (l3, (HH1, (HH2, HH3)))).
case (le_or_lt a1 a); intros HH4; auto.
exists a; exists (nil (A:=nat)); exists (n :: l1);
repeat (split; auto with datatypes).
intros n1 H1; case H1.
rewrite HH1.
intros n1 H1; apply le_trans with (2 := HH4); case in_app_or with (1 := H1);
auto with arith.
intros H2; apply lt_le_weak; auto.
simpl in |- *; intros [H2| H2]; [ rewrite H2 | idtac ]; auto.
exists a1; exists (a :: l2); exists l3;
repeat (split; simpl in |- *; auto with datatypes).
apply f_equal2 with (f := cons (A:=nat)); auto.
intros n1 [H2| H2]; [ rewrite <- H2 | idtac ]; auto.
Qed.
End FirstMax.
(* Find the minimum and the maximun in a list *)
Section FindMin.
Variable A : Type.
Variable f : A -> nat.
(* Search in the list for the min with respect to a valuation function f *)
Fixpoint find_min (l : list A) : option (nat * A) :=
match l with
| nil => None
| a :: l1 =>
match find_min l1 with
| None => Some (f a, a)
| Some (n1, b) =>
let n2 := f a in
match le_lt_dec n1 n2 with
| left _ => Some (n1, b)
| right _ => Some (n2, a)
end
end
end.

(* Specifications: *)
Theorem find_min_correct :
forall l : list A,
match find_min l with
| None => l = nil
| Some (a, b) => (In b l /\ a = f b) /\ (forall c : A, In c l -> f b <= f c)
end.