I've been using polymorphic variants for error handling with result types (taken from http://keleshev.com/composable-error-handling-in-ocaml) and it's been great for exhaustive checking. I recently came across the need to annotate the result type in a functor but not sure if it's possible. This is a snippet with some comments on what I'm trying to accomplish:
open Belt;
/* A quick example of what's working for us right now. This is fine and
the result error type is [> `Error1 | `Error2 ] */
let res = Result.flatMap(Result.Error(`Error1), _ => Result.Error(`Error2));
/* A really generic version of what what we're trying to do */
module type General = {
type t;
type error;
let res: Result.t(t, error);
};
module Make = (M: General) => {
let res = M.res;
};
module Specific1 =
Make({
type t = string;
type error = [ | `Specific1Error];
let res = Result.Error(`Specific1Error);
});
module Specific2 =
Make({
type t = int;
type error = [ | `Specific2Error];
let res = Result.Error(`Specific2Error);
});
/* This definitely doesn't compile because the two error types
aren't the same but wondering if anything above can be changed so it
understands the error type is [> `Specific1Error | `Specific2Error] */
let res = Result.flatMap(Specific1.res, _ => Specific2.res);
This isn't a complete answer, but it provides a bit more information and one possible solution or workaround.
It's possible to get the last line to compile by adding explicit coercion to the specific combined type:
Here they're both coerced to the same type, so we're all good. As for why it needs to be explicit, my understanding is that this is to prevent accidental mistakes from mistyping constructors. See more in this answer.
If
type errorhad specified a lower bound we wouldn't have to be explicit, as demonstrated by this:But since upper and lower bound polymorphic variants have an implicit type variable, we would at the very least have to change
type errortotype error('a). Unfortunately even then I'm not sure how to get the module signature to line up with the implementations since, for example, this:fails with
It's also not possible to coerce to a lower bound polymorphic variant type, and I'm not sure why that is either:
fails with
indicating that the bounds are simply ignored.
I've reached the limits of my knowledge here on several fronts, but I've added ocaml to your question since it has several followers with significant knowledge that can hopefully put the final pieces together.