Constrain a type to be a polymorphic variant

How can I constrain module A : A in module B, so that the following code works:

module type A = sig type err end

module type B = sig
  module A : A
  type err = [ A.err | `Another_err ]
end

if we had:

module type A2 = sig type err = [ `A | `B ] end

or

module type B3 = sig
  module A : A with type err = [ `A | `B ]
  type err = [ A.err | `Another_err ]
end

it would work, but I don’t want to specify the concrete values of err

Is there a syntax to say

module type B = sig
  module A : A with type err = <some way to specify that it has to be a polymorphic variant>
  type err = [ A.err | `Another_err ]
end

code: Sketch.sh - Interactive ReasonML/OCaml sketchbook

You are misreading the meaning of [A.err | `Another_err ]. Here A.err refers to the type declaration and not the type.

Thus, constraining a type constructor to be an abbreviation for some polymorphic variants would not bring you closer to your aim.

now I’m more confused than before, what is the difference between the type declaration and the type?

Doesn’t this [ A.err | 'Another_err ] for example refer to the actual module A.err implementation:

module type B3 = sig
  module A : A with type err = [ `A | `B ]
  type err = [ A.err | `Another_err ]
end

or did I misunderstand you, and there is no way to specify that in the type without making the polymorphic variant type public?

for some extra context I have different B implementations and don’t want to limit A.err to a specific polymorphic variant:

module My_b : B with module A = My_a = struct ... end
module Another_b : B with module A = Another_a = struct ... end

I meant that A.err refers precisely to the full type declaration

type err = [ `A | `B ]

both its left-hand side and right hand side. In other words, [ A.err | `Another_err ] merely inlines the type definition of A.err in the type expression and nothing more.

okay, [ A.err | 'Another_err ] inlines the definition of A.err, but that’s only possible if we know that A.err is a polymorphic variant

the issue in the original code example:

module type A = sig type err end

module type B = sig
  module A : A
  type err = [ A.err | `Another_err ]
end

is that A.err does not expand to a polymorphic variant type - it is simply an unknown type

Is there any way to say that module A in module B, will have a type err, that is a polymorphic variant, so that type err = [ A.err | 'Another_err ] compiles?

The condition is stronger than that, inlining a type definition requires the existence of a full definition. In other words, the only way to make

module type B = sig
  module A : A
  type err = [ A.err | `Another_err ]
end

is to add a corresponding type definition in the module type A.

module type B = sig
  module A : A with type err = [ `B ]
  type err = [ A.err | `Another_err ]
end

Another way to look at it is that polymorphic variants are ill-suited to do arbitrary set computations at the type level.

okay then, I was hoping that there is something like

module A : A with type err = [ ]

to allow arbitrary polymorphic variant, but will think how to rework this