Search code examples
ocamlabbreviation

Abbreviating constructor names in Ocaml


I have two modules. One defines a variant type:

module A = struct
  type foo = Bar of material | Baz | Boo

  (* other stuff *)
end

and I would like to be able to use foo's variants both as constructors and as left-hand-sides in another module

module B = struct
  type foo = A.foo  (* I can abbreviate A.foo by assigning it a local alias *)

  let f (x : foo) = match x with
    | Bar m       -> Bar (g m)  (* Any way to abbreviate Bar and friends? *)
    | Baz   | Boo -> x
end

but per "referring to named objects" I have to prefix the variant names with a module-path:

  let f (x : foo) = match x with
    | A.Bar m         -> A.Bar (g m)
    | A.Baz   | A.Boo -> x

Is there any way to skip avoid using the module path short of opening and pulling in all the other stuff from A?


Solution

  • You can open A locally:

    let f (x : foo) = A.(match x with
      | Bar m       -> Bar (g m)
      | Baz   | Boo -> x)
    

    or

    let f (x : foo) =
      let open A in
      match x with
      | Bar m       -> Bar (g m)
      | Baz   | Boo -> x)
    

    You can define Bar in a submodule so that less things are exposed:

    module A = struct
      module BasicDataAndOps = struct
        type foo = Bar of material | Baz | Boo
      end
      open BasicDataAndOps
      (* other stuff *)
    end
    
    module B = struct
      open A.BasicDataAndOps
      ...
    

    For use outside of patterns, you can define a "smart constructor" in B:

    let bar m = A.Bar m
    

    ETA: I forgot about the possibility to restate type definition, described in Ashish Argwal's answer: type foo = A.foo = Bar of material | Baz | Boo. Given that you already have type abbreviation in your example, this is the best answer.

    There is some work on type-based label disambiguation which could be helpful, but it may not get accepted into the language.