Admitted. (* Higher Order *)

(* Specifications: *)
Theorem and_commut : forall P Q : Prop,
P /\ Q -> Q /\ P.
Theorem and_assoc : forall P Q R : Prop,
P /\ (Q /\ R) -> (P /\ Q) /\ R.
Theorem contrapositive : forall (P Q : Prop),
(P -> Q) -> (~Q -> ~P).
Theorem not_both_true_and_false : forall P : Prop,
~ (P /\ ~P).
Theorem not_true_is_false : forall b : bool,
b <> true -> b = false.
Lemma not_true_iff_false : forall b,
b <> true <-> b = false.
Theorem iff_trans : forall P Q R : Prop,
(P <-> Q) -> (Q <-> R) -> (P <-> R).
Theorem or_distributes_over_and : forall P Q R : Prop,
P \/ (Q /\ R) <-> (P \/ Q) /\ (P \/ R).
Lemma mult_0 : forall n m, n * m = 0 <-> n = 0 \/ m = 0.
Admitted. (* OUT-OF-SCOPE *)
Lemma or_assoc :
forall P Q R : Prop, P \/ (Q \/ R) <-> (P \/ Q) \/ R.
Lemma mult_0_3 :
forall n m p, n * m * p = 0 <-> n = 0 \/ m = 0 \/ p = 0.
Lemma In_map_iff :
forall (A B : Type) (f : A -> B) (l : list A) (y : B),
In y (map f l) <->
exists x, f x = y /\ In x l.
Theorem restricted_excluded_middle_eq : forall (n m : nat),
n = m \/ n <> m.
Theorem not_exists_dist :
excluded_middle ->
forall (X:Type) (P : X -> Prop),
~ (exists x, ~ P x) -> (forall x, P x).
Theorem hoare_pre_false : forall (P Q : Assertion) c,
(forall st, ~(P st)) ->
{{P}} c {{Q}}.
Theorem hoare_asgn_fwd :
(forall {X Y: Type} {f g : X -> Y},
(forall (x: X), f x = g x) ->  f = g) ->
forall m a P,
{{fun st => P st /\ t_lookup st X = m}}
X ::= a
{{fun st => P (t_update st X m)
/\ t_lookup st X = aeval (t_update st X m) a }}.
Theorem hoare_asgn_fwd_exists :
(forall {X Y: Type} {f g : X -> Y},
(forall (x: X), f x = g x) ->  f = g) ->
forall a P,
{{fun st => P st}}
X ::= a
{{fun st => exists m, P (t_update st X m) /\
t_lookup st X = aeval (t_update st X m) a }}.
Theorem hoare_consequence_post : forall (P Q Q' : Assertion) c,
{{P}} c {{Q'}} ->
Q' ->> Q ->
{{P}} c {{Q}}.
Theorem hoare_consequence : forall (P P' Q Q' : Assertion) c,
{{P'}} c {{Q'}} ->
P ->> P' ->
Q' ->> Q ->
{{P}} c {{Q}}.
Lemma silly1 : forall (P : nat -> nat -> Prop) (Q : nat -> Prop),
(forall x y : nat, P x y) ->
(forall x y : nat, P x y -> Q x) ->
Q 42.
Lemma silly2 :
forall (P : nat -> nat -> Prop) (Q : nat -> Prop),
(exists y, P 42 y) ->
(forall x y : nat, P x y -> Q x) ->
Q 42.
Theorem hoare_skip : forall P,
{{P}} SKIP {{P}}.
Theorem hoare_seq : forall P Q R c1 c2,
{{Q}} c2 {{R}} ->
{{P}} c1 {{Q}} ->
{{P}} c1;;c2 {{R}}.
Theorem always_loop_hoare : forall P Q,
{{P}} WHILE BTrue DO SKIP END {{Q}}.