## mailop.api
#
# Here we define the core mailop api,
# in particular the 'do_one_mailop' and '==>' fns which are the
# primary client-code interface to the mailop system via
# handle-mail-from-multiple-sources calls looking like
#
# do_one_mailop [
# foo' ==> {. do_this(); },
# bar' ==> {. do_that(); }
# ];
# Compiled by:
#
src/lib/std/standard.lib### "Programming languages are like fairies;
### they are as real as you believe them to be."
api Mailop {
#
Mailop(X);
Run_Gun = Mailop(Void); # Purely for readability.
End_Gun = Mailop(Void); # Purely for readability.
###################################
# These are the big two from the client-code perspective:
#
do_one_mailop: List( Mailop(X) ) -> X; # Given a list of mailops (e.g., [ foo' ==> do_this, bar' ==> do_that ]), pick at most one that is ready to run and run it.
# # If no mailop if ready to fire, block until one is ready to fire and then fire it. (Timeout mailops provide a way to avoid blocking indefinitely.)
# # Whenever multiple mailops are ready to fire, an attempt is made to pick fairly between them -- everyone gets their turn eventually.
(==>): (Mailop(X), X -> Y) -> Mailop(Y); # Given 'mailop' and 'added_action', construct a new (compound) mailop which does
# exactly what 'mailop' does, except that afterwards it also does 'added_function'.
#
# This is typically used in a 'do_one_mailop' arglist, and in that context we think
# of it and use it as an if-then rule -- hence the infix "==>" name.
###################################
# These are support for imp-to-imp communications where # "imp" == "server microthread". Think "tiny daemon".
# you want zero risk of deadlock. If you like debugging
# erratic deadlocks you can safely skip this stuff:
#
Replyqueue;
make_replyqueue: Void -> Replyqueue;
put_in_replyqueue: (Replyqueue, Mailop(Void)) -> Void;
do_one_mailop': Replyqueue -> List( Mailop(Void) ) -> Void; # Just like do_one_mailop, except also processes the request queue of pending replies from other imps.
replyqueue_to_string: (Replyqueue, String) -> String; # Debug support. Input string is a name for the replyqueue.
###################################
# The remaining fns here are used
# much less often in client code:
dynamic_mailop: ( Void -> Mailop(X) ) -> Mailop(X); # Make do_one_mailop [...] mailop while do_one_mailop is running. Used in (for example):
src/lib/std/src/socket/socket.pkg dynamic_mailop_with_nack: (Mailop( Void ) -> Mailop(X) ) -> Mailop(X); # As above, but the make-mailop fn is also given a mailop used to signal client abortion of the mailop.
never': Mailop(X); # This mailop is never ready to fire. Used e.g., in dynamic_mailop.
always': X -> Mailop(X); # This mailop is always ready to fire and simply returns its argument as the mailop value.
if_then': (Mailop(X), X -> Y) -> Mailop(Y); # A non-infix synonym for '==>'. Given Mailop(X) and f: X -> Y, result returns f(Mailop(X)) whenever Mailop(X) fires.
make_exception_handling_mailop
:
(Mailop(X), Exception -> X) -> Mailop(X);
cat_mailops: List( Mailop(X) ) -> Mailop(X); # Combine a list of mailops into a single mailop. A frequent idiom is: block_until_mailop_fires (cat_mailops mailops);
block_until_mailop_fires: Mailop(X) -> X; # Run an individual mailop without bothering with a full do_one_mailop [...] statement.
# Typically used to block until the mailop fires, hence the name.
};
## COPYRIGHT (c) 1989-1991 John H. Reppy
## COPYRIGHT (c) 1995 AT&T Bell Laboratories.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.