A Message-Passing Interpretation of Adjoint Logic

04/02/2019
by   Klaas Pruiksma, et al.
Carnegie Mellon University
0

We present a system of session types based on adjoint logic which generalize standard binary session types. Our system allows us to uniformly capture several new behaviors in the space of asynchronous message-passing communication, including multicast, where a process sends a single message to multiple clients, replicable services, which have multiple clients and replicate themselves on-demand to handle requests from those clients, and cancellation, where a process discards a channel without communicating along it. We provide session fidelity and deadlock-freedom results for this system, from which we then derive a logically justified form of garbage collection.

READ FULL TEXT VIEW PDF
POST COMMENT

Comments

There are no comments yet.

Authors

page 1

page 2

page 3

page 4

10/05/2018

On Urgency in Asynchronous Timed Session Types

We study an urgent semantics of asynchronous timed session types, where ...
02/11/2020

Back to Futures

We briefly introduce the semi-axiomatic sequent calculus for linear logi...
12/23/2021

Deadlock-free asynchronous message reordering in Rust with multiparty session types

Rust is a modern systems language focused on performance and reliability...
10/01/2021

Deadlock Freedom for Asynchronous and Cyclic Process Networks

This paper considers the challenging problem of establishing deadlock fr...
11/25/2021

Deadlock Freedom for Asynchronous and Cyclic Process Networks (Extended Version)

This paper considers the challenging problem of establishing deadlock fr...
12/10/2013

Towards deductive verification of MPI programs against session types

The Message Passing Interface (MPI) is the de facto standard message-pas...
07/08/2021

Generalising Projection in Asynchronous Multiparty Session Types

Multiparty session types (MSTs) provide an efficient methodology for spe...
This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

1 Introduction

Binary session types [15] were designed to specify the communication behavior between two message-passing processes. But there are patterns of communication that do not fall into this category. One example is one provider of a replicable service with multiple clients. Another is a multicast, that is, a process sending one message to multiple recipients. A third one is a client that no longer wishes to use a service, a form of cancellation. In this paper we provide a uniform language and operational semantics rooted in logic that captures such patterns of asynchronous communication. It generalizes the usual binary session types by supporting multiple modes of communication. In each of these modes every channel has a unique provider (which may send or receive), and possibly multiple clients. We identify the following modes: linear (a unique client that must communicate, as with the usual binary session types), affine (a unique client that may communicate or cancel), strict (multiple clients, each of which must communicate), and unrestricted (multiple clients, each of which may or may not communicate, which captures both replicable services and multicast).

A type system that uniformly integrates all of these patterns is not obvious if we want to preserve the desirable properties of session fidelity and deadlock freedom that we obtain from binary session types. Underlying our approach is adjoint logic [25, 16, 24], which generalizes intuitionistic linear logic [13, 12] and LNL [3] by decomposing the usual exponential modality into two adjoint modal operators and also affords individual control over the structural rules of weakening and contraction. We provide a formulation of adjoint logic in which cut reduction corresponds to asynchronous communication, and from which session fidelity and deadlock freedom derive. Moreover, our formulation uses a form of explicit structural rules embedded in a multicut, where weakening corresponds to cancellation and contraction corresponds to duplication of a message or service.

Some of these patterns have been previously addressed with varying degrees of proximity to an underlying logic. A replicable service with multiple clients can be achieved with access points [10] or persistent services of type  [5]. Cancellation can be addressed with affine types [18, 26, 20] further developed for asynchronous communication and general handling of failure [9]. Cancellation can also be handled with modalities used to label cancellable types [4]. This approach differs from ours in a few respects — first, Caires and Pérez work in a purely synchronous setting, without multicast, and second, they focus heavily on introducing nondeterminism, which we believe to be orthogonal to (our form of) cancellation. Closest to the present proposal is a polarized formulation of asynchronous communication in adjoint logic [22] which had several shortcomings that are addressed here. Specifically, the mode hierarchy was fixed to have only three modes (linear, affine, and unrestricted), and the unrestricted mode only allowed a single kind of proposition . This meant that, for example, multicast was not representable. Also, the rules left weakening and contraction implicit, which means that there is no explicit cancellation or distributed garbage collection, which is only briefly hinted at as a possibility [14].

The Curry-Howard correspondence relates propositions to types, proofs to programs, and proof reduction to computation. Cut reductions in a pure sequent calculcus for linear logic [5, 28] naturally correspond to synchronous communication because both premises of the cut are reduced at the same time. We reformulate adjoint logic with a nonstandard sequent calculus in which noninvertible rules are presented as axioms, that is, rules with no premises. As our operational interpretation shows, an axiom can be seen as a message and cut reduction in this sequent calculus corresponds to asynchronous communication. Another unusual aspect of our sequent calculus is that we generalize cut to a sound rule of multicut [11, 19], which operationally allows one provider to connect with multiple clients. Two further consequences of this reformulation are that (a) no explicit rules are needed for weakening and contraction, and yet (b) channels and resources are tracked with sufficient precision that computation in a network of processes “leaves no garbage” (see section 4). This is the concurrent realization of the early observation by Girard and Lafont [12] that functional computation based on intuitionistic linear logic does not require a garbage collector. Cancellation [18, 9] is a natural consequence, without requiring any special mechanism, but our system goes beyond it in the sense that processes with multiple clients will also terminate once no clients are left.

