OCaml-GADT-Boolean表达式

OCaml-GADT-Boolean表达式,ocaml,gadt,Ocaml,Gadt,我想知道是否有办法做到这一点: type binary_operator = And | Or;; type canonical;; type not_canonical;; type 'canonical boolean_expression = | Var : int -> not_canonical boolean_expression | Not : 'canonical boolean_expression -> 'canonical boolean_expre

我想知道是否有办法做到这一点:

type binary_operator = And | Or;;

type canonical;;
type not_canonical;;

type 'canonical boolean_expression =
  | Var : int -> not_canonical boolean_expression
  | Not : 'canonical boolean_expression -> 'canonical boolean_expression
  | BinOp : canonical boolean_expression * binary_operator * canonical boolean_expression -> canonical boolean_expression
  | BinOp : _ boolean_expression * binary_operator * _ boolean_expression -> not_canonical boolean_expression
;;
这里的问题是我不能两次定义BinOp,而我想根据参数的类型


PS:“canonical”表示“表达式中包含的n个变量由0到(n-1)的整数表示”。这是一个不变量,我需要对我的一些函数强制使用它。

您必须为类型构造函数指定不同的名称,因为有些情况下gadt的行为与adt类似

假设您希望按如下方式定义您的类型:

type 'canonical boolean_expression =
  | Bool : bool -> canonical boolean_expression (* here I assume that you wanted to have that case too *)
  | Var : int -> not_canonical boolean_expression
  | Not : 'canonical boolean_expression -> 'canonical boolean_expression
  | BinOpC : canonical boolean_expression * binary_operator * canonical boolean_expression -> canonical boolean_expression
  | BinOpNC : _ boolean_expression * binary_operator * _ boolean_expression -> not_canonical boolean_expression
 ;;

现在考虑稍有修改的类型:

type 'canonical boolean_expression =
  | Bool : bool -> canonical boolean_expression
  | Var : int -> not_canonical boolean_expression
  | Not : 'canonical boolean_expression -> 'canonical boolean_expression
  | BinOpC : canonical boolean_expression * binary_operator * canonical boolean_expression -> canonical boolean_expression
  | BinOpNC : 'a boolean_expression * binary_operator * 'a boolean_expression -> 'a boolean_expression
;;
现在,您可以使用最后两个构造函数中的任意一个来完成
规范布尔表达式
的二进制操作。 显然,任意选择结果值的类型所获得的自由有其后果:您可以创建具有重叠“类型案例”的GADT。执行此操作时,任何接受这两个值之一的函数都必须测试这两种情况。因此,构造函数的名称不能完全相同,因为类型可能不足以知道我们正在处理哪些值

例如,以下功能:

 let rec compute = function 
    | Bool b -> b   
    | BinOpC (a,And,b) -> compute a && compute b
    | BinOpC (a,Or,b) -> compute a || compute b
 ;;
根据您的定义,您应该进行类型检查并毫无问题地处理规范表达式。通过我的修改,编译器将合理地抱怨
BinOpNC
还可能包含
规范表达式

这似乎是一个愚蠢的例子(事实上也是如此)来揭示gadt的这一方面,因为我对布尔表达式的修改定义显然是不正确的(从语义上讲),但编译器并不关心类型的实际意义


本质上,gadt仍然是adt,因为您可能仍然会发现必须依靠构造函数来选择正确的操作过程的情况。

您必须为它们指定特定的名称。否则,您将如何在代码中区分它们?通过参数。。。两个
标准布尔表达式表示它是第一个,其他任何东西都表示它是第二个。如果我在一边给它一个非标准布尔表达式,在另一边给它一个标准布尔表达式,你的类型不会失败吗?谈到BinOpNC构造函数。是的,因为我使用了相同的
'a
类型变量来表示这两个子表达式。也许gadt的
BinOp
臂的一个好定义是:
|BinOp:'a boolean_operation*'b boolean operation->('a*'b)boolean_operation
,因为它有助于生成正确的递归消耗函数。