I have been working on a toy example that better demonstrates the problem with OCaml’s current effect handling system:
open Effect
open Effect.Deep
open Eio
type _ Effect.t += Log : string -> unit t
(* The following function is not aware of any fibers. *)
let logging_with_prefix prefix f =
try_with f ()
{
effc =
(fun (type a) (eff : a t) ->
match eff with
| Log message ->
Some
(fun (k : (a, _) continuation) ->
print_string prefix;
print_endline message;
continue k ())
| _ -> None);
}
(* The following function is not aware of any fibers. *)
let logging = logging_with_prefix "LOG: "
(* The following function is not aware of any fibers. *)
let logging_important = logging_with_prefix "LOG IMPORTANT: "
(* The following function is generic and not aware of any effects. *)
let do_twice_parallel f = Fiber.both f f
(* The following function is performing but not handling any effects. *)
let double_hello () = do_twice_parallel (fun () -> perform (Log "Hello World!"))
let foo () =
Fiber.both
(fun () ->
(* This should run concurrently with fibers spawned outside [foo]. *)
for i = 1 to 5 do
perform (Log ("tick " ^ string_of_int i));
Fiber.yield ()
done)
(fun () ->
(* We only want this to be logged specially. *)
logging_important double_hello)
let () =
logging (fun () ->
Eio_main.run (fun _env ->
Fiber.both foo (fun () ->
for i = 1 to 5 do
perform (Log ("tock " ^ string_of_int i));
Fiber.yield ()
done)))
This creates the following output:
LOG: tick 1
LOG: Hello World!
LOG: Hello World!
LOG: tock 1
LOG: tick 2
LOG: tock 2
LOG: tick 3
LOG: tock 3
LOG: tick 4
LOG: tock 4
LOG: tick 5
LOG: tock 5
Now, how to fix the above example to write
LOG: tick 1
LOG IMPORTANT: Hello World!
LOG IMPORTANT: Hello World!
LOG: tock 1
LOG: tick 2
…
instead, without changing the function double_hello
and while further keeping do_twice_parallel
generic (edit: and without tapping into Eio
’s private effects)? I don’t think that’s possible, is it?
I was able to solve this in Lua by making the effect handling be aware of the fibers. See this Lua code, which, using this version of the Lua effect/fiber library, “correctly” prints “LOG IMPORTANT” in front of “Hello World!”:
LOG: tick 1
LOG IMPORTANT: Hello World!
LOG IMPORTANT: Hello World!
LOG: tick 2
LOG: tick 3
LOG: tock 1
LOG: tick 4
LOG: tock 2
LOG: tick 5
LOG: tock 3
LOG: tock 4
LOG: tock 5
(The order of the tick’s and tock’s is a bit off, but that’s not the point here.)
Update:
I opened this issue for tracking the problem: