coinduction.lagda.rst 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. .. _coinduction:
  2. ***********
  3. Coinduction
  4. ***********
  5. The corecursive definitions below are accepted if the option
  6. :samp:`--guardedness` is active:
  7. ::
  8. {-# OPTIONS --guardedness #-}
  9. (An alternative approach is to use :ref:`sized-types`.)
  10. ..
  11. ::
  12. module language.coinduction where
  13. open import Agda.Builtin.Nat
  14. open import Agda.Builtin.Bool
  15. open import Agda.Builtin.Equality
  16. open import Agda.Builtin.List
  17. module newcoinduction where
  18. .. _copatterns-coinductive-records:
  19. Coinductive Records
  20. -------------------
  21. It is possible to define the type of infinite lists (or streams) of
  22. elements of some type ``A`` as follows:
  23. ::
  24. record Stream (A : Set) : Set where
  25. coinductive
  26. field
  27. hd : A
  28. tl : Stream A
  29. As opposed to :ref:`inductive record types <recursive-records>`, we have to introduce the keyword
  30. ``coinductive`` before defining the fields that constitute the record.
  31. It is interesting to note that it is not necessary to give an explicit
  32. constructor to the record type ``Stream``.
  33. ..
  34. ::
  35. open Stream
  36. record _×_ (A B : Set) : Set where
  37. inductive
  38. constructor _,_
  39. field
  40. fst : A
  41. snd : B
  42. We can also define pointwise equality (a bisimulation and an equivalence) of a pair of ``Stream``\s as a
  43. coinductive record:
  44. ::
  45. record _≈_ {A} (xs : Stream A) (ys : Stream A) : Set where
  46. coinductive
  47. field
  48. hd-≡ : hd xs ≡ hd ys
  49. tl-≈ : tl xs ≈ tl ys
  50. Using :ref:`copatterns <copatterns>` we can define a pair of functions
  51. on ``Stream``\s such that one returns the elements in
  52. the even positions and the other the elements in the odd positions:
  53. ..
  54. ::
  55. open _≈_
  56. ::
  57. even : ∀ {A} → Stream A → Stream A
  58. hd (even xs) = hd xs
  59. tl (even xs) = even (tl (tl xs))
  60. odd : ∀ {A} → Stream A → Stream A
  61. odd xs = even (tl xs)
  62. split : ∀ {A} → Stream A → Stream A × Stream A
  63. split xs = even xs , odd xs
  64. as well as a function that merges a pair of ``Stream``\s by interleaving their elements:
  65. ::
  66. merge : ∀ {A} → Stream A × Stream A → Stream A
  67. hd (merge (xs , ys)) = hd xs
  68. tl (merge (xs , ys)) = merge (ys , tl xs)
  69. Finally, we can prove that ``merge`` is a left inverse for ``split``:
  70. ::
  71. merge-split-id : ∀ {A} (xs : Stream A) → merge (split xs) ≈ xs
  72. hd-≡ (merge-split-id _) = refl
  73. tl-≈ (merge-split-id xs) = merge-split-id (tl xs)
  74. Old Coinduction
  75. ---------------
  76. .. note::
  77. This is the old way of coinduction support in Agda. You are advised to use
  78. :ref:`copatterns-coinductive-records` instead.
  79. To use coinduction it is recommended that you import the module Coinduction from the `standard library <https://wiki.portal.chalmers.se/agda/pmwiki.php?n=Libraries.StandardLibrary>`_. Coinductive types can then be defined by labelling coinductive occurrences using the delay operator ``∞``:
  80. ..
  81. ::
  82. open import Agda.Builtin.Coinduction
  83. ::
  84. data Coℕ : Set where
  85. zero : Coℕ
  86. suc : ∞ Coℕ → Coℕ
  87. The type ``∞ A`` can be seen as a suspended computation of type ``A``. It comes with delay and force functions:
  88. .. code-block:: agda
  89. ♯_ : ∀ {a} {A : Set a} → A → ∞ A
  90. ♭ : ∀ {a} {A : Set a} → ∞ A → A
  91. Values of coinductive types can be constructed using corecursion, which does not need to terminate, but has to be productive. As an approximation to productivity the termination checker requires that corecursive definitions are guarded by coinductive constructors. As an example the infinite “natural number” can be defined as follows:
  92. ::
  93. inf : Coℕ
  94. inf = suc (♯ inf)
  95. The check for guarded corecursion is integrated with the check for size-change termination, thus allowing interesting combinations of inductive and coinductive types. We can for instance define the type of stream processors, along with some functions:
  96. ::
  97. -- Infinite streams.
  98. data Stream (A : Set) : Set where
  99. _∷_ : (x : A) (xs : ∞ (Stream A)) → Stream A
  100. -- A stream processor SP A B consumes elements of A and produces
  101. -- elements of B. It can only consume a finite number of A’s before
  102. -- producing a B.
  103. data SP (A B : Set) : Set where
  104. get : (f : A → SP A B) → SP A B
  105. put : (b : B) (sp : ∞ (SP A B)) → SP A B
  106. -- The function eat is defined by an outer corecursion into Stream B
  107. -- and an inner recursion on SP A B.
  108. eat : ∀ {A B} → SP A B → Stream A → Stream B
  109. eat (get f) (a ∷ as) = eat (f a) (♭ as)
  110. eat (put b sp) as = b ∷ ♯ eat (♭ sp) as
  111. -- Composition of stream processors.
  112. _∘_ : ∀ {A B C} → SP B C → SP A B → SP A C
  113. get f₁ ∘ put x sp₂ = f₁ x ∘ ♭ sp₂
  114. put x sp₁ ∘ sp₂ = put x (♯ (♭ sp₁ ∘ sp₂))
  115. sp₁ ∘ get f₂ = get (λ x → sp₁ ∘ f₂ x)
  116. It is also possible to define “coinductive families”. It is recommended not to use the delay constructor (``♯_``) in a constructor’s index expressions. The following definition of equality between coinductive “natural numbers” is discouraged:
  117. ::
  118. data _≈’_ : Coℕ → Coℕ → Set where
  119. zero : zero ≈’ zero
  120. suc : ∀ {m n} → ∞ (m ≈’ n) → suc (♯ m) ≈’ suc (♯ n)
  121. The recommended definition is the following one:
  122. ::
  123. data _≈_ : Coℕ → Coℕ → Set where
  124. zero : zero ≈ zero
  125. suc : ∀ {m n} → ∞ (♭ m ≈ ♭ n) → suc m ≈ suc n