Types 变体还是多态性变体?

Types 变体还是多态性变体?,types,programming-languages,functional-programming,ocaml,ml,Types,Programming Languages,Functional Programming,Ocaml,Ml,我注意到,在我认识的OCaml程序员中,有些人总是使用多态变量(未声明的变量,前缀为反引号),而其他人从不使用多态变量,更喜欢在类型中声明的变量 除了性能方面的原因(多态变体目前的编译效率低于简单变体),OCaml专家开发人员如何在它们之间进行选择?我在大多数模块接口中使用多态变体的唯一原因是为了解决经典变体的命名问题 如果以下方法可行,多态性变体在大多数情况下将不再有用: type t1 = String of string | Int of int | Bool of bool | List

我注意到,在我认识的OCaml程序员中,有些人总是使用多态变量(未声明的变量,前缀为反引号),而其他人从不使用多态变量,更喜欢在类型中声明的变量


除了性能方面的原因(多态变体目前的编译效率低于简单变体),OCaml专家开发人员如何在它们之间进行选择?

我在大多数模块接口中使用多态变体的唯一原因是为了解决经典变体的命名问题

如果以下方法可行,多态性变体在大多数情况下将不再有用:

type t1 = String of string | Int of int | Bool of bool | List of t1 list type t2 = String of string | Int of int | Other let simplify x = match (x : t1) with String s -> String s | Int n -> Int n | Bool _ | List _ -> Other t1类型=字符串的字符串| Int of Int | Bool of Bool | t1列表的列表 类型t2=字符串的字符串| Int of Int |其他 让我们简化x= 将(x:t1)与 字符串s->字符串s |Int n->Int n |布尔_ |列表->其他
2014-02-21更新:上述代码现在在OCaml 4.01中有效。万岁

我的用法可分为以下5类。1.接口2。模块化3。易读性4。简短5。诡计

  • 如果变量类型只是模块内部的,我使用常规变量,因为正如您所说的,它们的编译效率更高
  • 如果在接口中导出变量类型,并且我觉得某些情况可能会出现在其他模块中,但使它们依赖于模块并不一定有意义,我使用多态变量,因为它们不绑定到模块名称空间系统。示例:
    Xmlm
    的类型。将作为变量类型也意味着您可以使用相同的XML处理思想开发模块,而无需引入对
    Xmlm
    的依赖
  • 如果在接口中导出变量类型,我发现当变量类型的值被赋予模块的函数时,使用常规变量有时过于冗长。示例:
    Uuidm
    的。您不必编写
    Uuidm.create Uuidm.V4
    ,只需编写
    Uuidm.create`V4
    ,它同样清晰且不太冗长
  • 有时,特定函数可能返回不同的情况。如果这些情况仅由该函数使用,我将在接口中声明函数类型,而不必引入类型定义。例如
    parse:string->[`Error of string | `Ok of t]
  • 多态变体及其子类型允许您静态地对幻影类型强制执行不变量。此外,增量定义不变量的可能性对于静态强制不变量和文档编制都很有用
    最后,根据第4条,我有时在模块的实现中使用多态变体。但是界面上没有显示它们。我不鼓励这种用法,除非您声明多态变体并关闭它们,因为它削弱了静态类型规则

    多态性变体并不总是效率较低。以马丁为例:

    type base = [`String of string | `Int of int]
    type t1 = [base | `Bool of bool | `List of t1 list]
    type t2 = [base | `Other]
    
    let simplify (x:t1):t2 = match x with
    | #base as b -> b
    | `Bool _ | `List _ -> `Other
    
    要对标准变体执行此操作,需要两种不同的类型和完整的重新编码,对于多态变体,基本情况是物理不变的。当使用开放递归进行术语重写时,此功能真正发挥了作用:

    type leaf = [`String of string | `Int of int]
    type 'b base = [leaf | `List of 'b list]
    type t1 = [t1 base | `Bool of bool ]
    type t2 = [t2 base | `Other]
    
    let rec simplify (x:t1):t2 = match x with
    | #leaf as x -> x
    | `List t -> `List (List.map simplify t)
    | `Bool _ -> `Other
    
    当重写函数也考虑了开放递归时,优势就更大了

    不幸的是,Ocaml的Hindley-Milner类型推断不足以在没有显式类型的情况下完成这类工作,这需要对类型进行仔细的因式分解,这反过来又使得原型类型很困难。此外,有时还需要显式强制


    这种技术的最大缺点是,对于具有多个参数的术语,很快就会出现相当混乱的类型组合爆炸,最终更容易放弃静态强制,使用带有通配符和异常(即动态键入)的厨房水槽类型。

    我认为首选名称是“开放变体”现在,“开放变体”显然比“多态变体”更容易直观理解。我认为“开放变体”更准确地指的是像
    exn
    这样的类型。显而易见:普通ADT在类型方面并不完全等同于多态变体:如果你需要后者的特定属性,显然你必须使用它们(即,在数据类型中重叠枚举集,通过行多态性进行子类型划分)。真实世界的Ocaml有一个非常棒的总结。这应该在一些常见问题解答中。为了让我之后的读者了解何时使用多态变体这一主题:Martin的示例在Ocaml 4.01中终于合法了。高兴吧!