OCaml函子::违反直觉的行为 [英] OCaml functors :: counter-intuitive behaviour

查看:99
本文介绍了OCaml函子::违反直觉的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用OCaml(3.12.1)的模块语言,为模块定义函子和签名,等等,主要是按照

I am experimenting with the module language of OCaml (3.12.1), defining functors and signatures for modules and so on, mostly following the examples from Chapter 2 of the OCaml manual and I've stumbled, by accident, on a situation where apparently my mental model of how functors and module signatures work is flawed. I tried to narrow the situation I encountered to the shortest amount of code possible so don't ask what I am trying to accomplish, this is a totally contrived example to demonstrate the OCaml feature in question.

因此,我们有一个函子,该函子仅提供标识函数'f',并由提供该函数输入参数类型的模块进行参数化.像我说的那样完全是人为的例子.

So, we have a functor that simply provides an identity function 'f' and is parametrized by a module supplying the type of that function's input parameter. Totally contrived example like I said.

module type SOMETYPE = sig type t end ;;
module Identity = functor (Type: SOMETYPE) -> struct let f (x: Type.t) = x end ;;

鉴于上述情况,我们继续定义一个提供int类型的模块:

Given the above, we proceed to define a module to supply the int type:

module IntType = struct type t = int end ;;

..然后我们使用函子为int身份函数生成一个模块:

.. and then we use the functor to generate a module for the int identity function:

module IdentityInt = Identity(IntType) ;;                     

确定生成的模块及其f函数的行为符合预期:

Sure enough the generated module and its f function behave as expected:

#IdentityInt.f(3) + 10 ;;
- : int = 13

函子的心理模型是将模块作为输入和返回模块的函数,到目前为止似乎对我们有用. Identity函子希望将签名(模块类型)SOMETYPE的模块作为输入参数,并且确实我们提供的模块(IntType)具有正确的签名,因此将生成一个有效的输出模块(IdentityInt),其函数的行为符合预期.

The mental model of functors being functions that take modules as inputs and return modules seems to be serving us right so far. The Identity functor expects as input parameter a module of signature (module type) SOMETYPE, and indeed the module we supplied (IntType) has the correct signature and so a valid output module is produced (IdentityInt) whose f function behaves as expected.

现在出现了非直觉的部分.如果我们想明确说明所提供的模块IntType确实是SOMETYPE类型的模块,该怎么办.如:

Now comes the un-intuitive part. What if we would like to make it explicit that the supplied module IntType is indeed a SOMETYPE type of module. As in:

module IntType : SOMETYPE = struct type t = int end ;;

,然后以与以前相同的方式生成函子的输出模块:

and then generate the functor's output module the same way as before:

module IdentityInt = Identity(IntType) ;;

...让我们尝试使用新生成的模块的f功能:

... let's try to use the f function of the newly generated module:

IdentityInt.f 0 ;;

REPL对此投诉:

"Error: This expression [the value 0] has type int but an expression was expected of type IntType.t."

如何提供冗余但正确的类型信息会破坏代码?即使在情况A中,函子模块Identity也必须将IntType模块视为SOMETYPE类型.那么,如何明确声明IntTypeSOMETYPE类型会产生不同的结果呢?

How can providing redundant but correct type information break the code? Even in case A the functor module Identity had to treat the IntType module as SOMETYPE type. So how come explicitly declaring IntType to be SOMETYPE type yields a different outcome ?

推荐答案

:构造在核心语言和模块语言方面有所不同.在核心语言中,它是一个注释构造.例如,((3, x) : 'a * 'a list)约束表达式具有某种类型,该类型是'a * 'a list的实例.由于该对中的第一个元素是整数,因此let (a, b) = ((3, x) : 'a * 'a list) in a + 1的类型正确.模块上的:构造并不意味着这个.

The : construct is different in the core language and in the module language. In the core language, it is an annotation construct. For example, ((3, x) : 'a * 'a list) constrains the expression to have some type that is an instance of 'a * 'a list; since the first element of the pair is an integer, let (a, b) = ((3, x) : 'a * 'a list) in a + 1 is well-typed. The : construct on modules does not mean this.

构造M : S 密封模块到签名S.这是不透明的印章:键入M : S时,只有签名S中给出的信息仍然可用.当您编写module IntType : SOMETYPE = struct type t end时,这是

The construct M : S seals the module M to the signature S. This is an opaque seal: only the information given in the signature S remains available when typing uses of M : S. When you write module IntType : SOMETYPE = struct type t end, this is an alternate syntax for

module IntType = (struct type t end : SOMETYPE)

由于未指定SOMETYPE中的类型字段t,因此IntType具有抽象类型字段t:类型IntType是由该定义生成的新类型.

Since the type field t in SOMETYPE is left unspecified, IntType has an abstract type field t: the type IntType is a new type, generated by this definition.

顺便说一句,您可能是说module IntType = (struct type t = int end : SOMETYPE);但无论哪种方式,IntType.t都是抽象类型.

By the way, you probably meant module IntType = (struct type t = int end : SOMETYPE); but either way, IntType.t is an abstract type.

如果要指定某个模块具有某些签名,同时使某些类型保持公开状态,则需要为这些类型添加显式的相等性.没有添加所有可推断的相等性的构造,因为对模块应用签名通常意味着信息隐藏.为了简单起见,该语言仅提供了这一生成密封结构.如果要使用定义的签名SOMETYPE并保留类型t的透明度,请向签名添加约束:

If you want to specify that a module has a certain signature while leaving some types exposed, you need to add an explicit equality for these types. There's no construct to add all inferable equalities, because applying a signature to a module is usually meant for information hiding. In the interest of simplicity, the language only provides this one generative sealing construct. If you want to use the defined signature SOMETYPE and retain the transparency of the type t, add a constraint to the signature:

module IntType = (struct type t = int end : SOMETYPE with type t = int)

这篇关于OCaml函子::违反直觉的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