我正在试验OCaml(3.12.1)的模块语言,定义模块的函子和签名等等,主要是遵循Chapter 2 of the OCaml manual的例子,我偶然发现了意外,在这种情况下,显然我的心智模型如何运算符和模块签名的工作是有缺陷的。我试图缩小我遇到的最短代码量的情况,所以不要问我想要完成什么,这是一个完全人为的例子来演示OCaml特性。OCaml函子::反直觉行为
因此,我们有一个函数,它只是提供了一个标识函数'f',并通过提供该函数输入参数类型的模块进行参数化。像我说的那样完全做作的例子。
module type SOMETYPE = sig type t end ;;
module Identity = functor (Type: SOMETYPE) -> struct let f (x: Type.t) = x end ;;
鉴于上述情况,我们进行到定义一个模块提供int类型:
module IntType = struct type t = int end ;;
..然后我们使用仿函数来生成用于INT标识功能的模块:
module IdentityInt = Identity(IntType) ;;
果然产生模块及其f函数像预期的那样:
#IdentityInt.f(3) + 10 ;;
- : int = 13
函子的心智模型是将模块作为输入和返回模块的函数,目前为止我们似乎正在为我们服务。仿函数Identity
期望作为签名模块(模块类型)SOMETYPE的输入参数,实际上我们提供的模块(IntType
)具有正确的签名,因此会生成一个有效的输出模块(IdentityInt
),其函数的行为与预期相同。
现在是不直观的部分。如果我们想明确指出提供的模块IntType
确实是SOMETYPE类型的模块,该怎么办?如:
module IntType : SOMETYPE = struct type t = int end ;;
,然后生成仿函数的输出模块的方式和以前一样:
module IdentityInt = Identity(IntType) ;;
...让我们尝试用新生成的模块的f
功能:
IdentityInt.f 0 ;;
因此,REPL抱怨:
"Error: This expression [the value 0] has type int but an expression was expected of type IntType.t."
如何提供冗余但正确的类型信息破坏代码?即使在情况A中,功能模块身份必须将IntType
模块视为SOMETYPE
类型。那么如何明确宣布IntType
为SOMETYPE
类型会产生不同的结果?
第二个'module IntType'是否缺少'= int'部分? – Ptival 2012-03-19 22:39:04
不,这是我的REPL复制粘贴表单上的拼写错误。第二个模块IntType正确地读取:'module IntType:SOMETYPE = struct type t = int end',您将得到与上述相同的结果。我会编辑帖子以避免任何误解。 – 2012-03-20 07:41:30