(* T4: Polimorfismo y funciones deo orden superior en Coq *)
Require Export T3_Listas.
(* =====================================================================
§ Polimorfismo
================================================================== *)
(* =====================================================================
§§ Listas polimórficas
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir el tipo boollist para representar las listas de
booleanos con los constructores bool_nil y bool_cons tales que
+ bool_nil es la lista vacía y
+ (bool_cons x ys) es la lista obtenida añadiendo el booleano x a la
lista ys.
------------------------------------------------------------------ *)
Inductive boollist : Type :=
| bool_nil : boollist
| bool_cons : bool -> boollist -> boollist.
(* ---------------------------------------------------------------------
Ejemplo. Definir el tipo (list X) para representar las listas de
elementos de con los constructores nil y cons tales que
+ nil es la lista vacía y
+ (cons x ys) es la lista obtenida añadiendo el elemento x a la
lista ys.
------------------------------------------------------------------ *)
Inductive list (X:Type) : Type :=
| nil : list X
| cons : X -> list X -> list X.
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de list.
------------------------------------------------------------------ *)
Check list.
(* ===> list : Type -> Type *)
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de (nil nat).
------------------------------------------------------------------ *)
Check (nil nat).
(* ===> nil nat : list nat *)
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de (cons nat 3 (nil nat)).
------------------------------------------------------------------ *)
Check (cons nat 3 (nil nat)).
(* ===> cons nat 3 (nil nat) : list nat *)
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de nil.
------------------------------------------------------------------ *)
Check nil.
(* ===> nil : forall X : Type, list X *)
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de cons.
------------------------------------------------------------------ *)
Check cons.
(* ===> cons : forall X : Type, X -> list X -> list X *)
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de (cons nat 2 (cons nat 1 (nil nat))).
------------------------------------------------------------------ *)
Check (cons nat 2 (cons nat 1 (nil nat))).
(* ==> cons nat 2 (cons nat 1 (nil nat)) : list nat *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
repeat (X : Type) (x : X) (count : nat) : list X
tal que (repeat X x n) es la lista obtenida repitiendo n veces el
elemento x. Por ejemplo,
repeat nat 4 2 = cons nat 4 (cons nat 4 (nil nat)).
repeat bool false 1 = cons bool false (nil bool).
------------------------------------------------------------------ *)
Fixpoint repeat (X : Type) (x : X) (count : nat) : list X :=
match count with
| 0 => nil X
| S count' => cons X x (repeat X x count')
end.
Example test_repeat1 :
repeat nat 4 2 = cons nat 4 (cons nat 4 (nil nat)).
Proof. reflexivity. Qed.
Example test_repeat2 :
repeat bool false 1 = cons bool false (nil bool).
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Se definen los siguientes tipos
Inductive mumble : Type :=
| a : mumble
| b : mumble -> nat -> mumble
| c : mumble.
Inductive grumble (X:Type) : Type :=
| d : mumble -> grumble X
| e : X -> grumble X.
Decidir cuáles de los siguientes expresiones son del tipo (grumble X)
para algún X:
- [d (b a 5)]
- [d mumble (b a 5)]
- [d bool (b a 5)]
- [e bool true]
- [e mumble (b c 0)]
- [e bool (b c 0)]
- [c]
------------------------------------------------------------------ *)
Module MumbleGrumble.
Inductive mumble : Type :=
| a : mumble
| b : mumble -> nat -> mumble
| c : mumble.
Inductive grumble (X:Type) : Type :=
| d : mumble -> grumble X
| e : X -> grumble X.
End MumbleGrumble.
(* =====================================================================
§§§ Inferencia de tipos
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
repeat' X x count : list X
tal que (repeat' X x n) es la lista obtenida repitiendo n veces el
elemento x. Por ejemplo,
repeat' nat 4 2 = cons nat 4 (cons nat 4 (nil nat)).
repeat' bool false 1 = cons bool false (nil bool).
------------------------------------------------------------------ *)
Fixpoint repeat' X x count : list X :=
match count with
| 0 => nil X
| S count' => cons X x (repeat' X x count')
end.
(* ---------------------------------------------------------------------
Ejemplo. Calcular los tipos de repeat' y repeat.
------------------------------------------------------------------ *)
Check repeat'.
(* ===> forall X : Type, X -> nat -> list X *)
Check repeat.
(* ===> forall X : Type, X -> nat -> list X *)
(* =====================================================================
§§§ Síntesis de los tipos de los argumentos
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
repeat'' X x count : list X
tal que (repeat'' X x n) es la lista obtenida repitiendo n veces el
elemento x, usando argumentos implícitos. Por ejemplo,
repeat'' nat 4 2 = cons nat 4 (cons nat 4 (nil nat)).
repeat'' bool false 1 = cons bool false (nil bool).
------------------------------------------------------------------ *)
Fixpoint repeat'' X x count : list X :=
match count with
| 0 => nil _
| S count' => cons _ x (repeat'' _ x count')
end.
(* ---------------------------------------------------------------------
Ejemplo. Definir la lista formada por los números naturales 1, 2 y 3.
------------------------------------------------------------------ *)
Definition list123 :=
cons nat 1 (cons nat 2 (cons nat 3 (nil nat))).
Definition list123' :=
cons _ 1 (cons _ 2 (cons _ 3 (nil _))).
(* =====================================================================
§§§ Argumentos implícitos
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Especificar las siguientes funciones y sus argumentos
explícitos e implícitos:
+ nil
+ constructor
+ repeat
------------------------------------------------------------------ *)
Arguments nil {X}.
Arguments cons {X} _ _.
Arguments repeat {X} x count.
(* ---------------------------------------------------------------------
Ejemplo. Definir la lista formada por los números naturales 1, 2 y 3.
------------------------------------------------------------------ *)
Definition list123'' := cons 1 (cons 2 (cons 3 nil)).
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
repeat''' {X : Type} (x : X) (count : nat) : list X
tal que (repeat'' X x n) es la lista obtenida repitiendo n veces el
elemento x, usando argumentos implícitos. Por ejemplo,
repeat'' nat 4 2 = cons nat 4 (cons nat 4 (nil nat)).
repeat'' bool false 1 = cons bool false (nil bool).
------------------------------------------------------------------ *)
Fixpoint repeat''' {X : Type} (x : X) (count : nat) : list X :=
match count with
| 0 => nil
| S count' => cons x (repeat''' x count')
end.
Example test_repeat'''1 :
repeat''' 4 2 = cons 4 (cons 4 nil).
Proof. reflexivity. Qed.
Example test_repeat'''2 :
repeat false 1 = cons false nil.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejemplo. Definir el tipo (list' {X}) para representar las listas de
elementos de con los constructores nil y cons tales que
+ nil' es la lista vacía y
+ (cons' x ys) es la lista obtenida añadiendo el elemento x a la
lista ys.
------------------------------------------------------------------ *)
Inductive list' {X:Type} : Type :=
| nil' : list'
| cons' : X -> list' -> list'.
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
app {X : Type} (l1 l2 : list X) : (list X)
tal que (app xs ys) es la concatenación de xs e ys.
------------------------------------------------------------------ *)
Fixpoint app {X : Type} (l1 l2 : list X) : (list X) :=
match l1 with
| nil => l2
| cons h t => cons h (app t l2)
end.
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
rev {X:Type} (l:list X) : list X
tal que (rev xs) es la inversa de xs. Por ejemplo,
rev (cons 1 (cons 2 nil)) = (cons 2 (cons 1 nil)).
rev (cons true nil) = cons true nil.
------------------------------------------------------------------ *)
Fixpoint rev {X:Type} (l:list X) : list X :=
match l with
| nil => nil
| cons h t => app (rev t) (cons h nil)
end.
Example test_rev1 :
rev (cons 1 (cons 2 nil)) = (cons 2 (cons 1 nil)).
Proof. reflexivity. Qed.
Example test_rev2:
rev (cons true nil) = cons true nil.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
length {X : Type} (l : list X) : nat
tal que (length xs) es el número de elementos de xs. Por ejemplo,
length (cons 1 (cons 2 (cons 3 nil))) = 3.
------------------------------------------------------------------ *)
Fixpoint length {X : Type} (l : list X) : nat :=
match l with
| nil => 0
| cons _ l' => S (length l')
end.
Example test_length1:
length (cons 1 (cons 2 (cons 3 nil))) = 3.
Proof. reflexivity. Qed.
(* =====================================================================
§§§ Explicitación de argumentos
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Especificar que la siguiente definición es errónea
Fail Definition mynil := nil.
------------------------------------------------------------------ *)
Fail Definition mynil := nil.
(* ==> Error: Cannot infer the implicit parameter X of nil. *)
(* ---------------------------------------------------------------------
Ejemplo. Completar la definición anterior para obtener la lista
vacía de números naturales.
------------------------------------------------------------------ *)
Definition mynil : list nat := nil.
(* Alternativamente *)
Definition mynil' := @nil nat.
(* ---------------------------------------------------------------------
Ejemplo. Definir las siguientes abreviaturas
+ "x :: y" para (cons x y)
+ "[ ]" para nil
+ "[ x ; .. ; y ]" para (cons x .. (cons y []) ..).
+ "x ++ y" para (app x y)
------------------------------------------------------------------ *)
Notation "x :: y" := (cons x y)
(at level 60, right associativity).
Notation "[ ]" := nil.
Notation "[ x ; .. ; y ]" := (cons x .. (cons y []) ..).
Notation "x ++ y" := (app x y)
(at level 60, right associativity).
(* ---------------------------------------------------------------------
Ejemplo. Definir la lista cuyos elementos son 1, 2 y 3.
------------------------------------------------------------------ *)
Definition list123''' := [1; 2; 3].
(* =====================================================================
§§§ Ejercicios
================================================================== *)
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que la lista vacía es el elemento neutro por la
derecha de la concatenación.
------------------------------------------------------------------ *)
Theorem app_nil_r : forall (X:Type), forall l:list X,
l ++ [] = l.
Proof.
induction l.
+ reflexivity.
+ simpl. rewrite IHl. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que la concatenación es asociativa.
------------------------------------------------------------------ *)
Theorem app_assoc : forall A (l m n:list A),
l ++ m ++ n = (l ++ m) ++ n.
Proof.
intros A l m n.
induction l.
+ reflexivity.
+ simpl. rewrite IHl. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que la longitud de una concatenación es la suma de
las longitudes de las listas (es decir, es un homomorfismo).
------------------------------------------------------------------ *)
Lemma app_length : forall (X:Type) (l1 l2 : list X),
length (l1 ++ l2) = length l1 + length l2.
Proof.
intros X l1 l2.
induction l1.
+ reflexivity.
+ simpl. rewrite IHl1. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que
rev (l1 ++ l2) = rev l2 ++ rev l1.
------------------------------------------------------------------ *)
Theorem rev_app_distr: forall X (l1 l2 : list X),
rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof.
intros X l1 l2.
induction l1.
+ simpl. rewrite app_nil_r. reflexivity.
+ simpl. rewrite IHl1, app_assoc. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que
rev (rev l) = l.
------------------------------------------------------------------ *)
Theorem rev_involutive : forall X : Type, forall l : list X,
rev (rev l) = l.
Proof.
induction l.
+ reflexivity.
+ simpl. rewrite rev_app_distr, IHl. reflexivity.
Qed.
(* =====================================================================
§§ Polimorfismo de pares
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir el tipo prod (X Y) con el constructor pair tal que
(pair x y) es el par cuyas componentes son x e y.
------------------------------------------------------------------ *)
Inductive prod (X Y : Type) : Type :=
| pair : X -> Y -> prod X Y.
Arguments pair {X} {Y} _ _.
(* ---------------------------------------------------------------------
Ejemplo. Definir la abreviatura
"( x , y )" para (pair x y).
------------------------------------------------------------------ *)
Notation "( x , y )" := (pair x y).
(* ---------------------------------------------------------------------
Ejemplo. Definir la abreviatura
"X * Y" para (prod X Y)
------------------------------------------------------------------ *)
Notation "X * Y" := (prod X Y) : type_scope.
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
fst {X Y : Type} (p : X * Y) : X
tal que (fst p) es la primera componente del par p.
------------------------------------------------------------------ *)
Definition fst {X Y : Type} (p : X * Y) : X :=
match p with
| (x, y) => x
end.
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
snd {X Y : Type} (p : X * Y)
tal que (snd p) es la segunda componente del par p.
------------------------------------------------------------------ *)
Definition snd {X Y : Type} (p : X * Y) : Y :=
match p with
| (x, y) => y
end.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
combine {X Y : Type} (lx : list X) (ly : list Y) : list (X*Y)
tal que (combine lx ly) es la lista obtenida emparejando los
elementos de lx y ly (como zip de Haskell).
------------------------------------------------------------------ *)
Fixpoint combine {X Y : Type} (lx : list X) (ly : list Y) : list (X*Y) :=
match lx, ly with
| [] , _ => []
| _ , [] => []
| x :: tx, y :: ty => (x, y) :: (combine tx ty)
end.
(* ---------------------------------------------------------------------
Ejercicio. Calcular el resultado de
Check combine
------------------------------------------------------------------ *)
Check @combine.
(* ==> forall X Y : Type, list X -> list Y -> list (X * Y)*)
(* ---------------------------------------------------------------------
Ejercicio. Calcular el resultado de
Compute (combine [1;2] [false;false;true;true]).
------------------------------------------------------------------ *)
Compute (combine [1;2] [false;false;true;true]).
(* ==> [(1, false); (2, false)] : list (nat * bool) *)
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
split {X Y : Type} (l : list (X*Y)) : (list X) * (list Y)
tal que (split l) es el par de lista (lx,ly) cuyo emparejamiento es
l. (La función split es como unzip de Haskell). Por ejemplo,
split [(1,false);(2,false)] = ([1;2],[false;false]).
------------------------------------------------------------------ *)
Fixpoint split {X Y : Type} (l : list (X*Y)) : (list X) * (list Y) :=
match l with
| [] => ([], [])
| (x, y) :: t => let s := split t in (x :: fst s, y :: snd s)
end.
Example test_split:
split [(1,false);(2,false)] = ([1;2],[false;false]).
Proof. reflexivity. Qed.
(* =====================================================================
§§ Resultados opcionales polimórficos
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir el tipo (option X) con los constructores Some y None
tales que
+ (Some x) es un valor de tipo X.
+ None es el valor nulo.
------------------------------------------------------------------ *)
Inductive option (X:Type) : Type :=
| Some : X -> option X
| None : option X.
Arguments Some {X} _.
Arguments None {X}.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
nth_error {X : Type} (l : list X) (n : nat) : option X :=
tal que (nth_error l n) es el n-ésimo elemento de l. Por ejemplo,
nth_error [4;5;6;7] 0 = Some 4.
nth_error [[1];[2]] 1 = Some [2].
nth_error [true] 2 = None.
------------------------------------------------------------------ *)
Fixpoint nth_error {X : Type} (l : list X) (n : nat) : option X :=
match l with
| [] => None
| a :: l' => if beq_nat n O then Some a else nth_error l' (pred n)
end.
Example test_nth_error1 : nth_error [4;5;6;7] 0 = Some 4.
Proof. reflexivity. Qed.
Example test_nth_error2 : nth_error [[1];[2]] 1 = Some [2].
Proof. reflexivity. Qed.
Example test_nth_error3 : nth_error [true] 2 = None.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
hd_error {X : Type} (l : list X) : option X
tal que (hd_error l) es el primer elemento de l. Por ejemplo,
hd_error [1;2] = Some 1.
hd_error [[1];[2]] = Some [1].
------------------------------------------------------------------ *)
Definition hd_error {X : Type} (l : list X) : option X :=
match l with
| [] => None
| x :: _ => Some x
end.
Check @hd_error.
Example test_hd_error1 : hd_error [1;2] = Some 1.
Proof. reflexivity. Qed.
Example test_hd_error2 : hd_error [[1];[2]] = Some [1].
Proof. reflexivity. Qed.
(* =====================================================================
§ Funciones como datos
================================================================== *)
(* =====================================================================
§ Funciones de orden superior
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
doit3times {X:Type} (f:X->X) (n:X) : X
tal que (doit3times f) aplica 3 veces la función f. Por ejemplo,
doit3times minustwo 9 = 3.
doit3times negb true = false.
------------------------------------------------------------------ *)
Definition doit3times {X:Type} (f:X->X) (n:X) : X :=
f (f (f n)).
Check @doit3times.
(* ===> doit3times : forall X : Type, (X -> X) -> X -> X *)
Example test_doit3times: doit3times minustwo 9 = 3.
Proof. reflexivity. Qed.
Example test_doit3times': doit3times negb true = false.
Proof. reflexivity. Qed.
(* =====================================================================
§§ Filtrado
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
filter {X:Type} (test: X->bool) (l:list X) : (list X)
tal que (filter p l) es la lista de los elementos de l que verifican
p. Por ejemplo,
filter evenb [1;2;3;4] = [2;4].
------------------------------------------------------------------ *)
Fixpoint filter {X:Type} (test: X->bool) (l:list X)
: (list X) :=
match l with
| [] => []
| h :: t => if test h then h :: (filter test t)
else filter test t
end.
Example test_filter1: filter evenb [1;2;3;4] = [2;4].
Proof. reflexivity. Qed.
Definition length_is_1 {X : Type} (l : list X) : bool :=
beq_nat (length l) 1.
Example test_filter2:
filter length_is_1
[ [1; 2]; [3]; [4]; [5;6;7]; []; [8] ]
= [ [3]; [4]; [8] ].
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
countoddmembers' (l:list nat) : nat
tal que countoddmembers' l) es el número de elementos impares de
l. Por ejemplo,
countoddmembers' [1;0;3;1;4;5] = 4.
countoddmembers' [0;2;4] = 0.
countoddmembers' nil = 0.
------------------------------------------------------------------ *)
Definition countoddmembers' (l:list nat) : nat :=
length (filter oddb l).
Example test_countoddmembers'1: countoddmembers' [1;0;3;1;4;5] = 4.
Proof. reflexivity. Qed.
Example test_countoddmembers'2: countoddmembers' [0;2;4] = 0.
Proof. reflexivity. Qed.
Example test_countoddmembers'3: countoddmembers' nil = 0.
Proof. reflexivity. Qed.
(* =====================================================================
§§ Funciones anónimas
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Demostrar que
doit3times (fun n => n * n) 2 = 256.
------------------------------------------------------------------ *)
Example test_anon_fun':
doit3times (fun n => n * n) 2 = 256.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejemplo. Calcular
filter (fun l => beq_nat (length l) 1)
[ [1; 2]; [3]; [4]; [5;6;7]; []; [8] ]
------------------------------------------------------------------ *)
Example test_filter2':
filter (fun l => beq_nat (length l) 1)
[ [1; 2]; [3]; [4]; [5;6;7]; []; [8] ]
= [ [3]; [4]; [8] ].
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
filter_even_gt7 (l : list nat) : list nat
tal que (filter_even_gt7 l) es la lista de los elemntos de l que son
pares y mayores que 7. Por ejemplo,
filter_even_gt7 [1;2;6;9;10;3;12;8] = [10;12;8].
filter_even_gt7 [5;2;6;19;129] = [].
------------------------------------------------------------------ *)
Definition filter_even_gt7 (l : list nat) : list nat :=
filter (fun x => evenb x && leb 7 x) l.
Example test_filter_even_gt7_1 :
filter_even_gt7 [1;2;6;9;10;3;12;8] = [10;12;8].
Proof. reflexivity. Qed.
Example test_filter_even_gt7_2 :
filter_even_gt7 [5;2;6;19;129] = [].
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
partition : forall X : Type,
(X -> bool) -> list X -> list X * list X
tal que (patition p l) es el par de lista (lx,ly) tal que lx es la
lista de los elementos de l que cumplen p y ly la de las que no lo
cumplen. Por ejemplo,
partition oddb [1;2;3;4;5] = ([1;3;5], [2;4]).
partition (fun x => false) [5;9;0] = ([], [5;9;0]).
------------------------------------------------------------------ *)
Definition partition {X : Type}
(test : X -> bool)
(l : list X)
: list X * list X :=
(filter test l, filter (fun x => negb (test x)) l).
Example test_partition1: partition oddb [1;2;3;4;5] = ([1;3;5], [2;4]).
Proof. reflexivity. Qed.
Example test_partition2: partition (fun x => false) [5;9;0] = ([], [5;9;0]).
Proof. reflexivity. Qed.
(* =====================================================================
§§ Aplicación a todos los elementos (map)
================================================================== *)
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
map {X Y:Type} (f:X->Y) (l:list X) : (list Y)
tal que (map f l) es la lista obtenida aplicando f a todos los
elementos de l. Por ejemplo,
map (fun x => plus 3 x) [2;0;2] = [5;3;5].
map oddb [2;1;2;5] = [false;true;false;true].
map (fun n => [evenb n;oddb n]) [2;1;2;5]
= [[true;false];[false;true];[true;false];[false;true]].
------------------------------------------------------------------ *)
Fixpoint map {X Y:Type} (f:X->Y) (l:list X) : (list Y) :=
match l with
| [] => []
| h :: t => (f h) :: (map f t)
end.
Example test_map1: map (fun x => plus 3 x) [2;0;2] = [5;3;5].
Proof. reflexivity. Qed.
Example test_map2:
map oddb [2;1;2;5] = [false;true;false;true].
Proof. reflexivity. Qed.
Example test_map3:
map (fun n => [evenb n;oddb n]) [2;1;2;5]
= [[true;false];[false;true];[true;false];[false;true]].
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que
map f (rev l) = rev (map f l).
------------------------------------------------------------------ *)
Lemma map_app_distr : forall (X Y : Type) (f : X -> Y) (l t : list X),
map f (l ++ t) = map f l ++ map f t.
Proof.
intros X Y f l t.
induction l.
+ reflexivity.
+ simpl. rewrite IHl. reflexivity.
Qed.
Theorem map_rev : forall (X Y : Type) (f : X -> Y) (l : list X),
map f (rev l) = rev (map f l).
Proof.
intros X Y f l.
induction l.
+ reflexivity.
+ simpl. rewrite map_app_distr, IHl. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
flat_map {X Y:Type} (f:X -> list Y) (l:list X) : (list Y)
tal que (flat_map f l) es la concatenación de las listas obtenidas
aplicando f a l. Por ejemplo,
flat_map (fun n => [n;n;n]) [1;5;4] = [1; 1; 1; 5; 5; 5; 4; 4; 4].
------------------------------------------------------------------ *)
Fixpoint flat_map {X Y:Type} (f:X -> list Y) (l:list X)
: (list Y) :=
match l with
| [] => []
| x :: t => f x ++ flat_map f t
end.
Example test_flat_map1:
flat_map (fun n => [n;n;n]) [1;5;4]
= [1; 1; 1; 5; 5; 5; 4; 4; 4].
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
option_map {X Y : Type} (f : X -> Y) (xo : option X) : option Y
tal que (option_map f xo) es la aplicación de f a xo.
------------------------------------------------------------------ *)
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.
(* =====================================================================
§§ Plegados (fold)
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
fold {X Y:Type} (f: X->Y->Y) (l:list X) (b:Y) : Y
tal que (fold f l b) es el plegado de l con la operación f a partir
del elemento b. Por ejemplo,
fold mult [1;2;3;4] 1 = 24.
fold andb [true;true;false;true] true = false.
fold app [[1];[];[2;3];[4]] [] = [1;2;3;4].
------------------------------------------------------------------ *)
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.
Check (fold andb).
(* ===> fold andb : list bool -> bool -> bool *)
Example fold_example1 :
fold mult [1;2;3;4] 1 = 24.
Proof. reflexivity. Qed.
Example fold_example2 :
fold andb [true;true;false;true] true = false.
Proof. reflexivity. Qed.
Example fold_example3 :
fold app [[1];[];[2;3];[4]] [] = [1;2;3;4].
Proof. reflexivity. Qed.
(* =====================================================================
§§ Funciones que construyen funciones
================================================================== *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
constfun {X: Type} (x: X) : nat->X
tal que (constfun x) es la función que a todos los naturales le
asigna el x. Por ejemplo, si se define
Definition ftrue := constfun true.
entonces,
ftrue 0 = true.
(constfun 5) 99 = 5.
------------------------------------------------------------------ *)
Definition constfun {X: Type} (x: X) : nat->X :=
fun (k:nat) => x.
Definition ftrue := constfun true.
Example constfun_example1 : ftrue 0 = true.
Proof. reflexivity. Qed.
Example constfun_example2 : (constfun 5) 99 = 5.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejemplo. Calcular el tipo de plus.
------------------------------------------------------------------ *)
Check plus.
(* ==> nat -> nat -> nat *)
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
plus3 : nat -> nat
tal que (plus3 x) es tres más x. Por ejemplo,
plus3 4 = 7.
doit3times plus3 0 = 9.
doit3times (plus 3) 0 = 9.
------------------------------------------------------------------ *)
Definition plus3 := plus 3.
Example test_plus3 : plus3 4 = 7.
Proof. reflexivity. Qed.
Example test_plus3' : doit3times plus3 0 = 9.
Proof. reflexivity. Qed.
Example test_plus3'' : doit3times (plus 3) 0 = 9.
Proof. reflexivity. Qed.
(* =====================================================================
§ Ejercicios
================================================================== *)
Module Exercises.
(* ---------------------------------------------------------------------
Ejercicio. Definir, usando fold, la función
fold_length {X : Type} (l : list X) : nat
tal que (fold_length l) es la longitud de l. Por ejemplo,
fold_length [4;7;0] = 3.
------------------------------------------------------------------ *)
Definition fold_length {X : Type} (l : list X) : nat :=
fold (fun _ n => S n) l 0.
Example test_fold_length1 : fold_length [4;7;0] = 3.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejemplo. Demostrar que
fold_length l = length l.
------------------------------------------------------------------ *)
Theorem fold_length_correct : forall X (l : list X),
fold_length l = length l.
Proof.
intros X l.
unfold fold_length.
induction l.
- reflexivity.
- simpl. rewrite IHl. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir, usando fold, la función
fold_map {X Y:Type} (f : X -> Y) (l : list X) : list Y
tal que (fold_map f l) es la lista obtenida aplicando f a los
elementos de l.
------------------------------------------------------------------ *)
Definition fold_map {X Y:Type} (f : X -> Y) (l : list X) : list Y :=
fold (fun x t => (f x) :: t) l [].
(* ---------------------------------------------------------------------
Ejemplo. Demostrar que fold_map es equivalente a map.
------------------------------------------------------------------ *)
Theorem fold_map_correct : forall (X Y : Type) (f : X -> Y) (l : list X),
fold_map f l = map f l.
Proof.
intros X Y f l.
unfold fold_map.
induction l.
- reflexivity.
- simpl. rewrite IHl. reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejemplo. Definir la función
prod_curry {X Y Z : Type} (f : X * Y -> Z) (x : X) (y : Y) : Z
tal que (prod_curry f x y) es la versión curryficada de f.
------------------------------------------------------------------ *)
Definition prod_curry {X Y Z : Type}
(f : X * Y -> Z) (x : X) (y : Y) : Z := f (x, y).
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
prod_uncurry {X Y Z : Type} (f : X -> Y -> Z) (p : X * Y) : Z
tal que (prod_uncurry f p) es la versión incurryficada de f.
------------------------------------------------------------------ *)
Definition prod_uncurry {X Y Z : Type}
(f : X -> Y -> Z) (p : X * Y) : Z := f (fst p) (snd p).
Check @prod_curry.
Check @prod_uncurry.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que
prod_curry (prod_uncurry f) x y = 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.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que
prod_uncurry (prod_curry f) p = f p.
------------------------------------------------------------------ *)
Theorem curry_uncurry : forall (X Y Z : Type)
(f : (X * Y) -> Z) (p : X * Y),
prod_uncurry (prod_curry f) p = f p.
Proof.
intros.
destruct p.
reflexivity.
Qed.
(* ---------------------------------------------------------------------
Ejercicio. Demostrar que
forall X n l, length l = n -> @nth_error X l n = None
------------------------------------------------------------------ *)
(* ---------------------------------------------------------------------
Ejercicio. En los siguientes ejercicios se trabajará con la
definición de Church de los números naturales: el número natural n es
la función que toma como argumento una función f y devuelve como
valor la aplicación de n veces la función f.
------------------------------------------------------------------ *)
Module Church.
(* ---------------------------------------------------------------------
Ejercicio. Definir el tipo nat para los números naturales de Church.
------------------------------------------------------------------ *)
Definition nat := forall X : Type, (X -> X) -> X -> X.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
one : nat
tal que one es el número uno de Church.
------------------------------------------------------------------ *)
Definition one : nat :=
fun (X : Type) (f : X -> X) (x : X) => f x.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
two : nat
tal que two es el número dos de Church.
------------------------------------------------------------------ *)
Definition two : nat :=
fun (X : Type) (f : X -> X) (x : X) => f (f x).
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
zero : nat
tal que zero es el número cero de Church.
------------------------------------------------------------------ *)
Definition zero : nat :=
fun (X : Type) (f : X -> X) (x : X) => x.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
three : nat
tal que three es el número tres de Church.
------------------------------------------------------------------ *)
Definition three : nat := @doit3times.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
succ (n : nat) : nat
tal que (succ n) es el siguiente del número n de Church. Por ejemplo,
succ zero = one.
succ one = two.
succ two = three.
------------------------------------------------------------------ *)
Definition succ (n : nat) : nat :=
fun (X : Type) (f : X -> X) (x : X) => f (n X f x).
Example succ_1 : succ zero = one.
Proof. reflexivity. Qed.
Example succ_2 : succ one = two.
Proof. reflexivity. Qed.
Example succ_3 : succ two = three.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
plus (n m : nat) : nat
tal que (plus n m) es la suma de n y m. Por ejemplo,
plus zero one = one.
plus two three = plus three two.
plus (plus two two) three = plus one (plus three three).
------------------------------------------------------------------ *)
Definition plus (n m : nat) : nat :=
fun (X : Type) (f : X -> X) (x : X) => m X f (n X f x).
Example plus_1 : plus zero one = one.
Proof. reflexivity. Qed.
Example plus_2 : plus two three = plus three two.
Proof. reflexivity. Qed.
Example plus_3 :
plus (plus two two) three = plus one (plus three three).
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
mult (n m : nat) : nat
tal que (mult n m) es el producto de n y m. Por ejemplo,
mult one one = one.
mult zero (plus three three) = zero.
mult two three = plus three three.
------------------------------------------------------------------ *)
Definition mult (n m : nat) : nat :=
fun (X : Type) (f : X -> X) (x : X) => n X (m X f) x.
Example mult_1 : mult one one = one.
Proof. reflexivity. Qed.
Example mult_2 : mult zero (plus three three) = zero.
Proof. reflexivity. Qed.
Example mult_3 : mult two three = plus three three.
Proof. reflexivity. Qed.
(* ---------------------------------------------------------------------
Ejercicio. Definir la función
exp (n m : nat) : nat
tal que (exp n m) es la potencia m-ésima de n. Por ejemplo,
exp two two = plus two two.
exp three two = plus (mult two (mult two two)) one.
exp three zero = one.
------------------------------------------------------------------ *)
Definition exp (n m : nat) : nat :=
( fun (X : Type) (f : X -> X) (x : X) => (m (X -> X) (n X) f) x).
Example exp_1 : exp two two = plus two two.
Proof. reflexivity. Qed.
Example exp_2 : exp three two = plus (mult two (mult two two)) one.
Proof. reflexivity. Qed.
Example exp_3 : exp three zero = one.
Proof. reflexivity. Qed.
End Church.
End Exercises.