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).
list itself is a function from types to (inductively defined) types.
Check list.
(* ===> list : Type -> Type *)

The parameter X in the definition of list becomes a parameter to the list constructors.
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 *)
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."

We can now define polymorphic versions of the functions we've already seen...
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.


Arguments nil {X}.
Arguments cons {X} _ _.
Arguments repeat {X} x count.

Fixpoint app {X : Type} (l1 l2 : list X)
             : (list X) :=
  match l1 with
  | nill2
  | cons h tcons h (app t l2)
  end.

Fixpoint rev {X:Type} (l:list X) : list X :=
  match l with
  | nilnil
  | cons h tapp (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

We prefer to tell Coq to always try to infer type arguments. But, occasionally this can lead to problems:
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.

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].

Polymorphic Pairs

Similarly...
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.
(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.

What does this function do?
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.

Polymorphic Options


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.

Functions as Data


Higher-Order Functions



Fixpoint filter {X:Type} (test: Xbool) (l:list X)
                : (list X) :=
  match l with
  | [] ⇒ []
  | h :: tif test h then h :: (filter test t)
                        else filter test t
  end.

Anonymous Functions

Functions can be constructed "on the fly" without giving them names.
Example test_filter2':
    filter (fun l ⇒ (length l) =? 1)
           [ [1; 2]; [3]; [4]; [5;6;7]; []; [8] ]
  = [ [3]; [4]; [8] ].
Proof. reflexivity. Qed.

Map


Fixpoint map {X Y: Type} (f:XY) (l:list X) : (list Y) :=
  match l with
  | [] ⇒ []
  | h :: t ⇒ (f h) :: (map f t)
  end.

Example test_map1: map (fun xplus 3 x) [2;0;2] = [5;3;5].
Proof. reflexivity. Qed.

(* /HIDEFROMADVANCED *)

Fold


Fixpoint fold {X Y: Type} (f: XYY) (l: list X) (b: Y)
                         : Y :=
  match l with
  | nilb
  | h :: tf h (fold f t b)
  end.
This is the "reduce" in map/reduce...