PolyPolymorphism and Higher-Order Functions
...Coq lets us give a polymorphic definition that allows
list elements of any type:
Inductive list (X:Type) : Type :=
| nil
| cons (x : X) (l : list X).
| nil
| cons (x : X) (l : list X).
list itself is a function from types to (inductively
defined) types.
Check list.
(* ===> list : Type -> Type *)
(* ===> list : Type -> Type *)
Check (nil nat).
(* ===> nil nat : list nat *)
Check (cons nat 3 (nil nat)).
(* ===> cons nat 3 (nil nat) : list nat *)
Check nil.
(* ===> nil : forall X : Type, list X *)
Check cons.
(* ===> cons : forall X : Type, X -> list X -> list X *)
(* ===> nil nat : list nat *)
Check (cons nat 3 (nil nat)).
(* ===> cons nat 3 (nil nat) : list nat *)
Check nil.
(* ===> nil : forall X : Type, list X *)
Check cons.
(* ===> cons : forall X : Type, X -> list X -> list X *)
Notation: In .v files, the "forall" quantifier is spelled
out in letters. In the generated HTML files, it is usually
typeset as the usual mathematical "upside down A."
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.
match count with
| 0 ⇒ nil X
| S count' ⇒ cons X x (repeat X x count')
end.
Arguments nil {X}.
Arguments cons {X} _ _.
Arguments repeat {X} x count.
Fixpoint app {X : Type} (l1 l2 : list X)
: (list X) :=
match l1 with
| nil ⇒ l2
| cons h t ⇒ cons h (app t l2)
end.
Fixpoint rev {X:Type} (l:list X) : list X :=
match l with
| nil ⇒ nil
| cons h t ⇒ app (rev t) (cons h nil)
end.
Fixpoint length {X : Type} (l : list X) : nat :=
match l with
| nil ⇒ 0
| cons _ l' ⇒ S (length l')
end.
match l with
| nil ⇒ nil
| cons h t ⇒ app (rev t) (cons h nil)
end.
Fixpoint length {X : Type} (l : list X) : nat :=
match l with
| nil ⇒ 0
| cons _ l' ⇒ S (length l')
end.
Supplying Type Arguments Explicitly
Fail Definition mynil := nil.
We can fix this with an explicit type declaration:
Definition mynil : list nat := nil.
Alternatively, we can force the implicit arguments to be explicit by
prefixing the function name with @.
Check @nil.
(* ===> @nil : forall X : Type, list X *)
Definition mynil' := @nil nat.
(* ===> @nil : forall X : Type, list X *)
Definition mynil' := @nil nat.
Using argument synthesis and implicit arguments, we can define concrete notations that work for lists of any type.
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).
Definition list123''' := [1; 2; 3].
(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).
Definition list123''' := [1; 2; 3].
Inductive prod (X Y : Type) : Type :=
| pair (x : X) (y : Y).
Arguments pair {X} {Y} _ _.
Notation "( x , y )" := (pair x y).
Notation "X * Y" := (prod X Y) : type_scope.
| pair (x : X) (y : Y).
Arguments pair {X} {Y} _ _.
Notation "( x , y )" := (pair x y).
Notation "X * Y" := (prod X Y) : type_scope.
(The annotation : type_scope tells Coq that this abbreviation
should only be used when parsing types. This avoids a clash with
the multiplication symbol.)
Be careful not to get (X,Y) and X*Y confused!
Definition fst {X Y : Type} (p : X * Y) : X :=
match p with
| (x, y) ⇒ x
end.
Definition snd {X Y : Type} (p : X * Y) : Y :=
match p with
| (x, y) ⇒ y
end.
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.
: list (X*Y) :=
match lx, ly with
| [], _ ⇒ []
| _, [] ⇒ []
| x :: tx, y :: ty ⇒ (x, y) :: (combine tx ty)
end.
Module OptionPlayground.
Inductive option (X:Type) : Type :=
| Some (x : X)
| None.
Arguments Some {X} _.
Arguments None {X}.
End OptionPlayground.
Fixpoint nth_error {X : Type} (l : list X) (n : nat)
: option X :=
match l with
| [] ⇒ None
| a :: l' ⇒ if n =? O then Some a else nth_error l' (pred n)
end.
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_filter2':
filter (fun l ⇒ (length l) =? 1)
[ [1; 2]; [3]; [4]; [5;6;7]; []; [8] ]
= [ [3]; [4]; [8] ].
filter (fun l ⇒ (length l) =? 1)
[ [1; 2]; [3]; [4]; [5;6;7]; []; [8] ]
= [ [3]; [4]; [8] ].
Proof. reflexivity. Qed.
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.
(* /HIDEFROMADVANCED *)
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.
This is the "reduce" in map/reduce...