==================
      Dependent equality
      ==================

      Advanced Functional Programming
      School of Computer Science
      University of Birmingham, UK

      Martín Hötzel Escardó
      Lecture of 6rd February 2017

      (Adapted from http://www.cs.bham.ac.uk/~mhe/agda/VecConcatAssoc.html)

      (The ideas discussed here come from "univalent foundations" and
      "homotopy type theory", but you don't need to know that in order
      to understand what is explained here.
      https://homotopytypetheory.org/book/)

Summary
=======

1. It is relatively easy to prove that list concatenation is
associative:

  (xs ++ ys) ++ zs ≡ xs ++ (ys ++ zs).

You have already seen this, and we will quickly review it.

2. When we generalize lists to vectors, then this becomes a
problem. It is not that this is difficult to *prove*. Rather, it
becomes difficult to even figure out *what needs to be proved*: The
above equation doesn't type check, when xs, ys, zs are vectors rather
than lists, because its left and right sides live in different types,
as we shall see.

3. But once we know what to prove, the proof becomes just as easy as
that of associativity of list concatenation.

4. What we need is a concept of dependent equality: an equality that
depends on another equality. This is what we study in these notes.

This is a literate agda file
============================

This file (ending in .lagda rather than .agda) is in literate
style. This means that everything is a "comment", except things
enclosed in a code environment.

Getting started
===============

This file is self-contained. We don't use libraries so that we know
exactly what is used for this task from first principles, and also so
that we can see explicitly that this can be done without much
machinery. (Although it requires a lot of explanation and
understanding effort.)

\begin{code}

{-# OPTIONS --without-K #-}

module DependentEquality where

\end{code}

Standard stuff for equality, which you have already seen:

\begin{code}

data _≡_ {X : Set} : X  X  Set where
 refl : {x : X}  x  x

cong : {X Y : Set} (f : X  Y) {x₀ x₁ : X}  x₀  x₁  f x₀  f x₁
cong {X} {Y} f (refl {x}) = refl {Y} {f x}

\end{code}

You have already defined lists and concatenation, and shown that
concatenation is associative. Here is a recap:

\begin{code}

module recap where

  data List (X : Set) : Set where
    []  : List X
    _∷_ : X  List X  List X

  _++_ : ∀{X}  List X  List X  List X
  []       ++ ys = ys
  (x  xs) ++ ys = x  (xs ++ ys)

  ++-assoc :  {X} (xs ys zs : List X)
           (xs ++ ys) ++ zs  xs ++ (ys ++ zs)
  ++-assoc []       ys zs = refl
  ++-assoc (x  xs) ys zs = goal
   where
    IH : (xs ++ ys) ++ zs  xs ++ (ys ++ zs)
    IH = ++-assoc xs ys zs
    goal : x  ((xs ++ ys) ++ zs)    x  (xs ++ (ys ++ zs))
    goal = cong  ws  x  ws) IH

\end{code}

We have put the above in a separate submodule so that it doesn't
pollute our global name space and in particular the names _++_ and
++-assoc remain available for vector concatenation and associativity.

Standard stuff for natural numbers:

\begin{code}

data  : Set where
 zero : 
 succ :   

_+_ :     
zero   + y = y
succ x + y = succ(x + y)

+-assoc :  l m n  (l + m) + n  l + (m + n)
+-assoc zero     m n = refl
+-assoc (succ l) m n = goal
 where
  IH : (l + m) + n  l + (m + n)
  IH = +-assoc l m n
  goal : succ ((l + m) + n)  succ (l + (m + n))
  goal = cong succ IH

\end{code}

Notice how the proof of associativity of addition is analogous to the
proof of associativity of concatenation.

Vectors
=======

Sometimes it is useful to consider lists of a given length. These are
called vectors, and the type of vectors of elements of type X with
length n is written Vec X n and defined as follows:

\begin{code}

data Vec (X : Set) :   Set where
  []  : Vec X zero
  _∷_ : ∀{n}  X  Vec X n  Vec X (succ n)

\end{code}

For example, with this we can define safe head and tail functions:

\begin{code}

hd : {X : Set} {n : }  Vec X (succ n)  X
hd (x  xs) = x

tl : {X : Set} {n : }  Vec X (succ n)  Vec X n
tl (x  xs) = xs

\end{code}

Notice that we don't have a case for the empty vector [] because it
doesn't belong to the type Vec X (succ n).

We can also define a safe indexing operation. We first need to define,
given a natural number n : ℕ, the type of numbers from 0 to n-1, which
is written Fin n. We do this so that Fin 0 is an empty type:

\begin{code}

data Fin :   Set where
 zero : {n : }  Fin (succ n)
 succ : {n : }  Fin n  Fin (succ n)

\end{code}

Now, given a vector xs of length k and a number in i the range
0,1,..,n,n-1, that is, an element of Fin n, we can fetch the ith
element of xs in a type-safe way:

\begin{code}

fetch :  {X n}  Vec X n  Fin n  X
fetch (x  xs)  zero    = x
fetch (x  xs) (succ i) = fetch xs i

\end{code}

Vector concatenation is defined in the same way as list concatenation,
but with a different type:

\begin{code}

_++_ : ∀{X m n}  Vec X m  Vec X n  Vec X (m + n)
[]       ++ ys = ys
(x  xs) ++ ys = x  (xs ++ ys)

\end{code}

Dependent equality of Vectors
=============================

We now come to the heart of the problem considered here, the
formulation and proof of associativity of vector concatenation.

We try to prove this (uncomment to get an error):

\begin{code}

-- ++-assoc' : ∀{X} l m n (xs : Vec X l) (ys : Vec X m) (zs : Vec X n)
--          → (xs ++ ys) ++ zs  ≡ xs ++ (ys ++ zs)
-- ++-assoc' l m n xs ys zs = ?

\end{code} 

We get the cryptic error message 

  l != l + m of type ℕ
  when checking that the expression xs ++ (ys ++ zs) has type
  Vec X (l + m + n)

What is going on? We have

  (xs ++ ys) ++ zs : Vec X ((l + m) + n),
  xs ++ (ys ++ zs) : Vec X (l + (m + n)).

While we do have 

  (l + m) + n ≡ l + (m + n),

as proved above, we don't get that the types

  Vec X ((l + m) + n) and Vec X (l + (m + n))

are the same, which is perhaps counter-intuitive. 

We know that (l + m) + n ≡ l + (m + n) because we have proved it, but
when Agda type checks your code it doesn't use this equality. Why?

The only equalities Agda uses when type checking code are those that
it knows in advance, and that are built-in in the type checker, before
we write any code proving more equalities.

And the above associativity equality is not built-in: we had to prove
it. And it required some insight.

The only equalities that Agda uses when type checking your code are
those which are routine and don't require any insight whatsoever,
which can be proved mechanically, and which you could therefore call
obvious.

Hence the expressions

  (xs ++ ys) ++ zs and xs ++ (ys ++ zs)

live in different types as far as Agda is concerned.

But equality is only defined for elements of the same type. Hence the
two expressions cannot be equated.

To overcome this, we can explicitly tell Agda to use an equality we
have proved.

If we have

  p  : m ≡ n
  xs : Vec X m
  ys : Vec X n

we can define an equality

  xs ≡[ p ] ys

of xs and ys depending on the given equality p.

As usual, we define this by pattern matching on p. The neat thing is
that when p is refl, then Agda knows that xs and ys do live in the
same type, and hence we can use the usual equality to define our new
dependent equality:

\begin{code}

_≡[_]_ : ∀{X m n}  Vec X m  m  n  Vec X n  Set
xs ≡[ refl ] ys   =   xs  ys

\end{code}

Later we will generalize the above definition, because it actually has
little to do with vectors and is useful in many other similar
situations (which we will not explore in these notes).

The following generalizes our cong function to this situation, but
here we only consider the situation where the parameter to cong is
the "cons" function λ ws → x ∷ ws, which is what we needed above in
order to prove associativity of list concatenation, and which we will
need again to prove associativity of vector concatenation:

\begin{code}

cong-cons : ∀{X m n} (x : X) {xs : Vec X m} {ys : Vec X n} (p : m  n)
           xs ≡[ p ] ys  x  xs  ≡[ cong succ p ]  x  ys
cong-cons _ refl refl = refl

\end{code}

Notice that if p : m ≡ n, then cong succ p : succ m ≡ succ n, and that
if

  xs : Vec X m and ys : Vec X n

then

  x ∷ xs : Vec X (succ m) and x ∷ ys : Vec X (succ n).

This is why from

  xs ≡[ p ] ys

we get

  x ∷ xs ≡[ cong succ p ] x ∷ ys

in the above definition.

So what we want to prove is that

  (xs ++ ys) ++ zs  ≡[ p ]  xs ++ (ys ++ zs)

for a suitable p : (l + m) + n ≡ l + (m + n), which we can take to be
+-assoc l m n. 

This statement does type check, and its proof is essentially the same
as that for the case of lists, recalled above. The crucial thing is
that now we need to use the fact that addition of natural numbers is
associative, as discussed above.

And with these remarks we are done. Here is the formulation and proof
that vector concatenation is associative:

\begin{code}

++-assoc : ∀{X} l m n (xs : Vec X l) (ys : Vec X m) (zs : Vec X n)
          (xs ++ ys) ++ zs  ≡[ +-assoc l m n ]  xs ++ (ys ++ zs)
++-assoc zero     m n []       ys zs = refl
++-assoc (succ l) m n (x  xs) ys zs = goal
 where
  IH : (xs ++ ys) ++ zs  ≡[ +-assoc l m n ]  xs ++ (ys ++ zs)
  IH = ++-assoc l m n xs ys zs
  goal : x  ((xs ++ ys) ++ zs)  ≡[ cong succ (+-assoc l m n) ]
         x  (xs ++ (ys ++ zs))
  goal = cong-cons x (+-assoc l m n) IH

\end{code}

If you have begun to understand these subtleties, then I have achieved
my learning objective.

Dependent equality more generally
=================================

But, to conclude, I am a little bit more ambitious.

We want to briefly generalize the above. Notice that

  Vec X : ℕ → Set.

We replace "Vec X" by an arbitrary "B", and "ℕ" by an arbitrary "A":

  A : Set,
  B : A → Set.

Then B is a family of sets indexed by A. In our main example,

  A = ℕ,
  B = Vec X.

Our generalized dependent equality is

  b₀ ≡⟦ p ⟧ b₁

for

  a₀ a₁ : A,
     p  : a₀ ≡ a₁,
     b₀ : B a₀,
     b₁ : B a₁.

The types are more general, but the definition is the same as in the
particular case:

\begin{code}

_≡⟦_⟧_ : {A : Set} {B : A  Set} {a₀ a₁ : A}
        B a₀  a₀  a₁  B a₁  Set
b₀ ≡⟦ refl  b₁   =   b₀  b₁

\end{code}

We then generalize cong defined above to a dependent version:

\begin{code}

congd : {A : Set} {B : A  Set} (f : (a : A)  B a) {a₀ a₁ : A}
      (p : a₀  a₁)  f a₀ ≡⟦ p  f a₁
congd f refl = refl

\end{code}

Conclusion
==========

Equality is subtler than it seems at first sight, but with the right
concepts and tools, and with practical experience, it becomes natural.

Of course there is much more to say, and the systematic study of
(dependent or independent) equality in dependent type theory is the
topic of "univalent foundations" or "homotopy type theory", which is
beyond the scope of this module: https://homotopytypetheory.org/book

But in the past we have had successful reading groups and clubs with
undergrad, MSc, and PhD students, as well as with academic staff.

--------------------------------------------------------------------
Notational appendix. To complete our code so that it parses, we list
all fixities together for easy comparison of the operator precedences:

\begin{code}

infixr 5 _≡_
infixr 5 _≡[_]_
infixr 5 _≡⟦_⟧_
infixl 6 _++_
infixl 6 _+_
infixr 7 _∷_

\end{code}