We begin with a brief discussion of our type system (section 2), deferring discussion of the underlying logic to appendix A, in order to focus on the programming system. We then present an operational semantics (section 3): our first major contribution. It models a variety of asynchronous communication behaviors, uniformly generalizing previous systems. We close by briefly presenting our results on session fidelity and deadlock-freedom, along with a brief discussion of the “garbage-collection” result that follows from them (section 4).

2 Language and Typing

Figure 1: Process Assignment for Asynchronous Adjoint Logic

Our typing judgment for processes is based on intuitionistic sequents of the form

where each of the are channels that uses and is a channel that provides. All of these channels must be distinct and we abbreviate the collection of antecedents as . The session types and specify the communication behavior that the process must follow along each of the channels.

Such sequents are standard for the intuitionistic approach to understanding binary session types (e.g., [5]) where the channels are linear in that every channel in a network of processes has exactly one provider and exactly one client. In the closely related formulation based on classical linear logic [28] all channels are on the right-hand side of the turnstile, but each linear channel still has exactly two endpoints.

We generalize this significantly by assigning to each channel an intrinsic mode . Each mode is assigned a set of structural properties among W (for weakening) and C (for contraction). Separating from allows us to have multiple modes with the same set of structural properties.111 This allows us, for example, to model the modal logic S4 or lax logic (the logical origins of comonadic and monadic programming), each with two modes both satisfying weakening and contraction, as well as linear analogues of these constructions. No matter which structural properties are available for a channel, each active channel will still have exactly one provider. Beyond that, a channel with may not have any clients. Furthermore, a channel with may have multiple clients. All other properties of our system of session types for processes derive systematically from these simple principles.

The modes are organized into a preorder where requires that , that is, must allow more structural properties than . In order to guarantee session fidelity and deadlock freedom, for any sequent is must be the case that for every we have . For example, if permits contraction and therefore may have multiple clients, then for any in , mode must also permit contraction because (intuitively) if is referenced multiple times then, indirectly, so is . If then this is ensured. We express this with the presupposition that

where simply means for every . We will only consider sequents satisfying this presupposition, so our rules, when they are used to break down a conclusion into the premises, must preserve this fundamental property which we call the declaration of independence.

In our formulation, channels as well as types are endowed with modes which must always be consistent between a channel and its type (). We therefore often omit redundant mode annotations on channels.

The complete set of rules for the typing judgment are given in Fig. 1. We first examine the judgmental rules that explain the meaning of identity and composition. Identity (rule ) is straightforward: a process providing defers to the provider of , which is possible as long as and have the same type and mode. This is usually called forwarding or identification of the channels and .

The usual logical rule of cut corresponds to the parallel composition of two processes with a single private channel for communication between them. However, ordinary cut is insufficiently general to describe the situation where a single provider of a channel may have multiple clients () or no clients (). We therefore generalize it to a form of multicut, 222The term ”multicut” has been used in the literature for different rules. We follow here the proof theory literature [19, Section 5.1], where it refers to a rule that cuts out some number of copies of the same proposition A, as in Gentzen’s original proof of cut elimination [11], where he calls it “Mischung”. where the channel provided by is known by multiple aliases in the set of channels in as long as the multiplicity of the aliases is permitted by the mode. This is expressed as and is sufficient for static typing. Formally, we define this condition by if , always, and for if . When processes execute we will have an even more general situation where one provider has multiple separate client processes, which is captured in the typing judgment for process configurations (section 3).

Next we come to the various session types. From the logical perspective, these are the propositions of adjoint logic.

Here, stands for atomic propositions at mode . The other connectives, other than and , are standard linear logic connectives, except that they are only allowed to combine types (propositions) at the same mode. Since the mode of a connective can be inferred from the modes of the types it connects (other than for shifts), we omit subscripts on connectives. Note also that and have been generalized to -ary forms from the usual binary forms. This is convenient for programming. We will use a label set when working with the binary forms and , where selects the left-hand type and selects the right-hand type. The operational meaning of these connectives (as discussed further in section 3) is largely similar to that in past work (e.g. [5]), with and sending channels along other channels, sending an end-of-communication message, and and sending labels. The shifts send a simple message to signal a transition between modes, either up () from to some or down () from to some .

We provide proof terms for the rules in our sequent calculus, as shown in Figure 1. We can then interpret the proof terms as process expressions, and these rules are used to give the typing judgment for such processes. Table 1 gives the informal meaning of each such process term.

In general, our process syntax represents an intermediate point between a programmer-friendly syntax and a notation in which it is easy to describe the operational semantics and prove progress and preservation. When compared to, for instance, SILL [27], the main revisions are that (1) we make channel continuations explicit in order to facilitate asynchronous communication while preserving message order [8], and (2) we distinguish between an internal name for the channel provided by a process and external names connecting it to multiple clients.

Process term Meaning
Identify channels and .
Spawn a new process providing channel with aliases to be used by . Here, is the internal name in for the channel offered by , and is the set of external names of the same channel as used in .
Send the label and the channel along .
Receive a label and a channel from , continue as .
Send the channels and along .
Receive channels and from to be used in .
End communication over by sending a terminal message.
Wait for to be closed, continue as .
Send a shift, from mode to mode
Receive a shift from mode to mode
Table 1: Informal Meanings of Process Terms

