Remotely executed computations are described in a domain-specific language Chourai embedded in OCaml. The signature CHR defines the syntax of the language. Here is a part of CHR needed for the present introductory example. Chourai is typed; a Chourai expression of the type t is represented as an OCaml value of the type t chr ; the type constructor chr is abstract. Our current subset of the language includes integer, boolean and string literals, and applications:

module type CHR = sig type 'a chr val unit : unit chr val int : int -> int chr val bool : bool -> bool chr val string : string -> string chr val app : ('a -> 'b) chr -> 'a chr -> 'b chr val force : 'a chr -> 'a end

The signature also has the operation force to obtain the OCaml value represented by a Chourai computation. Invoking force forces the evaluation of the Chourai expression, unless it has been evaluated already. In the latter case, force immediately returns the computed value or an exception.

Eddy Westbrook has pointed out that 'a chr seems to be a co-monad: one may extract the value from the any 'a chr expression (by using the polymorphic function force, aka extract). There is, however, no polymorphic injection function 'a -> 'a chr -- there is no return .

The language Chourai has constants for (remotely applied) functions; our introductory example needs the factorial:

module type CHRFact = sig include CHR val fact : (int -> int) chr end

Different implementations of the Chourai signature interpret Chourai expressions in different ways. For example, one may implement Chourai to interpret the expressions locally and eagerly, which is useful for debugging. We demonstrate here an implementation that interprets Chourai remotely, on a server accessible through a network socket. The implementation is also a bit lazy. We develop the examples interactively, by submitting expressions to the top-level of the OCaml interpreter after loading the Chourai library. In the transcript below, the OCaml top-level responses are indented. We also show the corresponding trace of the server execution; each line of the trace is indented and prefix with server:

let t1 = app fact (int 7);; val t1 : int Rpc_dsl.BatchFact.chr = <abstr> let t2 = app fact (int 4);; val t2 : int Rpc_dsl.BatchFact.chr = <abstr> let t12 = (force t1 - force t2);; server: New connection server: Evaluating: App Tag:Factorial 7 server: Evaluating: App Tag:Factorial 4 server: Responses computed successfully. Replying... Waiting for a response val t12 : int = 5016

7! - 4!

t1

fact 7

t1

7!

7!

4!

force

force

force t1

force t2

let t1' = app fact (int 7);; val t1' : int Rpc_dsl.BatchFact.chr = <abstr> let t2' = app fact (int 4);; val t2' : int Rpc_dsl.BatchFact.chr = <abstr> let t12' = (force t2' - force t1');; server: New connection server: Evaluating: App Tag:Factorial 7 server: Evaluating: App Tag:Factorial 4 server: Responses computed successfully. Replying... Waiting for a response val t12' : int = -5016

7!

4!

force

So far we have batched independent function calls. We now evaluate (3!)! , which requires two remote function calls, with the result of the first one being the argument of the second one.

let t3 = app fact (int 3);; val t3 : int Rpc_dsl.BatchFact.chr = <abstr> let t4 = app fact t3;; val t4 : int Rpc_dsl.BatchFact.chr = <abstr> let t4v = force t4;; server: New connection server: Evaluating: App Tag:Factorial 3 server: Evaluating: App Tag:Factorial Var5 server: Responses computed successfully. Replying... Waiting for a response val t4v : int = 720 let t5 = force t3;; val t5 : int = 6

t4

fact (fact 3)

t5

t3

We now demonstrate exception handling. Our factorial server throws an exception if the argument of fact is negative.

let t3' = app fact (int (-1));; val t3' : int Rpc_dsl.BatchFact.chr = <abstr> let t4' = app fact t3';; val t4' : int Rpc_dsl.BatchFact.chr = <abstr> force t4';; server: New connection server: Evaluating: App Tag:Factorial -1 server: Responses computed partly or not at all. Replying... Waiting for a response Exception: Failure "Skipped due to the earlier: Failure(\"fact on a negative number\")". force t3';; Exception: Failure "Failure(\"fact on a negative number\")".

t4'

We emphasize the difference in the treatment of remote computations between Chourai and BRMI, or Java RMI in general. Remote object invocation (RMI) is typically explained in terms of stubs and proxies: ``A stub implements the remote interface and serves as the remote object's client-side proxy; operations on the stub are forwarded to the remote object'' (Tilevich et al., ICDCS 2009). The functional programming approach is again seems more perspicuous: a remote procedure call is just an application in an embedded DSL. A batch of related calls is the code of a nested application. One may even regard the type constructor chr as code of MetaOCaml. The nested Chourai application fact (fact 3) , represented in OCaml as app fact (app fact (int 3)) will result in the following batch when forced:

[(v1, App Factorial 3) (v2, App Factorial v1)]