Object 对于可扩展对象类型,我应该如何指向记录字段?

Object 对于可扩展对象类型,我应该如何指向记录字段?,object,ocaml,reason,lenses,Object,Ocaml,Reason,Lenses,想办法在一个物体上合理地定义一个简单的镜头 我尝试用以下代码使用可扩展对象(在字段列表前面加上。): type hasName('a, 't) = {.. name: 't} as 'a; type lens('s, 'v) = { get: 's => 'v, set: ('s, 'v) => 's, }; let nameLens: lens(hasName('a, 't), 't) = { get: s => s.name, set: (s, v) =&g

想办法在一个物体上合理地定义一个简单的镜头

我尝试用以下代码使用可扩展对象(在字段列表前面加上
):

type hasName('a, 't) = {.. name: 't} as 'a;
type lens('s, 'v) = {
  get: 's => 'v,
  set: ('s, 'v) => 's,
};
let nameLens: lens(hasName('a, 't), 't) = {
  get: s => s.name,
  set: (s, v) => {...s, name: v},
}

我得到“找不到记录字段名”错误,尽管
hasName
的类型肯定应该有一个。。。我做错了什么


免责声明:我对Reason/OCaml非常陌生,因此我可能会错过一些显而易见的东西。

错误消息不是很好(说得委婉一点),但如果仔细阅读,它确实指出了问题所在。它说“无法找到记录字段名称”。考虑到您拥有的是一个对象,而不是一个记录,这并不奇怪。这是一个错误,因为对象成员是通过
而不是
访问的(请参阅)

据我所知,这样做的原因是OCaml不支持特殊多态性(即函数或运算符重载),因此,为了使类型推断能够很好地工作,它需要在语法上区分不同类型上的操作。我还怀疑它不只是说“伙计,这是一个对象,不是一个记录”的原因是类型系统没有任何记录类型的概念,而是需要一个特定的记录类型。因此,它尝试首先查找字段,然后标识与之关联的特定记录类型。如果找不到字段,则不会将其视为类型错误,因为没有与之冲突的正确类型

在任何情况下,使用
#
而不是
都可以很容易地解决getter问题。然而,二传手的问题更大。在这里,您也使用了记录更新语法,并将得到一个类似的错误,但不幸的是,没有对象的直接等价物

使对象面向对象的一个原因是它们的实现是隐藏的。如果你不知道里面有什么,就不能从外面复制对象。虽然可以创建符合同一对象类型的不同对象,但只有在知道具体类型的情况下才能这样做。在这种情况下,你不会

因此,不可变地更新对象的方法是从对象内部使用setter方法进行更新,在该方法中,您知道需要知道的一切。不可变地更新当前对象的语法是
{}
,它仅在方法定义中有效。当然,我们还需要将这个setter方法添加到
hasName
类型中

综上所述,我们最终得出以下结论:

类型hasName('a,'t)=
{
..
姓名:"t,,
setName:'t=>'a,
}作为"a",;
类型透镜('s,'v)={
获取:“s=>”v,
集合:('s,'v)=>'s,
};
let nameLens:lens(hasName('a,'t),'t)={
get:s=>s#name,
集合:(s,v)=>s#集合名(v),
};
设obj={
val名称=
“我的名字”;
酒吧名称=
名称
pub setName=newName=>
{}
};
nameLens.set(obj,“新名称”)
|>nameLens.get
|>打印尾行

是的,您完全正确地理解了OCaml对不同类型使用不同运算符的原因。一个小问题是:当出现“记录字段未找到”错误时,记录投影`r。name`尚未键入。在尝试键入
字段
之前,typechecker正在尝试查找名为
字段
的所有记录标签。由于找不到任何标签,因此引发了一个错误,但该错误仍然是一个typechecker错误。@Octacron感谢您的澄清。我想更准确的说法是,它可能不是一个统一错误?事实上,它不是一个统一错误,因为typechecker无法找到要统一的类型。正如您所说,typechecker没有记录种类(或任何种类)的概念,因此它无法在检查标签之前将
s
的种类与记录种类统一起来。