# Non-dependent Elimination vs Dependent Elimination.

We consider here several types, and define their elimination principles both in the non-dependent and the dependent cases.

## Booleans

This is a basic coproduct type 1+1.
Inductive Bool : Type :=
| tt : Bool
| ff : Bool
.

### Non dependent elimination

This can be seen as a mapping from the boolean type into its Church encoding (or catamorphism).
Alternatively, the non-dependent elimination of a boolean b can be seen as the polymorphic function
fun t e => if b then t else e
: forall A, A -> A -> A
Note how both t and e must have the same type A.
Definition Bool_elim (b: Bool):
forall A: Type, A->A->A :=
fun (A: Type) (t f: A) =>
match b with
| tt => t
| ff => f
end .

### Dependent elimination

This can be seen as a generalization of the non-dependent elimination, except that the return type now depends on the value of the boolean b.
That is, the resulting type from the elimination is no longer a fixed type A, but it is F b for some function F: Bool -> Type.
Consequently, we no longer need to require that t and e have a common type A. Instead, is suffices that t has the type F tt and that e has the type F ff. Intuitively, t is returned by the elimination when b is tt, so in that case F tt and F b coincide. Simiarly, e is returned when b is ff, so F ff and F b coincide.
Hence, even if t and e have distinct types, when they are returned they both can be considered as having type F b.
Definition Bool_dep_elim (b: Bool):
forall F : Bool -> Type, F tt -> F ff -> F b :=
fun (F: Bool -> Type) (t: F tt) (f: F ff) =>
match b with
| tt => t
| ff => f
end .

Note that is the above match, t and f have different types, yet it type-checks!
This requires a non trivial type checking rule. For more details, you can see the dependentMatch file which shows how match works.

## Naturals

This is a recursive type, corresponding to the initial F-algebra F X = 1 + X.
Coq, which is based on the Calculus of Inductive Constructions, allows recursive types only when F is a (covariant) functor. In such way, it ensures that the logic is kept consistent.
Inductive Nat :=
| Zero : Nat
| Succ : Nat -> Nat
.

### Non dependent elimination

A mapping to the Church encoding / catamorphism.
Note that in A -> (A -> A) -> A, the first argument plays the role of Zero, while the second one plays the role of Succ.
Fixpoint Nat_elim (n: Nat):
forall A: Type, A -> (A -> A) -> A :=
fun (A: Type) (z: A) (s: A -> A) =>
match n with
| Zero => z
| Succ m => s (Nat_elim m A z s)
end .

Note that the Fixpoint above is checked by Coq to be terminating. When recursing, each recursive call must be made on a "smaller" term.
This is required to safeguard the logic consistency.

### Dependent elimination

Now the return type depends on n. The resulting elimination principle is the usual induction principle on naturals.
Fixpoint Nat_dep_elim (n: Nat):
forall F: Nat -> Type,
F Zero ->
(forall m: Nat, F m -> F (Succ m)) ->
F n :=
fun (F: Nat -> Type)
(z: F Zero)
(s: forall m: Nat, F m -> F (Succ m)) =>
match n with
| Zero => z
| Succ m => s m (Nat_dep_elim m F z s)
end .

## Lists of naturals

Inductive List: Type :=
| Nil: List
| Cons: Nat -> List -> List
.

### Non dependent elimination

Again, its Church encoding / catamorphism.
Fixpoint List_elim (l: List):
forall A: Type, A -> (Nat -> A -> A) -> A :=
fun (A: Type) (nil: A) (cons: Nat -> A -> A) =>
match l with
| Nil => nil
| Cons n l2 => cons n (List_elim l2 A nil cons)
end .

### Dependent elimination

The induction principle on List.
Fixpoint List_dep_elim (l: List):
forall F: List -> Type,
F Nil ->
(forall (n: Nat) (l2: List), F l2 -> F (Cons n l2)) ->
F l :=
fun (F: List -> Type)
(nil: F Nil)
(cons: forall (n: Nat) (l2: List), F l2 -> F (Cons n l2)) =>
match l with
| Nil => nil
| Cons n l2 => cons n l2 (List_dep_elim l2 F nil cons)
end .

## List of naturals, length-indexed

Intuitively, if n is a Nat, the type SizedList n below represents the lists of naturals whose length is exactly n.
Consequently, were we do not have to inductively define just one type, but a family of types indexed by a natural. This is represented by the Nat -> Type type below.
The Nat argument here is said to be the "index".
Note how the constructors NilS, ConsS return different types within the family -- i.e. their return type involves a different index.
Inductive SizedList: Nat -> Type :=
| NilS : SizedList Zero
| ConsS : Nat -> forall (n: Nat), SizedList n -> SizedList (Succ n)
.

### Non dependent elimination

Here we should have a fixed return type A, but since we are eliminating a family of types, we must let A to depend on the Nat index.
Fixpoint SizedList_elim (n: Nat) (l: SizedList n):
forall A: Nat -> Type,
A Zero ->
(Nat -> forall (k: Nat), A k -> A (Succ k)) ->
A n :=
fun (A: Nat -> Type)
(nil: A Zero)
(cons: Nat -> forall (k: Nat), A k -> A (Succ k)) =>
match l with
| NilS => nil
| ConsS m n2 l2 => cons m n2 (SizedList_elim n2 l2 A nil cons)
end .

### Dependent elimination

The return type now depends on both the index Nat, and the list itself!
Fixpoint SizedList_dep_elim (n: Nat) (l: SizedList n):
forall F: (forall m: Nat, SizedList m -> Type),
F Zero NilS ->
(forall (n2: Nat) (k: Nat) (l2: SizedList k),
F k l2 -> F (Succ k) (ConsS n2 k l2)) ->
F n l :=
fun (F: forall m: Nat, SizedList m -> Type)
(nil: F Zero NilS)
(cons: forall (n2: Nat) (k: Nat) (l2: SizedList k),
F k l2 -> F (Succ k) (ConsS n2 k l2)) =>
match l with

| NilS => nil
| ConsS m n2 l2 => cons m n2 l2 (SizedList_dep_elim n2 l2 F nil cons)
end .

## Existential quantification

Here, given the parameters T and P we define the type Ex T P.
Unlike SizedList this is not conisdered an indexed family of types. This is because the constructors do not need to involve different indexes.
Inductive Ex (T: Type) (P: T -> Type): Type :=
| witness : forall (t: T), P t -> Ex T P
.

### Non dependent elimination

Note: the return type does not depend on any index, since there are none -- T,P are parameters, not indexes.
Definition Ex_elim (T: Type) (P: T -> Type) (w: Ex T P):
(forall A: Type,
(forall (t: T), P t -> A) ->
A) :=
fun (A: Type)
(wit: forall (t: T), P t -> A) =>
match w with
| witness t h => wit t h
end .

### Dependent elimination.

Definition Ex_dep_elim (T: Type) (P: T -> Type) (w: Ex T P):
(forall F: Ex T P -> Type,
(forall (t: T) (h: P t), F (witness T P t h)) ->
F w) :=
fun (F: Ex T P -> Type)
(wit: forall (t: T) (h: P t), F (witness T P t h)) =>
match w with
| witness t h => wit t h
end .