1

我正在玩这段代码,但我不明白。

type t1 = [ `A ];;
type t2 = [ t1 | `B ] ;;
type t3 = [ t2 | `C ] ;;

module type MT =
sig
  type ('a,'b) fct
  val create : ('a -> 'b) -> ('a,'b) fct
end;;

module Mt : MT =
struct
    type ('a,'b) fct = 'a -> 'b
    let create f = f
end;;

let f = (fun x -> x : t2 -> t2) ;;
let af = Mt.create (fun x -> x : t2 -> t2);;

(f :> t1 -> t3);;
(af :> (t1, t3) Mt.fct);;

像这样它不起作用,因为编译器不知道 Mt.fct 的类型参数是协变的还是逆变的。但是,如果您将模块签名中的类型声明替换为:

type (-'a,'+b) fct

告诉编译器 b 是协变和逆变的,现在它可以工作了。而且因为我是一个棘手的小烦人的男孩,我试图通过告诉编译器 a 也是协变的来欺骗编译器!

type (+'a,'+b) fct

他虽然比我聪明,但他注意到我在对他撒谎。

Type declarations do not match:
         type ('a, 'b) fct = 'a -> 'b
       is not included in
         type (+'a, +'b) fct
       Their variances do not agree.

我的问题是:如果他无论如何都知道类型参数的差异,为什么不将它用于我的模块,而不是强迫我添加那些 + 和 -。这又是一个可判定性问题吗?

4

2 回答 2

3

类型归属 Mt : MT 是不透明的。因此编译器不能使用关于类型定义的信息,因为您可以随时更改定义(可以单独编译)。要看到这个,如果你这样做

module type MT =
sig
  type ('a,'b) fct = 'a -> 'b
  val create : ('a -> 'b) -> ('a,'b) fct
end;;

然后你写的代码编译得很好。

于 2013-08-01T23:18:40.453 回答
0

虽然编译器可以检查您的类型在特定参数位置实际上是协变的还是逆变的,但它不会立即假定这是您希望在抽象类型中公开的信息。毕竟,一旦编译器知道参数的变化,那么它将被允许根据需要对该参数执行强制转换——这可能根本不是您公共 API 的一部分!

于 2015-02-16T02:12:18.817 回答