# Function extensionality

```agda
module foundation.function-extensionality where
```

<details><summary>Imports</summary>

```agda
open import foundation.action-on-identifications-binary-functions
open import foundation.action-on-identifications-functions
open import foundation.dependent-pair-types
open import foundation.evaluation-functions
open import foundation.implicit-function-types
open import foundation.universe-levels

open import foundation-core.coherently-invertible-maps
open import foundation-core.equivalences
open import foundation-core.function-types
open import foundation-core.homotopies
open import foundation-core.identity-types
open import foundation-core.retractions
open import foundation-core.sections
```

</details>

## Idea

The
{{#concept "function extensionality axiom" Agda=function-extensionality Agda=funext}}
asserts that [identifications](foundation-core.identity-types.md) of (dependent)
functions are [equivalently](foundation-core.equivalences.md) described as
[homotopies](foundation-core.homotopies.md) between them. In other words, a
function is completely determined by its values.

Function extensionality is postulated by stating that the canonical map

```text
  htpy-eq : f = g → f ~ g
```

from identifications between two functions to homotopies between them is an
equivalence. The map `htpy-eq` is the unique map that fits in a
[commuting triangle](foundation-core.commuting-triangles-of-maps.md)

```text
              htpy-eq
    (f = g) ----------> (f ~ g)
           \            /
  ap (ev x) \          / ev x
             ∨        ∨
            (f x = g x)
```

In other words, we define

```text
  htpy-eq p x := ap (ev x) p.
```

It follows from this definition that `htpy-eq refl ≐ refl-htpy`, as expected.

## Definitions

### Equalities induce homotopies

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2}
  where

  htpy-eq : {f g : (x : A)  B x}  f  g  f ~ g
  htpy-eq p a = ap (ev a) p

  compute-htpy-eq-refl : {f : (x : A)  B x}  htpy-eq refl  refl-htpy' f
  compute-htpy-eq-refl = refl
```

### An instance of function extensionality

This property asserts that, _given_ two functions `f` and `g`, the map

```text
  htpy-eq : f = g → f ~ g
```

is an equivalence.

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2}
  where

  instance-function-extensionality : (f g : (x : A)  B x)  UU (l1  l2)
  instance-function-extensionality f g = is-equiv (htpy-eq {f = f} {g})
```

### Based function extensionality

This property asserts that, _given_ a function `f`, the map

```text
  htpy-eq : f = g → f ~ g
```

is an equivalence for any function `g` of the same type.

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2}
  where

  based-function-extensionality : (f : (x : A)  B x)  UU (l1  l2)
  based-function-extensionality f =
    (g : (x : A)  B x)  instance-function-extensionality f g
```

### The function extensionality principle with respect to a universe level

```agda
function-extensionality-Level : (l1 l2 : Level)  UU (lsuc l1  lsuc l2)
function-extensionality-Level l1 l2 =
  {A : UU l1} {B : A  UU l2}
  (f : (x : A)  B x)  based-function-extensionality f
```

### The function extensionality axiom

```agda
function-extensionality : UUω
function-extensionality = {l1 l2 : Level}  function-extensionality-Level l1 l2
```

Rather than postulating a witness of `function-extensionality` directly, we
postulate the constituents of a coherent two-sided inverse to `htpy-eq`. The
benefits are that we end up with a single converse map to `htpy-eq`, rather than
a separate section and retraction, although they would be homotopic regardless.
In addition, this formulation helps Agda display goals involving function
extensionality in a more readable way.

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2} {f g : (x : A)  B x}
  where

  postulate
    eq-htpy : f ~ g  f  g

    is-section-eq-htpy : is-section htpy-eq eq-htpy

    is-retraction-eq-htpy' : is-retraction htpy-eq eq-htpy

    coh-eq-htpy' :
      coherence-is-coherently-invertible
        ( htpy-eq)
        ( eq-htpy)
        ( is-section-eq-htpy)
        ( is-retraction-eq-htpy')

funext : function-extensionality
funext f g =
  is-equiv-is-invertible eq-htpy is-section-eq-htpy is-retraction-eq-htpy'

module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2}
  where

  equiv-funext : {f g : (x : A)  B x}  (f  g)  (f ~ g)
  pr1 (equiv-funext) = htpy-eq
  pr2 (equiv-funext {f} {g}) = funext f g

  is-equiv-eq-htpy :
    (f g : (x : A)  B x)  is-equiv (eq-htpy {f = f} {g})
  is-equiv-eq-htpy f g =
    is-equiv-is-invertible htpy-eq is-retraction-eq-htpy' is-section-eq-htpy

  abstract
    is-retraction-eq-htpy :
      {f g : (x : A)  B x}  is-retraction (htpy-eq {f = f} {g}) eq-htpy
    is-retraction-eq-htpy {f} {g} = is-retraction-map-inv-is-equiv (funext f g)

  eq-htpy-refl-htpy :
    (f : (x : A)  B x)  eq-htpy (refl-htpy {f = f})  refl
  eq-htpy-refl-htpy f = is-retraction-eq-htpy refl

  equiv-eq-htpy : {f g : (x : A)  B x}  (f ~ g)  (f  g)
  pr1 (equiv-eq-htpy {f} {g}) = eq-htpy
  pr2 (equiv-eq-htpy {f} {g}) = is-equiv-eq-htpy f g
```

