在OCaml中有没有一种方法可以在记录中声明一个整数,它是一些整数的间隔?

在OCaml中有没有一种方法可以在记录中声明一个整数,它是一些整数的间隔?,ocaml,Ocaml,我陷入了这个问题,我不得不: 将类型日期定义为一个三元组,其中第一个组件是一年,表示为一个三元组 整数,第二个分量是区间[1..12]中的整数 表示月份,最后一个组件表示带有整数的一天 号码 这很好,但是对于参数month,我需要1到12之间的整数作为输入。如果您希望月份只使用一个变量并枚举所有月份。你可以对第二天做同样的事情,但我会避免 如果你想要一个更一般的概念,比如范围类型:你不想要,因为月份有30天或31天,二月有28-29天,这取决于闰年,所以它是一个依赖范围。。。如果此支票可用,那么

我陷入了这个问题,我不得不: 将类型日期定义为一个三元组,其中第一个组件是一年,表示为一个三元组 整数,第二个分量是区间[1..12]中的整数 表示月份,最后一个组件表示带有整数的一天 号码


这很好,但是对于参数month,我需要1到12之间的整数作为输入。

如果您希望月份只使用一个变量并枚举所有月份。你可以对第二天做同样的事情,但我会避免

如果你想要一个更一般的概念,比如范围类型:你不想要,因为月份有30天或31天,二月有28-29天,这取决于闰年,所以它是一个依赖范围。。。如果此支票可用,那么您想要哪个范围?您需要的检查非常具体:作为一个例子,我只在带有扩展的cpp中看到了这一点,并且您被迫从范围中使用int(非常无用)。因为这个扩展需要静态int,所以不能真正用于date。OCaml不能这样做,因为所有int都是
int
而不是30或31。通常的解决方法是创建一个函数,使用三个int验证它们是否在有效范围内,并返回
日期选项
,同时从外部将其设置为私有,这样就不会破坏不变量。我们称之为智能构造函数

module SafeDate : sig
    type date = private { year: int; month: int; day:int}
    val create: int -> int -> int -> date option
end = struct
    type date = { year: int; month: int; day:int}
    let create year month day = if (* put formula/code to say if correct *) then Some{year; month; day} else None
end

不,但是你可以防止事故

OCaml(和其他地方)中的时间和日期库通常确保日期对象的组件位于正确的范围内,而无需特殊类型的系统欺骗

在OCaml中,一个好的解决方案可能是将日期字段公开为只读。这意味着模块的用户将无法使用符号
{year=…;month=…;day=…}
创建此类记录。这是通过提供一个显式模块接口(.mli文件)来实现的,该接口将日期类型声明为
private

(* Date.mli *)
type t = private {
  year: int;
  month: int;
  day: int;
}

(** Create a date object if and only if given acceptable values *)
val create : year:int -> month:int -> day:int -> t option
实现(
Date.ml
文件)与往常一样。特别是,类型定义中没有
private
关键字:

(* Date.ml *)
type t = {
  year: int;
  month: int;
  day: int;
}

let create ...
你也可以从中获得创意。例如,您可以让库安全地公开从年/月/日派生的字段,例如自年初以来的天数等

(* Date.ml *)
type t = {
  year: int;
  month: int;
  day: int;
}

let create ...