1416 lines
32 KiB
Coq
1416 lines
32 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 :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
c. State its associated fold-unfold lemmas.
|
|
*)
|
|
|
|
(*
|
|
d. Prove whether your implementation satisfies the specification.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
Abort.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
Abort.
|
|
*)
|
|
|
|
(*
|
|
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?
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* 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.
|
|
*)
|
|
|
|
(*
|
|
b. Implement the list_append function recursively.
|
|
*)
|
|
|
|
(*
|
|
Fixpoint list_append (V : Type) (v1s v2s : list V) : list V :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
c. State its associated fold-unfold lemmas.
|
|
*)
|
|
|
|
(*
|
|
d. Prove that your implementation satisfies the specification.
|
|
*)
|
|
|
|
(*
|
|
e. Prove whether nil is neutral on the left of list_append.
|
|
*)
|
|
|
|
(*
|
|
f. Prove whether nil is neutral on the right of list_append.
|
|
*)
|
|
|
|
(*
|
|
g. Prove whether list_append is commutative.
|
|
*)
|
|
|
|
(*
|
|
h. Prove whether list_append is associative.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
Abort.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
Abort.
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* 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.
|
|
*)
|
|
|
|
(*
|
|
b. Implement the reverse function recursively, using list_append.
|
|
*)
|
|
|
|
(*
|
|
Fixpoint list_reverse (V : Type) (vs : list V) : list V :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
c. State the associated fold-unfold lemmas.
|
|
*)
|
|
|
|
(*
|
|
d. Prove whether your implementation satisfies the specification.
|
|
*)
|
|
|
|
(*
|
|
e. Prove whether list_reverse is involutory.
|
|
*)
|
|
|
|
(*
|
|
Proposition list_reverse_is_involutory :
|
|
forall (V : Type)
|
|
(vs : list V),
|
|
list_reverse V (list_reverse V vs) = vs.
|
|
Proof.
|
|
Abort.
|
|
*)
|
|
|
|
(*
|
|
f. Prove whether reversing a list preserves its length.
|
|
*)
|
|
|
|
(*
|
|
g. Do list_append and list_reverse commute with each other (hint: yes they do) and if so how?
|
|
*)
|
|
|
|
(*
|
|
h. Implement the reverse function using an accumulator instead of using list_append.
|
|
*)
|
|
|
|
(*
|
|
Definition list_reverse_alt (V : Type) (vs : list V) : list V :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(* ********** *)
|
|
|
|
(* 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 :=
|
|
...
|
|
*)
|
|
|
|
(*
|
|
Hint: Does list_copy_as_list_map satisfy the specification of list_copy?
|
|
*)
|
|
|
|
(*
|
|
f. Prove whether mapping a function over a list preserves the length of this list.
|
|
*)
|
|
|
|
(*
|
|
g. Do list_map and list_append commute with each other and if so how?
|
|
*)
|
|
|
|
(*
|
|
h. Do list_map and list_reverse commute with each other and if so how?
|
|
*)
|
|
|
|
(*
|
|
i. Do list_map and list_reverse_alt commute with each other and if so how?
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(*
|
|
Definition bar (V : Type) (vs : list V) :=
|
|
list_fold_left V (list V) nil (fun v vs => v :: vs) vs.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(*
|
|
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.
|
|
*)
|
|
|
|
(*
|
|
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 *)
|