module Cf_gadget:sig
..end
This module implements a marginally more general version of the Gadget system described in Chapter 30 of Magnus Carlsson's and Thomas Hallgren's joint Ph.D. thesis.
In the context of this module, a "gadget" is a monad that evaluates into
a Cf_flow
object, capable of alternately reading from a source of input
values and writing to a sink of output values. The continuation monad is
specialized over an abstract "work" monad type, and a scheduler handles
the calls and jumps between multiple simultaneous work units, communicating
with one another over a very lightweight message passing abstraction called
a "wire".
The abstract work monad is a kind of state-continuation monad for
operations over the internal Cf_flow
value. The operations it supports
are lifted into the gadget monad, and they are summarized as follows:
A wire is logically composed of a receiver and a transmitter, with weak mutual references between them. When either end of the wire is reclaimed by the memory allocator, the other end is automatically rendered into a null wire, i.e. receivers never get messages and transmitters put messages by discarding them.
A pair of classes are provided to represent the receiver and the
transmitter on a wire. Objects of the rx
class define a get
method for
creating a "gate" that can receive a message. Objects of the tx
class
define a put
method for transmitting a message. Both objects can be
constructed with a wire object, and a convenience operators are defined for
creating a new wire and construction a pair of associated rx
and tx
objects.
Any gadget may read from the internal input stream or write to the external output stream. Conventionally, it is often simpler to define a a reader gadget and a writer gadget to localize these effects.
Note: see Magnus Carlsson's and Thomas Hallgren's joint
Ph.D. thesis for a complete
dissertation on the nature of the system of concepts behind this module.
type ('i, 'o)
work
Cf_flow
object.type ('i, 'o)
gate
guard
function.type ('x, 'i, 'o)
wire
'x
from a sender to a
a receiver in a ('i, 'o) work
continuation.type('i, 'o, 'a)
guard =(('i, 'o) gate, 'a) Cf_cmonad.t
type('i, 'o, 'a)
t =(('i, 'o) work, 'a) Cf_cmonad.t
val eval : ('i, 'o, unit) t -> ('i, 'o) Cf_flow.t
eval y
to obtain a new flow by evaluating the gadget monad y
.val start : ('i, 'o, unit) t -> ('i, 'o, unit) t
start y
to start a new gadget evaluating the gadget y
.val guard : ('i, 'o, unit) guard -> ('i, 'o, 'a) t
guard m
to receive the next message guarded by m
. The continuation
bound to the result is discarded and control passes to the scheduler.val abort : ('i, 'o, 'a) t
abort
to abort gadgeting and return to the scheduler. This is a
convenient shortcut for guard Cf_cmonad.nil
.val wire : ('i, 'o, ('x, 'i, 'o) wire) t
wire
to return a new wire for carrying messages of type 'x
.val wirepair : ('i, 'o, ('x, 'i, 'o) wire * ('y, 'i, 'o) wire)
t
wirepair
to return a pair of new wires for carrying messages of type
'x
and 'y
.val null : ('i, 'o, ('x, 'i, 'o) wire) t
null
to construct a wire that discards every message transmitted
without ever delivering it. Such wires can be useful for default arguments
to some gadget functions.val read : ('i, 'o, 'i) t
read
to get the next input value from the external stream.val write : 'o -> ('i, 'o, unit) t
write obj
to put the next output value into the
external stream.class type connector =object
..end
class[['x, 'i, 'o]]
rx :('x, 'i, 'o) wire ->
object
..end
class[['x, 'i, 'o]]
tx :('x, 'i, 'o) wire ->
object
..end
val connect : ('i, 'o, ('x, 'i, 'o) wire) t ->
('i, 'o, ('x, 'i, 'o) rx * ('x, 'i, 'o) tx) t
connect m
to construct a new matching pair of rx
and tx
objects
from the wire returned by m
.val simplex : ('i, 'o, ('x, 'i, 'o) rx * ('x, 'i, 'o) tx) t
simplex
to construct a new matching pair of rx
and tx
objects.
This is a convenient abbreviation of connect wire
.type('x, 'y, 'i, 'o)
pad =('x, 'i, 'o) rx * ('y, 'i, 'o) tx
pad
comprises a
receiver for control events and a transmitter for notification events, and
a fix
comprises the transmitter for control events and the receiver for
notification eventstype('x, 'y, 'i, 'o)
fix =('y, 'i, 'o) rx * ('x, 'i, 'o) tx
val connectpair : ('i, 'o, ('x, 'i, 'o) wire * ('y, 'i, 'o) wire)
t ->
('i, 'o, ('x, 'y, 'i, 'o) fix * ('x, 'y, 'i, 'o) pad)
t
connectpair m
to construct a new duplex communication channel,
composed with the wire pair returned by m
. A matching fix
and pad
of
the channel are returned.val duplex : ('i, 'o, ('x, 'y, 'i, 'o) fix * ('x, 'y, 'i, 'o) pad)
t
duplex
to construct a new duplex communication channel, composed of
two wires each in opposite flow. A matching fix
and pad
for each
channel are returned. This is a convenient abbreviation of
connectpair wirepair
.val wrap : ('x, 'i, 'o) #rx ->
('y, 'i, 'o) #tx ->
('x, 'y) Cf_flow.t -> ('i, 'o, unit) t
wrap rx tx w
to start a new gadget that wraps the flow w
, so that
it reads output from the flow (copying it to tx
object) and writes input
to the flow (copying it from the rx
object).class virtual[['i, 'o]]
next :object
..end
inherit ['i, 'o] next
to derive a class that implements an
intermediate state in a machine.
class virtual[['i, 'o]]
start :object
..end
inherit ['i, 'o] start
to derive a class to represent the
initial state of a machine.
val create : (('c, 'n, 'i, 'o) pad -> ('i, 'o) #start) ->
('i, 'o, ('c, 'n, 'i, 'o) fix) t
create f
to create a duplex channel, and apply f
to the resulting
pad
to obtain the initial state of a machine. The machine is started and
the corresponding fix
is returned.val createM : (('c, 'n, 'i, 'o) pad ->
('i, 'o, ('i, 'o) #start) t) ->
('i, 'o, ('c, 'n, 'i, 'o) fix) t
createM f
to create a duplex channel, and apply f
to the resulting
pad
to obtain a continuation monad that evaluates to the initial state of
a machine. The machine is started and the corresponding fix
is returned.