169 lines
5.8 KiB
HTML
169 lines
5.8 KiB
HTML
<h2>Agda Full Example</h2>
|
||
<p>** 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.</p>
|
||
<pre><code>-- 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; _+_; _*_; _^_; _∸_)
|
||
</code></pre> |