Creating GADT expression in OCaml

纵饮孤独 提交于 2019-11-28 11:27:44

As you've found, this approach doesn't type check. It also has a more fundamental problem: GADTs can be recursive, in which case it is flatly impossible to enumerate their cases.

Instead you can reify types as a GADT and pass them around. Here's a cut-down example:

type _ expr =
  | Num : int -> int expr
  | Add : int expr * int expr -> int expr
  | Lt  : int expr * int expr -> bool expr
  | And : bool expr * bool expr -> bool expr

type _ ty =
  | TyInt : int ty
  | TyBool : bool ty

let bin_op (type a) (type b) op (l : a expr) (r : a expr) (arg_ty : a ty) (ret_ty : b ty) : b expr =
  match op, arg_ty, ret_ty with
  | '+', TyInt, TyInt -> Add (l, r)
  | '<', TyInt, TyBool -> Lt (l, r)
  | '&', TyBool, TyBool -> And (l, r)
  | _, _, _ -> assert false

At some point you are going to want to have a value that can be 'any expression'. Introducing an existential wrapper allows this. Cheesy example: generating random expression trees:

type any_expr = Any : _ expr -> any_expr

let rec random_int_expr () =
  if Random.bool () then Num (Random.int max_int)
  else Add (random_int_expr (), random_int_expr ())

let rec random_bool_expr () =
  if Random.bool () then Lt (Num (Random.int max_int), Num (Random.int max_int))
  else And (random_bool_expr (), random_bool_expr ())

let random_expr () =
  if Random.bool () then Any (random_int_expr ())
  else Any (random_bool_expr ())

Your stated type for create_expr is char -> 'a expr -> 'a expr -> 'a expr. But the type for the '>' case would be char -> int expr -> int expr -> bool expr. So it seems there are problems with the basic plan.

In essence you want the type of the result to depend on the value of the character. I'm not absolutely positive, but I suspect this isn't possible in OCaml. Seems like it would require a more powerful type system.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!