import LexerFriendlyReasoning -- not yet working as intended

> infix 6 <=>

> %default total

> %auto_implicits off

> %access public export

> Domain : {A, B : Type} -> (A -> B) -> Type

> Domain {A} f = A

%endif

\section{Introduction}

\label{section:about}

This paper is about \emph{extensional equality preservation} in

dependently typed languages like Idris~\citep{idrisbook}, % idristutorial,

Agda~\citep{norell2007thesis} and Coq~\citep{CoqProofAssistant_8_11} that

implement %some version of

Martin-Löf's intensional type

theory \citep{martinlof1984}. % , nordstrom1990programming

%

%% We present our arguments in Idris but the results can be translated to

%% other implementations easily.

We discuss Idris code but the results could be translated to other

languages.

%

Extensional equality is a property of functions, stating that they are

``pointwise equal'':

%

%In Idris, it can be expressed as

%TR: Unfortunately doesn't typecheck without {A} ...

> (<=>) : {A, B : Type} -> (A -> B) -> (A -> B) -> Type

> (<=>) {A} f g = (x : A) -> f x = g x

Note that the definition of extensional equality |(<=>)| depends on another equality |(=)|.

%*PJ: Perhaps remark that it can be defined for dependent functions as well.

% In Agda: (formulation from \citep{DBLP:journals/jfp/AbelCDTW20})

% postulate ext : ∀ {l l'} {A : Set l} {B : A → Set l'} {f g : (a : A) → B a} →

% (∀ (a : A) → f a ≡ g a) → f ≡ g

% ext follows from univalence and can be used in type theories that assume UIP (uniqueness of identity proofs)

\paragraph*{Different flavours of equality.}%\hfill

%

\begin{quote}

``All animals are equal, but some animals are more equal than others'' [Animal Farm, Orwell (1946)]

\end{quote}

There are several kinds of ``equality'' relevant for programming.

%

%{

%format -> = "\rightarrow"

Programming languages usually offer a Boolean equality check operator and in Idris it is written |(==)|, has type |{A : Type} -> Eq A => A -> A -> Bool| and is packaged in the interface |Eq|.

%}

%

This is an ``ad-hoc'' equality, computing whatever the programmer supplies as an implementation.

%

This paper is not about value level Boolean equality.

On the type level, the dependently typed languages we consider in this paper provide

a notion of \emph{intensional equality}, also referred to as an ``equality type'',

which is an inductively defined family of types, usually written infix: |(a=b) : Type| for |a:A| and |b:B|. It has

just one constructor |Refl : a=a|.

%

The resulting notion is not as boring as it may look at first. We have |Refl:a=b| not only if |a| and |b| are identical, but

also if they \emph{reduce} to identical expressions. Builtin reduction rules normally include alpha-conversion (capture-free

renaming of bound variables), beta-reduction (using substitution) and eta-reduction: |f = \x=>f x|.

%

So, for example, we have |Refl: id x = x|.

%

Furthermore, user-defined equations are also used for reduction.

%

A typical example is addition of natural numbers: with |+| defined by pattern matching on the first argument, we have e.g.

|Refl:1+1=2|. However, while for a variable |n:Nat| we have |Refl : 0+n = n|, we do not have |Refl: n+0=n|.

One very useful property of intensional equality is that it is a congruence with respect to any function.

%

In other words, all functions preserve intensional equality.

%

The proof uses pattern matching, which is straightforward here because

|Refl| is the only constructor:

%

< cong : {A, B : Type} -> {f : A -> B} -> {a, a' : A} -> a = a' -> f a = f a'

< cong Refl = Refl

%if False

> checkClaim : (n : Nat) -> 0+n = n

> checkClaim n = Refl

< failClaim : (n : Nat) -> n+0 = n

< failClaim n = Refl

%endif

%

In a similar way, one can prove that |(=)| is an equivalence relation:

Reflexivity is directly implemented by |Refl|, while symmetry and

transitivity can be proven by pattern matching.

\paragraph*{Extensional equality.}

As one would expect, extensional equality is an equivalence relation

> reflEE : {A, B : Type} -> {f : A -> B} -> f <=> f

> symEE : {A, B : Type} -> {f, g : A -> B} -> f <=> g -> g <=> f

> transEE : {A, B : Type} -> {f, g, h : A -> B} -> f <=> g -> g <=> h -> f <=> h

>

> reflEE = \x => Refl

> symEE p = \x => sym (p x)

> transEE p q = \x => trans (p x) (q x)

In general, we can lift any (type-valued) binary relation on a type

|B| to a binary relation on function types with co-domain |B|.

%

% \REMARK{Nicola}{As the type of |extify| is now |BinRel B -> BinRel

% (A -> B)|, the name of the function and the name |eqB| in its

% implementation are perhaps not appropriate? |BinRel| also should

% perhaps be called |EndoRel|? Or just |Rel : Type -> Type -> Type| with

% |Rel A B = A -> B -> Type| and then |extify : Rel B B -> Rel (A -> B)

% (A -> B)|? Perhaps we can get rid of |BinRel| altogether (it is not

% used in the rest of the paper) and simply write |extify : {A, B :

% Type} -> (B -> B -> Type) -> ((A -> B) -> (A -> B) -> Type|? I am

% surprised that |extify| can be applied to |(=) : A -> B -> Type|!}