## Agda Full Example

** Copyright - this piece of code is a modified version of [https://plfa.github.io/Naturals/] by Philip Wadler, Wen Kokke, Jeremy G Siek and contributors.

    -- 1.1 Naturals

    module plfa.part1.Naturals where

    -- The standard way to enter Unicode math symbols in Agda
    -- is to use the IME provided by agda-mode.
    -- for example ℕ can be entered by typing \bN.

    -- The inductive definition of natural numbers.
    -- In Agda, data declarations correspond to axioms.
    -- Also types correspond to sets.
    -- CHAR: \bN → ℕ
    data ℕ : Set where
    	-- This corresponds to the `zero` rule in Dedekin-Peano's axioms.
    	-- Note that the syntax resembles Haskell GADTs.
    	-- Also note that the `has-type` operator is `:` (as in Idris), not `::` (as in Haskell).
    	zero : ℕ
    	-- This corresponds to the `succesor` rule in Dedekin-Peano's axioms.
    	-- In such a constructive system in Agda, induction rules etc comes by nature.
    	-- The function arrow can be either `->` or `→`.
    	-- CHAR: \to or \-> or \r- → →
    	suc  : ℕ → ℕ

    -- EXERCISE `seven`
    seven : ℕ
    seven = suc (suc (suc (suc (suc (suc (suc zero))))))

    -- This line is a compiler pragma.
    -- It makes `ℕ` correspond to Haskell's type `Integer`
    -- and allows us to use number literals (0, 1, 2, ...) to express `ℕ`.
    {-# BUILTIN NATURAL ℕ #-}

    -- Agda has a module system corresponding to the project file structure.
    -- e.g. `My.Namespace` is in
    -- `project path/My/Namespace.agda`.

    -- The `import` statement does NOT expose the names to the top namespace.
    -- You'll have to use `My.Namespace.thing` instead of directly `thing`.
    import Relation.Binary.PropositionalEquality as Eq
    -- The `open` statement unpacks all the names in a imported namespace and exposes them to the top namespace.
    -- Alternatively the `open import` statement imports a namespace and opens it at the same time.
    -- The `using (a; ..)` clause can limit a range of names to expose, instead of all of them.
    -- Alternatively, the `hiding (a; ..)` clause can limit a range of names NOT to expose.
    -- Also the `renaming (a to b; ..)` clause can rename names.
    -- CHAR: \== → ≡
    --       \gt → ⟨
    --       \lt → ⟩
    --       \qed → ∎
    open Eq using (_≡_; refl)
    open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; _∎)

    -- Addition of `ℕ`.
    -- Note that Agda functions are *like* Haskell functions.
    -- In Agda, operators can be mixfix (incl. infix, prefix, suffix, self-bracketing and many others).
    -- All the `holes` are represented by `_`s. Unlike Haskell, operator names don't need to be put in parentheses.
    -- Operators can also be called in the manner of normal functions.
    -- e.g. a + b = _+_ a b.
    -- Sections are also available, though somehow weird.
    -- e.g. a +_ = _+_ a.
    _+_ : ℕ → ℕ → ℕ
    -- Lhs can also be infix!
    -- This is the standard definition in both Peano and Agda stdlib.
    -- We do pattern match on the first parameter, it's both convention and for convenience.
    -- Agda does a termination check on recursive function.
    -- Here the first parameter decreases over evaluation thus it is *well-founded*.
    zero    + n = n
    (suc m) + n = suc (m + n)

    -- Here we take a glance at the *dependent type*.
    -- In dependent type, we can put values into type level, and vice versa.
    -- This is especially useful when we're expecting to make the types more precise.
    -- Here `_≡_` is a type that says that two values are *the same*, that is, samely constructed.
    _ : 2 + 3 ≡ 5
    -- We can do it by ≡-Reasoning, that is writing a (unreasonably long) chain of equations.
    _ =
    	begin
    		2 + 3
    	≡⟨⟩ -- This operator means the lhs and rhs can be reduced to the same form so that they are equal.
    		suc (1 + 3)
    	≡⟨⟩
    		suc (suc (0 + 3)) -- Just simulating the function evaluation
    	≡⟨⟩
    		suc (suc 3)
    	≡⟨⟩
    		5
    	∎ -- The *tombstone*, QED.

    -- Well actually we can also get this done by simply writing `refl`.
    -- `refl` is a proof that says "If two values evaluates to the same form, then they are equal".
    -- Since Agda can automatically evaluate the terms for us, this makes sense.
    _ : 2 + 3 ≡ 5
    _ = refl

    -- Multiplication of `ℕ`, defined with addition.
    _*_ : ℕ → ℕ → ℕ
    -- Here we can notice that in Agda we prefer to indent by *visual blocks* instead by a fixed number of spaces.
    zero    * n = zero
    -- Here the addition is at the front, to be consistent with addition.
    (suc m) * n = n + (m * n)

    -- EXERCISE `_^_`, Exponentation of `ℕ`.
    _^_ : ℕ → ℕ → ℕ
    -- We can only pattern match the 2nd argument.
    m ^ zero    = suc zero
    m ^ (suc n) = m * (m ^ n)

    -- *Monus* (a wordplay on minus), the non-negative subtraction of `ℕ`.
    -- if less than 0 then we get 0.
    -- CHAR: \.- → ∸
    _∸_ : ℕ → ℕ → ℕ
    m     ∸ zero  = m
    zero  ∸ suc n = zero
    suc m ∸ suc n = m ∸ n

    -- Now we define the precedence of the operators, as in Haskell.
    infixl 6 _+_ _∸_
    infixl 7 _*_

    -- These are some more pragmas. Should be self-explaining.
    {-# BUILTIN NATPLUS _+_ #-}
    {-# BUILTIN NATTIMES _*_ #-}
    {-# BUILTIN NATMINUS _∸_ #-}

    -- EXERCISE `Bin`. We define a binary representation of natural numbers.
    -- Leading `O`s are acceptable.
    data Bin : Set where
    	⟨⟩ : Bin
    	_O : Bin → Bin
    	_I : Bin → Bin

    -- Like `suc` for `Bin`.
    inc : Bin → Bin
    inc ⟨⟩ = ⟨⟩ I
    inc (b O) = b I
    inc (b I) = (inc b) O

    -- `ℕ` to `Bin`. This is a Θ(n) solution and awaits a better Θ(log n) reimpelementation.
    to : ℕ → Bin
    to zero    = ⟨⟩ O
    to (suc n) = inc (to n)

    -- `Bin` to `ℕ`.
    from : Bin → ℕ
    from ⟨⟩    = 0
    from (b O) = 2 * (from b)
    from (b I) = 1 + 2 * (from b)

    -- Simple tests from 0 to 4.
    _ : from (to 0) ≡ 0
    _ = refl

    _ : from (to 1) ≡ 1
    _ = refl

    _ : from (to 2) ≡ 2
    _ = refl

    _ : from (to 3) ≡ 3
    _ = refl

    _ : from (to 4) ≡ 4
    _ = refl

    -- EXERCISE END `Bin`

    -- STDLIB: import Data.Nat using (ℕ; zero; suc; _+_; _*_; _^_; _∸_)