Library
Module
Module type
Parameter
Class
Class type
This module proposes a re-interpretation of the effects management offered by OCaml 5 centered on the idea necessary in the implementation of a round-robin scheduler. For simplicity, as soon as we talk about scheduler, we will talk about round-robin scheduler. This one focuses on:
In this sense, the scheduler needs basic operations in the manipulation of tasks. Tasks are the functions (in the OCaml sense) to be executed. The scheduler must be able to:
Usually, the metric used to "stop" a task is time. That is to say that we could stop a task after 100ms has elapsed for example. Unfortunately, it seems difficult to translate this into OCaml. In this sense, the choice of our metric is: effect. That is to say that a task can only emit quanta effects (which we will of course have to manage). The quanta is the number of effects the task can produce.
Effect
module.If you follow us well and you are already familiar with the effects module in OCaml, you suspect that our implementation currently uses the Effect.Shallow
module which allows you to manage 1 effect (and only one).
It is allowed to use the Effect.Deep
module for the implementation of a scheduler - the latter makes it possible to manage several effects until a certain state of the function is obtained. In this case, when using the Effect.Deep
module, we spontaneously obtain 2 states:
Note, however, the subtlety of the first in relation to what we want to "observe" of a task for our scheduler. This case explains the fact that the task stopped on a blocking event. We consider that this subtlety discriminates the tasks (which is in opposition to our communist ideal) between those which block and those which do not block.
In this sense, in our ideal and according to what is required by a round-robin scheduler, the suspension mechanism (stop a task) intervenes systematically for each effect. Discrimination must be radically combated.
This module therefore allows us to "drive" our development on these principles described above - indeed, the Effect
module is perhaps a little too permissive. Thus, if you have to modify this module and specifically this interface, beware of a "balkanization" effect which could betray our ideals.
The type of continuations. ('a, 'b) continuation
is the state of a function _ -> 'b
. 'a
is the type of the value to continue the continuation. The user can also discontinue with an exception the continuation.
type 'a t = private
| Finished of ('a, exn) Stdlib.result
| Suspended : ('a, 'b) continuation * 'a Stdlib.Effect.t -> 'b t
| Unhandled : ('a, 'b) continuation * 'a -> 'b t
The type of function states.
The state of a function is its execution state. A function can finish with its return value or an exception, or it can suspend on an Effect.t
. In the case of a suspension, the user can "continue" the execution via what is expected by the function depending on the effect and the function once
. Note that once
can only be used once on a given value (otherwise, an exception Continuation_already_resumed
is raised by OCaml).
module Op : sig ... end
Type of the effect handler.
perform
is a function which should handle incoming effects and give an operation Op.t
via the given conitnuation k
.
val make : ('a -> 'b) -> 'a -> 'b t
make fn value
makes a new function state by executing the function with the given argument.
val suspended_with : ('c, 'a) continuation -> 'c Stdlib.Effect.t -> 'a t
suspended_with k eff
allows you to create a state from the given suspension k
and the effect eff
which produced the given suspension.
once ~perform state
applies perform
once on the given state if the latter emits an effect.
fail ~exn state
discontinue the given state with the given exception. It always return Finished (Error exn)
.
val pure : ('a, exn) Stdlib.result -> 'a t
pure value
returns Finished value
.
run ~quanta ~perform state
applies once
quanta
times. If perform
responds with Op.interrupt
(and therefore does nothing), even though there may be a few quanta left, the function returns the last state obtained.
The same applies to yield
, except that the continuation has burnt itself out. In other words, yield
is equivalent to send (); interrupt
but costs only one quanta.