OCaml中的模块化编程

5
我在处理一个ocaml项目时发现了一些我不太理解的东西。
假设我同时使用OCaml标准库中的Array和List模块。它们都实现了函数length,但类型不同。 在List模块中,它的类型如下:
length: a' list -> int

Array模块中,它的类型为:

length: a' array -> int

但是我想通过使用 open 关键字,在同一个模块中同时使用这两个模块:

open List
open Array

当我尝试在列表上使用length函数时,编译过程中出现了类型错误。
由于OCaml是一种强静态类型语言,所以我想知道为什么编译器不知道我想使用列表模块的长度函数,因为我声明我正在使用两个模块。

1
“我在想为什么编译器不知道我想要使用列表模块的长度函数,因为我声明了我要使用两个模块。” 是的,但在这种情况下,“fun s -> length s”的类型会是什么? - Pascal Cuoq
根据jrouquie的答案,它将是a'数组-> int - Joseph Elcid
1
确切地说,在假设的 OCaml 编译器中,如果尝试猜测,那么在 OCaml 类型系统中,该函数将没有单一最普遍的类型。您可能会对 Haskell 的解决方案感兴趣,即类型类:http://www.haskell.org/tutorial/classes.html - Pascal Cuoq
@PascalCuoq:你可以使用functors和模块类型在OCaml中实现Haskell的功能,只是你需要手动指定类型类的实例而不是被推断出来。 - newacct
1个回答

8

OCaml不会根据函数的类型选择其中一个。

当您编写代码时,

open Array

模块 Array 的函数将与同名的模块 List 中的函数屏蔽。 当您稍后调用函数 length 时,OCaml 查找名为 length 的函数,找到 Array.length 并抱怨此函数没有兼容的类型。
通常的方式是,如果需要该函数,则调用 List.length(而不仅仅是 length)。
总体而言,OCaml 没有名称重载(即具有相同名称但不同参数类型的两个函数或运算符),尤其是因为这会使类型推断变得更加困难。

2
另外,尽量避免打开模块——这会使阅读代码变得更加困难,因为读者必须记住哪些模块是打开的(以及它们的顺序);同时作为读者,你不会立即意识到一个函数来自哪个打开的模块。 - lambdapower
2
我想强调的是,如果所使用的值/函数的来源仍然清晰明了,那么打开模块是可以接受的。因此,不要打开像“List”或“Array”这样提供带有通用名称的函数的模块,但是打开“Printf”就完全没问题,因为它提供的函数printf、fprintf等其来源显而易见。 - Martin Jambon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接