Distributed Control Flow with Classical Modal Logic

In previous work we presented a foundational calculus for spatially distributed computing based on intuitionistic modal logic. Through the modalities • and O we were able to capture two key invariants: the mobility of portable code and the locality of fixed resources. This work investigates issues in distributed control flow through a similar propositions-as-types interpretation of classical modal logic. The resulting programming language is enhanced with the notion of a network-wide continuation, through which we can give computational interpretation of classical theorems (such as DA = -iO-u4). Such continuations are also useful primitives for building higher-level constructs of distributed computing. The resulting system is elegant, logically faithful, and computationally reasonable.


Introduction
This paper is an exploration of distributed control flow using a propositions-as-types interpretation of classical modal logic. We build on our previous intuitionistic calculus, Lambda 5 [8], which is a simple programming language (and associated logic) for distributed computing. Lambda 5 focuses particularly on the spatial distribution of programs, and allows the programmer to express the place in which computation occurs using modal typing judgments. Through the modal operators • and O we are then able to express invariants about mobility and locality of resources. Our new calculus, C5, extends Lambda 5 with network-wide first-class continuations, which arise naturally from the underlying classical logic. Networkwide continuations create a new relationship between the modalities • and O, which we see with several examples, and serve as building-blocks for other useful primitives. Before we introduce C5, we begin witfr a short reprise of Lambda 5.

Lambda 5
The Lambda 5 programming model is a network with many different places, or nodes. In order to be faithful to this model, we use a style of logic that has the ability to reason simultaneously from multiple perspectives, namely, modal logic. Compared to propositional logic, which is concerned with truth, modal logic deals with truth at different worlds. These worlds are related by an accessibility relation, which affects the strength of the modal connectives; different assumptions about accessibility give rise to different modal logics. For modelling a network where the worlds are nodes, we choose Intuitionistic S5 [15], whose relation is reflexive, symmetric, and transitive-every world is related to every other world. Therefore, except when comparing it to other systems, we essentially dispense with the accessibility relation altogether. This leads to a simple explanation of the judgments and connectives, which is as follows.
A true® <j is the basic judgment, meaning that the proposition A is true at the world UJ (we abbreviate this to A@u). There are two new proposition forms for quantifying over worlds. DA is the statement that A is true at every world. OA means that A is true at some world. Because we think of these worlds as places in the network, operationally we interpret type DA as representing mobile code or data of type A, and the type OA as an address of code or data of type A.
Propositions must be situated at a world in order to be judged true, so it is important to distinguish between the proposition OA and the judgment DA@UJ, the latter meaning that A is true in every world from the perspective of UJ. In S5, every world has the same perspective with regard to statements about all or some world(s). But operationally this will be significant, as there is no true "global" code, only mobile code that currently exists at some world.
Though the logic distinguishes between UA@u and OAQU/^ both have precisely the same immediate consequences. The typical rule for eliminating D, for instance as given by Simpson [15] is

Classical Control Flow
The notion that control operators such as Scheme's call/cc or Felleisen's C can be given logical meaning via classical logic is well known. Essentially, if we interpret the type -u4 as a continuation expecting a value of type A, then the types of these operators are classical tautologies. Griffin first proposed this in 1990 [5] with later refinements by (for example) Murthy [9]. Parigot's A/x-calculus [10] takes this idea and develops it into a full-fledged natural deduction system for classical logic. 1 It began to become clear that this was no accident-classical logic is the logic of control flow. Therefore, a natural next step is to look at classical S5 to see what kind of programming language it gives us, which is the topic of this paper. We find that the notion of a networkwide continuation arises naturally, giving a computational explanation to (intuitionistically ridiculous) classical theorems such as DA = -1O-1A We also believe that such primitives can be useful for building distributed computing mechanisms such as synchronous message passing.
The paper proceeds as follows. We first present classical S5 judgmentally, giving a natural deduction system and intuition for its operational behavior. We then verify that our proof system really is faithful by establishing a correspondence with a dual sequent calculus that admits cut. Next we give proof terms for some classical theorems, to elucidate the new connection between • and O made possible by network-wide continuations. In order to make these intuitions concrete, we then give an operational semantics based on an abstract network. We follow with some ideas about concurrency and how network-wide continuations can be used by distributed applications, and conclude with a discussion of related work.  All of the proofe in this paper have been formalized in the Twelf system [12] and verified by its metatheorem checker [14]. 2