Some simple examples.  We provide here some small examples with their types; additional examples which highlight more interesting behavior can be found in appendix C.

First, we have a process that can be written at any mode , which witnesses that is commutative.

If is a mode that admits contraction, we can write the following process, which witnesses that proves in the presence of contraction. ‘’ starts a comment.

If is a mode that admits weakening, we can write the following process, which witnesses that proves in the presence of weakening.

3 Operational Semantics

In order to describe the computational behavior of process expressions, we need to first give some syntax for the computational artifacts, which are running processes . Such a process executes and provides a channel while using the channels in the channel set . is a set of aliases for the channel , which can be referred to by one or more clients. Each alias is used by at most one client, but one client may use multiple such aliases. Note that as the aliases in are the only way to interact with the channel from an external process, the objects and are equivalent — changing the internal name of a process has no effect on its interactions with other processes.

A process configuration is a multiset of processes:

where we require that all the aliases or names provided by the processes are distinct, i.e., given objects and in the same process configuration, and are disjoint. We will specify the operational semantics in the form of multiset rewriting rules [7]. That means we show how to rewrite some subset of the configuration while leaving the remainder untouched. This form provides some assurance of the locality of the rules.

It simplifies the description of the operational semantics if for any process , consists of exactly the free channels (other than ) in . This requires that we restrict the labeled internal and external choices, and to the case where . Since a channel of empty choice type can never carry any messages, this is not a significant restriction in practice.

In order to understand the rules of the operational semantics, it will be helpful to understand the typing of configurations. The judgment has the form which expresses that using the channels in , configuration provides the channels in . This allows a channel that is not mentioned at all in to appear in both and —we think of such a channel as being “passed through” the configuration.

Note that while the configuration typing rules induce an ordering on a configuration, the configuration itself is not inherently ordered. The key rule is the first: for any object we require that is well-typed on some subset of the available channels while the others are passed through. Here we write for the set of channels declared in , which must be exactly those used in the typing of . Moreover, externally such a process provides the channels , all of the same type . We use the abbreviation for . Finally, we enforce that the number of clients must be compatible with the mode of the offered channel, which is exactly that , as defined in section 2.

The identity and composition rules are straightforward. The empty context provides if given , since it does not use any channels in or provide any additional channels. Composition just connects configurations with compatible interfaces: what is provided by is used by .

Figure 2: Computation Rules for Asynchronous Adjoint Logic

The computation rules we discuss in this section can be found in Figure 2. Remarkably, the computation rules do not depend on the modes, although some of the rules will naturally only apply at modes satisfying certain structural properties.

Judgmental rules.  The identity rule (written as ) describes how an identity process (for instance, ) may interact with other processes. We think of such a process as connecting the provider of to clients in , and therefore sometimes call it a forwarding process. A forwarding process interacts with the provider of , telling it to replace with in its set of clients. In adding to the set of clients, the forwarding process accomplishes its goal of connecting the provider of to , and so it can terminate.

The cut rule steps by spawning a new process which offers along a fresh set of channels , all of which are used in , the continuation of the original process. Here we write and for the set of free channels in and , respectively.

Structural rules.  A process with no clients can terminate (rule ), but must notify all of the processes it uses that they should also terminate. It does so by sending each one a forwarding message, effectively embodying a cancellation. In concert with the identity rule this accomplishes cascading cancellation in the distributed setting. Note that the mode of channel must admit weakening in order for the process on the left-hand side of the rule to be well-typed.

Similarly, a process with multiple clients can spawn a copy of itself, each with a strictly smaller set of clients (rule ). If the process is a replicable service, that is, if it has a negative type , , , then this corresponds to actual process replication. If it has a positive type , , , , this corresponds to duplicating a multicast message into copies for different subsets of recipients. The mode of the channel must admit contraction in order for the process on the left-hand side of the rule to be well-typed.

While both the and rules can be applied to any process with or multiple clients, respectively, this does not cause any problems as long as we forbid them from executing on identity processes. If we apply drop or copy to an identity process, we end up with another process of the same form on the right-hand side of the rule, and so we could repeatedly apply drop or copy and not make any progress. As such, we forbid this use of the drop and copy rules.

For any other type of process, regardless of whether we drop/copy first or execute another communication rule first, we can eventually reach the same state, and so we do not need to make additional restrictions (though an actual implementation would likely pick either a maximally eager or a maximally lazy strategy for applying these rules).

Additive and multiplicative connectives.  In the rule for , the process represents the message ‘label  with continuation ’. After this message has been received, the process terminates since was its only client. The recipient selects the appropriate branch of the construct and also substitutes the continuation channel for the continuation variable .

The computation rule is largely similar to that for , except that communication proceeds in the opposite direction—messages are sent to providers from clients, rather than from providers to clients as in the case of .

The multiplicative connectives and behave similarly to their additive counterparts, except that rather than sending and receiving labels, they send and receive channels together with a continuation, and so an extra substitution is required when receiving messages, while the behaves as a nullary , allowing us to signal that no more communication is forthcoming along a channel, and to wait for such a signal before continuing to compute.

