すべての構築が、不変条件を保持できるモジュール メンバーを通過するように型を定義したいと考えていますが、パターン マッチングのための分解は可能です。
私はちょうど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)
これらは可能な限り軽量でメモリ的にする必要があります。何か案は?