Сохранение инвариантов при разрешении деструктурирования

Я хочу определить тип, чтобы вся конструкция проходила через члены модуля, которые могут сохранять инварианты, но разрешать деструктурирование для сопоставления с образцом.

Я только изучаю OCaml, но следующее почти работает для пары int с инвариантом, что левое должно быть строго меньше, чем правое

module Range : sig
  type t = private { left:int; right:int }
  exception InvalidRange of (int*int)
  val make : int -> int -> t
end = struct
  type t = { left:int; right:int }
  exception InvalidRange of (int*int)
  let make left right = if left < right
    then { left; right }
    else raise (InvalidRange (left, right))
end

, которое работает таким образом

# let p = Range.make 1 2;;
val p : Range.t = {Range.left = 1; Range.right = 2}
# let q = Range.make 2 1;;
Exception: Range.InvalidRange (2, 1).

и деструктурирование работает по-своему

# let {Range.left=x; Range.right=y} = p;;
val x : int = 1
val y : int = 2

в то время как конструкция не работает

# let badp = {Range.left = 2; Range.right = 1};;
  let badp = {Range.left = 2; Range.right = 1};;
Error: Cannot create values of the private type Range.t
# open Range;;
# let badp = {left = 2; right=1};;
  let badp = {left = 2; right=1};;
Error: Cannot create values of the private type Range.t

, но мне бы очень хотелось иметь синтаксическое удобство деструктурирования кортежей. Приведенное ниже не работает:

module Range : sig
  type t = private int*int
  exception InvalidRange of (int*int)
  val make : int -> int -> t
end = struct
  type t = int*int
  exception InvalidRange of (int*int)
  let make left right = if left < right
    then (left, right)
    else raise (InvalidRange (left, right))
end

, но тогда я не могу деструктурировать его с помощью шаблона кортежа:

# let r = Range.make 1 2 ;;
val r : Range.t = (1, 2)
# let (a, b) = r;;
  let (a, b) = r;;
Error: This expression has type Range.t
       but an expression was expected of type 'a * 'b

Я мог бы изменить тип на type t = R of (int * int), но мне нужно они должны быть как можно более легкими с точки зрения памяти. Есть идеи?

6
задан Mike Samuel 22 May 2012 в 20:50
поделиться