From LF Require Import Tactics.
Set Default Goal Selector "!".

(** **** Exercise: 2 stars, standard, optional (silly_ex)

    Complete the following proof using only [intros] and [apply]. *)
Theorem silly_ex : forall p,
  (forall n, even n = true -> even (S n) = false) ->
  (forall n, even n = false -> odd n = true) ->
  even p = true ->
  odd (S p) = true.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 2 stars, standard (apply_exercise1)

    You can use [apply] with previously defined theorems, not
    just hypotheses in the context.  Use [Search] to find a
    previously-defined theorem about [rev] from [Lists].  Use
    that theorem as part of your (relatively short) solution to this
    exercise. You do not need [induction]. *)

Theorem rev_exercise1 : forall (l l' : list nat),
  l = rev l' ->
  l' = rev l.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars, standard (injection_ex3) *)
Example injection_ex3 : forall (X : Type) (x y z : X) (l j : list X),
  x :: y :: l = z :: j ->
  j = z :: l ->
  x = y.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 1 star, standard (discriminate_ex3) *)
Example discriminate_ex3 :
  forall (X : Type) (x y z : X) (l j : list X),
    x :: y :: l = [] ->
    x = z.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 2 stars, standard (eqb_true) *)
Theorem eqb_true : forall n m,
  n =? m = true -> n = m.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars, standard, especially useful (plus_n_n_injective)

    In addition to being careful about how you use [intros], practice
    using "in" variants in this proof.  (Hint: use [plus_n_Sm].) *)
Theorem plus_n_n_injective : forall n m,
  n + n = m + m ->
  n = m.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars, standard, especially useful (gen_dep_practice)

    Prove this by induction on [l]. *)

Theorem nth_error_after_last: forall (n : nat) (X : Type) (l : list X),
  length l = n ->
  nth_error l n = None.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(** **** Exercise: 3 stars (rev_acc_length)
    Below is a "tail-recursive" definition of list reverse, which uses an
    accumulator variable acc to store the partially-reversed list more efficiently. *)
Fixpoint rev_acc {X : Type} (l acc : list X) :=
  match l with
  | [] => acc
  | h :: t => rev_acc t (h :: acc)
  end.

(** Prove the following theorem about the length of rev_acc. *)
Theorem rev_acc_length : forall (X : Type) (l acc : list X),
  length (rev_acc l acc) = length l + length acc.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)

(* grad exercise *)
(** **** Exercise: 3 stars, advanced (filter_exercise) *)
Theorem filter_exercise : forall (X : Type) (test : X -> bool)
                                 (x : X) (l lf : list X),
  filter test l = x :: lf ->
  test x = true.
Proof.
  (* FILL IN HERE *) Admitted.
(** [] *)
