irrelevance.lagda.rst 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. ..
  2. ::
  3. {-# OPTIONS --irrelevant-projections #-}
  4. module language.irrelevance where
  5. open import Agda.Builtin.Nat
  6. open import Agda.Builtin.Equality
  7. .. _irrelevance:
  8. ***********
  9. Irrelevance
  10. ***********
  11. Since version 2.2.8 Agda supports irrelevancy annotations. The general rule is that anything prepended by a dot (.) is marked irrelevant, which means that it will only be typechecked but never evaluated.
  12. .. note::
  13. This section is about compile-time irrelevance. See :ref:`runtime-irrelevance` for the section on
  14. run-time irrelevance.
  15. The more recent :ref:`prop` serves a similar purpose and can be used to simulate irrelevance.
  16. Motivating example
  17. ==================
  18. One intended use case of irrelevance is data structures with embedded proofs, like sorted lists. ::
  19. data _≤_ : Nat → Nat → Set where
  20. zero≤ : {n : Nat} → zero ≤ n
  21. suc≤suc : {m n : Nat} → m ≤ n → suc m ≤ suc n
  22. postulate
  23. p₁ : 0 ≤ 1
  24. p₂ : 0 ≤ 1
  25. module No-Irrelevance where
  26. data SList (bound : Nat) : Set where
  27. [] : SList bound
  28. scons : (head : Nat)
  29. → (head ≤ bound)
  30. → (tail : SList head)
  31. → SList bound
  32. Usually, when we define datatypes with embedded proofs we are forced to reason about the values of these proofs. For example, suppose we have two lists ``l₁`` and ``l₂`` with the same elements but different proofs: ::
  33. l₁ : SList 1
  34. l₁ = scons 0 p₁ []
  35. l₂ : SList 1
  36. l₂ = scons 0 p₂ []
  37. Now suppose we want to prove that ``l₁`` and ``l₂`` are equal:
  38. .. code-block:: agda
  39. l₁≡l₂ : l₁ ≡ l₂
  40. l₁≡l₂ = refl
  41. It's not so easy! Agda gives us an error:
  42. .. code-block:: text
  43. p₁ != p₂ of type 0 ≤ 1
  44. when checking that the expression refl has type l₁ ≡ l₂
  45. We can't show that ``l₁ ≡ l₂`` by ``refl`` when ``p₁`` and ``p₂`` are relevant. Instead, we need to reason about proofs of ``0 ≤ 1``. ::
  46. postulate
  47. proof-equality : p₁ ≡ p₂
  48. Now we can prove ``l₁ ≡ l₂`` by rewriting with this equality: ::
  49. l₁≡l₂ : l₁ ≡ l₂
  50. l₁≡l₂ rewrite proof-equality = refl
  51. Reasoning about equality of proofs becomes annoying quickly. We would like to avoid this kind of reasoning about proofs here - in this case we only care that a proof of ``head ≤ bound`` exists, i.e. any proof suffices. We can use irrelevance annotations to tell Agda we don't care about the values of the proofs: ::
  52. data SList (bound : Nat) : Set where
  53. [] : SList bound
  54. scons : (head : Nat)
  55. → .(head ≤ bound) -- note the dot!
  56. → (tail : SList head)
  57. → SList bound
  58. The effect of the irrelevant type in the signature of scons is that scons’s second argument is never inspected after Agda has ensured that it has the right type. The type-checker ignores irrelevant arguments when checking equality, so two lists can be equal even if they contain different proofs: ::
  59. l₁ : SList 1
  60. l₁ = scons 0 p₁ []
  61. l₂ : SList 1
  62. l₂ = scons 0 p₂ []
  63. l₁≡l₂ : l₁ ≡ l₂
  64. l₁≡l₂ = refl
  65. Irrelevant function types
  66. =========================
  67. For starters, consider irrelevant non-dependent function types:
  68. .. code-block:: agda
  69. f : .A → B
  70. This type implies that ``f`` does not depend computationally on its argument.
  71. What can be done to irrelevant arguments
  72. ----------------------------------------
  73. **Example 1.** We can prove that two applications of an unknown irrelevant function to two different arguments are equal. ::
  74. -- an unknown function that does not use its second argument
  75. postulate
  76. f : {A B : Set} -> A -> .B -> A
  77. -- the second argument is irrelevant for equality
  78. proofIrr : {A : Set}{x y z : A} -> f x y ≡ f x z
  79. proofIrr = refl
  80. **Example 2.** We can use irrelevant arguments as arguments to other irrelevant functions. ::
  81. id : {A B : Set} -> (.A -> B) -> .A -> B
  82. id g x = g x
  83. **Example 3.** We can match on an irrelevant argument of an empty type with an absurd pattern ``()``. ::
  84. data ⊥ : Set where
  85. zero-not-one : .(0 ≡ 1) → ⊥
  86. zero-not-one ()
  87. What can't be done to irrelevant arguments
  88. ------------------------------------------
  89. **Example 1.** You can't use an irrelevant value in a non-irrelevant context.
  90. .. code-block:: agda
  91. bad-plus : Nat → .Nat → Nat
  92. bad-plus n m = m + n
  93. .. code-block:: text
  94. Variable m is declared irrelevant, so it cannot be used here
  95. when checking that the expression m has type Nat
  96. **Example 2.** You can't declare the function's return type as irrelevant.
  97. .. code-block:: agda
  98. bad : Nat → .Nat
  99. bad n = 1
  100. .. code-block:: text
  101. Invalid dotted expression
  102. when checking that the expression .Nat has type Set _47
  103. **Example 3.** You can't pattern match on an irrelevant value.
  104. .. code-block:: agda
  105. badMatching : Nat → .Nat → Nat
  106. badMatching n zero = n
  107. badMatching n (suc m) = n
  108. .. code-block:: text
  109. Cannot pattern match against irrelevant argument of type Nat
  110. when checking that the pattern zero has type Nat
  111. **Example 4.** We also can't match on an irrelevant record (see :ref:`record-types`).
  112. .. code-block:: agda
  113. record Σ (A : Set) (B : A → Set) : Set where
  114. constructor _,_
  115. field
  116. fst : A
  117. snd : B fst
  118. irrElim : {A : Set} {B : A → Set} → .(Σ A B) → _
  119. irrElim (a , b) = ?
  120. .. code-block:: text
  121. Cannot pattern match against irrelevant argument of type Σ A B
  122. when checking that the pattern a , b has type Σ A B
  123. If this were allowed, `b` would have type `B a` but this type is not
  124. even well-formed because `a` is irrelevant!
  125. Irrelevant declarations
  126. =======================
  127. Postulates and functions can be marked as irrelevant by prefixing the name with a dot when the name is declared. Irrelevant definitions can only be used as arguments of functions of an irrelevant function type ``.A → B``.
  128. Examples: ::
  129. .irrFunction : Nat → Nat
  130. irrFunction zero = zero
  131. irrFunction (suc n) = suc (suc (irrFunction n))
  132. postulate
  133. .assume-false : (A : Set) → A
  134. An important example is the irrelevance axiom ``irrAx``: ::
  135. postulate
  136. .irrAx : ∀ {ℓ} {A : Set ℓ} -> .A -> A
  137. This axiom is not provable inside Agda, but it is often very useful when working with irrelevance.
  138. The irrelevance axiom is a form of non-constructive choice.
  139. Irrelevant record fields
  140. ========================
  141. Record fields (see :ref:`record-types`) can be marked as irrelevant by
  142. prefixing their name with a dot in the definition of the record type.
  143. Projections for irrelevant fields are only created if option
  144. :option:`--irrelevant-projections` is supplied (since Agda > 2.5.4).
  145. **Example 1.** A record type containing pairs of numbers satisfying certain properties. ::
  146. record InterestingNumbers : Set where
  147. field
  148. n : Nat
  149. m : Nat
  150. .prop1 : n + m ≡ n * m + 2
  151. .prop2 : suc m ≤ n
  152. **Example 2.** For any type ``A``, we can define a 'squashed' version ``Squash A`` where all elements are equal. ::
  153. record Squash (A : Set) : Set where
  154. constructor squash
  155. field
  156. .unsquash : A
  157. open Squash
  158. .example : ∀ {A} → Squash A → A
  159. example x = unsquash x
  160. **Example 3.** We can define the subset of ``x : A`` satisfying ``P x`` with irrelevant membership certificates. ::
  161. record Subset (A : Set) (P : A -> Set) : Set where
  162. constructor _#_
  163. field
  164. elem : A
  165. .certificate : P elem
  166. .certificate : {A : Set}{P : A -> Set} -> (x : Subset A P) -> P (Subset.elem x)
  167. certificate (a # p) = irrAx p
  168. **Example 4.** Irrelevant projections are justified by the irrelevance axiom. ::
  169. .unsquash' : ∀ {A} → Squash A → A
  170. unsquash' (squash x) = irrAx x
  171. .irrAx' : ∀ {A} → .A → A
  172. irrAx' x = unsquash (squash x)
  173. Like the irrelevance axiom, irrelevant projections cannot be reduced.
  174. Dependent irrelevant function types
  175. ===================================
  176. Just like non-dependent functions, we can also make dependent functions irrelevant. The basic syntax is as in the following examples:
  177. .. code-block:: agda
  178. f : .(x y : A) → B
  179. f : .{x y z : A} → B
  180. f : .(xs {ys zs} : A) → B
  181. f : ∀ x .y → B
  182. f : ∀ x .{y} {z} .v → B
  183. f : .{{x : A}} → B
  184. The declaration
  185. .. code-block:: agda
  186. f : .(x : A) → B[x]
  187. f x = t[x]
  188. requires that ``x`` is irrelevant both in ``t[x]`` and in ``B[x]``. This is possible if, for instance, ``B[x] = C x``, with ``C : .A → Set``.
  189. Dependent irrelevance allows us to define the eliminator for the Squash type: ::
  190. elim-Squash : {A : Set} (P : Squash A → Set)
  191. (ih : .(a : A) → P (squash a)) →
  192. (a⁻ : Squash A) → P a⁻
  193. elim-Squash P ih (squash a) = ih a
  194. Note that this would not type-check with ``(ih : (a : A) → P (squash a))``.
  195. Irrelevant instance arguments
  196. =============================
  197. Contrary to normal instance arguments, irrelevant instance arguments (see :ref:`instance-arguments`) are not required to have a unique solution. ::
  198. record ⊤ : Set where
  199. instance constructor tt
  200. NonZero : Nat → Set
  201. NonZero zero = ⊥
  202. NonZero (suc _) = ⊤
  203. pred′ : (n : Nat) .{{_ : NonZero n}} → Nat
  204. pred′ zero {{}}
  205. pred′ (suc n) = n
  206. find-nonzero : (n : Nat) {{x y : NonZero n}} → Nat
  207. find-nonzero n = pred′ n