哪种样式更适合在Ocaml中声明类型?

时间:2011-07-18 09:02:36

标签: list types map ocaml

我经常需要声明一个包含地图或列表的类型,例如:

type my_type_1 = my_type_0 IntMap.t
type my_type_2 = my_type_0 List

此外,我还看到了另一种声明形式,它将地图或列表封装在记录中,例如:

type my_type_1 =
  | Bot_1
  | Nb_1 of my_type_0 IntMap.t
type my_type_2 =
  | Bot_2
  | Nb_2 of my_type_0 List

我的问题是,是否有些情况下第二种风格是必要的并且比第一种风格更好?

非常感谢!

3 个答案:

答案 0 :(得分:2)

由于在第二种情况下添加了Bot构造函数,因此您提供的两种类型不相同。这意味着两个my_type_1没有相同的语义。顺便提一下,构造Bot | Foo of 'a已由标准类型'a option提供,构造函数为SomeNone,因此第二个示例的类型my_type_1是等效的到第一个my_type_1 option

是否使用option类型或您自己的构造函数名称取决于您。一般情况下,如果您的类型的语义与失败,缺席或未定义的option概念一致,我会建议您使用选项类型。鉴于你的名字Bot,我认为这可能就是你正在做的事情,但是定义你自己的构造函数名称也没问题,在某些情况下可以更清楚。这个问题已在this blog post from ezyang中深入讨论。

现在,假设您的两个类型定义 等效(即,在没有Bot)构造函数的情况下,添加代数数据类型层(一个新构造函数)的目的是什么使用简单类型别名?好吧,它具有从表示类型中创建 distinct 类型的效果。例如,如果您定义type 'a stack = Stack of 'a list,则'a stack'a list不能相互混淆,如果您这样做,编译器将引发错误。这样可以用来强制执行(轻)类型分离,构造函数充当类型注释:

let empty = Stack []
let length (Stack li) = List.length li

我认为这主要是品味问题,但我建议您使用代数数据类型而不是别名,以确保原始类型不会出错。缺点是您必须包装原始数据类型的操作,就像我在上面的length函数中所做的那样。

答案 1 :(得分:1)

那些样式不同,但不同的类型:第一种类型声明是多态的专用实例(mytype_0)的缩写{ {1}}或List

第二组定义提供了“构造的”类型,IntMap(和Bot_1)为其提供了值。例如,可以使用这些“替代”来创建类型Bot_2的函数,它在计算不允许返回列表的特殊情况下返回T -> my_type_1,其方式与一个option type允许。对于第一组定义(必须始终提供所需的列表有效负载),这是不可能的。

答案 2 :(得分:0)

第二个不是“记录”(这是另一回事)。它创建了一个代数数据类型。我不知道如何解释它,但如果你使用Haskell或Standard ML,你就会知道。它基本上是一个标记的联合。 my_type_1 一个Bot_1(不带数据)或Nb_1(带有my_type_0 IntMap.t数据)。

第一个只是一个类型同义词(就像C中的typedef)。