Реализация конструкции + пример просмотра шаблона - PullRequest
0 голосов
/ 21 февраля 2019

Работал на примере шаблона проектирования под названием Constructor + View автора, который был объяснен с помощью типов, но испытывал затруднения при выяснении реализации.

Это сигнатура модуля:

module User : {
  type t;
  type view = { name: string, age: int };
  let make: (~name:string, ~age:int) => option(t);
  let view: t => view;
};

То есть User.t скрыто, но из одной функции вы можете сопоставить шаблон с пользовательской записью

Сначала думал, что User.t и User.view могут иметь одинаковые поля:

module User: {
  type t;
  type view = { name: string, age: int, };
  let make: (~name: string, ~age: int) => option(t);
  let view: t => view;
} = {
  type t = { name: string, age: int, };
  type view = { name: string, age: int, };
  let make = (~name, ~age) => Some({name, age});
  let view = t => {name: t.name, age: t.age};
};

Но возникла ошибка, которая выглядит так, как будто она не может определить разницу между view и t:

  Values do not match:
    let make: (~name: string, ~age: int) => option(view)
  is not included in
    let make: (~name: string, ~age: int) => option(t)

Пробовал еще пару вещей, первый простовынимает make и пытается заставить работать функцию view, но та же проблема:

module User: {
  type t;
  type view = { name: string, age: int, };
  let view: t => view;
} = {
  type t = { name: string, age: int, };
  type view = { name: string, age: int, };
  let view = t => {name: t.name, age: t.age};
};

с ошибкой:

  Values do not match:
    let view: view => view
  is not included in
    let view: t => view

Вторая попытка была для view type быть подмножеством полей (это был тот случай использования, на который я надеялся использовать этот шаблон), но в нем та же ошибка, что и выше:

module User: {
  type t;
  type view = { name: string, age: int, };
  let view: t => view;
} = {
  type t = { name: string, age: int, email: string };
  type view = { name: string, age: int, };
  let view = t => {name: t.name, age: t.age};
};

Мой вопрос здесь заключается в том, есть ли способ реализоватьчто-то, чтобы соответствовать подписи первого модуляUser.view - это те же поля или подмножество полей, что и User.t?Может заставить его работать, если записи имеют разные поля или я разделяю записи по модулям, но мне интересно узнать об этом конкретном случае использования.

1 Ответ

0 голосов
/ 21 февраля 2019

Записи являются номинальными, а не структурными типами.Поэтому недостаточно, чтобы тип выглядел одинаково, компилятор фактически должен вывести точное определение типа, что, конечно, невозможно, если два типа идентичны.Но даже если они не идентичны, компилятор будет бороться с полями с одинаковыми именами и просто использовать первое найденное совпадение, которое является последним определенным типом.

В вашем случае это не проблемавнешне, так как выставляется только view.Но внутренне вы должны помочь компилятору с несколькими аннотациями типов.Это составляет:

module User: {
  type t;
  type view = { name: string, age: int, };
  let make: (~name: string, ~age: int) => option(t);
  let view: t => view;
} = {
  type t = { name: string, age: int, };
  type view = { name: string, age: int, };
  let make = (~name, ~age) => Some({name, age}: t);
  let view = (t: t) => {name: t.name, age: t.age};
};
...