Shifts.  We present the computation rules for shifts with modes marked explicitly on the relevant channels. Channels whose modes are unmarked may be at any mode (provided, of course, that the declaration of independence is respected).

Operationally, behaves essentially the same as unary , while behaves as unary . Their significance lies in the mode shift of the continuation channel that is transmitted, which is required for the configuration to remain well-typed.

The messages or should be thought of as signaling a transition between modes — to mode for the former, and to mode for the latter. Whether the transition is up or down depends on which direction the message is being sent in. As with other messages (in particular, the messages for and ), the continuation channels are made explicit.

4 Session Fidelity, Deadlock-Freedom, and Garbage Collection

While we can prove cut elimination for the form of adjoint logic presented in appendix A, from a programmer’s perspective we are not interested in eliminating all cuts (which would correspond to reducing under -abstractions in a functional language) but rather we block when waiting to receive a message, analogous to a -abstraction waiting for input before it can reduce. What we prove instead are session fidelity and deadlock-freedom.

Session fidelity.  The session fidelity theorem follows from a case analysis on the computation rule used to get that . In each case, we break down to find the processes on which the computation rule acts, along with some collections of processes which are unaffected by the computation. From these pieces, we build a proof that .

Theorem 1 (Session Fidelity).

If and , then .

Deadlock-freedom.  The progress theorem for a functional language states that an expression is either a value or it can take a step. Here we do not have values, but there is nevertheless a clear analogue between, say, a value that waits for an argument, and a process that waits for an input. We formalize this in the definition below.

Definition 1.

We say that a process is poised on if:

  1. it is a process that sends on — that is, is of the form , or

  2. it is a process that receives on — that is, is of the form .

Intuitively, is poised on if it is blocked trying to communicate along . This definition allows us to state the following progress theorem:

Theorem 2 (Deadlock-Freedom).

If , then exactly one of the following holds:

  1. There is a such that .

  2. Every in is poised on .

In order to prove this theorem, we first prove a lemma allowing us to take advantage of the ordering induced by configuration typing. We note that if object is a client of object , must occur to the right of in the ordering, and so if we can analyze a configuration from right to left, we consider each process before (or after, depending on your view of induction) all of its dependencies. To formalize this, we present a second set of rules defining another form of configuration typing (which will turn out to prove the same judgments as the original form).

It is clear that if and are the same, then we can perform induction using the and rules rather than the , , and rules, allowing us to analyze a configuration from right to left. We formalize this as lemma 1.

Lemma 1.

if and only if .

This lemma is nearly immediate — all of the rules for are derivable from the rules of , and all rules of but are derivable from the rules of . We therefore need only show (by an induction over the right-hand premise) that the version of the rule with replaced by is admissible.

The proof of deadlock-freedom then proceeds by an induction on the derivation of , using lemma 1 to work right to left. Writing , we see that either can step, in which case so can , or every process in is poised. Now we carefully distinguish cases on (empty, singleton, or greater) and apply inversion to the typing of to see that in each case the process either is poised, can take a step independently, or can interact with provider of a channel in .

Garbage collection.  As we can see from the preservation theorem, the interface to a configuration never changes. While new processes may be spawned, they will have clients and are therefore not visible at the interface. This is in contrast to the semantics of shared channels in prior work (for example, in [5, 22]) where shared channels may show up as newly provided channels. Therefore they may be left over at the end of a computation without any clients.

This cannot happen here. Initially, at the top level, we envision starting with the configuration below on the left. Assuming this computation completes, by the progress property and the definition of poised, computation could only halt with the configuration on the right. In other words: no garbage!

One can generalize this to allow nontrivial output by allowing any purely positive type (that is, one which only uses the fragment of the logic with connectives , , , and ), such as .

We can formalize this intuition by defining an observable configuration which corresponds to our intuitive notion of garbage-free. We only define what it means for a configuration with purely positive type to be observable. It is likely that this definition can be extended to encompass negative types as well, but it is not nearly as natural to do so.

A configuration for which there is composed entirely of purely positive types such that is observable at if, when we repeatedly receive messages from all channels we know about, starting from a state where we only know about , we eventually receive a message from every object in . If we do not care about the particular channels in , we may say simply that is observable.

Definition 2.

We define what it means for a configuration to be observable at (written ) inductively over the structure of .

  1. .

  2. If , then .

  3. If , then .

  4. If , then .

We can then give the following corollary of our deadlock-freedom theorem:

Corollary 1.

If for some consisting entirely of purely positive types and cannot take any steps, then .

This proof proceeds by a simple induction on the derivation of , using (Lemma 1) to work from right to left. At each step, we note that the rightmost process is poised. Because consists only of purely positive types, the rightmost process must therefore be sending a positive message. Moreover, it can only use channels of purely positive type. Well-typedness of the configuration then lets us apply the inductive hypothesis to the remainder of the configuration, at which point we can simply apply the definition of observability.

5 Conclusion

At this point, our formulation of adjoint logic and its operational semantics seem to provide a good explanation for a variety of patterns of asynchronous communication. The key behaviors which we can model (and importantly, model in a uniform fashion) are cancellation, replication, and multicast. We also obtain a foundation for a system of distributed garbage collection. Moreover, if used linearly, our semantics coincides with the purely linear semantics developed in prior work.

