123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- -- This module gives an introduction to the module system of Agda.
- module Introduction.Modules where
- ---------------------------------------------------------------------------
- -- Simple sub-modules
- ---------------------------------------------------------------------------
- -- As mentioned in 'Introduction.Basics' each file contains a single top-level
- -- module. This module can contain any number of sub-modules. A sub-module is
- -- declared in the same way as the top-level module, except that its name is
- -- not qualified.
- module Numbers where
- -- The contents of the top-level module do not have to be indented, but the
- -- contents of a sub-module do.
- data Nat : Set where
- zero : Nat
- suc : Nat -> Nat
- -- Outside a module its contents can be accessed using the name of the module.
- one : Numbers.Nat
- one = Numbers.suc Numbers.zero
- -- Of course, this would get very tedious after a while, so to bring the
- -- contents of a module into scope you can use an 'open' declaration.
- open Numbers
- two : Nat
- two = suc one
- -- When opening a module it is possible to control what names are brought into
- -- scope. The open declaration supports three modifiers :
- -- using (x1; ..; xn) only bring x1 .. xn into scope
- -- renaming (x to y;..) bring y into scope and make it refer to the name x
- -- from the opened module.
- -- hiding (x1; ..; xn) bring everything except x1 .. xn into scope
- -- The using and hiding modifiers can be combined with renaming but not with
- -- each other.
- -- For example, this will bring the names z and s (and nothing else) into
- -- scope as new names for zero and suc.
- open Numbers using () renaming (zero to z; suc to s)
- -- We can now pattern match on the renamed constructors.
- plus : Nat -> Nat -> Nat
- plus z m = m
- plus (s n) m = s (plus n m)
- ---------------------------------------------------------------------------
- -- 'private' and 'abstract'
- ---------------------------------------------------------------------------
- -- Above we saw how to control which names are brought into scope when opening
- -- a module. It is also possible to restrict what is visible outside a module
- -- by declaring things 'private'. Declaring something private will only prevent
- -- someone from using it outside the module, it doesn't prevent it from showing
- -- up after reduction, or from it to reduce.
- -- To prevent something from reducing (effectively hiding the definition) it
- -- can be declared 'abstract'.
- module Datastructures where
- private
- data List (A : Set) : Set where
- nil : List A
- _::_ : A -> List A -> List A
- _++_ : {A : Set} -> List A -> List A -> List A
- nil ++ ys = ys
- (x :: xs) ++ ys = x :: (xs ++ ys)
- reverse : {A : Set} -> List A -> List A
- reverse nil = nil
- reverse (x :: xs) = reverse xs ++ (x :: nil)
- -- Not making the stack operations abstract will reveal the underlying
- -- implementation, even though it's private.
- Stack : Set -> Set
- Stack A = List A
- emptyS : {A : Set} -> Stack A
- emptyS = nil
- push : {A : Set} -> A -> Stack A -> Stack A
- push x xs = x :: xs
- abstract
- -- An abstract datatype doesn't reveal its constructors
- data Queue (A : Set) : Set where
- queue : (front back : List A) -> Queue A -- invariant : if the front is
- -- empty, so is the back
- -- Abstraction is contagious, anything that pattern matches on a queue must
- -- also be abstract.
- private
- -- make sure the invariant is preserved
- flip : {A : Set} -> Queue A -> Queue A
- flip (queue nil back) = queue (reverse back) nil
- flip q = q
- -- these functions will not reduce outside the module
- emptyQ : {A : Set} -> Queue A
- emptyQ = queue nil nil
- enqueue : {A : Set} -> A -> Queue A -> Queue A
- enqueue x (queue front back) = flip (queue front (x :: back))
- open Datastructures
- testS = push zero emptyS
- testQ = enqueue zero emptyQ
|