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|!}