假设我有一个类似于
的数据类型datatype IntLt = ltObj of int * int * (int * int -> bool)
也就是说,这个对象是一对对其进行相应操作的整数。有没有办法在创建ltObj时自动使用两个参数调用函数,如果结果为false则引发异常?
也就是说,我正在寻找数据类型构造的构造函数类型的过程,类似于Python中的__init__
或C / C ++ / Java中的常用构造函数。我不想为此使用仿函数和签名。
答案 0 :(得分:4)
在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
具体来说,请注意此处使用 opaque signature ascription :>
(也称为封装)。它确保给定类型IntLt.int_lt
的值,没有人能够知道其内部表示。这意味着没有人可以在不通过模块接口的情况下创建此类型的值,也无法访问它们。
现在,它使用签名,但不使用仿函数。 :)(尽管如此,还有一种通过abstype
构造创建ADT的方法。但是它被认为是不赞成密封的。)
答案 1 :(得分:1)
没有 - 如果您希望以后能够在构造函数上进行模式匹配。
您最接近的是创建一个能够满足您需求的函数,并使用它来构造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
值仍然有效。
如果在结构中创建数据类型,则可以选择阻止此操作。您可以使用签名隐藏结构外部的LtObj
值构造函数。但请注意,这也意味着值构造函数不能用于结构外的模式匹配。
*:因为f(a, b)
不成立。