prism/examples/prism-agda.html

169 lines
5.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>