CS 541 Lecture -*- Outline -*- Lecture adapted from Mads Tofte's "Four lectures on Standard ML" Edinburgh ECS-LFCS-89-73 * Programming with ML modules (chapter 7) introduction to ML's modules and method for programming ** Motivation: programming in the large controls name space, allows one to group names gives hierarchical structure to large system allows separate compilation fitting modules into the language allows use of the language to aid programming in the large Imagine building a symbol table for a parser. sketch of design by writing down signatures modules called structures ** Signatures are specification of syntax of a structure OTable is opaque in that it hides many details ---------------- (* SIGNATURES *) signature ValueSig = sig type value end; signature SymbolSig = sig eqtype sym val hash: sym -> int end; signature OTable = sig type table structure Sym: SymbolSig structure Val: ValueSig exception Lookup val lookup: table * Sym.sym -> Val.value val update: table * Sym.sym * Val.value -> table (* for all t: table, s: Sym.sym, v: Val.value lookup(update(t,s,v),s) = v *) end; ---------------- implement as a hash table require Sym to provide a hash function (Sym.sym -> int) assume another structure IntMap (arrays) for storing the table with polymorphic type IntMap.map ---------------- (* IMPLEMENTATION SIGNATURES *) signature IntMapSig = sig type 'a map val apply: ('a map)*int -> 'a val update: ('a map)*int*'a -> 'a map exception NotFound end; signature TTable = sig structure Sym: SymbolSig structure Val: ValueSig structure IntMap: IntMapSig datatype table = TBL of (Sym.sym * Val.value)list IntMap.map exception Lookup val lookup: table * Sym.sym -> Val.value val update: table * Sym.sym * Val.value -> table end; ---------------- the T in TTable means transparent these signatures describe the implementation view. ** Structures implementation of a signature -------------- (* STRUCTURES *) structure Data : ValueSig = struct type value = real end; structure Identifier : SymbolSig = struct type sym = string fun hash s = ord s; fun lt (s1:string, s2:string) = s1 < s2; end; ---------------- Note: can use struct ... end as an expression in certain contexts; doesn't always have to be bound to a name. *** signature constraints Identifier: SymbolSig hides the function "lt" above can be used to enforce information hiding and data abstraction can also view the same structure through more than one signature (e.g., testing, different clients) by binding same structure to more than one structure identifier with different signatures. ** Functors mappings from structures to structures allows you to separately compile structures that would otherwise need to have other structures compiled first. ---------------- (* FUNCTORS *) functor SymTblFct( structure IntMap: IntMapSig structure Val': ValueSig structure Sym': SymbolSig) : OTable = struct structure Sym = Sym' structure Val = Val' datatype table = TBL of (Sym.sym * Val.value) list IntMap.map exception Lookup fun find(sym,[]) = raise Lookup | find(sym,(sym',v)::rest) = if sym = sym' then v else find(sym,rest); fun lookup(TBL map, s) = let val n = Sym.hash(s) val l = IntMap.apply (map,n) in find(s,l) end handle IntMap.NotFound => raise Lookup (* ... *) end; ---------------- exercise: finish the body of SymTblFct after have defined structures, can get a symbol table: ------------- (* USING FUNCTORS *) structure MyTbl = SymTblFct( structure IntMap = FastIntMap structure Val = Data structure Sym = Identifier); ------------- functor body is evaluated each time the functor is applied linking is top-level structure delcarations and functor application ** Separate compilation file organization: functor result signature Symbol.sml SymbolSig.sml SymTblFun.sml SymTblSig.sml etc. ------------ (* format of a typical .sml file with functor definitions *) use "signatures.sml"; (* functor definitions *) (* ... *) ------------ put use of all signatures in a single file, because order is important, and don't want to record it several times ------------ (* signatures.sml file *) use "symbol.sig"; use "value.sig"; use "symtbl.sig"; use "lex.sig"; use "parse.sig"; -----------