(* for smlnj93 *) val print_string = String.print val print_real = Real.print (* for moscow ML load "Real"; val print_string = print val print_real = print o Real.toString *) local fun read_file (fname:string) : string list = let val instr = open_in fname fun load a = if end_of_stream instr then (close_in instr; rev a) else let val s = input_line instr val t = substring(s,0,size s - 1) in load (t::a) end in load nil end fun prep_db (a:string list) : (string*int) list * real = let fun atoi s = let fun f (nil,a) = a | f (d::r,a) = f(r,a * 10 + (ord(d) - ord("0"))) in f(explode s,0) end fun split s = let fun findtab n = if substring(s,n,1) = "\t" then (substring(s,0,n), atoi(substring(s,n+1,size s-n-1))) else findtab (n+1) in findtab 0 end val db = map split a val average = (real (fold (op+) (map #2 db) 0)) / (real (length db)) in (db,average) end fun do_query (db:(string * int) list,average:real) (k0:string) : unit = let exception NotFound fun lookup nil = raise NotFound | lookup ((k,v)::rest) = if k = k0 then v else lookup rest in print_string k0; print_string "\t"; (print_real ((real (lookup db))/average)) handle NotFound => print_string "isn't there"; print_string "\n" end in fun report (dbfile :string) : string -> unit = let val a = read_file dbfile val (db,average) = prep_db a fun queries (qfile : string) : unit = let val qs = read_file qfile in app (do_query (db,average)) qs end in queries end end; val query = report "dbfile"; query "qfile";