2233 lines
61 KiB
Coq
2233 lines
61 KiB
Coq
(* midterm-project.v *)
|
|
(* LPP 2024 - CS3234 2023-2024, Sem2 *)
|
|
(* Olivier Danvy <danvy@yale-nus.edu.sg> *)
|
|
(* Version of 22 Feb 2024 *)
|
|
|
|
(* ********** *)
|
|
|
|
(* A study of polymorphic lists. *)
|
|
|
|
(* members of the group:
|
|
date:
|
|
|
|
please upload one .v file and one .pdf file containing a project report
|
|
|
|
desiderata:
|
|
- the file should be readable, i.e., properly indented and using items or {...} for subgoals
|
|
- each use of a tactic should achieve one proof step
|
|
- all lemmas should be applied to all their arguments
|
|
- there should be no occurrences of admit, Admitted, and Abort
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* Paraphernalia: *)
|
|
|
|
Ltac fold_unfold_tactic name := intros; unfold name; fold name; reflexivity.
|
|
|
|
Require Import Arith Bool List.
|
|
|
|
(* ********** *)
|
|
|
|
Definition eqb_option (V : Type) (eqb_V : V -> V -> bool) (ov1 ov2 : option V) : bool :=
|
|
match ov1 with
|
|
Some v1 =>
|
|
match ov2 with
|
|
Some v2 =>
|
|
eqb_V v1 v2
|
|
| None =>
|
|
false
|
|
end
|
|
| None =>
|
|
match ov2 with
|
|
Some v2 =>
|
|
false
|
|
| None =>
|
|
true
|
|
end
|
|
end.
|
|
|
|
(* ********** *)
|
|
|
|
Fixpoint eqb_list (V : Type) (eqb_V : V -> V -> bool) (v1s v2s : list V) : bool :=
|
|
match v1s with
|
|
nil =>
|
|
match v2s with
|
|
nil =>
|
|
true
|
|
| v2 :: v2s' =>
|
|
false
|
|
end
|
|
| v1 :: v1s' =>
|
|
match v2s with
|
|
nil =>
|
|
false
|
|
| v2 :: v2s' =>
|
|
eqb_V v1 v2 && eqb_list V eqb_V v1s' v2s'
|
|
end
|
|
end.
|
|
|
|
Lemma fold_unfold_eqb_list_nil :
|
|
forall (V : Type)
|
|
(eqb_V : V -> V -> bool)
|
|
(v2s : list V),
|
|
eqb_list V eqb_V nil v2s =
|
|
match v2s with
|
|
nil =>
|
|
true
|
|
| v2 :: v2s' =>
|
|
false
|
|
end.
|
|
Proof.
|
|
fold_unfold_tactic eqb_list.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_eqb_list_cons :
|
|
forall (V : Type)
|
|
(eqb_V : V -> V -> bool)
|
|
(v1 : V)
|
|
(v1s' v2s : list V),
|
|
eqb_list V eqb_V (v1 :: v1s') v2s =
|
|
match v2s with
|
|
nil =>
|
|
false
|
|
| v2 :: v2s' =>
|
|
eqb_V v1 v2 && eqb_list V eqb_V v1s' v2s'
|
|
end.
|
|
Proof.
|
|
fold_unfold_tactic eqb_list.
|
|
Qed.
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 1: *)
|
|
|
|
Theorem soundness_of_equality_over_lists :
|
|
forall (V : Type)
|
|
(eqb_V : V -> V -> bool),
|
|
(forall v1 v2 : V,
|
|
eqb_V v1 v2 = true -> v1 = v2) ->
|
|
forall v1s v2s : list V,
|
|
eqb_list V eqb_V v1s v2s = true ->
|
|
v1s = v2s.
|
|
Proof.
|
|
intros V eqb_V.
|
|
intros S_eqb_V.
|
|
intros v1s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- intros v2s H_eqb_list.
|
|
case v2s as [ | v2 v2s' ].
|
|
+ reflexivity.
|
|
+ rewrite -> fold_unfold_eqb_list_nil in H_eqb_list.
|
|
discriminate H_eqb_list.
|
|
- intros v2s H_eqb_list.
|
|
case v2s as [ | v2 v2s' ].
|
|
+ rewrite -> fold_unfold_eqb_list_cons in H_eqb_list.
|
|
discriminate H_eqb_list.
|
|
+ rewrite -> fold_unfold_eqb_list_cons in H_eqb_list.
|
|
Search (_ && _ = true).
|
|
destruct (andb_true_iff (eqb_V v1 v2) (eqb_list V eqb_V v1s' v2s')) as [H_tmp _].
|
|
destruct (H_tmp H_eqb_list) as [v1_eq_v2 v1s'_eq_v2s'].
|
|
rewrite -> (S_eqb_V v1 v2 v1_eq_v2).
|
|
rewrite -> (IHv1s' v2s' v1s'_eq_v2s').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem completeness_of_equality_over_lists :
|
|
forall (V : Type)
|
|
(eqb_V : V -> V -> bool),
|
|
(forall v1 v2 : V,
|
|
v1 = v2 -> eqb_V v1 v2 = true) ->
|
|
forall v1s v2s : list V,
|
|
v1s = v2s ->
|
|
eqb_list V eqb_V v1s v2s = true.
|
|
Proof.
|
|
intros V eqb_V C_eqb_V v1s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- intros v2s H_eqb_list.
|
|
case v2s as [ | v2 v2s' ].
|
|
+ rewrite -> fold_unfold_eqb_list_nil.
|
|
reflexivity.
|
|
+ discriminate H_eqb_list.
|
|
- intros v2s v1s_eq_v2s.
|
|
case v2s as [ | v2 v2s' ].
|
|
+ discriminate v1s_eq_v2s.
|
|
+ rewrite -> fold_unfold_eqb_list_cons.
|
|
injection v1s_eq_v2s as v1_eq_v2 v1s'_eq_v2s'.
|
|
Check (C_eqb_V v1 v2 v1_eq_v2).
|
|
rewrite -> (C_eqb_V v1 v2 v1_eq_v2).
|
|
rewrite -> (IHv1s' v2s' v1s'_eq_v2s').
|
|
simpl (true && true).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(* ********** *)
|
|
|
|
(* A study of the polymorphic length function: *)
|
|
|
|
Definition specification_of_list_length (length : forall V : Type, list V -> nat) :=
|
|
(forall V : Type,
|
|
length V nil = 0)
|
|
/\
|
|
(forall (V : Type)
|
|
(v : V)
|
|
(vs' : list V),
|
|
length V (v :: vs') = S (length V vs')).
|
|
|
|
(* Unit-test function: *)
|
|
|
|
Definition test_list_length (candidate : forall V : Type, list V -> nat) :=
|
|
(candidate nat nil =? 0) &&
|
|
(candidate bool nil =? 0) &&
|
|
(candidate nat (1 :: nil) =? 1) &&
|
|
(candidate bool (true :: nil) =? 1) &&
|
|
(candidate nat (2 :: 1 :: nil) =? 2) &&
|
|
(candidate bool (false :: true :: nil) =? 2) &&
|
|
(candidate nat (3 :: 2 :: 1 :: nil) =? 3) &&
|
|
(candidate bool (false :: false :: true :: nil) =? 3).
|
|
|
|
(* The specification specifies at most one length function: *)
|
|
|
|
Theorem there_is_at_most_one_list_length_function :
|
|
forall (V : Type)
|
|
(list_length_1 list_length_2 : forall V : Type, list V -> nat),
|
|
specification_of_list_length list_length_1 ->
|
|
specification_of_list_length list_length_2 ->
|
|
forall vs : list V,
|
|
list_length_1 V vs = list_length_2 V vs.
|
|
Proof.
|
|
intros V list_length_1 list_length_2.
|
|
unfold specification_of_list_length.
|
|
intros [S_list_length_1_nil S_list_length_1_cons]
|
|
[S_list_length_2_nil S_list_length_2_cons]
|
|
vs.
|
|
induction vs as [ | v vs' IHvs'].
|
|
|
|
- Check (S_list_length_2_nil V).
|
|
rewrite -> (S_list_length_2_nil V).
|
|
Check (S_list_length_1_nil V).
|
|
exact (S_list_length_1_nil V).
|
|
|
|
- Check (S_list_length_1_cons V v vs').
|
|
rewrite -> (S_list_length_1_cons V v vs').
|
|
rewrite -> (S_list_length_2_cons V v vs').
|
|
rewrite -> IHvs'.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(* Recursive implementation of the length function: *)
|
|
|
|
Fixpoint list_length (V : Type) (vs : list V) : nat :=
|
|
match vs with
|
|
nil =>
|
|
0
|
|
| v :: vs' =>
|
|
S (list_length V vs')
|
|
end.
|
|
|
|
Compute (test_list_length list_length).
|
|
|
|
(* Associated fold-unfold lemmas: *)
|
|
|
|
Lemma fold_unfold_list_length_nil :
|
|
forall V : Type,
|
|
list_length V nil =
|
|
0.
|
|
Proof.
|
|
fold_unfold_tactic list_length.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_length_cons :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs' : list V),
|
|
list_length V (v :: vs') =
|
|
S (list_length V vs').
|
|
Proof.
|
|
fold_unfold_tactic list_length.
|
|
Qed.
|
|
|
|
(* The specification specifies at least one length function: *)
|
|
|
|
Theorem list_length_satisfies_the_specification_of_list_length :
|
|
specification_of_list_length list_length.
|
|
Proof.
|
|
unfold specification_of_list_length.
|
|
exact (conj fold_unfold_list_length_nil fold_unfold_list_length_cons).
|
|
Qed.
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 2: *)
|
|
|
|
(* Implement the length function using an accumulator. *)
|
|
|
|
Fixpoint list_length_acc (V : Type) (vs : list V) (acc : nat) : nat :=
|
|
match vs with
|
|
nil => acc
|
|
| v :: vs' =>
|
|
list_length_acc V vs' (S acc)
|
|
end.
|
|
|
|
Definition list_length_alt (V : Type) (vs : list V) : nat :=
|
|
list_length_acc V vs 0.
|
|
|
|
Compute (test_list_length list_length_alt).
|
|
|
|
Lemma fold_unfold_list_length_acc_nil :
|
|
forall (V : Type)
|
|
(acc : nat),
|
|
list_length_acc V nil acc = acc.
|
|
Proof.
|
|
fold_unfold_tactic list_length_acc.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_length_acc_cons :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs' : list V)
|
|
(acc : nat),
|
|
list_length_acc V (v :: vs') acc = list_length_acc V vs' (S acc).
|
|
Proof.
|
|
fold_unfold_tactic list_length_acc.
|
|
Qed.
|
|
|
|
Lemma about_list_length_acc :
|
|
forall (V : Type)
|
|
(vs : list V)
|
|
(acc : nat),
|
|
list_length_acc V vs (S acc) = S (list_length_acc V vs acc).
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- intro acc.
|
|
rewrite ->(fold_unfold_list_length_acc_nil V (S acc)).
|
|
rewrite -> (fold_unfold_list_length_acc_nil V acc).
|
|
reflexivity.
|
|
- intro acc.
|
|
rewrite -> (fold_unfold_list_length_acc_cons V v vs' (S acc)).
|
|
rewrite -> (IHvs' (S acc)).
|
|
rewrite -> (fold_unfold_list_length_acc_cons V v vs' acc).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem list_length_alt_satisfies_the_specification_of_list_length :
|
|
specification_of_list_length list_length_alt.
|
|
Proof.
|
|
unfold specification_of_list_length,list_length_alt.
|
|
split.
|
|
- intros V.
|
|
exact (fold_unfold_list_length_acc_nil V 0).
|
|
- intros V v vs'.
|
|
rewrite -> (fold_unfold_list_length_acc_cons V v vs' 0).
|
|
rewrite -> (about_list_length_acc V vs' 0).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(* ********** *)
|
|
|
|
(* A study of the polymorphic copy function: *)
|
|
|
|
Definition specification_of_list_copy (copy : forall V : Type, list V -> list V) :=
|
|
(forall V : Type,
|
|
copy V nil = nil)
|
|
/\
|
|
(forall (V : Type)
|
|
(v : V)
|
|
(vs' : list V),
|
|
copy V (v :: vs') = v :: (copy V vs')).
|
|
|
|
Definition test_list_copy (candidate : forall V : Type, list V -> list V) :=
|
|
(eqb_list nat Nat.eqb (candidate nat nil) nil) &&
|
|
(eqb_list bool Bool.eqb (candidate bool nil) nil) &&
|
|
(eqb_list nat Nat.eqb (candidate nat (1 :: nil)) (1 :: nil)) &&
|
|
(eqb_list bool Bool.eqb (candidate bool (true :: nil)) (true :: nil)) &&
|
|
(eqb_list nat Nat.eqb (candidate nat (2 :: 1 :: nil)) (2 :: 1 :: nil)) &&
|
|
(eqb_list bool Bool.eqb (candidate bool (false :: true :: nil)) (false :: true :: nil)).
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 3: *)
|
|
|
|
(*
|
|
a. Expand the unit-test function for copy with a few more tests.
|
|
*)
|
|
|
|
(*
|
|
b. Implement the copy function recursively.
|
|
*)
|
|
|
|
|
|
Fixpoint list_copy (V : Type) (vs : list V) : list V :=
|
|
match vs with
|
|
| nil => nil
|
|
| v :: vs' => v :: (list_copy V vs')
|
|
end.
|
|
|
|
(*
|
|
c. State its associated fold-unfold lemmas.
|
|
*)
|
|
|
|
Lemma fold_unfold_list_copy_nil :
|
|
forall (V : Type),
|
|
list_copy V nil = nil.
|
|
Proof.
|
|
intro V.
|
|
fold_unfold_tactic list_copy.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_copy_cons :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs : list V),
|
|
list_copy V (v :: vs) = v :: list_copy V vs.
|
|
Proof.
|
|
intros V v vs.
|
|
fold_unfold_tactic list_copy.
|
|
Qed.
|
|
|
|
(*
|
|
d. Prove whether your implementation satisfies the specification.
|
|
*)
|
|
Theorem list_copy_satifies_the_specification_of_list_copy :
|
|
specification_of_list_copy list_copy.
|
|
Proof.
|
|
unfold specification_of_list_copy.
|
|
split.
|
|
- intro V.
|
|
exact (fold_unfold_list_copy_nil V).
|
|
- intros V v vs'.
|
|
exact (fold_unfold_list_copy_cons V v vs').
|
|
Qed.
|
|
|
|
|
|
(*
|
|
e. Prove whether copy is idempotent.
|
|
*)
|
|
|
|
|
|
Proposition list_copy_is_idempotent :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_copy V (list_copy V vs) = list_copy V vs.
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> 2 (fold_unfold_list_copy_nil V).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_copy_cons V v vs').
|
|
rewrite -> (fold_unfold_list_copy_cons V v (list_copy V vs')).
|
|
rewrite -> IHvs'.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
f. Prove whether copying a list preserves its length.
|
|
*)
|
|
|
|
|
|
Proposition list_copy_preserves_list_length :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_length V (list_copy V vs) = list_length V vs.
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_copy_nil V).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_copy_cons V v vs').
|
|
rewrite -> (fold_unfold_list_length_cons V v (list_copy V vs')).
|
|
rewrite -> IHvs'.
|
|
rewrite -> (fold_unfold_list_length_cons V v vs').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
g. Subsidiary question: can you think of a strikingly simple implementation of the copy function?
|
|
if so, pray show that it satisfies the specification of copy;
|
|
is it equivalent to your recursive implementation?
|
|
*)
|
|
|
|
Definition identity (V : Type) (vs : list V) := vs.
|
|
|
|
Theorem identity_satisfies_the_specification_of_copy :
|
|
specification_of_list_copy identity.
|
|
Proof.
|
|
unfold specification_of_list_copy.
|
|
split.
|
|
- intro V.
|
|
unfold identity.
|
|
reflexivity.
|
|
- intros V v vs'.
|
|
unfold identity.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem about_list_copy :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_copy V vs = vs.
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs'].
|
|
- exact (fold_unfold_list_copy_nil V).
|
|
- rewrite -> (fold_unfold_list_copy_cons V v vs').
|
|
rewrite -> IHvs'.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem identity_and_list_copy_are_equivalent :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_copy V vs = identity V vs.
|
|
Proof.
|
|
intros V vs.
|
|
unfold identity.
|
|
exact (about_list_copy V vs).
|
|
Qed.
|
|
(* ********** *)
|
|
|
|
(* A study of the polymorphic append function: *)
|
|
|
|
Definition specification_of_list_append (append : forall V : Type, list V -> list V -> list V) :=
|
|
(forall (V : Type)
|
|
(v2s : list V),
|
|
append V nil v2s = v2s)
|
|
/\
|
|
(forall (V : Type)
|
|
(v1 : V)
|
|
(v1s' v2s : list V),
|
|
append V (v1 :: v1s') v2s = v1 :: append V v1s' v2s).
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 4: *)
|
|
|
|
(*
|
|
a. Define a unit-test function for list_append.
|
|
*)
|
|
Definition test_list_append (candidate : forall V : Type, list V -> list V -> list V) :=
|
|
(eqb_list nat Nat.eqb (candidate nat nil nil) nil) &&
|
|
(eqb_list bool Bool.eqb (candidate bool nil nil) nil) &&
|
|
(eqb_list nat Nat.eqb (candidate nat (2 :: nil) (1 :: nil) ) (2 :: 1 :: nil)) &&
|
|
(eqb_list bool Bool.eqb (candidate bool (true :: nil) (false :: nil)) (true :: false :: nil)) &&
|
|
(eqb_list nat Nat.eqb (candidate nat (4 :: 3 :: nil) (2 :: 1 :: nil)) (4 :: 3 :: 2 :: 1 :: nil)) &&
|
|
(eqb_list bool Bool.eqb (candidate bool (true :: false :: nil) (true :: false :: nil)) (true :: false :: true :: false :: nil)).
|
|
|
|
(*
|
|
b. Implement the list_append function recursively.
|
|
*)
|
|
|
|
|
|
Fixpoint list_append (V : Type) (v1s v2s : list V) : list V :=
|
|
match v1s with
|
|
| nil =>
|
|
v2s
|
|
| v1 :: v1s' =>
|
|
v1 :: list_append V v1s' v2s
|
|
end.
|
|
|
|
Compute test_list_append list_append.
|
|
|
|
(*
|
|
c. State its associated fold-unfold lemmas.
|
|
*)
|
|
|
|
Theorem fold_unfold_list_append_nil :
|
|
forall (V : Type)
|
|
(v2s : list V),
|
|
list_append V nil v2s = v2s.
|
|
Proof.
|
|
fold_unfold_tactic list_append.
|
|
Qed.
|
|
|
|
Theorem fold_unfold_list_append_cons :
|
|
forall (V : Type)
|
|
(v1 : V)
|
|
(v1s' v2s : list V),
|
|
list_append V (v1 :: v1s') v2s = v1 :: list_append V v1s' v2s.
|
|
Proof.
|
|
fold_unfold_tactic list_append.
|
|
Qed.
|
|
|
|
(*
|
|
d. Prove that your implementation satisfies the specification.
|
|
*)
|
|
|
|
Theorem list_append_satisfies_the_specification_of_list_append :
|
|
specification_of_list_append list_append.
|
|
Proof.
|
|
unfold specification_of_list_append.
|
|
split.
|
|
- intros V v2s.
|
|
exact (fold_unfold_list_append_nil V v2s).
|
|
- intros V v1 v1s' v2s.
|
|
exact (fold_unfold_list_append_cons V v1 v1s' v2s).
|
|
Qed.
|
|
|
|
Theorem there_is_at_most_one_list_append_function :
|
|
forall (V : Type)
|
|
(f g : (forall V : Type, list V -> list V -> list V)),
|
|
specification_of_list_append f ->
|
|
specification_of_list_append g ->
|
|
forall (v1s v2s : list V),
|
|
f V v1s v2s = g V v1s v2s.
|
|
Proof.
|
|
unfold specification_of_list_append.
|
|
intros V f g [S_f_nil S_f_cons] [S_g_nil S_g_cons] v1s v2s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- rewrite -> (S_f_nil V v2s).
|
|
rewrite -> (S_g_nil V v2s).
|
|
reflexivity.
|
|
- rewrite -> (S_f_cons V v1 v1s').
|
|
rewrite -> IHv1s'.
|
|
rewrite -> (S_g_cons V v1 v1s').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
e. Prove whether nil is neutral on the left of list_append.
|
|
*)
|
|
|
|
Theorem nil_is_neutral_on_the_left_of_list_append :
|
|
forall (V : Type)
|
|
(v2s : list V),
|
|
list_append V nil v2s = v2s.
|
|
Proof.
|
|
intros V v2s.
|
|
exact (fold_unfold_list_append_nil V v2s).
|
|
Qed.
|
|
|
|
(*
|
|
f. Prove whether nil is neutral on the right of list_append.
|
|
*)
|
|
Theorem nil_is_neutral_on_the_right_of_list_append :
|
|
forall (V : Type)
|
|
(v1s: list V),
|
|
list_append V v1s nil = v1s.
|
|
Proof.
|
|
intros V v1s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- exact (fold_unfold_list_append_nil V nil).
|
|
- rewrite -> (fold_unfold_list_append_cons V v1 v1s' nil).
|
|
rewrite -> IHv1s'.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
g. Prove whether list_append is commutative.
|
|
*)
|
|
|
|
Theorem list_append_is_not_commutative :
|
|
exists (V : Type)
|
|
(v1s v2s : list V),
|
|
list_append V v1s v2s <> list_append V v2s v1s.
|
|
Proof.
|
|
exists nat.
|
|
exists (1 :: nil).
|
|
exists (2 :: nil).
|
|
rewrite -> (fold_unfold_list_append_cons nat 1 nil (2 :: nil)).
|
|
rewrite -> (fold_unfold_list_append_nil nat (2 :: nil)).
|
|
rewrite -> (fold_unfold_list_append_cons nat 2 nil (1 :: nil)).
|
|
rewrite -> (fold_unfold_list_append_nil nat (1 :: nil)).
|
|
unfold not.
|
|
intro H_absurd.
|
|
discriminate H_absurd.
|
|
Qed.
|
|
|
|
|
|
(*
|
|
h. Prove whether list_append is associative.
|
|
*)
|
|
|
|
Theorem list_append_is_associative :
|
|
forall (V : Type)
|
|
(v1s v2s v3s : list V),
|
|
list_append V (list_append V v1s v2s) v3s = list_append V v1s (list_append V v2s v3s).
|
|
Proof.
|
|
intros V v1s v2s v3s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- rewrite -> (fold_unfold_list_append_nil V v2s).
|
|
rewrite -> (fold_unfold_list_append_nil V (list_append V v2s v3s)).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_append_cons V v1 v1s' v2s).
|
|
rewrite -> (fold_unfold_list_append_cons V v1 (list_append V v1s' v2s) v3s).
|
|
rewrite -> IHv1s'.
|
|
rewrite -> (fold_unfold_list_append_cons V v1 v1s' (list_append V v2s v3s)).
|
|
reflexivity.
|
|
Qed.
|
|
(*
|
|
i. Prove whether appending two lists preserves their length.
|
|
*)
|
|
|
|
Proposition list_append_and_list_length_commute_with_each_other :
|
|
forall (V : Type)
|
|
(v1s v2s : list V),
|
|
list_length V (list_append V v1s v2s) = list_length V v1s + list_length V v2s.
|
|
Proof.
|
|
intros V v1s v2s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- rewrite -> (fold_unfold_list_append_nil V v2s).
|
|
rewrite -> (fold_unfold_list_length_nil V).
|
|
rewrite -> (Nat.add_0_l).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_append_cons V v1 v1s').
|
|
rewrite -> (fold_unfold_list_length_cons V v1 (list_append V v1s' v2s)).
|
|
rewrite -> IHv1s'.
|
|
rewrite <- (Nat.add_succ_l (list_length V v1s') (list_length V v2s)).
|
|
rewrite -> (fold_unfold_list_length_cons V v1 v1s').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
j. Prove whether list_append and list_copy commute with each other.
|
|
*)
|
|
|
|
Proposition list_append_and_list_copy_commute_with_each_other :
|
|
forall (V : Type)
|
|
(v1s v2s : list V),
|
|
list_copy V (list_append V v1s v2s) = list_append V (list_copy V v1s) (list_copy V v2s).
|
|
Proof.
|
|
intros V v1s v2s.
|
|
rewrite -> (about_list_copy V (list_append V v1s v2s)).
|
|
rewrite -> (about_list_copy V v1s).
|
|
rewrite -> (about_list_copy V v2s).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(* ********** *)
|
|
|
|
(* A study of the polymorphic reverse function: *)
|
|
|
|
Definition specification_of_list_reverse (reverse : forall V : Type, list V -> list V) :=
|
|
forall append : forall W : Type, list W -> list W -> list W,
|
|
specification_of_list_append append ->
|
|
(forall V : Type,
|
|
reverse V nil = nil)
|
|
/\
|
|
(forall (V : Type)
|
|
(v : V)
|
|
(vs' : list V),
|
|
reverse V (v :: vs') = append V (reverse V vs') (v :: nil)).
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 5: *)
|
|
|
|
(*
|
|
a. Define a unit-test function for an implementation of the reverse function.
|
|
*)
|
|
|
|
Definition test_list_reverse (candidate : forall V : Type, list V -> list V) :=
|
|
(eqb_list nat Nat.eqb (candidate nat nil) nil) &&
|
|
(eqb_list bool Bool.eqb (candidate bool nil) nil) &&
|
|
(eqb_list nat Nat.eqb (candidate nat (1 :: nil) ) (1 :: nil)) &&
|
|
(eqb_list bool Bool.eqb (candidate bool (true :: nil)) (true :: nil)) &&
|
|
(eqb_list nat Nat.eqb (candidate nat (4 :: 3 :: nil)) (3 :: 4 :: nil)) &&
|
|
(eqb_list bool Bool.eqb (candidate bool (true :: false :: nil)) (false :: true :: nil)).
|
|
|
|
(*
|
|
b. Implement the reverse function recursively, using list_append.
|
|
*)
|
|
|
|
|
|
Fixpoint list_reverse (V : Type) (vs : list V) : list V :=
|
|
match vs with
|
|
| nil => nil
|
|
| v :: vs' => list_append V (list_reverse V vs') (v :: nil)
|
|
end.
|
|
|
|
Compute test_list_reverse list_reverse.
|
|
(*
|
|
c. State the associated fold-unfold lemmas.
|
|
*)
|
|
|
|
Lemma fold_unfold_list_reverse_nil :
|
|
forall (V : Type),
|
|
list_reverse V nil = nil.
|
|
Proof.
|
|
fold_unfold_tactic list_reverse.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_reverse_cons :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs : list V),
|
|
list_reverse V (v :: vs) = list_append V (list_reverse V vs) (v :: nil).
|
|
Proof.
|
|
fold_unfold_tactic list_reverse.
|
|
Qed.
|
|
|
|
(*
|
|
d. Prove whether your implementation satisfies the specification.
|
|
*)
|
|
Theorem list_reverse_satisfies_the_specification_of_list_reverse :
|
|
specification_of_list_reverse list_reverse.
|
|
Proof.
|
|
unfold specification_of_list_reverse.
|
|
intros append S_append.
|
|
split.
|
|
- intro V.
|
|
exact (fold_unfold_list_reverse_nil V).
|
|
- intros V v vs'.
|
|
rewrite -> (fold_unfold_list_reverse_cons V v vs').
|
|
exact (there_is_at_most_one_list_append_function
|
|
V list_append append
|
|
list_append_satisfies_the_specification_of_list_append S_append
|
|
(list_reverse V vs') (v :: nil)).
|
|
Qed.
|
|
(*
|
|
e. Prove whether list_reverse is involutory.
|
|
*)
|
|
|
|
Theorem about_list_reverse_and_list_append :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs : list V),
|
|
list_reverse V (list_append V vs (v :: nil)) = v :: (list_reverse V vs).
|
|
Proof.
|
|
intros V v vs.
|
|
induction vs as [ | v' vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_append_nil V (v :: nil)).
|
|
rewrite -> (fold_unfold_list_reverse_cons V v nil).
|
|
rewrite -> (fold_unfold_list_reverse_nil V).
|
|
rewrite -> (fold_unfold_list_append_nil V (v :: nil)).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_append_cons V v' vs' (v :: nil)).
|
|
rewrite -> (fold_unfold_list_reverse_cons V v' (list_append V vs' (v :: nil))).
|
|
rewrite -> (IHvs').
|
|
rewrite -> (fold_unfold_list_append_cons V v (list_reverse V vs') (v' :: nil)).
|
|
rewrite -> (fold_unfold_list_reverse_cons).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Proposition list_reverse_is_involutory :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_reverse V (list_reverse V vs) = vs.
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_reverse_nil V).
|
|
exact (fold_unfold_list_reverse_nil V).
|
|
- rewrite -> (fold_unfold_list_reverse_cons V v vs').
|
|
rewrite -> (about_list_reverse_and_list_append V v (list_reverse V vs')).
|
|
rewrite -> (IHvs').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
f. Prove whether reversing a list preserves its length.
|
|
*)
|
|
|
|
Theorem reversing_a_list_preserves_its_length :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_length V (list_reverse V vs) = list_length V vs.
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_reverse_nil V).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_cons V v vs').
|
|
Search list_length.
|
|
rewrite -> (list_append_and_list_length_commute_with_each_other V
|
|
(list_reverse V vs')
|
|
(v :: nil)).
|
|
rewrite -> IHvs'.
|
|
rewrite -> (fold_unfold_list_length_cons V v nil).
|
|
rewrite -> (fold_unfold_list_length_nil V).
|
|
rewrite -> (fold_unfold_list_length_cons V v vs').
|
|
Search (_ + 1).
|
|
rewrite -> (Nat.add_1_r (list_length V vs')).
|
|
reflexivity.
|
|
Qed.
|
|
(*
|
|
g. Do list_append and list_reverse commute with each other (hint: yes they do) and if so how?
|
|
j*)
|
|
|
|
Theorem list_append_and_list_reverse_commute_with_each_other :
|
|
forall (V : Type)
|
|
(v1s v2s : list V),
|
|
list_append V (list_reverse V v2s) (list_reverse V v1s) = list_reverse V (list_append V v1s v2s).
|
|
Proof.
|
|
intros V v1s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ]; intro v2s.
|
|
- rewrite -> (fold_unfold_list_reverse_nil V).
|
|
rewrite -> (nil_is_neutral_on_the_right_of_list_append V (list_reverse V v2s)).
|
|
rewrite -> (fold_unfold_list_append_nil V v2s).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_cons V v1 v1s').
|
|
rewrite <- (list_append_is_associative V (list_reverse V v2s) (list_reverse V v1s') (v1 :: nil)).
|
|
rewrite -> (IHv1s' v2s).
|
|
rewrite -> (fold_unfold_list_append_cons V v1 v1s' v2s).
|
|
rewrite -> (fold_unfold_list_reverse_cons V v1 (list_append V v1s' v2s)).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
h. Implement the reverse function using an accumulator instead of using list_append.
|
|
*)
|
|
|
|
Fixpoint list_reverse_acc (V : Type) (vs : list V) (acc : list V) : list V :=
|
|
match vs with
|
|
| nil => acc
|
|
| v :: vs' => list_reverse_acc V vs' (v :: acc)
|
|
end.
|
|
|
|
|
|
Definition list_reverse_alt (V : Type) (vs : list V) : list V :=
|
|
list_reverse_acc V vs nil.
|
|
|
|
Lemma fold_unfold_list_reverse_acc_nil :
|
|
forall (V : Type)
|
|
(acc : list V),
|
|
list_reverse_acc V nil acc = acc.
|
|
Proof.
|
|
fold_unfold_tactic list_reverse_acc.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_reverse_acc_cons :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs acc : list V),
|
|
list_reverse_acc V (v :: vs) acc = list_reverse_acc V vs (v :: acc).
|
|
Proof.
|
|
fold_unfold_tactic list_reverse_acc.
|
|
Qed.
|
|
|
|
Compute test_list_reverse list_reverse_alt.
|
|
|
|
Lemma about_list_reverse_acc :
|
|
forall (V : Type)
|
|
(vs acc : list V),
|
|
list_reverse_acc V vs acc = list_append V (list_reverse_acc V vs nil) acc.
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ]; intro acc.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_nil V acc).
|
|
rewrite -> (fold_unfold_list_reverse_acc_nil V nil).
|
|
rewrite -> (nil_is_neutral_on_the_left_of_list_append V acc).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' acc).
|
|
rewrite -> (IHvs' (v :: acc)).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' nil).
|
|
rewrite -> (IHvs' (v :: nil)).
|
|
rewrite -> (list_append_is_associative V (list_reverse_acc V vs' nil) (v :: nil) acc).
|
|
rewrite -> (fold_unfold_list_append_cons V v nil acc).
|
|
rewrite -> (fold_unfold_list_append_nil V acc).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem list_reverse_alt_satisfies_the_specification_of_list_reverse :
|
|
specification_of_list_reverse list_reverse_alt.
|
|
Proof.
|
|
unfold specification_of_list_reverse, list_reverse_alt.
|
|
intros append S_append.
|
|
split.
|
|
- intro V.
|
|
exact (fold_unfold_list_reverse_acc_nil V nil).
|
|
- intros V v vs'.
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' nil).
|
|
rewrite -> (there_is_at_most_one_list_append_function V
|
|
append list_append
|
|
S_append list_append_satisfies_the_specification_of_list_append
|
|
(list_reverse_acc V vs' nil)
|
|
(v :: nil)
|
|
).
|
|
exact (about_list_reverse_acc V vs' (v ::nil)).
|
|
Qed.
|
|
|
|
(*
|
|
i. Revisit the propositions above (involution, preservation of length, commutation with append)
|
|
and prove whether reverse_v1 satisfies them.
|
|
Two proof strategies are possible:
|
|
(1) self-contained proofs with Eureka lemmas, and
|
|
(2) proofs that hinge on the equivalence of list_reverse_alt and list_reverse.
|
|
This subtask is very instructive, but optional.
|
|
*)
|
|
|
|
Theorem about_list_reverse_acc_and_cons :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs acc : list V),
|
|
list_reverse_acc V (list_append V vs (v :: nil)) acc = v :: list_reverse_acc V vs acc.
|
|
Proof.
|
|
intros V v vs.
|
|
induction vs as [ | v' vs' IHvs' ]; intros acc.
|
|
- rewrite -> (fold_unfold_list_append_nil V (v :: nil)).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v nil acc).
|
|
rewrite -> (fold_unfold_list_reverse_acc_nil V (v :: acc)).
|
|
rewrite -> (fold_unfold_list_reverse_acc_nil V acc).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_append_cons V v' vs' (v :: nil)).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v' (list_append V vs' (v :: nil)) acc).
|
|
rewrite -> (IHvs' (v' :: acc)).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v' vs' acc).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem list_append_and_list_reverse_acc_commute_with_each_other :
|
|
forall (V : Type)
|
|
(v1s v2s : list V),
|
|
list_append V (list_reverse_acc V v2s nil) (list_reverse_acc V v1s nil) = list_reverse_acc V (list_append V v1s v2s) nil.
|
|
Proof.
|
|
intros V v1s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ]; intros v2s.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_nil V nil).
|
|
rewrite -> (fold_unfold_list_append_nil V v2s).
|
|
rewrite -> (nil_is_neutral_on_the_right_of_list_append V (list_reverse_acc V v2s nil)).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_cons V v1 v1s' nil).
|
|
rewrite -> (fold_unfold_list_append_cons V v1 v1s' v2s).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v1 (list_append V v1s' v2s) nil).
|
|
rewrite -> (about_list_reverse_acc V (list_append V v1s' v2s) (v1 :: nil)).
|
|
rewrite <- (IHv1s' v2s).
|
|
rewrite -> (list_append_is_associative V (list_reverse_acc V v2s nil) (list_reverse_acc V v1s' nil) (v1 :: nil)).
|
|
rewrite <- (about_list_reverse_acc V v1s' (v1 :: nil)).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Proposition list_reverse_alt_is_involutory :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_reverse_alt V (list_reverse_alt V vs) = vs.
|
|
Proof.
|
|
intros V vs.
|
|
unfold list_reverse_alt.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_reverse_acc_nil V).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' nil).
|
|
rewrite -> (about_list_reverse_acc V vs' (v :: nil)).
|
|
rewrite <- (list_append_and_list_reverse_acc_commute_with_each_other V (list_reverse_acc V vs' nil) (v :: nil)).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v nil nil).
|
|
rewrite -> (fold_unfold_list_reverse_acc_nil V (v::nil)).
|
|
rewrite -> IHvs'.
|
|
rewrite -> (fold_unfold_list_append_cons V v nil vs').
|
|
rewrite -> (fold_unfold_list_append_nil V vs').
|
|
reflexivity.
|
|
Restart.
|
|
intros V vs.
|
|
unfold list_reverse_alt.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_reverse_acc_nil V).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' nil).
|
|
rewrite -> (about_list_reverse_acc V vs' (v :: nil)).
|
|
rewrite -> (about_list_reverse_acc_and_cons V v (list_reverse_acc V vs' nil) nil).
|
|
rewrite -> IHvs'.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem list_reverse_alt_and_list_length_commute_with_each_other :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_length V (list_reverse_alt V vs) = list_length V vs.
|
|
Proof.
|
|
intros V vs.
|
|
unfold list_reverse_alt.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_reverse_acc_nil V nil).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' nil).
|
|
rewrite -> (about_list_reverse_acc V vs' (v :: nil)).
|
|
Search list_length.
|
|
rewrite -> (list_append_and_list_length_commute_with_each_other V (list_reverse_acc V vs' nil) (v :: nil)).
|
|
rewrite -> IHvs'.
|
|
rewrite -> (fold_unfold_list_length_cons V v nil).
|
|
rewrite -> (fold_unfold_list_length_nil V).
|
|
rewrite -> (fold_unfold_list_length_cons V v vs').
|
|
rewrite -> (Nat.add_1_r (list_length V vs')).
|
|
reflexivity.
|
|
Qed.
|
|
(* ********** *)
|
|
|
|
(* A study of the polymorphic map function: *)
|
|
|
|
Definition specification_of_list_map (map : forall V W : Type, (V -> W) -> list V -> list W) :=
|
|
(forall (V W : Type)
|
|
(f : V -> W),
|
|
map V W f nil = nil)
|
|
/\
|
|
(forall (V W : Type)
|
|
(f : V -> W)
|
|
(v : V)
|
|
(vs' : list V),
|
|
map V W f (v :: vs') = f v :: map V W f vs').
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 6:
|
|
|
|
a. Prove whether the specification specifies at most one map function.
|
|
*)
|
|
|
|
Proposition there_is_at_most_one_list_map_function :
|
|
forall list_map1 list_map2 : forall V W : Type, (V -> W) -> list V -> list W,
|
|
specification_of_list_map list_map1 ->
|
|
specification_of_list_map list_map2 ->
|
|
forall (V W : Type)
|
|
(f : V -> W)
|
|
(vs : list V),
|
|
list_map1 V W f vs = list_map2 V W f vs.
|
|
Proof.
|
|
intros list_map1 list_map2 S_list_map1 S_list_map2 V W f vs.
|
|
induction vs as [ | v vs' IHvs'].
|
|
- unfold specification_of_list_map in S_list_map1.
|
|
destruct S_list_map1 as [fold_unfold_list_map1_nil _].
|
|
destruct S_list_map2 as [fold_unfold_list_map2_nil _].
|
|
rewrite -> (fold_unfold_list_map2_nil V W f).
|
|
exact (fold_unfold_list_map1_nil V W f).
|
|
- unfold specification_of_list_map in S_list_map1.
|
|
destruct S_list_map1 as [_ fold_unfold_list_map1_cons].
|
|
destruct S_list_map2 as [_ fold_unfold_list_map2_cons].
|
|
rewrite -> (fold_unfold_list_map1_cons V W f v vs').
|
|
rewrite -> (fold_unfold_list_map2_cons V W f v vs').
|
|
rewrite -> IHvs'.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
b. Implement the map function recursively.
|
|
*)
|
|
|
|
Fixpoint list_map (V W : Type) (f : V -> W) (vs : list V) : list W :=
|
|
match vs with
|
|
nil =>
|
|
nil
|
|
| v :: vs' =>
|
|
f v :: list_map V W f vs'
|
|
end.
|
|
|
|
(*
|
|
c. State the associated fold-unfold lemmas.
|
|
*)
|
|
|
|
Lemma fold_unfold_list_map_nil :
|
|
forall (V W : Type)
|
|
(f : V -> W),
|
|
list_map V W f nil =
|
|
nil.
|
|
Proof.
|
|
fold_unfold_tactic list_map.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_map_cons :
|
|
forall (V W : Type)
|
|
(f : V -> W)
|
|
(v : V)
|
|
(vs' : list V),
|
|
list_map V W f (v :: vs') =
|
|
f v :: list_map V W f vs'.
|
|
Proof.
|
|
fold_unfold_tactic list_map.
|
|
Qed.
|
|
|
|
(*
|
|
d. Prove whether your implementation satisfies the specification.
|
|
*)
|
|
|
|
Proposition list_map_satisfies_the_specification_of_list_map :
|
|
specification_of_list_map list_map.
|
|
Proof.
|
|
unfold specification_of_list_map.
|
|
exact (conj fold_unfold_list_map_nil fold_unfold_list_map_cons).
|
|
Qed.
|
|
|
|
(*
|
|
e. Implement the copy function as an instance of list_map.
|
|
*)
|
|
|
|
|
|
Definition list_copy_as_list_map (V : Type) (vs : list V) : list V :=
|
|
list_map V V (fun i => i) vs.
|
|
|
|
Compute test_list_copy list_copy_as_list_map.
|
|
|
|
|
|
(*
|
|
Hint: Does list_copy_as_list_map satisfy the specification of list_copy?
|
|
*)
|
|
|
|
Theorem list_copy_as_list_map_satisfies_the_specification_of_list_copy :
|
|
specification_of_list_copy list_copy_as_list_map.
|
|
Proof.
|
|
unfold specification_of_list_copy, list_copy_as_list_map.
|
|
split.
|
|
- intros V.
|
|
exact (fold_unfold_list_map_nil V V (fun i => i)).
|
|
- intros V v vs'.
|
|
rewrite -> (fold_unfold_list_map_cons V V (fun i => i) v vs').
|
|
reflexivity.
|
|
Qed.
|
|
(*
|
|
f. Prove whether mapping a function over a list preserves the length of this list.
|
|
*)
|
|
Theorem list_map_and_list_length_commute_with_each_other :
|
|
forall (V W : Type)
|
|
(f : V -> W)
|
|
(vs : list V),
|
|
list_length W (list_map V W f vs) = list_length V vs.
|
|
Proof.
|
|
intros V W f vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_map_nil V W f).
|
|
rewrite -> (fold_unfold_list_length_nil W).
|
|
rewrite -> (fold_unfold_list_length_nil V).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_map_cons V W f v vs').
|
|
rewrite -> (fold_unfold_list_length_cons W (f v) (list_map V W f vs')).
|
|
rewrite -> IHvs'.
|
|
rewrite -> (fold_unfold_list_length_cons V v vs').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
g. Do list_map and list_append commute with each other and if so how?
|
|
*)
|
|
Theorem list_map_and_list_append_commute_with_each_other :
|
|
forall (V W : Type)
|
|
(f : V -> W)
|
|
(v1s v2s : list V),
|
|
list_append W (list_map V W f v1s) (list_map V W f v2s) = list_map V W f (list_append V v1s v2s).
|
|
Proof.
|
|
intros V W f v1s v2s.
|
|
induction v1s as [ | v1 v1s' IHv1s' ].
|
|
- rewrite (fold_unfold_list_map_nil V W f).
|
|
rewrite -> (nil_is_neutral_on_the_left_of_list_append W (list_map V W f v2s)).
|
|
rewrite -> (nil_is_neutral_on_the_left_of_list_append V v2s).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_map_cons V W f v1 v1s').
|
|
rewrite -> (fold_unfold_list_append_cons W (f v1) (list_map V W f v1s') (list_map V W f v2s)).
|
|
rewrite -> IHv1s'.
|
|
rewrite -> (fold_unfold_list_append_cons V v1 v1s' v2s).
|
|
rewrite -> (fold_unfold_list_map_cons V W f v1 (list_append V v1s' v2s)).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
h. Do list_map and list_reverse commute with each other and if so how?
|
|
*)
|
|
Theorem list_map_and_list_reverse_commute_with_each_other :
|
|
forall (V W : Type)
|
|
(f : V -> W)
|
|
(vs : list V),
|
|
list_reverse W (list_map V W f vs) = list_map V W f (list_reverse V vs).
|
|
Proof.
|
|
intros V W f vs.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_map_nil V W f).
|
|
rewrite -> (fold_unfold_list_reverse_nil W).
|
|
rewrite -> (fold_unfold_list_reverse_nil V).
|
|
rewrite -> (fold_unfold_list_map_nil V W f).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_map_cons V W f v vs').
|
|
rewrite -> (fold_unfold_list_reverse_cons W (f v) (list_map V W f vs')).
|
|
rewrite -> (fold_unfold_list_reverse_cons V v vs').
|
|
rewrite -> IHvs'.
|
|
Search list_reverse.
|
|
rewrite <- (list_map_and_list_append_commute_with_each_other V W f (list_reverse V vs') (v :: nil)).
|
|
rewrite -> (fold_unfold_list_map_cons V W f v nil).
|
|
rewrite -> (fold_unfold_list_map_nil V W f).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(*
|
|
i. Do list_map and list_reverse_alt commute with each other and if so how?
|
|
*)
|
|
Theorem list_map_and_list_reverse_alt_commute_with_each_other :
|
|
forall (V W : Type)
|
|
(f : V -> W)
|
|
(vs : list V),
|
|
list_reverse_alt W (list_map V W f vs) = list_map V W f (list_reverse_alt V vs).
|
|
Proof.
|
|
intros V W f vs.
|
|
unfold list_reverse_alt.
|
|
induction vs as [ | v vs' IHvs' ].
|
|
- rewrite -> (fold_unfold_list_map_nil V W f).
|
|
rewrite -> (fold_unfold_list_reverse_acc_nil W nil).
|
|
rewrite -> (fold_unfold_list_reverse_acc_nil V nil).
|
|
rewrite -> (fold_unfold_list_map_nil V W f).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_map_cons V W f v vs').
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons W (f v) (list_map V W f vs')).
|
|
rewrite -> (fold_unfold_list_reverse_acc_cons V v vs' nil).
|
|
rewrite -> (about_list_reverse_acc V vs' (v :: nil)).
|
|
rewrite <- (list_map_and_list_append_commute_with_each_other V W f (list_reverse_acc V vs' nil) (v::nil)).
|
|
rewrite -> (fold_unfold_list_map_cons V W f v nil).
|
|
rewrite -> (fold_unfold_list_map_nil V W f).
|
|
rewrite <- IHvs'.
|
|
rewrite <- (about_list_reverse_acc W (list_map V W f vs') (f v :: nil)).
|
|
reflexivity.
|
|
Qed.
|
|
(*
|
|
j. Define a unit-test function for the map function
|
|
and verify that your implementation satisfies it.
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* A study of the polymorphic fold-right and fold-left functions: *)
|
|
|
|
Definition specification_of_list_fold_right (fold_right : forall V W : Type, W -> (V -> W -> W) -> list V -> W) :=
|
|
(forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W),
|
|
fold_right V W nil_case cons_case nil =
|
|
nil_case)
|
|
/\
|
|
(forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W)
|
|
(v : V)
|
|
(vs' : list V),
|
|
fold_right V W nil_case cons_case (v :: vs') =
|
|
cons_case v (fold_right V W nil_case cons_case vs')).
|
|
|
|
Definition specification_of_list_fold_left (fold_left : forall V W : Type, W -> (V -> W -> W) -> list V -> W) :=
|
|
(forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W),
|
|
fold_left V W nil_case cons_case nil =
|
|
nil_case)
|
|
/\
|
|
(forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W)
|
|
(v : V)
|
|
(vs' : list V),
|
|
fold_left V W nil_case cons_case (v :: vs') =
|
|
fold_left V W (cons_case v nil_case) cons_case vs').
|
|
|
|
(* ***** *)
|
|
|
|
(* Task 7:
|
|
|
|
a. Implement the fold-right function recursively.
|
|
*)
|
|
|
|
Fixpoint list_fold_right (V W : Type) (nil_case : W) (cons_case : V -> W -> W) (vs : list V) : W :=
|
|
match vs with
|
|
nil =>
|
|
nil_case
|
|
| v :: vs' =>
|
|
cons_case v (list_fold_right V W nil_case cons_case vs')
|
|
end.
|
|
|
|
(*
|
|
b. Implement the fold-left function recursively.
|
|
*)
|
|
|
|
Fixpoint list_fold_left (V W : Type) (nil_case : W) (cons_case : V -> W -> W) (vs : list V) : W :=
|
|
match vs with
|
|
nil =>
|
|
nil_case
|
|
| v :: vs' =>
|
|
list_fold_left V W (cons_case v nil_case) cons_case vs'
|
|
end.
|
|
|
|
(*
|
|
c. state the fold-unfold lemmas associated to list_fold_right and to list_fold_left
|
|
*)
|
|
|
|
Lemma fold_unfold_list_fold_right_nil :
|
|
forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W),
|
|
list_fold_right V W nil_case cons_case nil =
|
|
nil_case.
|
|
Proof.
|
|
fold_unfold_tactic list_fold_right.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_fold_right_cons :
|
|
forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W)
|
|
(v : V)
|
|
(vs' : list V),
|
|
list_fold_right V W nil_case cons_case (v :: vs') =
|
|
cons_case v (list_fold_right V W nil_case cons_case vs').
|
|
Proof.
|
|
fold_unfold_tactic list_fold_right.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_fold_left_nil :
|
|
forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W),
|
|
list_fold_left V W nil_case cons_case nil =
|
|
nil_case.
|
|
Proof.
|
|
fold_unfold_tactic list_fold_left.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_list_fold_left_cons :
|
|
forall (V W : Type)
|
|
(nil_case : W)
|
|
(cons_case : V -> W -> W)
|
|
(v : V)
|
|
(vs' : list V),
|
|
list_fold_left V W nil_case cons_case (v :: vs') =
|
|
list_fold_left V W (cons_case v nil_case) cons_case vs'.
|
|
Proof.
|
|
fold_unfold_tactic list_fold_left.
|
|
Qed.
|
|
|
|
(*
|
|
d. Prove that each of your implementations satisfies the corresponding specification.
|
|
*)
|
|
|
|
Theorem list_fold_right_satisfies_the_specification_of_list_fold_right :
|
|
specification_of_list_fold_right list_fold_right.
|
|
Proof.
|
|
unfold specification_of_list_fold_right.
|
|
split.
|
|
- intros V W nil_case cons_case.
|
|
exact (fold_unfold_list_fold_right_nil V W nil_case cons_case).
|
|
- intros V W nil_case cons_case v vs'.
|
|
exact (fold_unfold_list_fold_right_cons V W nil_case cons_case v vs').
|
|
Qed.
|
|
|
|
Theorem list_fold_left_satisfies_the_specification_of_list_fold_left :
|
|
specification_of_list_fold_left list_fold_left.
|
|
Proof.
|
|
unfold specification_of_list_fold_left.
|
|
split.
|
|
- intros V W nil_case cons_case.
|
|
exact (fold_unfold_list_fold_left_nil V W nil_case cons_case).
|
|
- intros V W nil_case cons_case v vs'.
|
|
exact (fold_unfold_list_fold_left_cons V W nil_case cons_case v vs').
|
|
Qed.
|
|
|
|
(*
|
|
e. Which function do foo and bar (defined just below) compute?
|
|
*)
|
|
|
|
|
|
Definition foo (V : Type) (vs : list V) :=
|
|
list_fold_right V (list V) nil (fun v vs => v :: vs) vs.
|
|
|
|
Compute test_list_copy foo.
|
|
|
|
|
|
Definition bar (V : Type) (vs : list V) :=
|
|
list_fold_left V (list V) nil (fun v vs => v :: vs) vs.
|
|
|
|
Compute test_list_reverse bar.
|
|
|
|
(*
|
|
f. Implement the length function either as an instance of list_fold_right or as an instance of list_fold_left, and justify your choice.
|
|
*)
|
|
|
|
Definition list_length_as_list_fold_right (V : Type) (vs : list V) :=
|
|
list_fold_right V nat 0 (fun _ acc => S acc) vs.
|
|
|
|
Compute test_list_length list_length_as_list_fold_right.
|
|
|
|
Theorem list_length_as_list_fold_right_satisfies_the_specification_of_list_length :
|
|
specification_of_list_length list_length_as_list_fold_right.
|
|
Proof.
|
|
unfold specification_of_list_length, list_length_as_list_fold_right.
|
|
split.
|
|
- intro V.
|
|
rewrite -> (fold_unfold_list_fold_right_nil V nat 0 (fun v acc => S acc)).
|
|
reflexivity.
|
|
- intros V v vs'.
|
|
rewrite -> (fold_unfold_list_fold_right_cons V nat 0 (fun v acc => S acc) v vs').
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Definition list_length_as_list_fold_left (V : Type) (vs : list V) :=
|
|
list_fold_left V nat 0 (fun _ acc => S acc) vs.
|
|
|
|
Compute test_list_length list_length_as_list_fold_left.
|
|
|
|
Lemma about_list_length_and_list_fold_left :
|
|
forall (V : Type)
|
|
(vs : list V)
|
|
(acc : nat)
|
|
(f : V -> nat -> nat),
|
|
(f = fun (_: V) (acc: nat) => S acc) ->
|
|
list_fold_left V nat (S acc) f vs =
|
|
S (list_fold_left V nat acc f vs).
|
|
Proof.
|
|
intros V vs acc f S_f.
|
|
revert acc.
|
|
induction vs as [ | v vs' IHvs' ]; intro acc.
|
|
- rewrite -> (fold_unfold_list_fold_left_nil V nat acc f).
|
|
exact (fold_unfold_list_fold_left_nil V nat (S acc) f).
|
|
- rewrite -> (fold_unfold_list_fold_left_cons V nat (S acc) f v vs').
|
|
rewrite -> (fold_unfold_list_fold_left_cons V nat acc f v vs').
|
|
rewrite -> S_f.
|
|
rewrite <- S_f.
|
|
rewrite -> (IHvs' (S acc)).
|
|
reflexivity.
|
|
Qed.
|
|
Lemma about_list_length_and_list_fold_left_alt :
|
|
forall (V : Type)
|
|
(vs : list V)
|
|
(acc : nat),
|
|
list_fold_left V nat (S acc) (fun (_: V) (acc: nat) => S acc) vs =
|
|
S (list_fold_left V nat acc (fun (_: V) (acc: nat) => S acc) vs).
|
|
Proof.
|
|
intros V vs.
|
|
induction vs as [ | v vs' IHvs' ]; intro acc.
|
|
- rewrite -> (fold_unfold_list_fold_left_nil V nat acc (fun v acc => S acc)).
|
|
exact (fold_unfold_list_fold_left_nil V nat (S acc) (fun v acc => S acc)).
|
|
- rewrite -> (fold_unfold_list_fold_left_cons V nat (S acc) (fun v acc => S acc) v vs').
|
|
rewrite -> (fold_unfold_list_fold_left_cons V nat acc (fun v acc => S acc) v vs').
|
|
rewrite -> (IHvs' (S acc)).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem list_length_as_list_fold_left_satisfies_the_specification_of_list_length :
|
|
specification_of_list_length list_length_as_list_fold_left.
|
|
Proof.
|
|
unfold specification_of_list_length, list_length_as_list_fold_left.
|
|
split.
|
|
- intro V.
|
|
rewrite -> (fold_unfold_list_fold_left_nil V nat 0 (fun v acc => S acc)).
|
|
reflexivity.
|
|
- intros V v vs'.
|
|
remember (fun (_: V) (acc: nat) => S acc) as f eqn:H_f.
|
|
rewrite -> (fold_unfold_list_fold_left_cons V nat 0 f v vs').
|
|
rewrite -> H_f.
|
|
rewrite <- H_f.
|
|
exact (about_list_length_and_list_fold_left V vs' 0 f H_f).
|
|
Restart.
|
|
unfold specification_of_list_length, list_length_as_list_fold_left.
|
|
split.
|
|
- intro V.
|
|
rewrite -> (fold_unfold_list_fold_left_nil V nat 0 (fun v acc => S acc)).
|
|
reflexivity.
|
|
- intros V v vs'.
|
|
rewrite -> (fold_unfold_list_fold_left_cons V nat 0 (fun v acc => S acc) v vs').
|
|
exact (about_list_length_and_list_fold_left_alt V vs' 0).
|
|
Qed.
|
|
|
|
(*
|
|
g. Implement the copy function either as an instance of list_fold_right or as an instance of list_fold_left, and justify your choice.
|
|
*)
|
|
Definition list_copy_as_list_fold_right (V : Type) (vs : list V) :=
|
|
list_fold_right V (list V) nil (fun v acc => v :: acc) vs.
|
|
|
|
Compute test_list_copy list_copy_as_list_fold_right.
|
|
|
|
Theorem list_copy_as_list_fold_right_satisfies_the_specification_of_list_copy :
|
|
specification_of_list_copy list_copy_as_list_fold_right.
|
|
Proof.
|
|
unfold specification_of_list_copy, list_copy_as_list_fold_right.
|
|
split.
|
|
- intros V.
|
|
remember (fun v acc => v :: acc) as f eqn:H_f.
|
|
exact (fold_unfold_list_fold_right_nil V (list V) nil f).
|
|
- intros V v vs'.
|
|
remember (fun v acc => v :: acc) as f eqn:H_f.
|
|
rewrite -> (fold_unfold_list_fold_right_cons V (list V) nil f v vs').
|
|
rewrite -> H_f.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Definition list_copy_as_list_fold_left (V : Type) (vs : list V) :=
|
|
list_fold_left V (list V) nil (fun v acc => list_append V acc (v :: nil)) vs.
|
|
|
|
Lemma about_list_copy_and_list_fold_left :
|
|
forall (V : Type)
|
|
(v : V)
|
|
(vs acc : list V)
|
|
(f : V -> list V -> list V),
|
|
(f = (fun (v : V) (acc : list V) => list_append V acc (v :: nil))) ->
|
|
list_fold_left V (list V) (v :: acc) f vs = v :: list_fold_left V (list V) acc f vs.
|
|
Proof.
|
|
intros V v vs acc f H_f.
|
|
revert acc.
|
|
induction vs as [ | v' vs' IHvs' ];intros acc.
|
|
- rewrite -> (fold_unfold_list_fold_left_nil V (list V) (v :: acc) f).
|
|
rewrite -> (fold_unfold_list_fold_left_nil V (list V) acc f).
|
|
reflexivity.
|
|
- rewrite -> (fold_unfold_list_fold_left_cons V (list V) (v :: acc) f v' vs').
|
|
rewrite -> H_f.
|
|
rewrite <- H_f.
|
|
rewrite -> (fold_unfold_list_append_cons V v acc (v' :: nil)).
|
|
rewrite -> (IHvs' (list_append V acc (v' :: nil))).
|
|
rewrite -> (fold_unfold_list_fold_left_cons V (list V) acc f v' vs').
|
|
rewrite -> H_f.
|
|
rewrite <- H_f.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Theorem list_copy_as_list_fold_left_satisfies_the_specification_of_list_copy :
|
|
specification_of_list_copy list_copy_as_list_fold_left.
|
|
Proof.
|
|
unfold specification_of_list_copy, list_copy_as_list_fold_left.
|
|
split.
|
|
- intros V.
|
|
remember (fun v acc => list_append V acc (v :: nil)) as f eqn:H_f.
|
|
exact (fold_unfold_list_fold_left_nil V (list V) nil f).
|
|
- intros V v vs'.
|
|
remember (fun v acc => list_append V acc (v :: nil)) as f eqn:H_f.
|
|
rewrite -> (fold_unfold_list_fold_left_cons V (list V) nil f v vs').
|
|
rewrite -> H_f.
|
|
rewrite <- H_f.
|
|
rewrite -> (fold_unfold_list_append_nil V (v :: nil)).
|
|
exact (about_list_copy_and_list_fold_left V v vs' nil f H_f).
|
|
Qed.
|
|
|
|
Compute test_list_copy list_copy_as_list_fold_left.
|
|
|
|
(*
|
|
h. Implement the append function either as an instance of list_fold_right or as an instance of list_fold_left, and justify your choice.
|
|
*)
|
|
|
|
(* Fixpoint list_append (V : Type) (v1s v2s : list V) : list V := *)
|
|
(* match v1s with *)
|
|
|
|
(* | nil => *)
|
|
(* v2s *)
|
|
(* | v1 :: v1s' => *)
|
|
(* v1 :: list_append V v1s' v2s *)
|
|
(* end. *)
|
|
|
|
Definition list_append_as_list_fold_right (V : Type) (v1s v2s : list V) : list V :=
|
|
list_fold_right V (list V) v2s (fun v ih => v :: ih) v1s.
|
|
|
|
Compute test_list_append list_append_as_list_fold_right.
|
|
|
|
Theorem list_append_as_list_fold_right_satsifies_the_specification_of_list_append :
|
|
specification_of_list_append list_append_as_list_fold_right.
|
|
Proof.
|
|
unfold specification_of_list_append, list_append_as_list_fold_right.
|
|
split.
|
|
- intros V v2s.
|
|
remember (fun v ih => v :: ih) as f eqn:H_f.
|
|
exact (fold_unfold_list_fold_right_nil V (list V) v2s f).
|
|
- intros V v1 v1s' v2s.
|
|
remember (fun v ih => v :: ih) as f eqn:H_f.
|
|
rewrite -> (fold_unfold_list_fold_right_cons V (list V) v2s f v1 v1s').
|
|
rewrite -> H_f.
|
|
reflexivity.
|
|
Qed.
|
|
|
|
(* This is very very wrong, but I'm giving up for now *)
|
|
Definition list_append_as_list_fold_left (V : Type) (v1s v2s : list V) : list V :=
|
|
list_fold_left V (list V) v1s (fun v acc => v::acc) v2s.
|
|
|
|
Compute list_append_as_list_fold_left nat (1 :: 2 :: nil) (3 :: 4 :: nil).
|
|
|
|
Compute test_list_append list_append_as_list_fold_left.
|
|
|
|
|
|
|
|
|
|
(*
|
|
i. Implement the reverse function either as an instance of list_fold_right or as an instance of list_fold_left, and justify your choice.
|
|
*)
|
|
|
|
Definition list_reverse_as_list_fold_left (V: Type) (vs : list V) : list V :=
|
|
list_fold_left V (list V) nil (fun v acc => v :: acc) vs.
|
|
|
|
Compute list_reverse_as_list_fold_left nat (1 :: 2 :: nil).
|
|
|
|
Compute test_list_reverse list_reverse_as_list_fold_left.
|
|
|
|
Theorem list_reverse_as_list_fold_left_satsifies_the_specification_of_list_reverse:
|
|
specification_of_list_reverse list_reverse_as_list_fold_left.
|
|
Proof.
|
|
unfold specification_of_list_reverse, list_reverse_as_list_fold_left.
|
|
intros append S_append.
|
|
split.
|
|
- intros V.
|
|
remember (fun v acc => v :: acc) as f eqn:H_f.
|
|
exact (fold_unfold_list_fold_left_nil V (list V) nil f).
|
|
- intros V v vs'.
|
|
remember (fun v acc => v :: acc) as f eqn:H_f.
|
|
rewrite -> (fold_unfold_list_fold_left_cons V (list V) nil f v vs').
|
|
|
|
split.
|
|
|
|
Qed.
|
|
|
|
(*
|
|
j. Implement the map function either as an instance of list_fold_right or as an instance of list_fold_left, and justify your choice.
|
|
*)
|
|
|
|
|
|
(*
|
|
k. Implement eqb_list either as an instance of list_fold_right or as an instance of list_fold_left, and justify your choice.
|
|
*)
|
|
|
|
(*
|
|
l. Implement list_fold_right as an instance of list_fold_left, using list_reverse.
|
|
*)
|
|
|
|
(*
|
|
m. Implement list_fold_left as an instance of list_fold_right, using list_reverse.
|
|
*)
|
|
|
|
(*
|
|
n. Implement list_fold_right as an instance of list_fold_left, without using list_reverse.
|
|
*)
|
|
|
|
(*
|
|
Definition list_fold_right_left (V W : Type) (nil_case : W) (cons_case : V -> W -> W) (vs : list V) : W :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
o. Implement list_fold_left as an instance of list_fold_right, without using list_reverse.
|
|
*)
|
|
|
|
(*
|
|
Definition list_fold_left_right (V W : Type) (nil_case : W) (cons_case : V -> W -> W) (vs : list V) : W :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
p. Show that
|
|
if the cons case is a function that is left permutative (defined just below),
|
|
applying list_fold_left and applying list_fold_right
|
|
to a nil case, this cons case, and a list
|
|
give the same result
|
|
*)
|
|
|
|
Definition is_left_permutative (V W : Type) (op2 : V -> W -> W) :=
|
|
forall (v1 v2 : V)
|
|
(w : W),
|
|
op2 v1 (op2 v2 w) = op2 v2 (op2 v1 w).
|
|
|
|
(*
|
|
Theorem folding_left_and_right_over_lists :
|
|
forall (V W : Type)
|
|
(cons_case : V -> W -> W),
|
|
is_left_permutative V W cons_case ->
|
|
forall (nil_case : W)
|
|
(vs : list V),
|
|
list_fold_left V W nil_case cons_case vs =
|
|
list_fold_right V W nil_case cons_case vs.
|
|
Proof.
|
|
Abort.
|
|
*)
|
|
|
|
(*
|
|
q. Can you think of corollaries of this property?
|
|
*)
|
|
|
|
Lemma plus_is_left_permutative :
|
|
is_left_permutative nat nat plus.
|
|
Proof.
|
|
Abort.
|
|
|
|
(*
|
|
Corollary example_for_plus :
|
|
forall ns : list nat,
|
|
list_fold_left nat nat 0 plus ns = list_fold_right nat nat 0 plus ns.
|
|
Proof.
|
|
Check (folding_left_and_right_over_lists nat nat plus plus_is_left_permutative 0).
|
|
exact (folding_left_and_right_over_lists nat nat plus plus_is_left_permutative 0).
|
|
Qed.
|
|
*)
|
|
|
|
(* What do you make of this corollary?
|
|
Can you think of more such corollaries?
|
|
*)
|
|
|
|
(*
|
|
r. Subsidiary question: does the converse of Theorem folding_left_and_right_over_lists hold?
|
|
*)
|
|
|
|
(*
|
|
Theorem folding_left_and_right_over_lists_converse :
|
|
forall (V W : Type)
|
|
(cons_case : V -> W -> W),
|
|
(forall (nil_case : W)
|
|
(vs : list V),
|
|
list_fold_left V W nil_case cons_case vs =
|
|
list_fold_right V W nil_case cons_case vs) ->
|
|
is_left_permutative V W cons_case.
|
|
Proof.
|
|
Abort.
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* Task 8: *)
|
|
|
|
Fixpoint nat_fold_right (V : Type) (zero_case : V) (succ_case : V -> V) (n : nat) : V :=
|
|
match n with
|
|
O =>
|
|
zero_case
|
|
| S n' =>
|
|
succ_case (nat_fold_right V zero_case succ_case n')
|
|
end.
|
|
|
|
Lemma fold_unfold_nat_fold_right_O :
|
|
forall (V : Type)
|
|
(zero_case : V)
|
|
(succ_case : V -> V),
|
|
nat_fold_right V zero_case succ_case O =
|
|
zero_case.
|
|
Proof.
|
|
fold_unfold_tactic nat_fold_right.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_nat_fold_right_S :
|
|
forall (V : Type)
|
|
(zero_case : V)
|
|
(succ_case : V -> V)
|
|
(n' : nat),
|
|
nat_fold_right V zero_case succ_case (S n') =
|
|
succ_case (nat_fold_right V zero_case succ_case n').
|
|
Proof.
|
|
fold_unfold_tactic nat_fold_right.
|
|
Qed.
|
|
|
|
Fixpoint nat_fold_left (V : Type) (zero_case : V) (succ_case : V -> V) (n : nat) : V :=
|
|
match n with
|
|
O =>
|
|
zero_case
|
|
| S n' =>
|
|
nat_fold_left V (succ_case zero_case) succ_case n'
|
|
end.
|
|
|
|
Lemma fold_unfold_nat_fold_left_O :
|
|
forall (V : Type)
|
|
(zero_case : V)
|
|
(succ_case : V -> V),
|
|
nat_fold_left V zero_case succ_case O =
|
|
zero_case.
|
|
Proof.
|
|
fold_unfold_tactic nat_fold_left.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_nat_fold_left_S :
|
|
forall (V : Type)
|
|
(zero_case : V)
|
|
(succ_case : V -> V)
|
|
(n' : nat),
|
|
nat_fold_left V zero_case succ_case (S n') =
|
|
nat_fold_left V (succ_case zero_case) succ_case n'.
|
|
Proof.
|
|
fold_unfold_tactic nat_fold_left.
|
|
Qed.
|
|
|
|
(* ***** *)
|
|
|
|
(* The addition function: *)
|
|
|
|
Definition recursive_specification_of_addition (add : nat -> nat -> nat) :=
|
|
(forall y : nat,
|
|
add O y = y)
|
|
/\
|
|
(forall x' y : nat,
|
|
add (S x') y = S (add x' y)).
|
|
|
|
Definition tail_recursive_specification_of_addition (add : nat -> nat -> nat) :=
|
|
(forall y : nat,
|
|
add O y = y)
|
|
/\
|
|
(forall x' y : nat,
|
|
add (S x') y = add x' (S y)).
|
|
|
|
Definition test_add (candidate: nat -> nat -> nat) : bool :=
|
|
(Nat.eqb (candidate 0 0) 0)
|
|
&&
|
|
(Nat.eqb (candidate 0 1) 1)
|
|
&&
|
|
(Nat.eqb (candidate 1 0) 1)
|
|
&&
|
|
(Nat.eqb (candidate 1 1) 2)
|
|
&&
|
|
(Nat.eqb (candidate 1 2) 3)
|
|
&&
|
|
(Nat.eqb (candidate 2 1) 3)
|
|
&&
|
|
(Nat.eqb (candidate 2 2) 4)
|
|
&&
|
|
(* commutativity: *)
|
|
(Nat.eqb (candidate 2 10) (candidate 10 2))
|
|
&&
|
|
(* associativity: *)
|
|
(Nat.eqb (candidate 2 (candidate 5 10))
|
|
(candidate (candidate 2 5) 10))
|
|
(* etc. *)
|
|
.
|
|
|
|
(* Testing the unit-test function: *)
|
|
|
|
Compute (test_add Nat.add).
|
|
|
|
Fixpoint r_add (x y : nat) : nat :=
|
|
match x with
|
|
O =>
|
|
y
|
|
| S x' =>
|
|
S (r_add x' y)
|
|
end.
|
|
|
|
Lemma fold_unfold_r_add_O :
|
|
forall y : nat,
|
|
r_add O y =
|
|
y.
|
|
Proof.
|
|
fold_unfold_tactic r_add.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_r_add_S :
|
|
forall x' y : nat,
|
|
r_add (S x') y =
|
|
S (r_add x' y).
|
|
Proof.
|
|
fold_unfold_tactic r_add.
|
|
Qed.
|
|
|
|
(* Implement the addition function as an instance of nat_fold_right or nat_fold_left, your choice. *)
|
|
|
|
Definition r_add_right (x y : nat) : nat :=
|
|
nat_fold_right nat y (fun ih => S ih) x.
|
|
|
|
Compute (test_add r_add_right).
|
|
|
|
Proposition r_add_satisfies_the_recursive_specification_of_addition :
|
|
recursive_specification_of_addition r_add_right.
|
|
Proof.
|
|
unfold recursive_specification_of_addition, r_add_right.
|
|
split.
|
|
- intro y.
|
|
exact (fold_unfold_nat_fold_right_O nat y (fun ih => S ih)).
|
|
- intros x' y.
|
|
exact (fold_unfold_nat_fold_right_S nat y (fun ih => S ih) x').
|
|
Qed.
|
|
|
|
(*
|
|
Definition r_add_left (x y : nat) : nat :=
|
|
... nat_fold_left ... ... ... x ... .
|
|
*)
|
|
|
|
(* ***** *)
|
|
|
|
(* The power function: *)
|
|
|
|
Definition recursive_specification_of_power (power : nat -> nat -> nat) :=
|
|
(forall x : nat,
|
|
power x 0 = 1)
|
|
/\
|
|
(forall (x : nat)
|
|
(n' : nat),
|
|
power x (S n') = x * power x n').
|
|
|
|
Definition test_power (candidate : nat -> nat -> nat) : bool :=
|
|
(candidate 2 0 =? 1) &&
|
|
(candidate 10 2 =? 10 * 10) &&
|
|
(candidate 3 2 =? 3 * 3).
|
|
|
|
Fixpoint r_power (x n : nat) : nat :=
|
|
match n with
|
|
O =>
|
|
1
|
|
| S n' =>
|
|
x * r_power x n'
|
|
end.
|
|
|
|
Compute (test_power r_power).
|
|
|
|
Lemma fold_unfold_r_power_O :
|
|
forall x : nat,
|
|
r_power x O =
|
|
1.
|
|
Proof.
|
|
fold_unfold_tactic r_power.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_r_power_S :
|
|
forall x n' : nat,
|
|
r_power x (S n') =
|
|
x * r_power x n'.
|
|
Proof.
|
|
fold_unfold_tactic r_power.
|
|
Qed.
|
|
|
|
Fixpoint tr_power_aux (x n a : nat) : nat :=
|
|
match n with
|
|
O =>
|
|
a
|
|
| S n' =>
|
|
tr_power_aux x n' (x * a)
|
|
end.
|
|
|
|
Lemma fold_unfold_tr_power_aux_O :
|
|
forall x a : nat,
|
|
tr_power_aux x 0 a =
|
|
a.
|
|
Proof.
|
|
fold_unfold_tactic tr_power_aux.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_tr_power_v1_S :
|
|
forall x n' a : nat,
|
|
tr_power_aux x (S n') a =
|
|
tr_power_aux x n' (x * a).
|
|
Proof.
|
|
fold_unfold_tactic tr_power_aux.
|
|
Qed.
|
|
|
|
Definition tr_power (x n : nat) : nat :=
|
|
tr_power_aux x n 1.
|
|
|
|
Compute (test_power tr_power).
|
|
|
|
(*
|
|
Definition r_power_right (x n : nat) : nat :=
|
|
... nat_fold_right ... ... ... n ... .
|
|
|
|
Compute (test_power r_power_right).
|
|
*)
|
|
|
|
(*
|
|
Definition r_power_left (x n : nat) : nat :=
|
|
... nat_fold_left ... ... ... n ... .
|
|
|
|
Compute (test_power r_power_left).
|
|
*)
|
|
|
|
(*
|
|
Definition tr_power_right (x n : nat) : nat :=
|
|
... nat_fold_right ... ... ... n ... .
|
|
|
|
Compute (test_power tr_power_right).
|
|
*)
|
|
|
|
(*
|
|
Definition tr_power_left (x n : nat) : nat :=
|
|
... nat_fold_left ... ... ... n ... .
|
|
|
|
Compute (test_power tr_power_left).
|
|
*)
|
|
|
|
(* ***** *)
|
|
|
|
(* The factorial function: *)
|
|
|
|
Definition recursive_specification_of_the_factorial_function (fac : nat -> nat) :=
|
|
(fac 0 = 1)
|
|
/\
|
|
(forall n' : nat,
|
|
fac (S n') = S n' * fac n').
|
|
|
|
Definition test_fac (candidate : nat -> nat) : bool :=
|
|
(candidate 0 =? 1)
|
|
&&
|
|
(candidate 1 =? 1 * 1)
|
|
&&
|
|
(candidate 2 =? 2 * 1 * 1)
|
|
&&
|
|
(candidate 3 =? 3 * 2 * 1 * 1)
|
|
&&
|
|
(candidate 4 =? 4 * 3 * 2 * 1 * 1)
|
|
&&
|
|
(candidate 5 =? 5 * 4 * 3 * 2 * 1 * 1).
|
|
|
|
Fixpoint r_fac (n : nat) : nat :=
|
|
match n with
|
|
O =>
|
|
1
|
|
| S n' =>
|
|
S n' * r_fac n'
|
|
end.
|
|
|
|
Compute (test_fac r_fac).
|
|
|
|
Lemma fold_unfold_r_fac_O :
|
|
r_fac 0 =
|
|
1.
|
|
Proof.
|
|
fold_unfold_tactic r_fac.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_r_fac_S :
|
|
forall n' : nat,
|
|
r_fac (S n') =
|
|
S n' * r_fac n'.
|
|
Proof.
|
|
fold_unfold_tactic r_fac.
|
|
Qed.
|
|
|
|
Proposition r_fac_satisfies_the_recursive_specification_of_the_factorial_function :
|
|
recursive_specification_of_the_factorial_function r_fac.
|
|
Proof.
|
|
unfold recursive_specification_of_the_factorial_function.
|
|
exact (conj fold_unfold_r_fac_O fold_unfold_r_fac_S).
|
|
Qed.
|
|
|
|
(* Re-implement r_fac as an instance of nat_fold_right or nat_fold_left, your choice: *)
|
|
|
|
(*
|
|
Definition r_fac_right (n : nat) : nat :=
|
|
... nat_fold_right ... ... ... n ... .
|
|
|
|
Compute (test_fac r_fac_right).
|
|
|
|
Definition fac_left (n : nat) : nat :=
|
|
... nat_fold_left ... ... ... n ... .
|
|
|
|
Compute (test_fac r_fac_left).
|
|
*)
|
|
|
|
Fixpoint tr_fac_aux (n a : nat) : nat :=
|
|
match n with
|
|
O =>
|
|
a
|
|
| S n' =>
|
|
tr_fac_aux n' (S n' * a)
|
|
end.
|
|
|
|
Definition tr_fac (n : nat) : nat :=
|
|
tr_fac_aux n 1.
|
|
|
|
Compute (test_fac tr_fac).
|
|
|
|
Lemma fold_unfold_tr_fac_aux_O :
|
|
forall a : nat,
|
|
tr_fac_aux 0 a =
|
|
a.
|
|
Proof.
|
|
fold_unfold_tactic tr_fac_aux.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_tr_fac_aux_S :
|
|
forall n' a : nat,
|
|
tr_fac_aux (S n') a =
|
|
tr_fac_aux n' (S n' * a).
|
|
Proof.
|
|
fold_unfold_tactic tr_fac_aux.
|
|
Qed.
|
|
|
|
Proposition tr_fac_satisfies_the_recursive_specification_of_the_factorial_function :
|
|
recursive_specification_of_the_factorial_function tr_fac.
|
|
Proof.
|
|
unfold recursive_specification_of_the_factorial_function.
|
|
Abort.
|
|
|
|
(* Re-implement tr_fac as an instance of nat_fold_right or nat_fold_left, your choice: *)
|
|
|
|
(*
|
|
Definition tr_fac_right (n : nat) : nat :=
|
|
... nat_fold_right ... ... ... n ... .
|
|
|
|
Compute (test_fac tr_fac_right).
|
|
|
|
Definition tr_fac_left (n : nat) : nat :=
|
|
... nat_fold_left ... ... ... n ... .
|
|
|
|
Compute (test_fac tr_fac_alt).
|
|
*)
|
|
|
|
(* ***** *)
|
|
|
|
Definition specification_of_the_fibonacci_function (fib : nat -> nat) :=
|
|
fib 0 = 0
|
|
/\
|
|
fib 1 = 1
|
|
/\
|
|
forall n'' : nat,
|
|
fib (S (S n'')) = fib (S n'') + fib n''.
|
|
|
|
Definition test_fib (candidate: nat -> nat) : bool :=
|
|
(candidate 0 =? 0)
|
|
&&
|
|
(candidate 1 =? 1)
|
|
&&
|
|
(candidate 2 =? 1)
|
|
&&
|
|
(candidate 3 =? 2)
|
|
&&
|
|
(candidate 4 =? 3)
|
|
&&
|
|
(candidate 5 =? 5)
|
|
(* etc. *).
|
|
|
|
Fixpoint r_fib (n : nat) : nat :=
|
|
match n with
|
|
0 =>
|
|
0
|
|
| S n' =>
|
|
match n' with
|
|
0 =>
|
|
1
|
|
| S n'' =>
|
|
r_fib n' + r_fib n''
|
|
end
|
|
end.
|
|
|
|
Compute (test_fib r_fib).
|
|
|
|
Lemma fold_unfold_r_fib_O :
|
|
r_fib O =
|
|
0.
|
|
Proof.
|
|
fold_unfold_tactic r_fib.
|
|
Qed.
|
|
|
|
Lemma fold_unfold_r_fib_S :
|
|
forall n' : nat,
|
|
r_fib (S n') =
|
|
match n' with
|
|
0 =>
|
|
1
|
|
| S n'' =>
|
|
r_fib n' + r_fib n''
|
|
end.
|
|
Proof.
|
|
fold_unfold_tactic r_fib.
|
|
Qed.
|
|
|
|
Corollary fold_unfold_r_fib_SO :
|
|
r_fib 1 =
|
|
1.
|
|
Proof.
|
|
rewrite -> (fold_unfold_r_fib_S 0).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Corollary fold_unfold_r_fib_SS :
|
|
forall n'' : nat,
|
|
r_fib (S (S n'')) =
|
|
r_fib (S n'') + r_fib n''.
|
|
Proof.
|
|
intro n''.
|
|
rewrite -> (fold_unfold_r_fib_S (S n'')).
|
|
reflexivity.
|
|
Qed.
|
|
|
|
Proposition r_fib_satisfies_the_specification_of_the_fibonacci_function :
|
|
specification_of_the_fibonacci_function r_fib.
|
|
Proof.
|
|
unfold specification_of_the_fibonacci_function.
|
|
exact (conj fold_unfold_r_fib_O (conj fold_unfold_r_fib_SO fold_unfold_r_fib_SS)).
|
|
Qed.
|
|
|
|
(* Implement the Fibonacci function as an instance of nat_fold_right or nat_fold_left, your choice: *)
|
|
|
|
(*
|
|
Definition fib_right (n : nat) : nat :=
|
|
... nat_fold_right ... ... ... n ... .
|
|
|
|
Compute (test_fib tr_fib_right).
|
|
|
|
Definition fib_left (n : nat) : nat :=
|
|
... nat_fold_left ... ... ... n ... .
|
|
|
|
Compute (test_fib fib_left).
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* Task 9 *)
|
|
|
|
(* Under which conditions -- if any -- are nat_fold_right and nat_fold_left equivalent? *)
|
|
|
|
(* ********** *)
|
|
|
|
(* end of midterm-project.v *)
|