开放对象类型过早统一

时间:2016-05-11 23:58:31

标签: types ocaml

我有一个很大的let块来处理大量的计算,我试图通过将其中的块分解为函数来将其分解为更小的块。我需要将一个对开放对象进行操作的函数传递给那些组件,并且遇到下面简化代码中最好表达的烦恼:

type 'a foo = 'a
  constraint 'a = < bar: string option; .. >

type foo' = < bar: string option; >

type bar = < bar: int option; qux: int option >

type ('a, 'b) fn = 'a foo -> 'b foo

let a = object method bar = None method qux = None end
let b = object method bar = None end

(* Doesn't work *)
let xyz fn =
  let res = fn a in
  let res' = fn b in
  res, res'

(* Doesn't work *)
let xyz (fn:('a, 'b) fn) =
  let res = fn a in
  let res' = fn b in
  res, res'

(* Doesn't work *)
type fn' = foo' -> foo'
let xyz (fn:fn') =
  let res = fn a in
  let res' = fn b in
  res, res'

(* Sub-par solution: imagine needing several of these conversions across several
   functions, which is the situation I have when trying to decompose a large let
   block into component functions like xyz. *)
let xyz (fn:('a, 'b) fn) =
  let res = fn (a :> foo') in
  let res' = fn b in
  res, res'

(* Another sub-par solution: *)
type ('a, 'b) fn'' = { fn: 'a. 'a foo -> 'b foo }
let xyz (fn:('a, 'b) fn'') =
  let fn = fn.fn in
  let res = fn a in
  let res' = fn b in
  res, res'

(* What I want: *)
type ('a, 'b) fn''' = 'a. 'a foo -> 'b foo
let xyz (fn:('a, 'b) fn''') =
  let res = fn a in
  let res' = fn b in
  res, res'


(* What I am currently using (don't pass the function around to HOFs: keep the
   computation all in a massive let statement. *)
let _ =
  let a : foo = object method bar = None method qux = None end in
  let b : bar = object method bar = None end in
  let fn a = object method bar = a#bar method qux = None end in
  (* fn gets the correctly inferred type of < bar : 'a; .. > -> < bar : 'a; qux : 'b option > *)
  fn a, fn b

任何指导,或仅仅是为什么我想要的原因是不可能的/保证现在确实可能/承诺有一天 - 在一个更光明的世界 - 这将起作用,将非常感激。

1 个答案:

答案 0 :(得分:4)

你想要的是在定义中多态地使用函数参数:即将fn应用于xyz内的两个不同对象类型的值。这称为Rank-2多态(https://wiki.haskell.org/Rank-N_types),但在Hindley Milner类型系统中不支持(它只能处理Rank-1)。 OCaml基于Hindley Milner,也不直接支持Rank-N。

目前OCaml对Rank-2多态性的支持非常间接:通过多态记录成员进行模拟,没有任何类型推断。我想你的“另一个低于标准的解决方案”是最好的方式。