In parallel work we have also provided a shared memory semantics for a closely related formulation of adjoint logic with implicit structural rules [23]. In future work, we plan to investigate if the declaration of independence is sufficient to allow a modular combination of different operational interpretations for different modes. Of particular interest here would be the semantics with manifest sharing [2].

Acknowledgments

Supported by NSF Grant No. CCF-1718267: “Enriching Session Types for Practical Concurrent Programming”

References

  • [1]
  • [2] Stephanie Balzer & Frank Pfenning (2017): Manifest Sharing with Session Types. In: International Conference on Functional Programming (ICFP), ACM, pp. 37:1–37:29, doi:http://dx.doi.org/10.1145/3110281.
  • [3] Nick Benton (1994): A Mixed Linear and Non-Linear Logic: Proofs, Terms and Models. In Leszek Pacholski & Jerzy Tiuryn, editors: Selected Papers from the 8th International Workshop on Computer Science Logic (CLS’94), Springer LNCS 933, Kazimierz, Poland, pp. 121–135, doi:http://dx.doi.org/10.1007/BFb0022251. An extended version appears as Technical Report UCAM-CL-TR-352, University of Cambridge.
  • [4] Luís Caires & Jorge A Pérez (2017): Linearity, control effects, and behavioral types. In: European Symposium on Programming, Springer, pp. 229–259, doi:http://dx.doi.org/10.1007/978-3-662-54434-1˙9.
  • [5] Luís Caires & Frank Pfenning (2010): Session Types as Intuitionistic Linear Propositions. In: Proceedings of the 21st International Conference on Concurrency Theory (CONCUR 2010), Springer LNCS 6269, Paris, France, pp. 222–236, doi:http://dx.doi.org/10.1007/978-3-642-15375-4˙16.
  • [6] Luís Caires, Frank Pfenning & Bernardo Toninho (2016): Linear Logic Propositions as Session Types. Mathematical Structures in Computer Science 26(3), pp. 367–423, doi:http://dx.doi.org/10.1016/j.tcs.2010.01.028.
  • [7] Iliano Cervesato & Andre Scedrov (2009): Relating State-Based and Process-Based Concurrency through Linear Logic. Information and Computation 207(10), pp. 1044–1077, doi:http://dx.doi.org/10.1016/j.ic.2008.11.006.
  • [8] Henry DeYoung, Luís Caires, Frank Pfenning & Bernardo Toninho (2012): Cut Reduction in Linear Logic as Asynchronous Session-Typed Communication. In P. Cégielski & A. Durand, editors: Proceedings of the 21st Conference on Computer Science Logic, CSL 2012, pp. 228–242, doi:http://dx.doi.org/10.4230/LIPIcs.CSL.2012.228.
  • [9] Simon Fowler, Sam Lindley, J. Garrett Morris & Sára Decova (2019): Exceptional Asynchronous Session Types. In: Proceedings of the 46th Symposium on Programming Languages (POPL 2019), ACM, Cascais, Portugal, pp. 28:1–28:29.
  • [10] Simon J. Gay & Vasco T. Vasconcelos (2010): Linear Type Theory for Asynchronous Session Types. Journal of Functional Programming 20(1), pp. 19–50, doi:http://dx.doi.org/10.1006/inco.1994.1093.
  • [11] Gerhard Gentzen (1935): Untersuchungen über das Logische Schließen. Mathematische Zeitschrift 39, pp. 176–210, 405–431, doi:http://dx.doi.org/10.1007/BF01201353. English translation in M. E. Szabo, editor, The Collected Papers of Gerhard Gentzen, pages 68–131, North-Holland, 1969.
  • [12] J.-Y. Girard & Y. Lafont (1987): Linear Logic and Lazy Computation. In H. Ehrig, R. Kowalski, G. Levi & U. Montanari, editors: Proceedings of the International Joint Conference on Theory and Practice of Software Development, 2, Springer-Verlag LNCS 250, Pisa, Italy, pp. 52–66, doi:http://dx.doi.org/10.1007/BFb0014972.
  • [13] Jean-Yves Girard (1987): Linear Logic. Theoretical Computer Science 50, pp. 1–102, doi:http://dx.doi.org/10.1016/0304-3975(87)90045-4.
  • [14] Dennis Griffith (2016): Polarized Substructural Session Types. Ph.D. thesis, University of Illinois at Urbana-Champaign.
  • [15] Kohei Honda (1993): Types for Dyadic Interaction. In: 4th International Conference on Concurrency Theory, CONCUR’93, Springer LNCS 715, pp. 509–523, doi:http://dx.doi.org/10.1007/3-540-57208-2_35.
  • [16] Daniel R. Licata & Michael Shulman (2016): Adjoint Logic with a 2-Category of Modes. In: International Symposium on Logical Foundations of Computer Science (LFCS), Springer LNCS 9537, pp. 219–235, doi:http://dx.doi.org/10.1007/978-3-319-27683-0˙16.
  • [17] Daniel R. Licata, Michael Shulman & Mitchell Riley (2017): A Fibrational Framework for Substructural and Modal Logics. In: International Conference on Formal Structures for Computation and Deduction, LIPIcs, Oxford, doi:http://dx.doi.org/10.4230/LIPIcs.FSCD.2017.25.
  • [18] Dimitris Mostrous & Vasco Vasconcelos (2014): Affine Sessions. In E. Kühn & R. Pugliese, editors: 16th International Conference on Coordination Models and Languages, Springer LNCS 8459, Berlin, Germany, pp. 115–130, doi:http://dx.doi.org/10.1007/978-3-662-43376-8˙8.
  • [19] Sara Negri & Jan von Plato (2001): Structural Proof Theory. Cambridge University Press, doi:http://dx.doi.org/10.1017/CBO9780511527340.
  • [20] Luca Padovani (2017): A Simple Library Implementation of Binary Sessions. Journal of Functional Programming 27(e4), doi:http://dx.doi.org/10.1016/0304-3975(83)90059-2.
  • [21] Frank Pfenning (2016): Law and Order. Available at http://www.cs.cmu.edu/~fp/courses/15816-f16/lectures/08-lawandorder.pdf. Lecture notes on Substructural Logics.
  • [22] Frank Pfenning & Dennis Griffith (2015): Polarized Substructural Session Types. In A. Pitts, editor: Proceedings of the 18th International Conference on Foundations of Software Science and Computation Structures (FoSSaCS 2015), Springer LNCS 9034, London, England, pp. 3–22, doi:http://dx.doi.org/10.1007/978-3-662-46678-0˙1. Invited talk.
  • [23] Frank Pfenning & Klaas Pruiksma (2018): A Shared Memory Semantics for Session Types. Invited talk at the Workshop on Linearity/TLLA, Oxford, UK.
  • [24] Klaas Pruiksma, William Chargin, Frank Pfenning & Jason Reed (2018): Adjoint Logic. Available at http://www.cs.cmu.edu/~fp/papers/adjoint18b.pdf. Unpublished manuscript.
  • [25] Jason Reed (2009): A Judgmental Deconstruction of Modal Logic. Available at http://www.cs.cmu.edu/~jcreed/papers/jdml2.pdf. Unpublished manuscript.
  • [26] Alceste Scalas & Nobuko Yoshida (2016): Lightweight Session Programming in Scala. In: Proceedings of the 30th European Conference on Object-Oriented Programming (ECOOP 2016), LICIcs 56, Rome, Italy, pp. 21:1–21:28, doi:http://dx.doi.org/10.4230/LIPIcs.ECOOP.2016.21.
  • [27] Bernardo Toninho, Luís Caires & Frank Pfenning (2013): Higher-Order Processes, Functions, and Sessions: A Monadic Integration. In M.Felleisen & P.Gardner, editors: Proceedings of the European Symposium on Programming (ESOP’13), Springer LNCS 7792, Rome, Italy, pp. 350–369, doi:http://dx.doi.org/10.1007/978-3-642-37036-6_20.
  • [28] Philip Wadler (2012): Propositions as Sessions. In: Proceedings of the 17th International Conference on Functional Programming, ICFP 2012, ACM Press, Copenhagen, Denmark, pp. 273–286, doi:http://dx.doi.org/10.1145/2364527.2364568.

