Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Picking which ocaml module to use with command line parameter

In my code I've module M = Implementation1 and then I reference M, instead of Implementation1. The problem is, I've to recompile my program to change Implementation1 to Implementation2. I'd like to control which implementation to use from with a command line parameter. Is that possible?

Is the situation simpler, when all implementations share signature?

like image 504
pbp Avatar asked Jan 11 '23 11:01

pbp


2 Answers

Since both implementation are known statically you can use first class modules. There are quite a few different possibilities on how to structure your program, here's one that minimizes toplevel reference cells and toplevel effectful statements:

module type M = sig
  val test : unit -> unit
end

module M1 : M = struct
  let test () = Printf.printf "Implementation 1\n%!" 
end

module M2 : M = struct
  let test () = Printf.printf "Implementation 2\n%!"
end

let test m = 
  let module M = (val m : M) in 
  (* If other modules of your program depend on the implementation of 
     M, functorize them over sig M and instantiate them with M here. *)
  M.test ()

let main () = 
  let exec = Filename.basename Sys.executable_name in 
  let usage = Printf.sprintf
      "Usage: %s [OPTION]...\n\
       Program synopsis.\n\
       Options:" exec 
  in
  let m = ref (module M1 : M) in
  let options = [
    "-m1", Arg.Unit (fun () -> m := (module M1 : M)), 
    " Use implementation 1 (default)"; 
    "-m2", Arg.Unit (fun () -> m := (module M2 : M)),
    " Use implementation 2"; ]
  in
  let anon _ = raise (Arg.Bad "no positional argument supported") in 
  Arg.parse (Arg.align options) anon usage; 
  test !m

let () = main ()
like image 180
Daniel Bünzli Avatar answered Jan 31 '23 07:01

Daniel Bünzli


For most versions of OCaml you can do this with camlp4.

IFDEF USE_IMP1 THEN
  module M = Implementation1
ELSE
  module M = Implementation2
END

Then passing the pre-processing options like the following will choose the correct one to incorporate in the build.

-pp "camlp4of -UUSE_IMP1" //to undefine USE_IMP1
-pp "camlp4of -DUSE_IMP1" //to define USE_IMP2

For versions of OCaml >= 4.00.0 you can use the First-Class modules and an expression like,

module Choose = (val (if use_impl1 then (module Impl_1) else (module Impl_2)) : IMP)

to use an if statement to choose the module as determined by the use_impl1 value.

like image 33
nlucaroni Avatar answered Jan 31 '23 07:01

nlucaroni