可以注释组合的多态变体类型吗?

时间:2018-12-25 07:44:56

标签: module ocaml reason polymorphic-variants

我一直在使用多态变体对结果类型进行错误处理(取自http://keleshev.com/composable-error-handling-in-ocaml),对于穷举检查非常有用。我最近遇到了需要在函子中注释结果类型的需求,但不确定是否可行。这是一个片段,其中包含对我要完成的操作的一些评论:

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);

2 个答案:

答案 0 :(得分:2)

这不是一个完整的答案,但是它提供了更多信息以及一种可能的解决方案或解决方法。

可以通过向特定的组合类型添加显式强制来获得最后一行的编译:

let res =
    Result.flatMap(
      Specific1.res :> Result.t(string, [`Specific1Error | `Specific2Error]),
      _ => (Specific2.res :> Result.t(int, [`Specific1Error | `Specific2Error])));

在这里,它们都被强制为同一类型,所以我们都很好。至于为什么需要明确的原因,我的理解是,这是为了防止错误地构造函数引起意外错误。在this answer中查看更多信息。

如果type error指定了下限,则不必显式,如下所示:

let error1 : Result.t(int, [> `Error1]) = Result.Error(`Error1);
let error2 : Result.t(int, [> `Error2]) = Result.Error(`Error2);

let res = Result.flatMap(error1, _ => error2);

但是由于上限和下限多态变体具有隐式类型变量,因此我们至少必须将type error更改为type error('a)。不幸的是,即使那样,我仍然不确定如何使模块签名与实现保持一致,例如:

type error('a) = [> | `Specific1Error] as 'a;

失败

Signature mismatch:
...
Type declarations do not match:
  type 'a error = 'a constraint 'a = [> `Specific1Error ]
is not included in
  type 'a error
Their constraints differ.

也不可能强制转换为下限多态变体类型,但我不确定为什么是这样:

let res =
    Result.flatMap(
      Specific1.res :> Result.t(string, [> `Specific1Error]),
      _ => (Specific2.res :> Result.t(int, [> `Specific2Error])));

失败

This has type:
  (int, [ `Specific2Error ]) Result.t
But somewhere wanted:
  (int, [ `Specific1Error ]) Result.t
These two variant types have no intersection

表示将忽略边界。

我在几个方面都达到了我的知识极限,但是我向您的问题添加了,因为它有几个具有丰富知识的追随者,希望可以将最后的内容整合在一起。

答案 1 :(得分:0)

您是否有必要在return str.split(/\s+|_|(?=[A-Z])/).toLowerCase().join('-') 模块签名中密封error类型的原因?既然您似乎需要知道所有这些错误变量的总和才能注释最终的General值,那么您可以执行以下操作吗? (请原谅为标准OCaml语法和习语的翻译。)

res