Appendix A Adjoint Logic

We present here a brief overview of the formulation of adjoint logic that we take as a basis for the semantics presented in the main body of the paper. Adjoint logic can be thought of as a schema to define particular logics. The schema is parameterized by a set of modes of truth , where each proposition and logical connective is indexed by its mode. Furthermore, each mode intrinsically carries a set of structural properties where stands for weakening and stands for contraction. As a concession to simplicity of the presentation, in this paper we always allow exchange, although nothing stands in the way of an even more general framework [21]. In addition, an instance requires a preorder between modes, where expresses that the proof of a proposition of mode may depend on a hypotheses of mode . This preorder embodies the declaration of independence:

A proof of may only depend on hypotheses for .

The form of a sequent is

where is a collection of antecedents of the form with each , where all the variables are distinct. This critical presupposition is abbreviated as . Furthermore, the order of the antecedents does not matter since we always allow exchange.

In addition, we require the preorder between modes to be compatible with their structural properties: that is, implies . This is necessary to guarantee cut elimination.

Finally, we may define fragments by restricting the set of propositions we consider for a given mode.

The propositions at each mode are constructed uniformly, remaining within the same mode, except for the shift operators that move between modes. They are (pronounced up), which is a proposition at mode and requires ; and (down), which is also a proposition at mode , and which requires .

At this point we can already write out the syntax of propositions.

Here stands for atomic propositions at mode . Due to the needs of our operational interpretation, we generalize internal and external choice to -ary constructors parameterized by an index set . So we write .

Remarkably, the right and left rules in the sequent calculus defining the logical connectives are the same for each mode and are complemented by the permissible structural rules.

Figure 3: Rules of Adjoint Logic

a.1 Judgmental and structural rules

The rules for adjoint logic can be found in fig. 3, in which we give a more standard presentation of the logic than that used by the operational semantics (fig. 1). We begin with the judgmental rules of identity and cut, which express the connection between antecedents and succedents. Identity says that if we assume we are allowed to conclude . Cut says the opposite: if we can conclude we are allowed to assume as long as the declaration of independence is respected.

As is common for the sequent calculus, we read the rules in the direction of bottom-up proof construction. For the cut rule, this means we should assume that the conclusion is well-formed and, in particular, that and . Therefore, if we check that , then we know that the second premise, , will also be well-formed. For the first premise to be well-formed, we need to check outright that .

