open Batteries module type N = sig type t val make: unit -> t val add_to_self: t -> t -> unit val as_float: t -> float end module Int: N = struct type t = int ref let make () = ref 1 let add_to_self x y = x := !x + !y let as_float = (!) |- float_of_int end module Float: N = struct type t = float ref let make () = ref 0.5 let add_to_self x y = x := !x +. !y let as_float = (!) end let which_module = function | "float" -> (module Float: N) | "int" -> (module Int: N) | _ -> invalid_arg "which_module" let parse: string -> (module N with type t = 'a) * 'a = fun (type a) s -> let module C = (val (which_module s): N) in (module C: N), C.make () let do_repetitive_work: (module N with type t = 'a) -> 'a -> 'a = fun (type a) m (x: a) -> let module C = (val m: N with type t = a) in let y = C.make (); C.add_to_self y x; C.add_to_self y (C.make ()); y let () = if !Sys.interactive then () else let m, x = parse Sys.argv.(1) in let module C = (val m: N) in do_repetitive_work (module C: N with type t = C.t) x |> C.as_float |> Printf.printf "%g\n"