### Function extensionality for implicit functions

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2} {f g : {x : A}  B x}
  where

  equiv-funext-implicit :
    (Id {A = {x : A}  B x} f g)  ((x : A)  f {x}  g {x})
  equiv-funext-implicit =
    equiv-funext ∘e equiv-ap equiv-explicit-implicit-Π f g

  htpy-eq-implicit :
    Id {A = {x : A}  B x} f g  (x : A)  f {x}  g {x}
  htpy-eq-implicit = map-equiv equiv-funext-implicit

  funext-implicit : is-equiv htpy-eq-implicit
  funext-implicit = is-equiv-map-equiv equiv-funext-implicit

  eq-htpy-implicit :
    ((x : A)  f {x}  g {x})  Id {A = {x : A}  B x} f g
  eq-htpy-implicit = map-inv-equiv equiv-funext-implicit
```

## Properties

### `htpy-eq` preserves concatenation of identifications

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2} {f g h : (x : A)  B x}
  where

  htpy-eq-concat :
    (p : f  g) (q : g  h)  htpy-eq (p  q)  htpy-eq p ∙h htpy-eq q
  htpy-eq-concat refl refl = refl
```

### `eq-htpy` preserves concatenation of homotopies

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2} {f g h : (x : A)  B x}
  where

  eq-htpy-concat-htpy :
    (H : f ~ g) (K : g ~ h)  eq-htpy (H ∙h K)  (eq-htpy H  eq-htpy K)
  eq-htpy-concat-htpy H K =
      ( ap
        ( eq-htpy)
        ( inv (ap-binary _∙h_ (is-section-eq-htpy H) (is-section-eq-htpy K)) 
          inv (htpy-eq-concat (eq-htpy H) (eq-htpy K)))) 
      ( is-retraction-eq-htpy (eq-htpy H  eq-htpy K))
```

### `htpy-eq` preserves inverses

For any two functions `f g : (x : A) → B x` we have a
[commuting square](foundation-core.commuting-squares-of-maps.md)

```text
                  inv
       (f = g) ---------> (g = f)
          |                  |
  htpy-eq |                  | htpy-eq
          ∨                  ∨
       (f ~ g) ---------> (g ~ f).
                inv-htpy
```

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2} {f g : (x : A)  B x}
  where

  compute-htpy-eq-inv : inv-htpy {f = f} {g}  htpy-eq ~ htpy-eq  inv
  compute-htpy-eq-inv refl = refl

  compute-inv-htpy-htpy-eq : htpy-eq  inv ~ inv-htpy {f = f} {g}  htpy-eq
  compute-inv-htpy-htpy-eq = inv-htpy compute-htpy-eq-inv
```

### `eq-htpy` preserves inverses

For any two functions `f g : (x : A) → B x` we have a commuting square

```text
                inv-htpy
       (f ~ g) ---------> (g ~ f)
          |                  |
  eq-htpy |                  | eq-htpy
          ∨                  ∨
       (f = g) ---------> (g = f).
                  inv
```

```agda
module _
  {l1 l2 : Level} {A : UU l1} {B : A  UU l2} {f g : (x : A)  B x}
  where

  compute-eq-htpy-inv-htpy :
    inv  eq-htpy ~ eq-htpy  inv-htpy {f = f} {g}
  compute-eq-htpy-inv-htpy H =
    ( inv (is-retraction-eq-htpy _)) 
    ( inv (ap eq-htpy (compute-htpy-eq-inv (eq-htpy H))) 
      ap (eq-htpy  inv-htpy) (is-section-eq-htpy _))

  compute-inv-eq-htpy :
    eq-htpy  inv-htpy {f = f} {g} ~ inv  eq-htpy
  compute-inv-eq-htpy = inv-htpy compute-eq-htpy-inv-htpy
```

## See also

- The fact that the univalence axiom implies function extensionality is proven
  in
  [`foundation.univalence-implies-function-extensionality`](foundation.univalence-implies-function-extensionality.md).
- Weak function extensionality is defined in
  [`foundation.weak-function-extensionality`](foundation.weak-function-extensionality.md).
- Transporting along homotopies is defined in
  [`foundation.transport-along-homotopies`](foundation.transport-along-homotopies.md).