* Programming with ML modules ** Motivation: programmin in the large ** Signatures ---------------- signature OTable = sig type table exception Lookup val lookup: table * Sym.sym -> Val.value val update: table * Sym.sym * Val.value -> table end; ---------------- ---------------- signature TTable = sig 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; ---------------- ** Structures ---------------- structure SymTbl: TTable = struct 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; ---------------- *** signature constraints ------------ structure SmallTbl: OTable = SymTbl ------------ *** sharing **** dynamic semantics **** static semantics ** Functors ---------------- functor SymTblFct( structure IntMap: IntMapSig structure Val: ValSig structure Sym: SymSig): sig type table exception Lookup val lookup: table * Sym.sym -> Val.value val update: table * Sym.sym * Val.value -> table end = struct 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; ---------------- ------------- structure MyTbl = SymTblFct(structure IntMap = FastIntMap structure Val = Data structure Sym = Identifier) ------------- ** Substructures ------------ signature SymTblSig = sig structure Val: ValSig structure Sym: SymSig type table exception Lookup val lookup: table * Sym.sym -> Val.value val update: table * Sym.sym * Val.value -> table end; ------------ ---------------- functor SymTblFct( structure IntMap: IntMapSig structure Val': ValSig structure Sym': SymSig): SymTblSig = struct structure Val = Val' structure Sym = Sym' datatype table = TBL of (Sym.sym * Val.value)list IntMap.map exception Lookup (* ... *) end; ---------------- ** Sharing ------------- signature LExSig = sig structure Sym : SymSig val getsym : unit -> Sym.sym end; ------------- ------------- functor ParseFct(structure SymTbl: SymTblSig structure Lex: LexSig) = struct (* ...*) let val next = Lex.getsym() in SymTbl.update(table, next, "declared") end end; ------------- -------------- functor ParseFct(structure SymTbl: SymTblSig structure Lex: LexSig sharing SymTbl.sym = Lex.Sym and type SymTbl.Val.value = string) = struct (* ...*) let val next = Lex.getsym() in SymTbl.update(table, next, "declared") end end; -------------- ** Building the system *** always use functors for writing code *** linking is top-level structure delcarations and functor application ------------------ structure Val = ValFct() structure Sym = SymFct() structure TTable = SymTblFct(structure IntMap = IntMapFct() structure Val = Val strucutre Sym = Sym) structure Lex = LexFct(Sym) structure Parser = ParseFct(structure SymTbl = TTable structure Lex = Lex) ------------------ ** Separate compilation ------------ (* format of a typical .sml file with functor definition *) use "signatures.sml"; functor ParseFct( ... ------------ ------------ (* signatures.sml file *) use "symbol.sig"; use "value.sig"; use "symtbl.sig"; use "lex.sig"; use "parse.sig"; ----------- ** Good Style ------------- signature BigTbl = sig include SmallTbl datatype DebugInfo = (* ... *) val printInfo : unit -> unit end; ------------- ** Bad Style ------------- structure Parser = struct structure Lex = Lex structure MyPervasives = MyPervasives structure ErrorReports = ErrorReports structure PrintFcns = PrintFcns structure Table = Table structure BigTable = BigTable structure Aux = Aux fun f(...) = ... Table.lookup ... end; ------------- ------------- structure Parser = struct structure Lex = Lex open MyPervasives ErrorReports PrintFcns Table BigTable Aux fun f(...) = ... lookup ... end; -------------