Classical S5
Because we wish to take a propositions-as-types interpretation of modal logic, a judgmental proof theory for our logic is critical. In this section we give such a presentation of Classical S5.
Because modal logic is concerned with truth relativized to worlds, our judgments must reflect that. We have two main judgments in our proof theory. The first, simply states that the proposition A is true at the world u. Dually, we have A false* a; 2 They can be found at http://vww.cs.emu.«du/~concert/. which says that the proposition A is false at the world LJ. Although these two judgments are dual, the natural deduction system is biased towards the first; it is primarily concerned with deducing that propositions are true. We will only make assumptions about falsehood for the purpose of deriving a contradiction. As is standard, we reify the hypotheses about truth and falsehood into contexts (eliding true and false), and the central judgment of our proof theory becomes where we deduce that A is true at world LJ under truth assumptions of the form appearing in F and falsehood assumptions of the form C*UJ" appearing in A. We also have hypotheses about the existence of worlds. It is cumbersome to write a context of world assumptions and conditions on world existence in every judgment. Instead we use pure hypothetical notation to express a judgment hypothetical in the existence of world a/ (which may be the same as a;!). We also take the common shortcut of only permitting mention of worlds that exist. Therefore, all judgments are hypothetical in at least some world (the world at which the conclusion is formed), until we introduce world constants in Section 5.
Operationally, we will think of a falsehood assumption A * u as a continuation, living at world a;, that expects something of type A.
Our natural deduction system appears in Figure 1. These rules include proof terms, which we will explain shortly. Aside from the falsehood context, the rules for D, O and D are the same as in Lambda 5. The new connectives J_ (discussed below) and A are treated as they would be in the intuitionistic case. The major additions are the structural rules be (by contradiction) and # (contradict), which enable classical reasoning.
The be rule is read as follows: In order to prove A@LJ, we can assume that A is false at LJ. This corresponds directly to the classical axiom (-u4 D A) 3 A. Operationally, this grabs the current continuation and binds the falsehood variable to it. The # rule may be alarming at first glance, because it requires the assumption A*OJ to appear in the conclusion. This is because the # rule is actually the hypothesis rule for falsehood assumptions, and will have a corresponding substitution principle. 3 The rule simply states that if we have the assumption that A is false and are able to prove that A is true (at the same world), then we can deduce a contradiction and thus any proposition. The # rule is realized operationally as a throw of an expression to a matching continuation. Note that continuations are global-we can throw from any world to a remote continuation A*LJ, provided that we are able to construct a proof of A@LJ.
The rules for • and O are important to review. • elimination is the easiest to understand: If we know that DA is true at some world, then we know A is true at the same world. To prove OA, we must prove A at a hypothetical world about which nothing is known (rule • J). Operationally, we realize UA as a piece of suspended code, with the hypothetical world u/ bound within it. Introduction of O is simple; if we know A then we know that A is true somewhere (namely here). Operationally this will record the value in a table and return an address that witnesses its existence. Elimination of O is as follows: if we know OA, then we know there is some world where A is true (but we don't know anything else about it). Call this world a/ and assume AQLJ' in order to continue reasoning. Finally, we provide motion rules (as per our decomposition) DM and OM. Both simply allow knowledge of DA or OA at one world to be transported to another. Operationally these move the values between worlds.
Bottom has no introduction form, but we allow the remote elimination of it (rule -LE 1 ). This is similar to the motion rules for D and O, except that nothing is ever returned, because there is no canonical value of type _L. For this reason we call the proof term rpc, as it invokes a sort of remote procedure call on the target world. 4 For each kind of hypothesis we have a substitution theorem. Here, truth substitution [M/x]N is defined in the standard way. Note again that a proof of type B<®uj f can contain sub-expressions that are well-typed at other worlds! In the operational semantics we will always ship these expressions to their home world before evaluating them. Theorem 2, however, warrants special attention. This principle is dual to the # rule just as Theorem 1 is dual to hyp. The # rule contradicts an A* a) with an A@CJ, so to eliminate a falsehood assumption by substitution we are able to assume A®u and must produce another contradiction. Reading h as logical consequence, we have that if A false gives B, and A true gives C (for all C), then B. This can easily be seen as a consequence of excluded middle. We write this substitution as [x.M/u]N where x is a binder (with scope through M) that stands for the value thrown to u. It is defined pointwise on N except for a use of the # rule on u: This principle is close to what Parigot calls structural substitution for the A//-calculus. Operationally, we see this as replacing the throw with some other handler for A. Since the new handler must have parametric type, typically it is a throw to some other continuation, perhaps after performing some computation on the proof of A.
Proof of Theorem 2 is by a straightforward induction on the derivation of B, appealing to Theorem 1 in the case above. We wish to know that our proof theory (specially constructed to give rise to a good operational semantics) is not simply ad hoc; that it really embodies classical S5, and is globally sound. To do so we prove in the next section a correspondence to a straightforward sequent formulation of classical S5 with the subformula property. We'll use the sequent calculus as intuition as we develop proof terms for some classically true propositions. Following that is a discussion of the operational semantics (Section 5), which does not depend on the sequent calculus.

Sequent Calculus
Our sequent calculus is motivated by simplicity and duality alone, because we will not give it a computational interpretation. One traditional way of doing classical theorem proving is to negate the target formula and prove a contradiction from it. We base our sequent calculus around this view: the sequent r # A means that the truth assumptions in F and the falsehood assumptions in A are mutually contradictory. 5 The calculus is given in Figure 2. We treat contexts as unordered multisets, so the action can occur anywhere in either context.
These rules should be read bottom-up, as if during proof search. The contra rule allows us to form a contradiction whenever a proposition is both true and false at the same world. The DT rule says that if we know UA@UJ, then we know A@UJ 1 for any u/ that exists. On the other hand, if we know that DA is false, then we know A is false at some world a/. However, we must treat this world as hypothetical and fresh since we don't know which one it is. The rules for O are perfect mirror images of the rules for D. For implication, we use the classical truth tables to provide rules of inference. If we know that AD B is false, then we know A is true but B is false. If we know that A D B is true, then we know that either A is false or B is true.
A key feature of the sequent calculus is the subformula property: every step (when read bottom-up) proceeds by decomposing exactly one connective. This means that proofs in the sequent calculus work by only examining the structure of the proposition at hand; this gives us a nice orthogonality condition for the connectives in our logic.
The translation from natural deduction to the sequent calculus requires a lemma (which should not be a rule of inference because it violates the subformula property). In an intuitionistic calculus this would be cut; for the symmetric classical calculus it turns out to be the familiar classical notion of excluded middle.

Theorem 3 (Excluded Middle
Proof of Theorem 3 is by lexicographic induction on the proposition A and then on the two derivations. • With excluded middle, we can prove the correspondence between natural deduction and the sequent calculus. It is easy to see why 4(b) is the right statement. Since we think of F # A as a proof of contradiction, this corresponds to a derivation that proves any proposition at any world in natural deduction. Theorem 4(a) is more subtle. We show that if A is true under assumptions F and A, then A being false at the same world is contradictory with those assumptions. Computationally, we can think of this as the "final continuation" to which the result computed in natural deduction is passed. Putting these two theorems together, we have that F; A h M : A@u gives F # AMJ, A, which then gives VC, a/. F; A, W.AMJJ h M f : C®UJ'. In particular, we choose C = A and a/ = a;, and then by application of be we have the original judgment (with perhaps a different proof term letcct/inM'). Thus h and # are really equivalent.
The proof of Theorem 4{a) is by straightforward induction on the derivation, using Theorem 3 where necessary. (The structural rules be and # just become uses of contraction and weakening in the sequent calculus.) Proof of 4(b) is tricker. Uses of T rules are easy; they correspond directly to the elimination rules 6 in natural deduction. But since our natural deduction is biased towards manipulating truth rather than falsehood, the F rules are more difficult and make nontrivial use of the falsehood substitution theorem. For instance, in the AF case we have by induction: ; A,up:A A B*cj,ua:A*cj \-N x \C®u f (VC,a/) N 2 : CW By two applications of Theorem 2, we get that the following proof term has any type at any world: rr -n x.\y. throw (x, y) to up/ub]N 2 /ua N\ First, we form a throw of the pair (x,y) to our pair continuation up. This has free truth hypotheses x : A and y : B. Therefore, we can use it to substitute away the ub continuation in N 2 (any throw of M to ub becomes a throw of (x, M) to up). Finally, we can use this new term to substitute away ua in JVi, giving us a term that depends only on the pair continuation up. This pattern of prepending work onto continuations through substitution is characteristic of this proof, and reflects our bias towards the truth judgment in natural deduction. As another example, in the case for the OF rule we have by induction: T; A, u:A*u', ud:OA*u h TV : CW' (VC, u/') Our proof term in natural deduction is then: Simply enough, if u is ever thrown to, then we instead take that term's address (which lives at a/), move it to a;, and throw it to our OA continuation ud.
Finally, the case for OF is interesting because it involves a letcc. 7 By induction we have: W. r;A,u:A*Lj',vb:nA*u;\-N:Cau/' (VC,a/ ; ) Then the proof term witnessing the theorem here is: It is not possible to use falsehood substitution on u in this case. To do so we would need to turn a term of type A@a/ into a UA@u; to throw to ub. Although at a meta-level we know that we can choose any u/, it won't be possible to internalize this in order to create a DA. Instead we must introduce a new box, and choose u/ to be the new hypothetical world that the •/ rule introduces. At that point we use letcc to create a real A*a/ assumption to discharge u. The remaining cases are similar or straightforward, and can be found in full detail in the Twelf code, which can be found in Appendix A. 8 •

Examples
In this section we give proof terms showing the new connection between D and O made possible by network-wide continuations.
Because the examples we'll look at involve negation (-»i4), we'll need to briefly explain how we treat it.

Negation
Although we have not given the rules for the negation connective, it is easily added to the system. Here we equivaiently take the standard shortcut of treating -u4 as an abbreviation for A D J_. We computationally read -IAQU as a continuation expecting A, although this should be distinguished from primitive continuations u with type A*u: the former is formed by lambda abstraction and eliminated by application, while the latter is formed with letcc and eliminated by a throw to it. The two are related in that we can reify a continuation assumption u:A*u as a negated formula -*A by lambda abstracting a throw to it: Xa. throw a tou. Likewise, we can get a falsehood assumption from a term M of type -i-A, namely M(letcc u in...). Finally, note that we have derived sequent calculus rules -iT and -»F. Each just flips the proposition under negation to the other side of the sequent, as expected. (The reader can verify that these are indeed the rules derived from D T and D F if the antecedent of implication is J_.)

Classical Axioms
Our first example comes from the standard practice in classical modal logic of defining • in terms of O: From left to right the implication is intuitionistically valid, so we'll look at the proof of the implication right to left. We begin with the sequent calculus proof, to show why this is clearly true classically. We elide any residual assumptions that go unused. contra -*F OF

T F
Critically, we are using OF to get the hypothetical world at which nA is false. From there, we can learn ->A at the same world, which leads to a contradiction. In natural deduction, the proof tells an interesting story:
(need to return A) letcc u in rpc[a;] (applying dc will yield J_) dc(get o [uj](here(Xa. throw a to u))) In each example, we'll assume that the whole term lives at the world UJ. Operationally, the reading of -IO-VA D OA is that given a continuation dc (expecting the address of an A continuation), we will return a boxed A that is well-formed anywhere. The proof term given accomplishes this by creating a box that, when opened, grabs the current continuation u, which has type A*LJ'. With the continuation in hand, we travel back to u (where dc lives), and apply dc to the address of a function that throws to u. In short, at the moment the box is opened we have a lack of an A, which we can grab with letcc and then take the address of with here. This is enough to send to the continuation that we're provided.
Dually we can define O in terms of •. Again, one direction is intuitionistically valid. The other, is asked to conjure up an address of an arbitrary A given a continuation. It is implemented by the following proof term: Here, we immediately do a letcc, grabbing the OA continuation at UJ. We then form a box to pass to the continuation be. It contains a function of type ADI, which takes the address of its argument and throws it to the saved continuation u. Thus the location of A that we return is any world that invokes the -u4 that we've boxed up.
We've left disjunction out of our calculus. Theoretically it poses no problem, although operationally it requires us to perform some tricks to avoid a strange "remote case analysis." In Section 7 however, we see that we can encode it using the de Morgan translation into -• and A. Regardless of how we implement it, disjunction is a source of a wealth of interesting programs.
Without being as formal, let's take a look at a program implementing the classical axiom DA V O-iA We'll assume constructors inl and inr for injecting into the disjunction. Those familiar with the implementation of the axiom A V ->A might guess that this returns the address of an A continuation, as in that case. Actually, this doesn't work! We can't build a DA by accumulating evidence for A at different worlds. Instead, we return again a box that does something when opened.
letcc win throw(inr(get o (a/] here(Aa. throw a to u))) to uo) First we save the current continuation as uo, since we will need to "change our minds" about which clause we return! Initially, we return a box whose body also grabs the continuation (of type A*u f ) as u. Suppose the box is opened at the world J. We then throw to the remote continuation uo a program that comes back to a/, forms a term of -u4, publishes it, and moves it to the first world.
To summarize, when asked for DA V O-u4, the program 1. initially says DA 2. if the box is opened, the program uses the lack of A to produce a O-iA, time travels back to when it was asked about the disjunction, and returns this different answer.
3. if the -u4 continuation is ever invoked, the program goes back and uses the A to fulfill the outstanding lack of A at the world where the box was opened.
In the style of sci-fi storytelling popular when describing such things, we conclude our examples with the following fable (with apologies to Wadler [16]): A magician who purports to be from the future is making bold claims. Asking for a volunteer, he offers the following prize to anyone who comes on stage: "I'm going to hand you a box that has you inside it!" "Either that, or I'll give you the address of a place with a magical time travelling portal." Being questionably brave, you volunteer and walk onto the stage. The magician hands you your prize-a large cardboard box. Noting your skepticism, he adds, "You can open it anywhere, and you'll be inside." You decide to take the box home. It's much too light to have anything in it, let alone yourself! You open the box and look inside, wondering what sort of gag he has planned. But suddenly you find that the box has disappeared, and you're standing on stage waiting for him to tell you what you've won, again.
"The address of the time-travelling portal is," he begins, rattling off your home address. You are startled that he could have known your address, but when you later arrive home, you see an open cardboard box waiting. Is this supposed to be the portal? Knowing it to be harmless, but insisting upon proving the magician to be a fraud, you step into it.
A hot flash of embarassment passes over you as you realize that you are now standing in a cardboard box, in your house, as promised.

Type System and Operational Semantics
Our deductive proof theory begets a natural programming language whose syntax is the proof terms from Figure 1. In order to give this language an operational interpretation, we need to introduce a number of syntactic constructs, which are given in Figure 3.
As in Lambda 5, the behavior of a program is specified in terms of an abstract network that steps from state to state. The network is built out of a fixed number of worlds, whose names we write as bold w. Because we can now mention specific worlds in addition to hypothetical worlds a;, we introduce world expressions, which are written with a Roman w. A network state N has two parts. First is a world configuration W which identifies two tables  Figure 3: Syntax of type system with each world w* present. The first table %% stores network-wide continuations by mapping continuation labels k to literal continuations k. The second table b { maps value labels £ to values in order to store values whose address we have published. These tables have types X and (3 respectively (which map labels k and £ to types), and so we can likewise construct the type of an entire configuration, written E. Aside from the current world configuration, a network state also contains a cursor denoting the current focus of computation. The cursor either takes the form w : [k -< v] (returning the value v to the continuation k) or w : [k >-M] (evaluating the expression M in continuation k). In either case it selects a world w where the computation is taking place.
Continuations themselves are stacks of frames (expressions with a "hole," written o) with a bottommost return, finish or abort. The finish continuation represents the end of computation, so a network state whose cursor is returning a value to finish is called terminal The abort continuation will be unreachable, and return will send the received value to a remote continuation.
Most of the expressions and values are straightforward. As in Lambda 5, the canonical value for • abstracts over the hypothetical world and leaves its argument unevaluated (box a/.M). The canonical form for O is a pair of a world name and a label w.£, which addresses a table entry at that world. Such an address is well-formed anywhere (assuming that w's table has a label £ containing a value of type A) and has type OA@w'. On the other hand we have another sort of label, written just £, which is disembodied from its world. These labels arise from the letd construct, which deconstructs an address w.£ into its components w and £ (see the OE rule from Figure 1). Disembodied labels only make sense at a single world-here £ would have type A@w.
Although the external language only allows a throw to a continuation variable, intermediate states of evaluation require that these be replaced with the continuation expression w.k, which pairs a continuation label with the world at which it lives. These continuation expressions are filled in by letcc. The cursor is well-formed EhN

Judgment
The network is well-formed Figure 4: Index of Judgments. In each judgment E is a configuration typing, F is a context of truth hypotheses, and A is a context of falsehood hypotheses The type system is given in Figure 5 (we omit for space the rules that are the same as in Figure 1 except for the configuration typing E). The index of judgments in Figure 4 may be a useful reference in understanding them.
The rules addr and lab are used to type run-time artifacts of address publishing. In either case, we look up the type in the appropriate table typing /3. As mentioned, throw allows a continuation expression Z, which must take the form of a variable (typed with hyp* as in the logic) or address into a continuation table.
Typing of literal continuations k is fairly unsurprising. Note that the judgment Ehfc: A*w means that the continuation k expects a value of type A at w. The return continuation arises only from a get o or get a , and so it allows only values of type OA or DA. We re-use the network continuation mechanism here to refer to the outstanding get o or get D on the remote machine.
For an entire network to be well-formed (rule net), all of the tables must have the type indicated by the configuration type E, which means that they must have exactly the same . Finally, the cursor must be well-formed: it must select a world that exists in the network, and there must exist a type A such that its continuation and value or expression both have type A and are closed.
Having set up the syntax and type system, we can now give the operational semantics and type safety theorem. After the following section we remark on how the semantics can be made concurrent, and some thoughts on applications of distributed continuations.

Operational Semantics
The operational semantics of our language is given in Figure 6, as a binary relation i-» between network states. The semantics evaluates programs sequentially, though we give a concurrent semantics in Section 6. As should be obvious, the semantics is continuation-based. At any step, the cursor is selecting a world and continuation, with a value to return to it or an expression to evaluate. The rules generally fall into a few categories, as exemplified by the (standard) rules for D: There are push rules, in which we begin evaluating a subexpression of some M, pushing the context into the continuation, swap rules, where we have finished evaluating one subexpression and move onto the next, and reduction rules, where we have a value and actually do something with it. Every well-typed machine state will be closed with respect to truth, falsehood, and world hypotheses, so we don't have rules for variables and can specialize some rules.
The first interesting rule is O r r. It publishes the value v and returns its address by generating a new label, mapping that label to v within its value table, and returning the pair w.£, where w is the current world. Whenever we try to evaluate a label (rule ^-r), we look it up in the current world's value table in order to fetch the value. A key consequence of type safety (Theorems 5, 6) is that labels are only evaluated in the correct world. To eliminate an address (rule O e -r) we substitute the constituent world and label through the body of the letd. Note that this step is slightly non-standard, because we substitute the expression £ for a variable rather than some value. But because the variable is in general at a different world, we are not in a position to get its value yet. We instead wait until the expression £ is sent to its home world (perhaps as part of some larger expression) to be looked up. The rules for • are much simpler: box CJ.M is already a value (rule Df-v), and to unbox we simply substitute the current world for the hypothetical one (rule n e -i).
When encountering a letcc, we grab the current continuation k. Because the continuation may be referred to from elsewhere in the network, we publish it in a table and form a global address for it (of the form w.k), just as we did for O addresses. This value is substituted for the falsehood variable u using standard substitution-not the special falsehood substitition we used in Section 2. The latter was a proof-theoretic notion used to eliminate uses of the hypothesis; here we want the use of the hypothesis (throw) to have run-time significance. A point of comparison is the above paragraph, where we substituted the expression £ for a variable because we wanted to delay the operation until the time the variable is "looked up." Throwing to a continuation (rule throw) is handled straightforwardly. The continuation expression will be closed, and therefore of the form w 7 .k. We look up the label k in w 7 -or rather, cause w 7 to look it up-and pass the expression M to it. Note that we do not evaluate the argument before throwing it to the remote continuation. In general we can not evaluate it, because it is only well-typed at the remote world, which may be different from the world we're in.
Finally, we have the rules that move between worlds. The rule for rpc is easiest; since the target world expression must be closed it will be a world constant in the domain of W. We simply move the cursor to that world (destroying the current continuation, which can never be reached), and begin evaluating the expression M under the unreachable continuation abort. The rules for get o and get D work similarly, but they need to save the current continuation since they will be returned to! These steps push a return frame, which reduces like throw. In contrast, however, the argument (of type DA or O^4) will be eagerly evaluated, because such values are portable. (After all, the whole point is to create the box at one world and then move it to another.) In order for our language to make sense it must be type safe; any well-typed program must have a well-defined meaning as a sequence of steps in the abstract network. Type safety is stated as usual in terms of progress and preservation:

Theorem 6 (Preservation) // S h N and N H-+ N' then 3S'. S'DE and £' h N'.
Progress says that any well-formed network state can take another step, or is done. (Recall a terminal network is one where the cursor is returning a value to a finish continuation.) Preservation says that any well-typed network state that takes a step results in another well-typed state (perhaps in an extended configuration typing E' 9 ). By iterating alternate applications of these theorems we see that any well-typed program is able to step repeatedly and remain well-formed, or else eventually comes to rest in a terminal state.

Concurrency and Communication
Many distributed computing problems benefit from concurrency, with one or more processes running on each node in the network. This section gives some brief thoughts on concurrency in our classical calculus.
First-class continuations are often used in the implementation of coroutines. With primitives for recursion and state we could also implement coroutines in C5, however, such an implementation is silly because it would require the implementation of a global scheduler, and would anyway defeat the purpose of concurrency on multiple nodes-only one coroutine would be running at any given time! Fortunately, our operational semantics admits ad hoc concurrency easily. If we simply replace the cursor R in our network state "W; i?" with a multiset of cursors 5ft, then we can permit a step on any one of these cursors essentially according to the old rules. With concurrency in place we can implement CML-style channels [13] with the help of continuations (and a few other features for developing mutable recursive structures). The type of a channel carrying values of type A could be: Here a channel is represented as the address of a pair of queues. In order to send to this channel, the sender must be able to bring a value of type A to the world where the channel lives, so it must be a box or diamond type itself (or see Section 8 for more options). The first queue holds the values that have been sent on the channel and not yet received, the second holds the continuations of outstanding recvs. To implement recv (assuming no values are waiting in the first queue), we grab the current continuation, enqueue it, and abort. This is a standard technique; the point here is to emphasize the utility of continuations as primitives for implementing useful distributed computing features.

Disjunction
To add disjunction to C5, we need to use the following elimination form in order to preserve the correspondence with classical S5: This rule is completely unsurprising except that the case object M is at a different world, u/. In our logic we've tried hard to avoid this sort of action-at-a-distance, instead preferring to have our introduction and elimination rules compute locally. However, a motion rule for disjunction is out of the question, because it is unsound: it is not the case that if F; A h A V B@LJ then necessarily FjAhiV B@LJ'. In our previous paper we speculated that this rule could be implemented nonetheless by sending back merely a bit telling the caseanalyzing world which branch it should enter, but this requires some suspicious operational machinery. The same is true in the classical case, which is why we have avoided treating disjunction so far.
The problem with a local rule (where all four worlds are the same) comes when translating the sequent calculus rule and a derivation of F, x:A V B@UJ\ A h x : A V B@u> by the hyp rule. However, we cannot apply a local V-elimination rule, because it would require its object x to be at the same world as its conclusion. Thus we axe able to prove Cato;, but not at all worlds.
As it turns out, support for disjunction and remote disjunction elimination is already present in C5, thanks to one of de Morgan's laws. Suppose that we define A V B as follows

A V B = -i(-i>4 A -i£)
That is, AW B becomes a continuation that takes two continuations: one if the disjunct is A, and one if the disjunct is B. This technique is well-known for CPS conversion, and first-class continuations let us do it without having to CPS-convert the entire program. Encoding the injections is easy: This has exactly the same typing conditions as the remote rule above; x is bound to the remote type A@w\ even though the expression Ni is evaluated at LJ.
Classical logic is ripe with possibilities for definition. It is interesting to consider their implications. Recall that in Section 4 we proved OA equivalent to -1D-1A This means that, as classicists typically do, we could then just consider OA as a derived form. This would amount to a roundabout way of using the continuation table to publish values rather than the value table. Clearly, we could also take the even stranger route of defining UA in terms of O, which gives us a mobile code "server" that sends code to our continuation whenever we like.

Generalizing get
The typing rules and operational semantics for get o and get D are almost identical, suggesting the possibility of factoring out the common functionality into a single construct. In fact, when we add base types to C5 the desire for such a general get mechanism becomes clear-the calculus does not currently support a way to directly retrieve simple data like integers, so the programmer is required to implement this mobility himself by deconstructing the value at the source world and reintroducing it at the destination.
Not all types support this kind of mobility. Therefore, we create a judgment A mobile, and only allow get on types that satisfy it. r;Ah-M: Aoa/ A mobile r;Ahget[u/]M: The mobile judgment is defined inductively: Note that DA is always mobile, whereas A A B is only mobile if both of its constituent types are also mobile. We have also left out implication entirely. The general principle that decides mobility for a type is as follows: Type A can be considered mobile if whenever F; A h A@u;, then F; A h A®uj f for any u/. This tells us when we can logically introduce a get at A without getting in trouble. However, because get is only required for completeness at • and O types (since we have otherwise reduced their strength), we have significant flexibility in what other types we allow to be mobile. This is largely an operational concern, the question being: Can we provide a more efficient implementation than the one that the user would otherwise have to write? Sometimes the answer is clearly yes, as in the case of integers. For other types the answer is probably no; although if A and B are mobile then AD B satisfies the principle above, implementing get primitively for functions seems to require building a proxy for the function, which is what a programmer would do to implement this mobility himself.

Related Work
Parigot's A/i-calculus has inspired many computational proof systems for classical logic, including Wadler's dual calculus [16]. The calculus is sequent-oriented and contains cut as a computational primitive, emphasizing the duality of computing with values and covalues (continuations). For programming in C5, we choose a natural deduction system which is deliberately non-dual. We bias the logic towards truth, which corresponds to computing mainly with values (as is typical) rather than covalues. Nevertheless, we expect that a dual version of classical S5 could be easily made to work, perhaps starting from the sequent calculus presented in Section 3.
Recently, others have used modal logic to describe distributed tasks or as the basis for programming languages, although we know of no modal systems that feature distributed continuations.
Borghuis and Feijs give an early computational interpretation of modal logic in their intuitionistic Modal Type System for Networks [2]. Their calculus and logic describe programs on a network with stationary services (e.g., printers, file converters) and mobile data (e.g., documents). They use •, annotated with a location, to represent services. For example, B°(A D B) means a function from A to B at the location o. However, the calculus has no way of internalizing mobility as a proposition, so mobile data is limited to base types. Services are similarly restricted to depth-one arrow types. By using • for mobile code and O for stationary resources, we believe our resulting calculus is both simpler and more general.
Moody [7] gives a system based on the constructive modal logic S4 due to Pfenning and Davies [11]. This language is based on judgments A true (here), Aposs (somewhere), and A valid (everywhere) rather than the "explicit worlds" formulation of Lambda 5 and C5. The operational semantics of his system takes the form of a process calculus with nondeterminism, concurrency and synchronization; a significantly different approach from our sequential abstract machine. Interpreted in the Kripke model, S4's accessibility relation satisfies only reflexivity and transitivity, not symmetry. Moody uses the limited accessibility to express process interdependence rather than-as we do-connections between actual network locations. Programs are therefore somewhat higher-level and express potential mobility instead of explicit code motion as in our mobility rules. In particular, due to the lack of symmetry it is not possible to return to world after a remote procedure call from it, except by returning a value.
Jia and Walker [6] give a judgmental account of an S5-like system based on intuitionistic hybrid logic. Hybrid logics internalize worlds inside propositions by including a proposition that a value of type A resides at world a;, U A at a;." This leads to a technically different logic and language although they give a similar interpretation to the modalities. Their rules for • and O are non-local, which means that they rely heavily on global actions. Like Moody, they give their network semantics as a process calculus with passive synchronization across processes as a primitive notion.

Future Work
Our language now has a full arsenal of connectives and control operators, each connected to logic. Much work remains before C5 can be a practical programming language rather than exploratory calculus. Some are routine-adding extra-logical primitives like recursion and references-and some are difficult-compilation of mobile code fragments, distributed garbage collection, failure recovery, and certification.
Although we believe that C5 accomodates concurrency easily, it would be nice to have a logically-inspired account of it. Some other directions remain open to try. Proof search in linear logic sequent calculus [4] is known to admit an interpretation as concurrent computation [3]. Perhaps linear S5 in sequent style would be able to elegantly express both spatial properties and concurrency in logic?
We have presented a proof theory and corresponding programming language, C5, based on the classical modal logic S5. By exploiting the modalities we are able to give a logical account of mobility and locality, and thus an expressive programming language for distributed computing. From the logic's classical nature we derive the mechanism of distributed continuations, which creates a new connection between the • and O connectives, and forms a basis for the implementation of distributed computing primitives.