"constructors" 的 OCaml 命名约定是什么?
What's the OCaml naming convention for "constructors"?
一个OCaml模块通常至少包含一个抽象类型,其惯用名称是t
。此外,通常有一个函数可以构造该类型的值。
这个的常用/惯用名称是什么?
这里的标准库不一致。例如:
- 有
Array.make
和一个已弃用的函数 Array.create
。所以该函数应该命名为 make
?
- 另一方面,有
Buffer.create
但没有 Buffer.make
。所以该函数应该命名为 create
?
我很久以前学习这门语言时也有过同样的问题。我从不使用 make
,而且我认为很少有人使用。
如今,我将 create
用于繁重的、通常是命令式或有状态的值,例如Unicode text segmenter. And I use v
for, functional, lighter values in DSL/combinator based settings, e.g. the various constructors in Gg, for example for 2D vectors, or colors.
正如 camlspotter 在他的回答中提到的那样,标准库将 make
和 create
区分为需要填写初始值的值。我认为最好在这里保持常规并始终使用 create
不管怎样。如果您的值支持可选的初始填充值,请向 create
添加一个可选参数,而不是乘以 API 入口点。
有些人发现这种模块设计方式使 OCaml 编程更容易,但这不是强制性的 OCaml 编程风格,我认为它没有正式名称。我个人称其为“1-data-type-per-1-module”风格。 (我写了a blog post about this但是是日文的,希望有自动翻译器能给你一些有用的信息...)
定义一个专用于一种数据类型的模块并修复该类型的名称t
有一些值:
不错的命名空间
模块名称解释了它的类型和值是什么,因此您不需要在内部重复类型名称:Buffer.add_string
而不是 add_string_to_buffer
,Buffer.create
而不是 create_buffer
。您还可以避免在本地模块打开时键入相同的模块名称:
let f () =
let open Buffer in
let b = create 10 in (* instead of Buffer.create *)
add_string b "hello"; (* instead of Buffer.add_string *)
contents b (* instead of Buffer.contents *)
简单的 ML 函子应用程序
如果 ML 仿函数采用具有数据类型的参数模块,我们有一个约定,该类型应该被称为 t
。数据类型为 t
的模块无需重命名类型即可轻松应用于这些函子。
对于Array.create
和Array.make
,我认为这是为了区分String.create
和String.make
。
String.create
是创建一个未初始化内容的字符串。创建的字符串包含随机字节。
String.make
是创建一个用给定的 char
. 填充的字符串
我们已经 Array.create
很久了,以创建一个数组,其内容填充给定值。此行为对应于 String.make
而不是 String.create
。这就是为什么它现在重命名为 Array.make
,而 Array.create
已过时。
我们不能在 OCaml 中让 Array.create
具有与 String.create
相同的行为。与字符串不同,数组不能在没有初始化的情况下创建,因为随机字节通常可能不代表内容的有效 OCaml 值,这会导致程序崩溃。
在此之后,我个人使用 X.create
作为函数来创建一个不需要初始值来填充的 X.t
。如果需要填充,我使用 X.make
。
一个OCaml模块通常至少包含一个抽象类型,其惯用名称是t
。此外,通常有一个函数可以构造该类型的值。
这个的常用/惯用名称是什么?
这里的标准库不一致。例如:
- 有
Array.make
和一个已弃用的函数Array.create
。所以该函数应该命名为make
? - 另一方面,有
Buffer.create
但没有Buffer.make
。所以该函数应该命名为create
?
我很久以前学习这门语言时也有过同样的问题。我从不使用 make
,而且我认为很少有人使用。
如今,我将 create
用于繁重的、通常是命令式或有状态的值,例如Unicode text segmenter. And I use v
for, functional, lighter values in DSL/combinator based settings, e.g. the various constructors in Gg, for example for 2D vectors, or colors.
正如 camlspotter 在他的回答中提到的那样,标准库将 make
和 create
区分为需要填写初始值的值。我认为最好在这里保持常规并始终使用 create
不管怎样。如果您的值支持可选的初始填充值,请向 create
添加一个可选参数,而不是乘以 API 入口点。
有些人发现这种模块设计方式使 OCaml 编程更容易,但这不是强制性的 OCaml 编程风格,我认为它没有正式名称。我个人称其为“1-data-type-per-1-module”风格。 (我写了a blog post about this但是是日文的,希望有自动翻译器能给你一些有用的信息...)
定义一个专用于一种数据类型的模块并修复该类型的名称t
有一些值:
不错的命名空间
模块名称解释了它的类型和值是什么,因此您不需要在内部重复类型名称:Buffer.add_string
而不是 add_string_to_buffer
,Buffer.create
而不是 create_buffer
。您还可以避免在本地模块打开时键入相同的模块名称:
let f () =
let open Buffer in
let b = create 10 in (* instead of Buffer.create *)
add_string b "hello"; (* instead of Buffer.add_string *)
contents b (* instead of Buffer.contents *)
简单的 ML 函子应用程序
如果 ML 仿函数采用具有数据类型的参数模块,我们有一个约定,该类型应该被称为 t
。数据类型为 t
的模块无需重命名类型即可轻松应用于这些函子。
对于Array.create
和Array.make
,我认为这是为了区分String.create
和String.make
。
String.create
是创建一个未初始化内容的字符串。创建的字符串包含随机字节。String.make
是创建一个用给定的char
. 填充的字符串
我们已经 Array.create
很久了,以创建一个数组,其内容填充给定值。此行为对应于 String.make
而不是 String.create
。这就是为什么它现在重命名为 Array.make
,而 Array.create
已过时。
我们不能在 OCaml 中让 Array.create
具有与 String.create
相同的行为。与字符串不同,数组不能在没有初始化的情况下创建,因为随机字节通常可能不代表内容的有效 OCaml 值,这会导致程序崩溃。
在此之后,我个人使用 X.create
作为函数来创建一个不需要初始值来填充的 X.t
。如果需要填充,我使用 X.make
。