Я хочу определить тип, чтобы вся конструкция проходила через члены модуля, которые могут сохранять инварианты, но разрешать деструктурирование для сопоставления с образцом.
Я только изучаю 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)
, но мне нужно они должны быть как можно более легкими с точки зрения памяти. Есть идеи?