【问题标题】:How to define an abstract (opaque) interface for a polymorphic object type?如何为多态对象类型定义抽象(不透明)接口?
【发布时间】:2021-05-24 21:34:10
【问题描述】:

ReasonML

module type T = {
  type t('a); // Does not work
  type b; // Works
};

module A: T = {
  type t('a) = {.. b: bool} as 'a;
  type b = bool;
};
module B: T = {
  type t('a) = {.. c: int} as 'a;
  type b = int;
};

Ocaml

module type T  = sig
  type 'a t /* Doesn't work */
  type b /* Works */
end
module A : T = struct type 'a t = < b :bool  ;.. > as 'a
                      type b = bool end 
module B : T = struct type 'a t = < c :int  ;.. > as 'a
                      type b = int end  

如何定义模块类型 A t('a) 使其抽象但与实现中的开放多态对象类型兼容?

【问题讨论】:

    标签: ocaml reason rescript


    【解决方案1】:

    &lt;b : bool; .. &gt;&lt;c : int; ..&gt; 类型不兼容,就像 intbool 不兼容一样。换句话说,如果我们将row polymorphism 放在一边,而专注于简单的类型构造函数,那么您将尝试定义一个与intbool 类型匹配的接口,而不是其他类型,也就是bounded polymorphism

    了解subtyping is not inheritance 也很重要。在您的情况下,您有两类对象,b-class 对象具有方法 b

    class virtual b = object
      method virtual b : bool
    end
    

    c- 具有方法c 的对象类,

    
    class virtual c = object
      method virtual c : int
    end
    

    我们可以定义一个对象类bc,这两个方法自然是通过继承来实现的,

    class virtual bc = object
      inherit b
      inherit c
    end
    

    现在,让我们做一些物体来玩吧,

    let b : b = object method b = true end
    let c : c = object method c = 42 end
    let bc : bc = object
      method b = false
      method c = 56
    end
    
    

    我们可以看到,尽管 bc 类类型被定义为从 b 和 c 继承,但我们不能将 b 强制转换为 c

    # (b : b :> bc);;
    Line 1, characters 0-13:
    1 | (b : b :> bc);;
        ^^^^^^^^^^^^^
    Error: Type b = < b : bool > is not a subtype of bc = < b : bool; c : int > 
           The first object type has no method c
    

    这很有意义,因为我们试图将基类的对象向下转换为派生类的对象,这是非法操作。因此,当您具有按继承排序的类类型层次结构时,基类是超类型,派生类是子类型。例如,如果 v 继承自 uvu 的子类型,

    v inherits-from u
    -----------------
       u :> v
    

    一旦你清楚地了解了这一点,你就可以设计一个合适的界面了。

    【讨论】:

    • 我知道A.t和B.t不兼容,但是如何定义一个兼容的抽象接口呢?比如 bool 和 int 不兼容,但是我仍然可以在接口中定义类型 b。如果我们完全删除模块 B,代码仍然无法编译。
    • 鉴于您最初的设计约束,没有这样的界面。这就是我和@octachron 想说的。因此,您需要重新考虑为什么最终会出现不兼容的界面,或者发布另一个问题来描述您的原始问题。鉴于它的状态,答案很简单——不,不存在这样的模块类型,也不应该存在。
    【解决方案2】:

    不清楚是否真的有用,但需要在模块类型中显式添加约束:

    module type TA  = sig
      type 'a t constraint 'a = < b:bool; .. >
    end
    module A : TA = struct
      type 'a t = < b :bool  ;.. > as 'a
    end
    

    【讨论】:

    • TA怎么也兼容模块B?例如,我想实现一个接口(类型类)与Functor一起使用,可以传入模块A或B。
    • 你不能。 AB中对类型参数'a的约束不兼容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2014-08-23
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多