变体与GADT方法

时间:2018-02-20 11:22:12

标签: ocaml variant gadt

在OCaml中,我想定义一个函数f,它接受​​input来更新记录x。在以下两种方法中,我很感兴趣一种方法是否优于另一种方法(可读性除外)。

变体方法

type input =
  | A of int
  | B of string

let f x = function
  | A a -> { x with a }
  | B b -> { x with b }

GADT方法

type _ input =
  | A : int input
  | B : string input

let f (type t) x (i: t input) (v: t) =
  match i with
  | A -> { x with a = v }
  | B -> { x with b = v }

2 个答案:

答案 0 :(得分:2)

ADT专业人士:

  • 直截了当,不需要类型注释或任何花哨的东西
  • 编写string -> input类型的函数非常简单。

GADT专业人士:

  • 避免一层拳击。
    但是,如果您需要一个解析函数,这将被完全否定,这将迫使您将内容打包在存在主义之下。

更准确地说,GADT版本可以看作是ADT版本的分解。您可以系统地将一个转换为另一个,并且内存布局将类似(借助于小注释):

type a and b and c

type sum =
  | A of a
  | B of b
  | C of c

type _ tag =
  | A : a tag
  | B : b tag
  | C : c tag

type deppair = Pair : ('a tag * 'a) -> deppair [@@ocaml.unboxed]

let pack (type x) (tag : x tag) (x : x) = Pair (tag, x)
let to_sum (Pair (tag, v)) : sum = match tag with
  | A -> A v
  | B -> B v
  | C -> C v

let of_sum : sum -> deppair = function
  | A x -> pack A x
  | B x -> pack B x
  | C x -> pack C x

答案 1 :(得分:0)

正如您注意到GADT的(非)可读性是一个很大的缺点。尽可能避免GADT。更容易打字和更容易阅读。不太复杂的错误消息。

在运行时简化它们是相同的。它们表示为带有标记和字段的简单整数或块,代码使用标记进行匹配和分支。所以两者都没有给你带来优势。

在编译时,GADT更强大,因为编译器可以用ADT不允许的方式检查类型。一个例子是存在类型,如另一个答案中的例子。因此,当您无法使用ADT时,请使用GADT。