The structural rules of weakening and contraction just need to verify that the mode of the principal formula permits the rule.

a.2 Additive and multiplicative connectives

The logical rules defining the additive and multiplicative connectives are simply the linear rules for all modes, since we have separated out the structural rules. Except in one case, , the well-formedness of the conclusion implies the well-formedness of all premises.

As for , we know from the well-formedness of the conclusion that , , and . These facts by themselves already imply the well-formedness of the second premise, but we need to check that in order for the first premise to be well-formed.

a.3 Shifts

The shifts represent the most interesting aspects of the rules. Recall that in and we require that . We first consider the two rules for . We know from the conclusion of the right rule that and from the requirement of the shift that . Therefore, as is transitive, and the premise is always well-formed. This also means (although we do not prove it here) that this rule is invertible.

From the conclusion of the left rule, we know , , and . This does not imply that , which we need for the premise to be well-formed and thus needs to be checked. Therefore, this rule is non-invertible.

The downshift rules are constructed analogously, taking only the declaration of independence and properties of the preorder as guidance. Note that in this case the left rule is always applicable (that is, invertible), while the right rule is non-invertible.

a.4 Multicut

Because we have an explicit rule of contraction, cut elimination does not follow by a simple structural induction. However, we can follow Gentzen [11] and allow multiple copies of the same proposition to be removed by the cut, which then allows a structural induction argument. In anticipation of the operational interpretation, we have labeled our antecedents with unique variables, so the generalized form of cut called multicut (see, for example, [19]) can remove copies. Of course, such cuts are only legal if the propositions that are removed satisfy the necessary structural rules. For , we require that the mode support weakening.

For , we obtain the usual cut rule and no special requirements are needed.

For , the mode of the cut formula must admit contraction.

Here, we have used the abbreviation to stand for .

Note that each of these rules has a side condition that can be interpreted informally as stating that the number of antecedents cut must be compatible with the mode : if there are no antecedents removed, must admit weakening, and if we remove two or more, must admit contraction. This is exactly as defined in section 2.

This allows us to write down a single rule encompassing all three of the above cases for multicut:

Note that the standard cut rule is the instance of the multicut rule where , and so proving multicut elimination for adjoint logic also yields cut elimination for the standard cut rule.

a.5 Identity Expansion and Cut Elimination

We present standard identity expansion and cut elimination results as evidence for the correctness of the sequent calculus as capturing the meaning of the logical connectives via their inference rules. Cut-free proofs will always decompose propositions when read from conclusion to premise and thus yield a conservative extension result. Finally, the fine detail of the proof is significant because the cut reductions, which constitute the essence of the proof, are the basis for the operational semantics.

Theorem 3 (Identity Expansion).

If , then there exists a proof that using identity rules only at atomic propositions, which is cut-free if the original proof is.

Proof.

We begin by proving that for any formula , there is a cut-free proof that using identity rules only at atomic propositions. This follows easily from an induction on .

Now, we arrive at the theorem by induction over the structure of the given proof that . ∎

Theorem 4 (Cut Elimination).

If , then there is a cut-free proof of .

Proof.

This proof follows the structure of many cut-elimination results. First we prove admissibility of multicut in the cut-free system. This is established by a straightforward nested induction, first on the proposition and then simultaneously on the structure of the deductions and . This is followed by a simple structural induction to prove cut elimination, using the admissibility of (multi)cut when it is encountered. If we ignore the modes, this proof is very similar to the original proof of Gentzen [11]. ∎

Corollary 2.

Adjoint logic is a conservative extension of each of the logics at a fixed mode. That is, if is a sequent purely at mode (in that every type in is at mode and neither nor the types in make use of shifts), then is provable using the rules of adjoint logic iff it is provable using the rules which define the logic at mode .

a.6 Adjunction properties

As yet, we have not discussed the meaning of the name “adjoint logic”. This can be justified by showing that for fixed , and yield an adjoint pair of functors . Since prior results (see [3] and [17]) already establish this property and we have little new to contribute here, we omit the details here.

Appendix B Asynchronous Adjoint Logic

As has been observed before, intuitionistic and classical linear logics can be put into a Curry–Howard correspondence with session-typed communicating processes [5, 28, 6]. A linear logical proposition corresponds to a session type, and a sequent proof to a process expression. The transition rules of the operational semantics derive from the cut reductions.

Under the intuitionistic interpretation a sequent proof333for now on the linear fragment, and also labeling the succedent with a fresh variable of

corresponds to a process that provides channel and uses channels . The types of the channels prescribe the pattern of communication: in the succedent, positive types () will send and negative types () will receive. In the antecedent, the roles are reversed. Cut corresponds to parallel composition of two processes, with a private channel between them, while identity simply equates two channels.

b.1 Enforcing Asynchronous Communication

Under this interpretation, a cut of a right rule against a matching left rule allows computation to proceed by mimicking the cut reduction from the proof of Theorem 4. For example, a cut at type is replaced by a cut at type for some . This corresponds to passing a message (‘’) from the process providing to the process using . By its very nature, this form of cut reduction is synchronous: both provider and client proceed simultaneously because the channel connects the two process continuations.

