构造+视图模式实例的实现

问题描述 投票:0回答:1

正在通过作者的一个design pattern called 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.tUser.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};
};

但得到一个看起来无法区分viewt的错误:

  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类型成为字段的子集(这是我希望使用此模式的用例),但这与上面的错误相同:

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相同的字段或字段子集?如果记录有不同的字段,或者我按模块分隔记录但对这个特定用例感到好奇,可以使它工作。

design-patterns ocaml typeerror record reason
1个回答
2
投票

记录是名义上的,而不是结构类型。因此,类型看起来相同是不够的,编译器实际上必须推断出确切的类型定义,如果两种类型相同,这当然是不可能的。但即使它们不相同,编译器也会遇到同名的字段,只需要找到它找到的第一个匹配项,这是最后定义的类型。

在你的情况下,这不是外部问题,因为只暴露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};
};
© www.soinside.com 2019 - 2024. All rights reserved.