Functional programming 抽象型协变/逆变

Functional programming 抽象型协变/逆变,functional-programming,ocaml,covariance,contravariance,typing,Functional Programming,Ocaml,Covariance,Contravariance,Typing,我在玩这个代码,我不懂一些东西 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 cre

我在玩这个代码,我不懂一些东西

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.

我的问题是:如果他知道类型参数的变化,为什么不把它用于我的模块,而不是强迫我添加+和-。这又是一个可判定性问题吗

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

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

那么你写的代码就可以编译了

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

我知道如果你用这种签名写一个函子,他不可能知道。但是这里我有一个实现,他可以知道我的类型有什么不同。问题是它实际上没有实现。例如,您可以将实现放在另一个文件中,单独编译它,然后编译器实际上只有接口可以继续。当一个程序被分割成不同的文件时,您不会希望它编译失败,但当它在同一个文件中时,您不会希望它编译失败。编译器在(不透明的)签名归属期间确实隐藏了实现。对于
A,
B来说,`for`是什么?这是定义多态变体的方式。这几乎类似于执行类型t=A | B,只是您可以使用A和B创建其他类型,从而创建子类型。