open Batteries type init_param = | Int of int | Float of float module type N = sig type t val make: init_param -> t val add_to_self: t -> t -> unit val as_string: t -> string end module Int: N = struct type t = int ref let make = function | Int i -> ref i | _ -> invalid_arg "make" let add_to_self x y = x := !x + !y let as_string = (!) |- Printf.sprintf "%di" end module Float: N = struct type t = float ref let make = function | Float f -> ref f | _ -> invalid_arg "make" let add_to_self x y = x := !x +. !y let as_string = (!) |- Printf.sprintf "%gf" end let parse: string -> (module N) * init_param = fun s -> if String.exists s "." then (module Float: N), Float (float_of_string s) else (module Int: N), Int (int_of_string s) let do_repetitive_work: (module N with type t = 'a) -> 'a -> init_param -> 'a = fun (type a) m (x: a) i -> let module C = (val m: N with type t = a) in let y = C.make i in C.add_to_self y x; C.add_to_self y (C.make i); y let () = if !Sys.interactive then () else let m, i = parse Sys.argv.(1) in let module C = (val m: N) in let x = C.make i in do_repetitive_work (module C: N with type t = C.t) x i |> C.as_string |> Printf.printf "%s\n"