For realistic languages, and also for the paradigm to smoothly extend to the case of adjoint logic where some modes permit weakening and contraction, we would like to prescribe asynchronous communication instead.

We observe that the asynchronous -calculus replaces the usual action prefix for output by a process expression without a continuation, thereby ensuring that communication is asynchronous. Such a process represents the message sent along channel . Under our interpretation, the continuation process corresponds to the proof of the premise of a rule. Therefore, if we can restructure the sequent calculus so that the rules that send (, , , , , , ) have zero premises, then we may achieve a similar effect.

As an example, we consider the two right rules for . Reformulated as axioms, they become

In the presence of cut, these two rules together produce the same theorems as the usual two right rules. In one direction, we use cut

and in the other direction we use identity

to derive the other rules.

Returning to the -calculus, instead of explicitly sending a message we spawn a new process in parallel . This use of parallel composition corresponds to a cut; receiving a message is achieved by cut reduction:

We see the cut reduction completely eliminates the cut in one step, which corresponds precisely to receiving a message. In this example the message would be since the axiom was used; for it would be .

In summary, if we restructure the sequent calculus so that the non-invertible rules (those that send) have zero premises, then (1) messages are proofs of axioms, (2) message sends are modeled by cut, and (3) message receives are a new form of cut reduction with a single continuation.

In the process we give something up, namely the traditional cut elimination theorem. For example, the sequent has no cut-free proof since no rule matches this conclusion. The saving grace is that we can reach a normal form where each cut just simulates the usual rules of the sequent calculus. This can be shown by translation to the ordinary sequent calculus, applying cut elimination, and translating the result back. Proofs in this normal form have the subformula property. Perhaps more importantly, we have session fidelity and deadlock freedom (section 4) for the corresponding process calculus even in the presence of recursive types and processes, which is ultimately what we care about for the resulting concurrent programming language.

b.2 Eliminating Weakening and Contraction

We have introduced multicut entirely with the standard motivation of providing a simple proof of the admissibility of cut using structural induction. Surprisingly, we can streamline the system further by using multicut to eliminate weakening and contraction from the logic altogether, as in the system we use as the basis for our typing rules (fig. 1).

Consider a mode with . Then contraction is a simple instance of multicut with an instance of the identity rule.

Similarly, for a mode with , weakening is also an instance of multicut.

Cut reductions in the presence of contraction entail many residual contractions, as is evident already from Gentzen’s original proof. Under our interpretation of contraction above, these residual contractions simply become multicuts with the identity. The operational interpretation of identities then plays three related roles: with one client, an identity achieves a renaming, redirecting communication; with two or more clients, an identity implements copying; with zero clients, its effect is cancellation or garbage collection. The central role of identities can be seen in full detail in Figure 2, once we have introduced our notation for processes and process configurations.

Appendix C Program Examples

In the examples that follow, we will work with two modes, and , with , , and . In these examples we also use recursively defined types and processes without formally defining these constructs, since they are well-known from the literature and orthogonal to our concerns (see, for example, [27]).

c.1 Example: Circuits

We call channels that are subject to weakening and contraction shared channels. As an example that requires shared channels we use circuits. We start by programming a nor gate that processes infinite streams of zeros and ones. This is somewhat verbose, but note that all channels here are shared. For this particular gate they could also be linear because they are neither reused nor canceled. This illustrates that programming can be uniform at different modes, which is a significant advantage of our system over systems of session types based on linear logic with an exponential . Our implementation of nor has the property that for bits , , and with , the following transitions are possible and characterize nor:  ( fresh)

This multi-step reduction is shown in full (one step at a time) below. We only show the initial portion of each process term, which is enough to disambiguate where in the program we are, as otherwise process terms become unwieldy and reduce clarity. We also assume the existence of a rule that lets us invoke a defined process, replacing the call with the process definition, after appropriate substitution. At each step, we have highlighted in red the process(es) that are about to transition.

When we build an or-gate out of a nor-gate we need to exploit sharing to implement simple negation. In the example below, and are both names for the same shared channel. The process invoked as will multicast a message to the clients of and . An analogous computation to the above is possible, except that at an intermediate stage of the computation, we will also have a shared channel carrying the (multicast) message with .

c.2 Example: Map

Mapping a process over a list allows us to demonstrate the use of replicable services, as well as cancellation. We define a whole family of types indexed by a type , which is not formally part of the language but is expressed at the metalevel. Such a list should not be viewed as a data structure in memory. Instead, it is a behavioral description of a stream of messages. A process that maps a channel of type to one of type will itself have type . However, this process must be shared since it needs to be applied to every element. We therefore obtain the following type and definition, where all channels not annotated with a mode subscript are at mode . % receive element with continuation % duplicate the channel % obtain a fresh linear instance of % send to , response will be along fresh % select % send with continuation % recurse with continuation channels % Cancel the channel % select % wait for to close % close and terminate In this example, is a replicable and cancelable service. In the case of a nonempty list, we create two names for the channel — one to use immediately and one to pass to the recursive call. Note that the service itself remains a single service with two clients until the message is sent to it, at which point it replicates itself, creating one copy to handle this request and leaving another to deal with future requests. In the case of an empty list, we have no elements to map over, and so we do not need to use . As such, we cancel it before continuing.