我正在尝试在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中是否可行?
答案 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_iinc
和do_finc
,则表格的类型更接近您想要的类型。
我不确定您的计划是否有效,因为您可能期望OCaml接受类型错误的程序并在运行时抱怨。相反,OCaml在编译时抱怨,你可能不得不编写自己的代码在运行时抱怨:-)但这可能有助于解决第一个问题。