I’m still struggling with some dark parts of the type system in OCaml.
In particular, I am trying to model a specific kind of delayed computation, and I’m encountering some issues with unbound types getting out of scope. I am guessing there’s a way of fixing it but I can’t find it.
Here’ s a very simplified version of what I’m trying to do :
type 'a t = | Done : 'a -> 'a t | Delayed : (unit -> 'a t) -> 'a t | Chained : 'a t * ('a -> 'b t) -> 'b t
This type would come with the proper functions :
let return x = Done x let delay f = Delayed f let bind x f = Chained (x, f) let (let*) = bind
That would let me do something like
let five : int t = let* three = delay (fun () -> let y = 1 in let z = 2 in delay (fun () -> return (y + z))) in return (three + 2)
and then a function that is called
resolve and lets me do something like
let x : int = resolve five (* x is the int 5 *)
However, the implementation of resolve is not compiling :
let rec resolve : 'a t -> 'a = function | Done x -> x | Delayed f -> resolve (f ()) | Chained (x, f) -> resolve (f (resolve x))
File "bin/test.ml", line 9, characters 42-43: 9 | | Chained (x, f) -> resolve (f (resolve x)) ^ Error: This expression has type $Chained_'a t but an expression was expected of type 'a t The type constructor $Chained_'a would escape its scope
This is disturbing to me because it is not the first time that I try hiding internal types and I have made it work in the past. For example :
type packedPP = PP : ((('a, Format.formatter, unit) format -> 'a) -> unit) -> packedPP let pf fmt (PP msgf) = Format.fprintf fmt |> msgf let msgf = PP (fun m -> m "aa %d" 4) let () = pf Format.std_formatter msgf
It compiles and properly show “aa 4”…
Is there a way to make it work ?