let-and-where.lagda.rst 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. ..
  2. ::
  3. {-# OPTIONS --rewriting --sized-types #-}
  4. module language.let-and-where where
  5. open import language.built-ins
  6. .. _let-and-where:
  7. ********************************
  8. Local Definitions: let and where
  9. ********************************
  10. There are two ways of declaring local definitions in Agda:
  11. - let-expressions
  12. - where-blocks
  13. .. _let-expressions:
  14. let-expressions
  15. ===============
  16. A let-expression defines an abbreviation.
  17. In other words, the expression that we define in a let-expression can
  18. neither be recursive, nor can let bound functions be defined by
  19. pattern matching.
  20. Example::
  21. f : Nat
  22. f = let h : Nat → Nat
  23. h m = suc (suc m)
  24. in h zero + h (suc zero)
  25. let-expressions have the general form
  26. .. code-block:: agda
  27. let f₁ : A₁₁ → … → A₁ₙ → A₁
  28. f₁ x₁ … xₙ = e₁
  29. fₘ : Aₘ₁ → … → Aₘₖ → Aₘ
  30. fₘ x₁ … xₖ = eₘ
  31. in e’
  32. where previous definitions are in scope in later definitions. The
  33. type signatures can be left out if Agda can infer them.
  34. After type-checking, the meaning of this is simply the substitution
  35. ``e’[f₁ := λ x₁ … xₙ → e; …; fₘ := λ x₁ … xₖ → eₘ]``. Since Agda
  36. substitutes away let-bindings, they do not show up in terms Agda
  37. prints, nor in the goal display in interactive mode.
  38. .. _let-record-pattern:
  39. Let binding record patterns
  40. ---------------------------
  41. For a record
  42. .. code-block:: agda
  43. record R : Set where
  44. constructor c
  45. field
  46. f : X
  47. g : Y
  48. h : Z
  49. a let expression of the form
  50. .. code-block:: agda
  51. let (c x y z) = t
  52. in u
  53. will be translated internally to as
  54. .. code-block:: agda
  55. let x = f t
  56. y = g t
  57. z = h t
  58. in u
  59. This is not allowed if ``R`` is declared ``coinductive``.
  60. .. _where-blocks:
  61. where-blocks
  62. ============
  63. where-blocks are much more powerful than let-expressions, as they
  64. support arbitrary local definitions.
  65. A ``where`` can be attached to any function clause.
  66. where-blocks have the general form
  67. .. code-block:: agda
  68. clause
  69. where
  70. decls
  71. or
  72. .. code-block:: agda
  73. clause
  74. module M where
  75. decls
  76. A simple instance is
  77. .. code-block:: agda
  78. g ps = e
  79. where
  80. f : A₁ → … → Aₙ → A
  81. f p₁₁ … p₁ₙ= e₁
  82. f pₘ₁ … pₘₙ= eₘ
  83. Here, the ``pᵢⱼ`` are patterns of the corresponding types and ``eᵢ`` is an expression that can contain occurrences of ``f``.
  84. Functions defined with a where-expression must follow the rules for general definitions by pattern matching.
  85. Example::
  86. reverse : {A : Set} → List A → List A
  87. reverse {A} xs = rev-append xs []
  88. where
  89. rev-append : List A → List A → List A
  90. rev-append [] ys = ys
  91. rev-append (x ∷ xs) ys = rev-append xs (x ∷ ys)
  92. Variable scope
  93. --------------
  94. The pattern variables of the parent clause of the where-block are in
  95. scope; in the previous example, these are ``A`` and ``xs``. The
  96. variables bound by the type signature of the parent clause are not in
  97. scope. This is why we added the hidden binder ``{A}``.
  98. Scope of the local declarations
  99. -------------------------------
  100. The ``where``-definitions are not visible outside of the clause that
  101. owns these definitions (the parent clause). If the ``where``-block is
  102. given a name (form ``module M where``), then the definitions are
  103. available as qualified by ``M``, since module ``M`` is visible even
  104. outside of the parent clause. The special form of an anonymous module
  105. (``module _ where``) makes the definitions visible outside of the
  106. parent clause without qualification.
  107. If the parent function of a named ``where``-block
  108. (form ``module M where``) is ``private``,
  109. then module ``M`` is also ``private``.
  110. However, the declarations inside ``M`` are not private unless declared
  111. so explicitly. Thus, the following example scope checks fine::
  112. module Parent₁ where
  113. private
  114. parent = local
  115. module Private where
  116. local = Set
  117. module Public = Private
  118. test₁ = Parent₁.Public.local
  119. Likewise, a ``private`` declaration for a parent function does not
  120. affect the privacy of local functions defined under a
  121. ``module _ where``-block::
  122. module Parent₂ where
  123. private
  124. parent = local
  125. module _ where
  126. local = Set
  127. test₂ = Parent₂.local
  128. They can be declared ``private`` explicitly, though::
  129. module Parent₃ where
  130. parent = local
  131. module _ where
  132. private
  133. local = Set
  134. Now, ``Parent₃.local`` is not in scope.
  135. A ``private`` declaration for the parent of an ordinary
  136. ``where``-block has no effect on the local definitions, of course.
  137. They are not even in scope.
  138. Proving properties
  139. ==================
  140. Sometimes one needs to refer to local definitions in proofs about the
  141. parent function. In this case, the ``module ⋯ where`` variant is preferable.
  142. .. code-block:: agda
  143. reverse : {A : Set} → List A → List A
  144. reverse {A} xs = rev-append xs []
  145. module Rev where
  146. rev-append : List A → List A → List A
  147. rev-append [] ys = ys
  148. rev-append (x :: xs) ys = rev-append xs (x :: ys)
  149. This gives us access to the local function as
  150. .. code-block:: agda
  151. Rev.rev-append : {A : Set} (xs : List A) → List A → List A → List A
  152. Alternatively, we can define local
  153. functions as private to the module we are working in; hence, they
  154. will not be visible in any module that imports this module but it will
  155. allow us to prove some properties about them.
  156. ::
  157. private
  158. rev-append : {A : Set} → List A → List A → List A
  159. rev-append [] ys = ys
  160. rev-append (x ∷ xs) ys = rev-append xs (x ∷ ys)
  161. reverse' : {A : Set} → List A → List A
  162. reverse' xs = rev-append xs []
  163. More Examples (for Beginners)
  164. =============================
  165. Using a let-expression::
  166. tw-map : {A : Set} → List A → List (List A)
  167. tw-map {A} xs = let twice : List A → List A
  168. twice xs = xs ++ xs
  169. in map (\ x → twice [ x ]) xs
  170. Same definition but with less type information::
  171. tw-map' : {A : Set} → List A → List (List A)
  172. tw-map' {A} xs = let twice : _
  173. twice xs = xs ++ xs
  174. in map (\ x → twice [ x ]) xs
  175. Same definition but with a where-expression
  176. ::
  177. tw-map'' : {A : Set} → List A → List (List A)
  178. tw-map'' {A} xs = map (\ x → twice [ x ]) xs
  179. where twice : List A → List A
  180. twice xs = xs ++ xs
  181. Even less type information using let::
  182. g : Nat → List Nat
  183. g zero = [ zero ]
  184. g (suc n) = let sing = [ suc n ]
  185. in sing ++ g n
  186. Same definition using where::
  187. g' : Nat → List Nat
  188. g' zero = [ zero ]
  189. g' (suc n) = sing ++ g' n
  190. where sing = [ suc n ]
  191. More than one definition in a let::
  192. h : Nat → Nat
  193. h n = let add2 : Nat
  194. add2 = suc (suc n)
  195. twice : Nat → Nat
  196. twice m = m * m
  197. in twice add2
  198. More than one definition in a where::
  199. fibfact : Nat → Nat
  200. fibfact n = fib n + fact n
  201. where fib : Nat → Nat
  202. fib zero = suc zero
  203. fib (suc zero) = suc zero
  204. fib (suc (suc n)) = fib (suc n) + fib n
  205. fact : Nat → Nat
  206. fact zero = suc zero
  207. fact (suc n) = suc n * fact n
  208. Combining let and where::
  209. k : Nat → Nat
  210. k n = let aux : Nat → Nat
  211. aux m = pred (h m) + fibfact m
  212. in aux (pred n)
  213. where pred : Nat → Nat
  214. pred zero = zero
  215. pred (suc m) = m