📥 Download raw
module Padova2025.Cubical.Issues.FunctionExtensionality where

Function extensionality

open import Padova2025.ProgrammingBasics.Booleans
open import Padova2025.ProgrammingBasics.Naturals.Base
open import Padova2025.ProvingBasics.Equality.Base

Let us consider the following three function definitions.

example₁ : Bool  Bool
example₁ x = x

example₂ : Bool  Bool
example₂ false = false
example₂ true  = true

example₃ : Bool  Bool
example₃ false = false
example₃ true  = true
-- Yes, identical to the definition of example₂.

Obviously, these functions have the same values on all inputs:

all-same₁₂ : (x : Bool)  example₁ x  example₂ x
all-same₁₂ false = refl
all-same₁₂ true  = refl

all-same₂₃ : (x : Bool)  example₂ x  example₃ x
all-same₂₃ false = refl
all-same₂₃ true  = refl

Not provably the same. However, in standard Agda we can not prove that the functions themselves are the same—the following holes cannot be filled (and the proposal refl does not typecheck):

_ : example₁ ≡ example₂
_ = ?

_ : example₂ ≡ example₃
_ = ?

Not provably distinct. On the other hand, in Agda we can also not prove the three functions above to be distinct, that is we cannot write down terms of type exampleᵢ ≡ exampleⱼ → ⊥. Agda is (like any other reasonable formal system) incomplete and the equality type is underspecified.

A principle. The principle that functions with equal values are themselves equal is known as function extensionality. Blackboard mathematics has it, while standard Agda does not.

FunctionExtensionality : Set₁
FunctionExtensionality = {X Y : Set} {f g : X  Y}  ((x : X)  f x  g x)  f  g

Postulating function extensionality

We may, if we prefer, postulate function extensionality:

postulate
  funext : FunctionExtensionality

Adding function extensionality to Martin-Löf type theory preserves its consistency. Moreover, if one entertains the idea of a platonic heaven, then one can rest assured that the resulting type theory still provides an apt language for talking about the objects of the platonic heaven.

However, by postulating function extensionality we lose canonicity: With this postulate, it can happen that elements of inductively defined types do not reduce to a constructor call. A basic example is already provided by funext itself.

does-not-reduce-to-refl : example₁ ≡ example₂
does-not-reduce-to-refl = funext all-same₁₂
does-not-reduce-to-a-numeral : ℕ
does-not-reduce-to-a-numeral = check does-not-reduce-to-refl
  where
  check : {g : Bool → Bool} → example₁ ≡ g → ℕ
  check refl = zero

Avoiding function extensionality

For many purposes, function extensionality can easily be avoided by employing pointwise equality instead of true _≡_, as follows.

_≈_ : {X Y : Set}  (X  Y)  (X  Y)  Set
f  g = (x : _)  f x  g x

all-same₁₂' : example₁  example₂
all-same₁₂' = all-same₁₂

But it is also desireable to actually have function extensionality. Such a system is offered by Cubical Agda.