Как определить абстрактный (непрозрачный) интерфейс для полиморфного типа объекта?

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

Окамль

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) так, чтобы он был абстрактным, но совместимым с открытыми полиморфными типами объектов в реализациях?


person Chris    schedule 21.05.2021    source источник


Ответы (2)


Типы <b : bool; .. > и <c : int; ..> несовместимы так же, как несовместимы int и bool. Другими словами, если мы поместим полиморфизм строк в сторону и сосредоточьтесь на конструкторах простых типов, тогда вы пытаетесь определить интерфейс, который соответствует типам int и bool и ничему другому, он же ограниченный полиморфизм.

Также важно понимать, что подтипирование не является наследование. В вашем случае у вас есть два класса объектов, объекты класса b, которые имеют метод 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 наследуется от u, то v является подтипом u,

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

Как только вы получите четкое представление об этом, вы сможете разработать правильный интерфейс.

person ivg    schedule 24.05.2021
comment
Я понимаю, что A.t и B.t несовместимы, но как определить совместимый абстрактный интерфейс? Например, bool и int несовместимы, но я все еще могу определить тип b в интерфейсе. Если мы полностью удалим модуль B, код все равно не скомпилируется. - person Chris; 24.05.2021
comment
Учитывая ваше первоначальное ограничение дизайна, такого интерфейса нет. Это то, что я и @octachron пытаемся сказать. Поэтому вам нужно переосмыслить, почему вы оказались в несовместимых интерфейсах, или опубликовать другой вопрос, описывающий вашу первоначальную проблему. Учитывая его состояние, ответ прост - нет, такого типа модуля нет и быть не должно. - person ivg; 24.05.2021

Неясно, действительно ли это полезно, но вам нужно явно добавить ограничение в тип модуля:

module type TA  = sig
  type 'a t constraint 'a = < b:bool; .. >
end
module A : TA = struct
  type 'a t = < b :bool  ;.. > as 'a
end
person octachron    schedule 22.05.2021
comment
Как TA может быть также совместим с модулем B? Например, я хотел бы реализовать интерфейс (класс типа) для использования с Functor, и можно передать модуль A или B. - person Chris; 23.05.2021
comment
Вы не можете. Ограничения параметра типа 'a в A и B несовместимы друг с другом. - person octachron; 23.05.2021