(* QuickChick Prelude *)
Set Warnings "-extraction-opaque-accessed,-extraction".
Set Warnings "-notation-overridden,-parsing".
Set Bullet Behavior "Strict Subproofs".
(* End prelude *)
Require Export Lists.
Inductive list (X:Type) : Type :=
| nil : list X
| cons : X -> list X -> list X.
Instance dec_list' {A} (p q : list A)
(D : forall (x y : A), Dec (x = y)) : Dec (p = q).
Admitted. (* QuickChick app_assoc. *)
Admitted. (* QuickChick app_length. *)
Admitted. (* QuickChick rev_app_distr. *)
Admitted. (* QuickChick rev_involutive. *)
Inductive prod (X Y : Type) : Type :=
| pair : X -> Y -> prod X Y.
Arguments pair {X} {Y} _ _.
Notation "( x , y )" := (pair x y).
Notation "X * Y" := (prod X Y) : type_scope.
Instance dec_prod' {A} {B} (p q : prod A B)
(DA : forall (x y : A), Dec (x = y))
(DB : forall (x y : B), Dec (x = y)) : Dec (p = q).
Definition option_map {X Y : Type} (f : X -> Y) (xo : option X)
: option Y :=
match xo with
| None => None
| Some x => Some (f x)
end.
Fixpoint fold {X Y:Type} (f: X->Y->Y) (l:list X) (b:Y)
: Y :=
match l with
| nil => b
| h :: t => f h (fold f t b)
end.
Definition constfun {X: Type} (x: X) : nat->X :=
fun (k:nat) => x.
(** **** Exercise: 2 stars (fold_length)  *)
(** Many common functions on lists can be implemented in terms of [fold].  For example, here is an alternative definition of [length]: *)
Definition fold_length {X : Type} (l : list X) : nat :=
fold (fun _ n => S n) l 0.
Admitted. (* QuickChick fold_length_correct. *)
Definition prod_curry {X Y Z : Type}
(f : X * Y -> Z) (x : X) (y : Y) : Z := f (x, y).
Definition prod_uncurry {X Y Z : Type}
(f : X -> Y -> Z) (p : X * Y) : Z
:= let (x,y) := p in f x y.

Theorem uncurry_curry : forall (X Y Z : Type)
(f : X -> Y -> Z)
x y,
prod_curry (prod_uncurry f) x y = f x y.