假设我有一个看起来像的数据类型
datatype IntLt = ltObj of int * int * (int * int -> bool)
也就是说,这个对象是一对整数,对它们进行了相应的操作。有没有办法在创建 ltObj 时自动调用带有两个参数的函数,如果结果为假则引发异常?
也就是说,我正在寻找关于数据类型构造的构造函数类型过程,类似于__init__
Python 或 C/C++/Java 中的常用构造函数。我不想为此使用函子和签名。
假设我有一个看起来像的数据类型
datatype IntLt = ltObj of int * int * (int * int -> bool)
也就是说,这个对象是一对整数,对它们进行了相应的操作。有没有办法在创建 ltObj 时自动调用带有两个参数的函数,如果结果为假则引发异常?
也就是说,我正在寻找关于数据类型构造的构造函数类型过程,类似于__init__
Python 或 C/C++/Java 中的常用构造函数。我不想为此使用函子和签名。
在 ML 中强制执行此类不变量的惯用方式是通过模块系统定义抽象数据类型 (ADT)。这是一个简单的草图:
signature INT_LT =
sig
type int_lt
val int_lt : int * int * (int * int -> bool) -> int_lt
val pair : int_lt -> int * int
... (* other abstract operations you might want *)
end
structure IntLt :> INT_LT =
struct
type int_lt = int * int * (int * int -> bool)
fun int_lt(x, y, f) =
if f(x, y) then (x, y, f) else raise Domain
fun pair(x, y, f) = (x, y)
...
end
具体来说,请注意此处使用不透明签名归属 :>
(也称为密封)。它确保给定一个类型的值,IntLt.int_lt
没有人可以知道它的内部表示。这意味着没有人可以在不通过您的模块接口的情况下创建这种类型的值,也不能访问它们。
现在,这使用签名,但不使用仿函数。:) (话虽如此,还有一种通过abstype
构造创建 ADT 的方法。但它被认为已弃用,有利于密封。)
没有 - 如果您希望稍后能够在构造函数上进行模式匹配。
您最接近的方法是创建一个满足您需求的函数,并使用它来构造IntLt
值:
exception InvalidIntLt of int * int;
fun createIntLt (a, b, f) =
if f(a, b)
then LtObj (a, b, f)
else raise InvalidIntLt (a, b);
IntLt
请注意,使用构造函数指定 invalid* 值仍然有效。
如果您在结构中创建数据类型,则可以选择防止这种情况发生。您可以使用签名将值构造函数隐藏在LtObj
结构之外。但是请注意,这也意味着值构造函数不能用于结构之外的模式匹配。
*:那f(a, b)
不成立。