多态变体和方差

时间:2014-04-01 10:23:16

标签: polymorphism ocaml variance

我正在尝试在OCaml中创建一个过程对象语言系统。一般的想法是将多态变体的值存储在一个数组中,让程序更新这个数组(命令性地):

module StrMap = Map.Make(String) 

module IntMap = Map.Make(struct type t = int let compare = compare end)

(* store generic labeled objects *)
type 'a env = ([> ] as 'a) IntMap.t

(* a procedure working on such an object array *)
type 'a procedure = 'a env -> 'a env

(* store procedures *)
type 'a proc_table = ('a procedure) StrMap.t

let do_iinc = function 
  | `Int n -> `Int (n+1)

let iinc x env = 
  let v = do_iinc (IntMap.find x env) in 
  IntMap.add x v env

let do_finc = function 
  | `Float f -> `Float (f +. 1.0)

let finc x env = IntMap.add x (do_finc (IntMap.find x env)) env

(* type error :( *)
let table  = 
  StrMap.add "iinc" (iinc 0)
         (StrMap.add "finc" (finc 1)
                 StrMap.empty)

这让我很困惑。我的“更新”对于具体类型是不变的。 OCaml不应该能够找出该表:([`Float of float ; `Int of int ] procedure) StrMap.t

我怀疑问题与地图的方差有关,但我没有确认,因为我无法使用具体的多态变体注释该类型。

我的想法在OCaml中是否可行?

2 个答案:

答案 0 :(得分:1)

我不清楚你要做什么,但对我来说看起来不安全。

您的finc 1没有您建议的类型[`Float of float ; `Int of int ] procedure,其类型[`Float of float ] procedure相当于[`Float of float] IntMap.t -> [`Float of float] IntMap.t

这是因为您应用于参数成员do_finc的{​​{1}}函数只知道如何处理env - 它没有[`Float of float]的情况}。

如果[`Int of int]具有您想要的类型,请考虑以下表达式中会发生什么:

table

答案 1 :(得分:1)

此功能的类型:

let do_finc = function 
  | `Float f -> `Float (f +. 1.0)

[< `Float of float ] -> [> `Float of float ]。换句话说,它将最多一个`Float替换的任何变体类型作为输入;即,要么有`Float替代,要么根本没有替代。在我看来,您希望该函数适用于至少 `Float替代的变体,即具有`Float和任意数量的其他变体的变体:< / p>

let do_finc = function 
  | `Float f -> `Float (f +. 1.0)
  | _ -> failwith "wanted a float"

如果我以这种方式更改do_iincdo_finc,则表格的类型更接近您想要的类型。

我不确定您的计划是否有效,因为您可能期望OCaml接受类型错误的程序并在运行时抱怨。相反,OCaml在编译时抱怨,你可能不得不编写自己的代码在运行时抱怨:-)但这可能有助于解决第一个问题。