Example:
list.gi:
// this is to output information, // that we implement type `t', but not to // disclosure what it is. type <'a>t; 'a hd(<'a>t x); <'a>t tl(<'a>t x); int cnt; <'a>t create(); <'b>t map(*('a) -> 'b f, <'a>t l); void iter(*('a) -> void f, <'a>t l);
list.g:
// this is local datatype. opt_struct <'a>t { 'a data; <'a>opt_struct next; } // this will be exported out (`public') 'a hd(<'a>t x) { return x.data; } <'a>t tl(<'a>t x) { return x.next; } // this is local, can't be called from outside the module void helper(<'a>t x) { ... } // and more publics int cnt; <'a>t create() { cnt++; return null; } <'b>t map(*('a) -> 'b f, <'a>t l) { ... } void iter(*('a) -> void f, <'a>t l) { ... } // ...
Then if you want to use the module, it can be done with :: notation, like this:
<int>List::t l = List::create(); ... int k = List::hd(l);
In case of some modules it might be useful to open them, i.e. import all symbols from module intro current namespace, so you no longer have to use :: notation (but you still can, it is often suggested for readability):
open List; ... <int>List::t l = List::create(); ... int k = hd(l); <int>List rest = tl(l);