构造+视图模式实例的实现
Implementation of construction + view pattern example
正在研究作者的 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.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
类型成为字段的子集(这是我希望使用此模式的用例),但这与上面的错误相同:
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
相同的字段或字段子集?如果记录有不同的字段,或者如果我按模块分隔记录但对特定用例感到好奇,可以使它工作。
记录是名义上的,不是结构类型。因此,类型看起来相同是不够的,编译器实际上必须推断出确切的类型定义,如果两种类型相同,这当然是不可能的。但是,即使它们不相同,编译器也会与同名字段斗争,并且只使用它找到的第一个匹配项,这是最后定义的类型。
在你的情况下,这不是外部问题,因为只有 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};
};
正在研究作者的 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.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
类型成为字段的子集(这是我希望使用此模式的用例),但这与上面的错误相同:
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
相同的字段或字段子集?如果记录有不同的字段,或者如果我按模块分隔记录但对特定用例感到好奇,可以使它工作。
记录是名义上的,不是结构类型。因此,类型看起来相同是不够的,编译器实际上必须推断出确切的类型定义,如果两种类型相同,这当然是不可能的。但是,即使它们不相同,编译器也会与同名字段斗争,并且只使用它找到的第一个匹配项,这是最后定义的类型。
在你的情况下,这不是外部问题,因为只有 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};
};