Reputation: 16392
I have a large let
block which handle a lot of computation, and I'm trying to break it down into smaller pieces by factoring out chunks of it into functions. I need to pass a function which operates on open objects to those components, and am running into annoyances best expressed in the simplified code below:
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
Any guidance, or just reasons as to why what I want is impossible/assurance that it is indeed possible right now/promises that one day—in a brighter world—this will work, would be much appreciated.
Upvotes: 3
Views: 133
Reputation: 9040
What you want is to use function arguments polymorphically inside the definition: i.e. applying fn
to two values of different object types inside xyz
. This is called Rank-2 polymorphism (https://wiki.haskell.org/Rank-N_types) but is not supported in Hindley Milner type system (it can only handle Rank-1). OCaml is based on Hindley Milner and does not support Rank-N directly either.
Currently OCaml support of Rank-2 polymorphism is very indirect: simulation via polymorphic record members, without any type inference. I guess your "Another sub-par solution" is the best way here.
Upvotes: 4