如何命名 OCaml 变体中的字段?

How can I name fields in an OCaml variant?

具有很多字段的变体开始变得笨拙。每个字段的作用在注释中结束:

type ty =
  | FunTy of (*all*) ty list * (*params*) ty list * (*return type*) ty
  ...

一个解决方案是将变体的值作为记录。

type ty =
  | FunTy of ft
  ...
and ft = {
  forall : ty list;
  p_tys : ty list;
  ret_ty : ty
}

但是,需要间接引用记录字段。这对我的目的来说并不重要,但我可以看到这种性能差异使得重构在实践中变得不合常理。

为了使这个答案保持客观,参考 OCaml 文档或风格指南会有所帮助。

这是风格问题,所以我会记下我对此的看法。

对于这个特定的示例,我们可以选择使用元组或记录指定 Variant 构造函数,即使我认为对于太多字段,也应该使用记录。

无论是元组还是记录,无论如何模式匹配都足够了。

无论是tuple还是record,在处理values的时候都会指定所有字段。

然而,真正的优势来自处理太多字段的记录,因为

  1. 记录字段通过键标识,更方便管理,字段无序处理,更好地掌握在作者手中。
  2. 元组字段是有序的,这意味着作者在处理元组数据时必须小心

虽然元组在内存方面会更少,但是当字段数量变大时,记录确实有优势。

此观点仅针对元组或记录。任何其他组合,可能会遵循不同的意见......与我不同。 :-)

从 OCaml 4.03(2016 年发布)开始,您可以使用 inline records,它为您提供了记录语法的漂亮接口——此外,您可以拥有可变字段——具有与元组相同的内存表示语法。

type ty =
  | FunTy of {
      forall : ty list;
      p_tys : ty list;
      ret_ty : ty
    }
  ...

您可以使用一些工具来操作包含的记录,但是(与元组语法中的参数“元组”没有区别)它不是第一个 class 值(有关更多信息,请参见上面链接的文档详情)。

当您看到构造函数采用许多参数的变体类型时,您可能希望考虑以另一种方式使用更多间接。考虑一个简单的、人为的例子,指定一个类型来构建一个三角形。我们需要在 2D 或 3D space.

中存储每个角的坐标
type triangle = 
  Triangle_2d of float * float * (* Point A *) 
                 float * float * (* Point B *)
                 float * float   (* Point C *)
| Triangle_3d of float * float * float * (* Point A *)
                 float * float * float * (* Point B *)
                 float * float * float   (* Point C *)

谈论笨拙。所以让我们使用记录。

type triangle = 
  Triangle_2d of { ax : float; ay : float; 
                   bx : float; by : float;
                   cx : float; cy : float }
| Triangle_3d of { ax : float; ay : float; az : float;
                   bx : float; by : float; bz : float;
                   cx : float; cy : float; cz : float }

但是仔细想想,我们不就是指定坐标吗?所以也许我们应该创建一个坐标类型。

type coordinate = 
  Coord_2d of { x : float; y : float }
| Coord_3d of { x : float; y : float; z : float }

然后我们的三角形类型就是:

type triangle = 
  Triangle_2d of { a : coord; b : coord } 
| Triangle_3d of { a : coord; b : coord; c : coord }

甚至:

type triangle = 
  Triangle_2d of coord * coord 
| Triangle_3d of coord * coord * coord

确实看起来更清晰了,但它也让我们把问题分解成更小的部分。如果我想计算三角形上两个顶点之间的距离,我不需要对整个三角形进行数学运算。我可以简单的定义一个函数来处理坐标,我可以在这一层处理2D和3D坐标的区别。我什至可以将其分解并编写将 3D 坐标投影到给定轴或平面上的函数。