Ocaml 如何按类型构造函数比较相等值? 背景

Ocaml 如何按类型构造函数比较相等值? 背景,ocaml,equality,reason,Ocaml,Equality,Reason,我是一个比较新的推理者,对比较带有参数的变体是多么容易感到惊喜: type t=Header | Int(Int)| String(String)| Int(list(Int))| Strings(list(String))| Footer; 比较不同的变体很好,而且可以预测: /*不相等*/ 页眉==页脚 Int(1)=页脚 Int(1)==Int(2) /*相等的*/ Int(1)==Int(1) 这甚至适用于复杂类型: /*相等*/ 字符串([“你好”,“世界])==字符串([“你好”

我是一个比较新的推理者,对比较带有参数的变体是多么容易感到惊喜:

type t=Header | Int(Int)| String(String)| Int(list(Int))| Strings(list(String))| Footer;
比较不同的变体很好,而且可以预测:

/*不相等*/
页眉==页脚
Int(1)=页脚
Int(1)==Int(2)
/*相等的*/
Int(1)==Int(1)
这甚至适用于复杂类型:

/*相等*/
字符串([“你好”,“世界])==字符串([“你好”,“世界])
/*不相上下*/
字符串([“Hello”,“World”])==字符串([“a”,“b”])
问题: 是否可以仅通过我找不到的现有内置运算符/函数或其他语言构造来比较类型构造函数

设a=String(“a”);
设b=字符串(“b”);
/*不相上下*/
a==b
为论证起见,我想考虑所有的“字符串”,但如何?*

可以通过检查值的内部表示形式来实现,但我不建议这样做,因为它非常脆弱,我不确定在编译器版本和各种后端之间为这些内部构件提供了哪些保证。相反,我建议要么编写手工构建的函数,要么使用一些ppx生成与手工编写的代码相同的代码

但这一点都不好玩,所以尽管如此,这应该是你想要的,使用几乎没有记录的:

let equal_tag=(a:a,b:a)=>{
设a=Obj.repr(a);
设b=Obj.repr(b);
开关(对象is_块(a),对象is_块(b)){
|(真,真)=>Obj.tag(a)==Obj.tag(b)
|(假,假)=>a==b
|_uz=>错误
};
};
在哪里

equal_标记(页眉、页脚)==false;
equal_标记(头,Int(1))==false;
相等标签(字符串(“a”)、字符串(“b”)==真;
相等标记(Int(0),Int(0))==true;
要了解此函数的工作原理,您需要了解OCaml如何在内部表示值。这在OCaml手册的章节中的一节中进行了描述(例如,在这里我们已经看到一些迹象表明,这可能不适用于各种JavaScript后端,尽管我认为至少目前是这样。我已经用BuckleScript/rescript对此进行了测试,而js_of_OCaml倾向于更接近内部。)

具体而言,本节介绍了有关变体表示的以下内容:

t型=
|A(*第一个常量构造函数->整数“Val_int(0)”*)
|字符串(*第一个非常量构造函数->带标记0*的块)
|C(*第二个常量构造函数->整数“Val_int(1)”*)
|bool的D(*第二个非常量构造函数->带标记1*的块)
|t*t的E(*第三个非常量构造函数->带标记2*的块)
也就是说,没有有效负载的构造函数直接表示为整数,而有有效负载的构造函数则表示为带有标记的“块”。还要注意,块标记和非块标记是独立的,因此我们不能先从值中提取一些“通用”标记值,然后进行比较。相反,我们必须检查它们是否都是块,然后比较它们的标记


最后,请注意,虽然此函数将接受任何类型的值,但它只在编写时考虑了变量。比较其他类型的值可能会产生意外的结果。这是不使用此功能的另一个很好的理由。

谢谢。事实上,看看
Obj
的文档,这正是我想要的。我将尝试将非变体输入到
Obj.is\u block
中,看看会发生什么。当
a
b
是标记类型时,我很可能会得到一个匹配,然后返回到
普及。比较所有其他情况下的