Polymorphic variants: can the row variable be manipulated for type-level subtraction?

Hey there! I’d like to know if there is a way to properly write or type handle_a so that the type system acknowledges the “subtraction” of the `A case handled by the function, while still propagating everything else—both known variants (like `B) and unknown ones.

module PV = struct
  type a = [ `A  ]
  type b = [ `B  ]

  let handle_a : type x.
    (unit -> x) ->
    [> a | b ] ->
    (x, [> b ]) result
  = fun handler -> function
    | `A -> Ok (handler ())
    | `B -> Error `B
    | rest -> Error rest
end

The inferred type is:

x. (unit -> 'x) -> ([> `A | `B ] as 'a) -> ('x, 'a) result

So there is just one implicit variable for the input variant, which gets propagated to the output instead of being refined as I manually typed it.

If the row variable were directly manipulable, I imagine the function could be typed something like this:

module PV = struct
  type a = [ `A  ]
  type b = [ `B  ]

  let handle_a : type x row.
    (unit -> x) ->
    [a | b | row] ->
    (x, [b | row]) result
  = fun handler -> function
    | `A -> Ok (handler ())
    | `B -> Error `B
    | rest -> Error rest
end
1 Like

I think this is access to row variables · Issue #6952 · ocaml/ocaml · GitHub - interestingly, the extensible tuples part of that has become resurrected in discussions around tuple projections in Labeled tuple projections by johnyob · Pull Request #57 · ocaml/RFCs · GitHub

I saw that issue but it seemed a dead end to me. I therefore asked the question in the hope that there were alternatives :smiley:

This is purposefully not supported by the implementation of polymorphic variants. This was done to avoid exposing the row type variable, and the full kind system for tags (which can be internally present | absent | either but the absent kind is not visible in the surface language).

I guess there aren’t plans to expose the row type variable anytime soon right? I don’t know if it’s worth trying to reopen that issue. Thanks.