Under consideration for publication in Math. Struct. in Comp. Science
Linearity, Session Types and the Pi Calculus Marco Giunti1 and Vasco Thudichum Vasconcelos2 1 2
´ INRIA Saclay and LIX, Ecole Polytechnique, France LaSIGE, Faculty of Sciences, University of Lisbon
Received 20 December 2011
We present a reconstruction of session types in a conventional pi calculus. Our session types are qualified as linear or unrestricted. Linearly typed communication channels are guaranteed to occur in exactly one thread, possibly multiple times; afterwards they evolve to unrestricted channels. We equip types with a constructor that describes the two ends of a same communication channel, and propose a type system that is sound with respect to the reduction relation. We then introduce an algorithmic type system which we prove sound and complete with respect to original system. We assess the expressivity of our typing system by providing three distinct encodings (from the pi calculus with polarized variables, from the pi calculus with accept and request primitives, and from the linear pi calculus) into our system. For each language we present operational and typing correspondences, showing that our system e↵ectively subsumes the linear pi calculus as well as foregoing works on session types. In the case of the linear pi calculus we also provide a completeness result, thus proving that linear pi is a sublanguage of ours.
1. Introduction Session types allow a concise description of protocols by detailing the sequence of messages involved in each particular run of the protocol. Introduced firstly for a dialect of the pi calculus (HVK98; THK94), the concept has been transferred to di↵erent realms, including functional and object-oriented programming and operating systems; refer to (DCd10) for a recent overview. In this paper we introduce a type system with session types for the conventional pi calculus that turns out to be more flexible than the type systems found in the literature. By way of motivation, consider a service allowing to create online petitions. Petition creators receive from the petition service provider a channel on which they supply the title and the description of the petition, as well as the due date. After the initial setup, the exact same channel is ready to be distributed among the client’s acquaintances to collect thousands of signatures, but not without the creator signing the petition first. The code for the creator can be written as follows, petitionOnline(p).phtitlei.phdescriptioni.phdueDatei.phsignaturei.(a1 hpi | . . . | an hpi) where x(y) denotes reading value y on channel x, xv denotes sending value v on channel x, and the vertical bar denotes parallel composition. Each of the acquaintances (not shown
M. Giunti and V.T. Vasconcelos
2
in the example), after reading p on channel ai , can sign the petition and further distribute the channel at will. The protocol for channel p can be concisely described by a type of the form below, composed of an initial linear part that becomes shared (or unrestricted) in the later part. lin !String.lin !String.lin !Date.S
where
S = un !String.S
The final part is unrestricted because it is desirable, but not absolutely necessary, that acquaintances (including the petition creator) sign the petition; conversely, the initial part is linear because petitions cannot be signed without first setting up the title, the description and the due date. Recursive types such as S are so common that we introduce an abbreviation for them; rather than talking of type S such that S = un !String.S, we simply write ⇤!String. In the process above, each channel ai forwards p at type S. Such a channel may be given the type lin!S.end, if we require that acquaintances can only receive the petition channel once; the continuation is end, the type of a channel on which no further interaction is possible. Concentrating on the type of channel petitionOnline, we see that petition creators need it at a type of the form ⇤?T , so that they may create as many petitions (of type T ) as required. The code for the service provider may be written as follows, !(⌫p)petitionOnlinehpi.p(title).p(description).p(dueDate).!p(signature).ProcessSignatures where ! in a processes denotes a replicated process—a process of which an unbounded number of copies are available—since the service must available to multiple clients, and where (⌫p) denotes the creation of a new channel. For each copy, the service provider starts by creating a new petition channel p. One of its ends is then sent to the client (via a message petitionOnlinehpi), the other is kept for further interaction (in the process starting at p(title)). It should be easy to see that the service provider itself sees the channel petitionOnline at a type of the form ⇤!T . The whole system, composed by the service provider running in parallel with all petition creators, can be typed by reconciling the two end point types ⇤?T and ⇤!T in a single channel type of the form (⇤?T , ⇤!T ). A novelty of our system is that channel types are always pairs, denoting the operations available to each channel end. So, in fact, type T above must describe the operations on both ends of channel p, as available to petition writers. Since petition writers are given read/write access to exactly one end of the channel (the read/write permission to the other end stays with the service provider, so that interaction goes according to plan), type T for channel p is (lin !String.lin !String.lin !Date.⇤!String, end) So now we can better understand the phenomenon taking place at the service provider, when it sends message petitionOnlinehpi. The type of channel p, as created in (⌫p), is (lin !String.lin !String.lin !Date.⇤!String, lin ?String.lin ?String.lin ?Date.⇤?String) This type is then split in two types: type T above and a type T 0 of the form below. (end, lin ?String.lin ?String.lin ?Date.⇤?String)
Linearity, Session Types and the Pi Calculus
3
Type T is sent to petition writers; type T 0 is kept by the service provider and is the type that governs further interaction at the server side (the subprocess starting at p(title)). We mentioned above that type end describes a channel end point on which no further interaction (read or write) is possible. This does not mean that a process, knowing a given channel end point at type end, cannot use it at all; it only means that read/write operations are forbidden on the channel end point. What other operations are then available on such an end point? In the simplest form of pi-calculus (the one studied in this paper) the only remaining operation is sending the channel around. We can nevertheless think of other operations, such as testing the channel for equality. Suppose the petition server keeps track of the titles of all petitions so far created. Further suppose that channel dbSet is used to write a pair channel-title in the database. Upon the reception of the title, the server may update the database as follows. !(⌫p)petitionOnlinehpi.p(title).dbSethp, titlei.p(description) . . . Once again, type splitting allows to type this variant of the server. When typing the subprocess starting at dbSethp, titlei, the type T 00 = (lin ?String.lin ?Date.⇤?String, end) of channel p is split in two: T 00 itself and (end, end). Type T 00 is used to type the continuation process (the process starting at p(description)), whereas type (end, end) is used to pass p to the database. The database cannot use p to read or write, but may store it in some data structure or compare it for equality, for example. The ability to pass part of the functionality of a linear channel and retain the rest goes beyond what is usually available to session typing systems. The language of the pi calculus, when considered in conjunction with a type system with session types, is known to require a means to distinguish the two ends of a session channel in order to preserve type soundness (DCDMY09; GH05; YV07). Alternative solutions not requiring such a distinction rely on the restriction of channel passing to bound output. Such systems include the original formulation of delegation in session types (HVK98) as well as more recent works (CDCGP09; Pad09). Two approaches for distinguishing the ends of a channel are available in the literature: polarized channel variables (GH05), and form of channel double binder (Vas09). In the pi calculus with polarities, the two ends of a channel x are distinguished by labelling each with a di↵erent label: x+ and x denote the two ends of channel x. Since from an identifier x we can recover the two ends of the channel, the restriction of (the two ends of) x can be made with the usual pi calculus restriction operator (⌫x)P . Typing contexts, however accept two di↵erent entries for the same channel, one labelled with +, the other with , as in the typing sequent below. , x+ : S1 , x : S2 ` x+ v.P1 | x (w).P2 A variant of the above work, (Vas09), uses distinct variables to describe the two ends of a same channel. In this case one cannot obtain the second end of a channel from the other end. It is restriction that puts together the two channel ends, by binding them together, as in (⌫yz)P . The assumptions in typing contexts are for simple variables, as
M. Giunti and V.T. Vasconcelos
4
in the example below where y and z denote the two ends of a same channel. , y : S1 , z : S2 ` yv.P1 | z(w).P2 The first work uses non-conventional typing contexts, where typing information of a same channel x is split among two di↵erent entries, x+ and x . The second work uses standard contexts but relies on a new scope restriction operator that binds two variables together. The goal of this work is to equip types with a constructor able to denote the two ends of a same channel. We then have the best of both worlds where we use the standard pi calculus (Milner et al. (MPW92)) with standard typing sequents: , x : (S1 , S2 ) ` xv.P1 | x(w).P2 At the same time, by taking advantage of the type splitting operation, we enlarge the class of typable processes by decomposing the behaviour of a channel in two parts, sending one part, while retaining the other. We test the flexibility of our type system by embedding the pi calculus with polarities and session types (GH05) (hence the conventional pi calculus (MPW92)). We do the same for the original version of session type, the pi calculus with accept/request primitives (HVK98), and the linear pi calculus (KPT99). For each of these languages we prove an operational and a typing correspondence result. The embeddings show that our type system is an extension of advanced type systems for pi calculi. The outline of the paper is as follows. The next section recalls the pi calculus. Section 3 introduces our type system, and Section 4 its algorithmic variant. Then, the subsequent three sections present the embeddings of the three languages mentioned above: the pi calculus with polarities (Section 5), the accept/request pi calculus (Section 6) and the linear pi calculus (Section 7). The last section presents the related as well as future work. 2. Pi Calculus This section introduces the pi-calculus, its syntax and semantics. The syntax is in Figure 1. We rely on a countable set of variables, ranged over by x, y, z. Values include variables and the booleans true and false. For processes we have (synchronous, unary) output and input, in the forms xv.P and x(y).P , as well as parallel composition, conditional, scope restriction, replication and the terminated process. The binders for the language appear in parenthesis: x is bound in both y(x).P and (⌫x)P . Free and bound variables in processes are defined accordingly, and so is alpha conversion, and substitution of a variable x by a value v in a process P , denoted P [v/x]. The set of free variables in a process P is denoted by fv(P ). We follow Barendregt’s variable convention, requiring bound variables to be distinct from free variables in any mathematical context. Structural congruence is the smallest relation on processes including the rules in the same figure. The first three rules say that parallel composition is commutative, associative and has 0 for neutral element. The last rule on the first line captures the essence of replication as an unbounded number of identical processes. The rules in the second line deal with scope restriction. The first, scope extrusion, allows the scope of x to encom-
Linearity, Session Types and the Pi Calculus
5
Syntax v ::=
Values: true
true
false
false
x P ::=
x(x).P P |P
composition
(⌫x)P
restriction
!P
replication
if v then P else P
variable Processes:
xv.P
input
output
conditional
0
inaction
P ⌘ P Rules for structural congruence P |Q⌘Q|P
(P | Q) | R ⌘ P | (Q | R)
(⌫x)P | Q ⌘ (⌫x)(P | Q)
P |0⌘P
(⌫x)0 ⌘ 0
!P ⌘ P |!P
(⌫x)(⌫y)P ⌘ (⌫y)(⌫x)P
P ! P Rules for reduction xv.P | x(y).Q ! P | Q[v/y]
if true then P else Q ! P
P ! Q (⌫x)P ! (⌫x)Q
[R-Com]
if false then P else Q ! Q
P ! Q P |R ! Q|R
P ⌘P
0
0
[R-IfT] [R-IfF] 0
P ! Q Q0 ⌘ Q P ! Q [R-Res] [R-Par] [R-Struct]
Fig. 1. Pi calculus: Syntax and operational semantics
pass Q; due to variable convention, x bound in (⌫x)P , cannot be free in Q. The other two rules state that restricting over a terminated process has no e↵ect and that the order of restrictions can be exchanged. The reduction reduction is the smallest relation on processes including the rules in Figure 1. The [R-Com] rule communicates value v from an output prefixed one xv.P to an input prefixed process x(y).Q; the result is the parallel composition of the continuation processes, where the bound variable y is replaced by value v in the input process. The rules for the conditional are straightforward. The rules in the last line allow reduction to happen underneath scope restriction and parallel composition, and incorporate structural congruence into reduction. 3. Type Checking This section introduces our type system as well as its the main result, namely soundness with respect to the reduction relation. The syntax of types is described in Figure 2. Types include the boolean type and channel types. The novelty with respect linear and session-based systems for the pi calculus is the introduction of a new type constructor to describe the two ends of a same channel, (S1 , S2 ), where S1 details the behaviour of one end, whereas S2 details that of the other end. An end point type S can be a pre type qualified with lin or un, the end type, a recursive type or a type variable. Each qualifier in a type controls the number of times the channel can be used at a given point: exactly once for lin; zero or more times for un. A pre type of the form !T.S describes a channel
M. Giunti and V.T. Vasconcelos q ::=
6
Qualifiers: lin
linear
un
unrestricted
p ::=
a µa.S T ::=
Pre end point types: ?T.S
receive
!T.S
send
S ::=
End point types: qp
qualified end point
end
used end point
type variable recursive end point Types:
bool
boolean
(S, S)
channel
::=
Contexts: ;
empty context , x: T
variable binding
Fig. 2. Pi calculus: Types and typing contexts
end able to send a value of type T and to proceed as prescribed by S. Similarly, pre type ?T.S describes a channel end able to receive a value of type T and continue as S. End point type end describes a channel end on which no further interaction is possible. For recursive (end point) types we rely on a set of type variables, ranged over by a. Recursive types are required to be contractive, that is, containing no subexpression of the form µa1 . . . µan .a1 . End point type equality is not syntactic. Instead, we define it as the equality of regular infinite trees obtained by the infinite unfolding of recursive types. The formal definition, which we omit, is co-inductive. In this way we use types µa.lin!bool.lin?bool.a and lin!bool.µb.lin?bool.lin!bool.b interchangeably, in any mathematical context. This allows us never to consider a type µa.S explicitly (or a for that matter). Instead, we pick another type in the same equivalence class, namely S[µa.S/a]. If the result of the process turns out to start with a µ, we repeat the procedure. Unfolding is bound to terminate due to contractiveness. In other words, we take an equi-recursive view of types (Pie02). Type duality plays a central role in the theory of session types, ensuring that communication between the two ends of a channel proceeds smoothly. Intuitively, the dual of output is input and the dual of input is output. In particular if S2 is dual of S1 , then q?T.S1 is dual of q!T.S2 . End point type end is dual of itself. Rather than providing a co-inductive definition of duality, we start by defining a function from end-point channels into end-point channels as follows. q ?T.S = q !T.S
q !T.S = q ?T.S
end = end
µa.S = µa.S
a=a
Then, to check that a given end point type S1 is dual of another type S2 , we first build the dual of S1 and then check that the thus obtained type is equivalent to S2 . For example, to show that type µa.lin?bool.lin!bool.a is a dual of type lin!bool.µb.lin?bool.lin!bool.b, we build µa.lin?bool.lin!bool.a = µa.lin!bool.lin?bool.a, and then show that µa.lin!bool.lin?bool.a = lin!bool.µb.lin?bool.!bool.b. Qualifiers are important: S and S must be equally qualified so that a linear output process may find a linear input process to embark in reduction. Contexts, or type environments, are inductively defined in Figure 2. In a context , x : T
Linearity, Session Types and the Pi Calculus S=S
S End point type splitting rules end
S=S T =T
7
S = end S
un p = un p un p
T Type splitting rules bool = bool bool
=
R = R1 R2 S = S1 S2 (R, S) = (R1 , S1 ) (R2 , S2 )
Context splitting rules = 1 , x: T = (
;=; ; + (x : T ) =
T = T1 T2 , x : T 1 1 ) ( 2 , x : T2 ) 2
= 1 , x: T = (
T = T2 T1 , x : T 1 1 ) ( 2 , x : T2 ) 2
Context update rule ( , x : T1 ) + (x : T2 ) = , x : T1
T2
` v : T Typing rules for values un( ) ` true : bool
un( ) ` false : bool
un( ) , x: T ` x: T
[T-True] [T-False] [T-Var]
` P Typing rules for processes un( ) `0
1
` P1
1
2
2 ` P2 ` P1 | P2
`P
un( ) `!P
[T-Inact] [T-Par] [T-Repl]
, x : (S, S) ` P 2 ` P1 2 ` P2 [T-If] [T-Res] ` if v then P1 else P2 ` (⌫x)P 0 ( 2 + x : (S, S 0 )), y : T ` P q = un ) q?T.S = S 1 ` x : (q?T.S, S ) [T-InL] ` x(y).P 1 2 0 ( 2 + x : (S 0 , S)), y : T ` P q = un ) q?T.S = S 1 ` x : (S , q?T.S) [T-InR] 1 2 ` x(y).P 0 0 q = un ) q!T.S = S 1 ` x : (q !T.S, S ) 2 ` v: T 3 + x : (S, S ) ` P [T-OutL] 1 2 3 ` xv.P 0 0 q = un ) q!T.S = S 1 ` x : (S , q !T.S) 2 ` v: T 3 + x : (S , S) ` P [T-OutR] 1 2 3 ` xv.P 1
` v : bool 1
2
Fig. 3. Pi calculus: Type checking
we assume that x does not occur in ; we also assume that the various variable bindings in are unordered. We define the un predicate over end point types, types and contexts. For end point types, predicate un is true of end, of un p, and of µa.S when un(S). For types, predicate un is true of bool and of (S1 , S2 ) if un(S1 ) and un(S2 ). The predicate is then extended pointwise to contexts, so that un( ) if and only if un(T ) for all x : T in . We say that a type T is unrestricted (or shared ) when un(T ), and similarly for an end point S. We say that an end point S is linear if S is not unrestricted, that is, if S is of the form lin p. Typing relies on the splitting operation described in Figure 3. Any end point type S can be split in two: S itself and end, in either order. Unrestricted end point types S, on the other hand, may be split into two copies of S. In this way we make sure that linear
M. Giunti and V.T. Vasconcelos
8
end point types are never duplicated or eliminated, but we may loose information about unrestricted end points. For types, bool, as an unrestricted type according to the definition above, is split into two identical copies. Channel types are split in two by splitting the two end point types they are formed of. Finally, context splitting is defined inductively, based on type splitting. The two rules for non-empty contexts allow to “send” the first component of a linear end point type to the left context, or to the right context. We often write T1 T2 for the type T such that T = T1 T2 , if there is such a type in the splitting relation, and similarly for end point types S and contexts . Below we show some examples of type splitting, where L, L1 , L2 represent linear types and U, U1 , U2 unrestricted types. (U1 , U2 ) = (U1 , U2 ) (U1 , U2 ) (U1 , U2 ) = (end, U2 ) (U1 , end) (L1 , L2 ) = (end, end) (L1 , L2 ) (L1 , L2 ) = (L1 , end) (end, L2 ) (L, U ) = (L, U ) (end, U ) What we do not have is duplication or elimination of linear types, (L1 , L2 ) = (L1 , L2 ) (L1 , L2 ) (L1 , L2 ) = (L1 , end) (end, end) exchanging of end point types (U1 6= U2 ), (U1 , U2 ) = (U1 , U2 ) (U2 , U1 ) or the complete elimination of types (T 6= (end, end)) T = (end, end) (end, end). We also need and operation to update a given context , x : T1 with a context entry x : T2 , yielding a context where x is associated with the type T such that T = T1 T2 . The operation is used to type the continuation process in the rules for input and output. Equipped with the notions of type duality, unrestricted contexts, and context splitting and updating we are ready to introduce the typing rules in Figure 3. Those for values are straightforward: the type of a boolean value is bool (rules [T-True] and [T-False]) and that of a variable x is read from the context (rule [T-Var]). In both cases, the “unused” part of the context must be unrestricted, so that linear values may be consumed. For processes, rule [T-Inact] says that the terminated process can only be typed in an unrestricted context, ensuring that linear channels are given a chance to be consumed. Rule [T-Par] uses context splitting to partition linearly typed variables between the two processes: the incoming context is split into 1 and 2 , and we use the former to type check process P1 and the latter to type check process P2 . Rule [T-Repl] for replication requires the typing context not to contain linear values, for P may be used an unbounded number of types. Rule [T-If] for the conditional process splits the incoming context in two parts: one used to check the condition, the other to check both branches. The same context for the two branches is justified by the fact that only one of P1 or P2 will be
Linearity, Session Types and the Pi Calculus
9
executed. Rule [T-Res] allows restricting channels whose end points are dual, making sure that communication on the channel happens according to the plan. There are two rules for input processes, [T-InL] and [T-InR], depending on whether the input end of the type for x presents itself on the left or on the right. Rule [T-InL], splits the context in two: one for typing x, the subject of communication, the other to type P , the continuation process. The type for x must be of the form (q?T.S, S 0 ); the continuation process is typed at a context containing an entry y : T for the bound variable. The new type for x is obtained by adding to the type of x in 2 a type composed of the continuation S and the unused end point type S 0 . For example, if x : (lin?T.S, L) is in 1 2 , then the type for x in 2 may take one of two forms: (end, end) or (end, L). In either case, the type for the continuation is (S, L) = (end, end) (S, L) = (end, L) (S, end). If x : (lin?T.S, U ) is in 1 2 , then either x : (end, U ) or x : (end, end) is in 2 , and (S, U ) is used to type P in both cases. Finally, if x : (un?T.S, U ) is in 1 2 , then x : (un?T.S, U ) or x : (un?T.S, end) or x : (end, U ) or x : (end, end) is in 2 . Again, in all cases, x : (S, U ) is used to type the continuation, but only if un?T.S = S in the first two cases (this can happen when S is for example of the form µa.?T.a). The proviso in the typing rule, q = un ) q?T.S = S, is also necessary when we compose (end, U ) in 2 with (S, U ) above. Would un?T.S be an arbitrary unrestricted type, we would be able to type the continuation at an arbitrary type S = end S. Take for example S = lin?bool.end, so that the type under consideration becomes un?T.lin?bool.end. A channel that starts with an unrestricted type to become linear is always unsound. To see why, further take = x : (un?T.S, un!T.S) and P = x(y).x(z). It should be easy to see that ` P , and also ` ⇤P | xv. But the last process reduces to process ⇤P | x(z) which is not typable under x : (S, S). Rules [T-OutL] and [T-OutR] are similar, only that we split the context in three parts, the first to type x, the subject of communication, the second to type v, the object of communication, and the last to type P , the continuation process. If a linear channel end is passed, splitting makes sure the continuation process keeps the channel at an end type. Splitting is quite flexible: given a (L1 , L2 ) type, we may pass (L1 , L2 ) and keep (end, end) (or vice-versa), or pass (L1 , end) and keep (end, L2 ) (or vice-versa). We complete this section by typing parts of the example in the introduction. Consider the subprocess phsignaturei.(a1 hpi | . . . | an hpi) of the petition writer, and the typing context = signature : String, p : (S, end), where S is such that S = un!String.S. In order to apply rule [T-OutL], we need to split in three parts; since is unrestricted all parts can be made identical and equal to . Using rule [T-Var] we have ` p : (S, end) as well as ` signature : String. Then in order to type the continuation process we need to compute + p : (S, end), which is equal to since the type of p in is (S, end) and S in an unrestricted type. Notice that x : (S, end) is still available to type the continuation process a1 hpi | . . . | an hpi. For another example of context splitting, consider petitionOnlinehpi.p(title) . . . , a subprocess of the petition server. Suppose that we have a typing context , p : (S 0 , S 0 ), where contains entry petitionOnline : ⇤!T , as well as the required entries to type ProcessSignatures and the database operations, and where S 0 is the end point type lin !String.lin !String.lin !Date.⇤!String and T the type (S 0 , end). In order to use rule
M. Giunti and V.T. Vasconcelos
10
[T-OutL], we start by splitting , p : (S 0 , S 0 ) in three parts. Let U ( ) denote the context containing exactly the unrestricted entries in . Our three contexts are U ( ) to type 0 channel petitionOnline, U ( ), p : (S 0 , end) to type channel p and , p : (end, S ) to type the continuation process. Another interesting example of context splitting occurs later on, in subprocess dbSethp, titlei . . . , where the context is now , p : T 00 , where T 00 is the type T 00 = (lin ?String.lin ?Date.⇤?String, end). In this case we split T 00 in (end, end) and T 00 , use the former to type parameter p, and the latter to type the continuation. Reduction preserves typability, but not for arbitrary contexts. To understand the situation, take for P the process x(z).if z then 0 else 0 | (⌫y)xy. We can easily see that P is typable under the context x : (lin!(end, end).end, lin?bool.end). But P reduces to process (⌫y)if y then 0 else 0 which is not typable (at all). The reader may have noticed the peculiarity of the type for channel x: one end point sends (end, end), the other expects a bool. This context is not balanced, the type of one end point is not dual to the type of the other. The whole purpose of balancing is to make sure that the type of y in the output matches that of z in the input. A similar phenomenon happens with structural congruence. Take for T the type (lin!bool.end, ⇤!bool), then process xtrue | ⇤xtrue is typable under context x : T , but the structural congruent process ⇤xtrue is not. Once again, requiring balanced contexts solves the problem. Given that type preservation is only certain under balanced contexts and that unbalanced types cannot possibly be restricted by rule [T-Res], the reader may wonder why we consider them at all. It turns out that free channel output may lead to situations where a thread holds the two ends of a same channel (YV07). For instance, process zx | z(w).w(y).xtrue, typable under context z : (⇤?S, ⇤!S), x : (S, S) with S = lin?bool, reduces to process P = x(y).xtrue, which we want to type under the same context. By applying rule [T-InL] to P we obtain a judgment with a un-lin type, namely z : (⇤?S, ⇤!S), x : (end, lin!bool) ` xtrue. A further application of rule [T-OutR] gets rid of the un-lin type, yielding z : (⇤?S, ⇤!S), x : (end, end) ` 0 typable under rule [T-Inact]. We thus observe the presence of unbalanced contexts in a derivation tree conducting to a sequent with a balanced context. The rest of this section presents the main result of our type system, namely that reduction preserves typability. A milestone along the path to the result is a lemma that says that structural congruence preserves typability, as well. After a few general lemmas about context splitting, we build towards structural congrence preserves typability, by proving standard results such as weakening and strenghtening. The last part of the section paves the way to reduction preserves typability, by proving a substitution lemma. Given a context , notation U ( ) denotes the sub-context of containing the unrestricted entries, and notation dom( ) denotes the set of variables in . Lemma 3.1 (Properties of Context Splitting). Let 1 2 3 4 5
Relation is associative and commutative. U( ) = . dom( ) = dom( 1 ) = dom( 2 ). If 1 = 01 , x : T1 and un(T1 ) then = ( 01 If un( 1 ) then = 2 .
0 2 ), x :
=
T2 with
2.
1
2
=
0 2, x :
T2 .
Linearity, Session Types and the Pi Calculus 6 If
is balanced and un(
1)
then un(
11
2 ).
Proof. A straightforward induction on the length of tradiction.
. The last case follows by con-
Lemma 3.2 (Unrestricted weakening). Let T be an unrestricted type and S an unrestricted end point type. 1 2 3 4
If ` v : T 0 then , x : T ` v : T 0 . If ` P then , x : T ` P . If , x : (S 0 , end) ` P then , x : (S 0 , S) ` P . If , x : (end, S 0 ) ` P then , x : (S, S 0 ) ` P .
Proof. A simple case analysis in the first case, and induction on the structure of P in remaining. Lemma 3.3 (Strengthening). 1 If , x : T ` v : T 0 and x 6= v then ` v : T 0 and un(T ). 2 If , x : T ` P and x 62 fv(P ) then ` P and un(T ). Proof. A simple case analysis in the first case, and induction on the structure of P in the second. Recall that we say that a context is balanced when x : (S1 , S2 ) 2 implies S1 = S2 . Balanced contexts are needed in order to show that ` P | !P implies `!P , as discussed above. Lemma 3.4 (Structural congruence preserves typability). If anced and P ⌘ Q then ` Q.
` P and
bal-
Proof. The proof follows by an analysis of the axioms in the definition of relation ⌘. The axioms for associativity, commutativity, and the neutral of parallel composition follow from the basic results about context splitting, Lemma 3.1 items 1–2. The case of (⌫x)0 ⌘ 0 is straightforward to establish. The case of (⌫x)(⌫y)P ⌘ (⌫y)(⌫x)P follows by the fact that contexts are considered up to permutations of its entries. The case of axiom !P ⌘ P |!P , when read left-to-right, relies on Lemma 3.1 item 5. When read right-to-left, we know from rules [T-Par],[T-Repl] that = 1 2 and , hence ` P. 1 ` P and un( 2 ). Then Lemma 3.1 item 5 guarantees that 1 = In order to apply rule [T-Repl], we need to establish that un( ), for which we use Lemma 3.1 item 6. In the case of axiom (⌫x)P | Q ⌘ (⌫x)(P | Q), variable convention tells us that x 62 fv(Q) and also that x 62 . When read left-to-right, we know from rules [T-Par],[T-Res] that 1 , x : (S, S) ` P and 2 ` Q with = 1 2 . We start by weakening the sequent 0 0 ) where S 0 is S if un(S), else end. Is is then easy to see that ` Q by introducing x : (S , S 2 ( 1 , x : (S, S)) ( 2 , x : (S 0 , S 0 )) is defined and equal to , x : (S, S). Conclude the case with rules [T-Par],[T-Res]. For the right-to-left case, the same two rules give us that , x : (S, S) = 1 2 and 1 ` P and 2 ` Q. We now analyze 1 and 2 . Lemma 3.1 item 3 tells us that 1 , 2 are of the form 01 , x : T1 , 2 , x : T2 , and Lemma 3.3 tells
M. Giunti and V.T. Vasconcelos
12
that T2 is unrestricted and that 02 ` Q. When S = lin p we apply [T-Res] and infer 0 1 ` (⌫x)P . Otherwise, we have un(S), and four cases arise, corresponding to T = (S, S) or T = (end, end) or T = (S, end) or T = (end, S). In the first two cases we apply [T-Res] and infer 01 ` (⌫x)P . In the last two we use Unrestricted Weakening to obtain 0 1 , x : (S, S) ` P . Conclude with rule [T-Par]. Lemma 3.5 (Inversion of the Splitting Relation). Let T1 be a type of the form (q1 !T10 .S1 , q2 ?T20 .S2 ). If = ( 1 , x : T1 ) and x : T2 2 2 , where T2 is 2 , then x : T1 2 of one of the four forms below. 1 (end, end) 2 T1 when q1 = q2 = un 3 (q1 !T10 .S1 , end) when q1 = un 4 (end, q2 ?T20 .S2 ) when q2 = un Proof. Directly from the definition of context splitting. Note that there is an obvious dual lemma where x : (q2 ?T20 .S2 , q1 !T10 .S1 ) 2 (end, q1 !T10 .S1 ) in case 3, and is (q2 ?T20 .S2 , end) in case 4. Lemma 3.6 (Substitution). If 3 ` P [v/x].
1
` v : T and
2, x :
T ` P and
3
=
and T2 is
1
2,
then
Sketch The proof is by induction on the typing derivation and uses weakening and strengthening (Lemmas 3.2, 3.3). The proof is elaborate but straightforward. Theorem 3.7 (Type Preservation). If 2 ` P2 and 1 2 3
1 1 1
= = =
2,
1
` P1 with
1
balanced and P1 ! P2 , then
or
3, x : 3, x :
(q!T.S, q?T.S) and (q?T.S, q!T.S) and
2 2
= =
3, x : 3, x :
(S, S), or (S, S).
Furthermore, in the last two cases, if q = un then q!T.S = S. Proof. The proof is by induction on the derivation for the reduction. Notice that 2 is balanced in any case. When the derivation ends with rule [R-IfT] or [R-IfF] we use Lemma 3.1 item 5. When reduction ends with rule [R-Struct] we use Lemma 3.4. When reduction ends with rule [R-Par] we have = 1 2 and 1 ` P and 2 ` Q. 0 0 Given the induction hypothesis we know that 1 ` P . Distinguish the three situations as in the statement of the theorem. For the first, 1 = 01 , complete the proof with the [T-Par] rule. The two remaining cases are similar; we concentrate on the second (of the three). We know by induction that 1 = 3 , x : (q!T.S, q?T.S) and 01 = 3 , x : (S, S). Further distinguish two cases: q = lin and q = un. When q = lin we know that 1 2 = ( 3 , x : (lin!T.S, lin?T.S)) ( 02 , x : (end, end)) = 3 02 , x : (lin!T.S, lin?T.S), 0 hence 01 2 = 3 2 = 2 , x : (S, S) as required. When q = un, we know that 1 ( 3 , x : (un!T.S, un?T.S)) ( 02 , x : T ). There are four cases for T , namely (un!T.S, un?T.S), (un!T.S, end), (end, un?T.S) and (end, end). In all cases, 1 2 = 3 02 , x : (un!T.S, un?T.S)
Linearity, Session Types and the Pi Calculus
13
0 hence 01 2 = 3 2 , x : (un!T.S, un?T.S). But in this case, the induction hypothesis also tells us that un!T.S = S as required. When the derivation ends with rule [R-Res] we know that , y : (S, S) ` P from ` (⌫y)P . The induction hypothesis tells us that 2 ` P 0 for 2 in the conditions of the theorem. We distinguish two cases. When y = x, we know that = 3 and apply rule [T-Res] to complete the case. Otherwise, we know that 3 = 03 , y : T and we apply rule [T-Res] to obtain 03 , x : T2 ` (⌫y)P ; it should be easy too see that 03 , x : T2 is in the form required by the theorem. When the derivation ends with rule [R-Com], there are two derivations to consider: [T-Par] preceded by [T-OutL] and [T-InR], or [T-Par] preceded by [T-OutR] and [T-InL]. We concentrate on the former, the latter is similar. From the derivation we learn that 00 000 0 00 1 = 01 1 1 2 2, 0 0 2 ` x : (q !T .S , S ), 1 1 1 1 1 00 3 1 ` v : T1 , 000 4 x : (S1 , S10 ) ` P , 1 0 0 5 2 ` x : (S2 , q2 ?T2 .S2 ), 00 6 ( 2 x : (S20 , S2 )), y : T2 ` Q, 7 q1 = un implies q1 !T1 .S1 = S1 , and q2 = un implies q2 ?T2 .S2 = S2 .
We claim that T1 = T2 and that there is a context 1 such that 1 = 001 ( 002 x : (S20 , S2 )) holds. By (3), (6) and the substitution lemma we get 1 ` Q[v/y]. We 0 further claim that 2 = ( 000 1 holds for some 2 . From (4), 1 ` Q[v/y], 1 x : (S1 , S1 )) and the [T-Par] rule we obtain 2 ` P | Q[v/y]. It remains to show that q1 = q2 and S1 = S 2 and = 3 , x : (q1 !T1 .S1 , q1 ?T1 .S 1 ) and 2 = 3 , x : (S1 , S1 ), in addition to the three claims above. We address the various pending results in turn. 0 00 000 00 Given that is commutative and associative we know that 01 2 and 1 1 2 are defined. Let T be the type (q1 !T1 .S1 , q2 ?T2 .S2 ). From (2) and (5) and the definition 0 of context splitting we know that x : T 2 01 2 . Now we apply Lemma 3.5 to contexts 0 0 00 000 00 , to obtain x : T 2 . But is balanced by hypothesis, hence and 1 2 1 1 2 T1 = T2 and S1 = S2 and q1 = q2 . It remains to show that x : (S1 , S2 ) is in 2 . 000 00 Let U = (U1 , U2 ) be the type for x in 001 1 2 . Lemma 3.5 also allows to figure out the four possible cases for U . Taking for A an arbitrary end point type, and abbreviating types un!T1 .S1 and un?T1 .S2 to un! and un?, respectively, we fill the below table to complete the proof. U1 U 2 S1 S10 S20 S2 U1 S20 U2 S2 S1 (U1 S20 ) S10 (U2 S2 ) end un! un! end
end un? end un?
A un! un! un!
end un? end un?
end un! un! end
A un? un? un?
end un! un! end
A
A
A
un? un? un?
un! un! un!
un? un? un?
00 It should be easy to see that the type for x in each context 001 , 000 1 and 2 is exactly of one of the four possible forms for U . The columns for S1 and S2 are filled together based on the following facts: contexts 000 x : (S1 , S10 ) and 002 x : (S20 , S2 ) are defined, 1
M. Giunti and V.T. Vasconcelos
14
S1 = S2 , and item (7) above. The columns for S1 and S20 are again filled together based on the following facts: (q1 !T1 .S1 , q2 ?T2 .S2 ) = (q1 !T1 .S1 , S10 ) (S20 , q2 ?T2 .S2 ), contexts 000 x : (S1 , S10 ) and 002 x : (S20 , S2 ) are defined. From the type splitting we get that S20 1 is end or un!, and S10 is end or un?. Corollary 3.8. If then 2 ` P2 with
1 2
` P1 with balanced.
1
balanced and P reduces in zero or more steps to P2 ,
Proof. By induction on the length of the derivation. When P1 ! P2 , theorem 3.7 ensures that 2 is balanced. 4. Algorithmic Type Checking In this section we present a sound and complete algorithm for the type system introduced in the previous section. The syntax of processes accepted by the algorithm are obtained by replacing in Figure 1 processes of the form (⌫x)P with the type annotated process (⌫x : S)P . The algorithmic type system is described in Figure 4. Rules for values have the form 1 ` v : T ; 2 , and for processes the form 1 ` P : 2 ; N , where N is a set of annotated variables of the form xl or xr . The reading of the rules is as follows: 1 , v, T and P constitute the input to the algorithm, while 2 and N are produced as output. The rules for processes produce, in addition to a context, a set N of used (or forbidden) end points, whose meaning we explain below. In a successful run of the algorithm, it will always be the case that dom( 2 ) = dom( 1 ) and that x 2 dom( 2 ) for all xl , xr 2 N . For the algorithmic rules we do not rely on context splitting of Figure 3; instead we pass the incoming context 1 to the type checking function and obtain as a result 2 , the unused part of the context. The typing rules for values comprise all possible combinations of T1 , T2 , T3 such that , x : T1 ` x : T2 ; ( , x : T3 ). Basically, the idea is that if T1 = (L, S1 ) and T2 = (L, S2 ), then the linear end point L of T1 is returned as end in the type T3 , so that it cannot be further used for input/output. Symmetrically, if T2 = (end, S2 ) then the end point L of T1 is returned as L in T3 , because it has not been used in input/output. For unrestricted end point types, if T1 = (U, S1 ) then it must be the case that T2 = (U, S2 ) or T = (end, S2 ) because of unrestricted weakening. The rule for inaction, replication and conditional processes—[A-Inact],[A-Repl] and [A-If]—are standard. To type process 0 using [A-Inact] any context suffices; the context received in input is forwarded to the output, together with the empty set of used end points. The rule [A-If] for typing a conditional process starts by checking whether the value in the condition is a boolean. The context returned is used to type both branches of the conditional. If the contexts returned by the two calls are equal, then the first context is returned in output. The same applies to the set of annotated variables. The rule for replication [A-Repl] requires the context returned in output to be equal to the one received in input. Indeed, a change in the output context would indicate that a linear resource has been consumed, which must be forbidden under replication. To explain the rule for parallel processes, [A-Par], it is convenient to illustrate the
Linearity, Session Types and the Pi Calculus ÷N =
Context di↵erence rules ( 1 , x : (end, S)) ÷ N = ( 1 , x : (U, S)) ÷ N, xl =
÷;= ` x: T ;
( 1 , x : (S, end)) ÷ N = ( 1 , x : (S, U )) ÷ N, xr =
2 2
2 2
Typing rules for values ` b : bool ;
, x : bool ` x : bool ; ( , x : bool)
, x : T1 ` x : T2 : ( , x : T3 )
`P:
15
where L1 , L2 are linear, U1 , U2 are unrestricted, and:
T1
T2
T3
T1
T2
T3
(U1 , U2 ) (U1 , U2 ) (U1 , U2 ) (L1 , L2 ) (L1 , L2 ) (L1 , L2 ) (L1 , L2 )
(U1 , U2 ) (end, U2 ) (U1 , end) (L1 , L2 ) (end, end) (L1 , end) (end, L2 )
(U1 , U2 ) (U1 , U2 ) (U1 , U2 ) (end, end) (L1 , L2 ) (end, L2 ) (L1 , end)
(L, U ) (L, U ) (L, U ) (U, L) (U, L) (U, L)
(L, U ) (end, U ) (end, end) (U, L) (U, end) (end, end)
(end, U ) (L, U ) (L, U ) (U, end) (U, L) (U, L)
; N Typing rules for processes 1
` 0: ; ; 1
` P1 :
` v : bool ;
2
2 1
; N1 2 ÷ N 1 ` P2 : 1 ` P1 | P2 : 3 ; N 2
2 ` P1 : 3 ; N ` if v then P1 else P2 :
3
2 3
;N
`P: ; N ` !P : ; N [A-Inact] [A-Par] [A-Repl] ; N2
` P2 :
3
;N
[A-If]
1 , y : (S, S) ` P : 2 ; N ` (⌫y : S)P : ( 2 ÷ {yl , yr }) \ y ; N \ {yl , yr } ( 2 + x : (S1 , S2 )), y : T ` P : 3 ; N (⇤) 1 ` x : (q?T.S1 , S2 ) ; 2 1 ` x(y).P : ( 3 ÷ {yl , yr }) \ y ; N \ {yl , yr } [ (if q = lin then {xl } else ;) ( 2 + x : (S1 , S2 )), y : T ` P : 3 ; N (⇤) 1 ` x : (S1 , q?T.S2 ) ; 2 1 ` x(y).P : ( 3 ÷ {yl , yr }) \ y ; N \ {yl , yr } [ (if q = lin then {xr } else ;) 1 ` x : (q !T.S1 , S2 ) ; 2 2 ` v: T ; 3 3 + x : (S1 , S2 ) ` P : 4 ; N 1 ` xv.P : 4 ; N [ (if q = lin then {xl } else ;)
[A-Res]
1
1
` x : (S2 , q !T.S1 ) ; 1
2
` xv.P :
2
` v: T ; 3 3 + x : (S1 , S2 ) ` P : ; N [ (if q = lin then {xr } else ;)
4
;N
[A-InL] [A-InR] (⇤⇤) [A-OutL] (⇤⇤)
4
(⇤) q = un ) q?T.S = S
[A-OutR]
(⇤⇤) q = un ) q!T.S = S
Fig. 4. Pi calculus: Algorithmic type checking
context di↵erence mechanism by introducing the rules for input and output processes. We have two rules for input, [A-InL] and [A-InR], and two rules for output, [A-OutL] and [A-OutR], respectively corresponding to the cases when the left or the right end point is used to type the subject x of the communication. Rule [A-InL] applies when we can
M. Giunti and V.T. Vasconcelos
16
type the input subject x at type (q?T.S1 , S2 ) by using the context 1 received in input. The continuation P is typed by using the context 2 updated with the typing x : (S1 , S2 ) and extended with the binding y : T , mimicking the typing rule [T-InL] in Figure 3. In the particular case where 1 contains the entry x : (lin ?T.S1 , ⇤!bool) and is used to type x with (lin ?T.S1 , S2 ), we have that S2 = ⇤!bool or S2 = end, and that 2 contains the entry x : (end, ⇤!bool). In both cases, the environment for the continuation is equal to 3 , y : T where 3 contains the entry x : (S1 , ⇤!bool); this follows from S1 = end S1 and S1 = S1 end and un p = un p un p. The novelty with respect to the system in Figure 3 is the mechanism of used end points, that is the set N produced at output. We say that a variable x occurs in subject position in processes xv.P and x(y).P . Then, N is the set of free linear end points used in subject position. When the left end point used to type x is linear, that is q = lin, we add to set N an an entry xl ; this is to signal that a linear end point has been used at subject position (its type advanced). Then, in order to preserve the linear discipline of sessions, the continuation end point S1 must be consumed within the recursive call for process P . This is enforced by the rule for parallel processes, [A-Par], which, in order to type the next parallel process, requires the di↵erence between the context and the set produced as output by the first process to be defined, thus rejecting the case whether x has type (L, S2 ) and xl 2 N . When x has type (U, S2 ) and xl 2 N , the same mechanism permits also to convert the unrestricted end point U to end, which preserves the idea of the system in Figure 3. Going back to rule [A-InL], we can now understand the shape of the output context ( 3 ÷ {yl , yr }) \ y and used set N \ {yl , yr } [ (if q = lin then {xl } else ;). This context is obtained by the context di↵erence of 3 produced as output by the call for the continuation, and of the left and right end points of the the bound variable y; a linear use of y must have been consumed within the continuation. The variable y is then removed from the output context, while the end points yl , yl are removed from the set N ; lastly the entry xl is added to the used set, provided that q = lin. Conversely, when q = un the set N does not change; this case is directly related to the case q = un in rule [T-InL], Figure 3. The same mechanism based on context di↵erence is implemented in the rules for output. To illustrate, consider rule [A-OutL] which is meant to type an output process xv.P under a context 1 containing an entry x : (q !T.S1 , S2 ). Context 2 is then used to type the variable v at type T , producing in turn a context 3 . Lastly 3 , updated with the typing x : (S1 , S2 ), is used to type the continuation P , which produces the output context 4 and becomes the context in the output of the call to the original input process. The set of used names, N [ (if q = lin then {xl } else ;), is obtained by adding to the used set N the endpoint xl whenever q = lin, and corresponds to N otherwise. Lastly, the rule for restriction [A-Res] requires the continuation to be typed with the input context extended with the typing for the bound variable, which is read from the type annotation. Similarly to the input cases, if a linear usage is prescribed for the new variable then it must be used to the end within its scope; this is enforced by means of the context di↵erence mechanism. It is straightforward to see that the rules in Figure 4 directly lead to an implementation.
Linearity, Session Types and the Pi Calculus
17
For instance, we could deploy each rule as a pattern of an ML function with signature check(g : context, p : process) : (context, nset) (cf. (Giu11)). For each function call, we have that zero, one or two patterns match the goal. In the first case an exception is thrown. The last case may arise when the type of a channel using as subject of the communication is composed by two end points of the same shape, i.e., T = (q1 ?T1 .S1 , q2 ?T2 .S2 ). The choice of the wrong end point can be handled by catching the exception generated by the call, and in turn by trying to type check the process by using the other end point. The same happens to values, where, e.g., a goal , x : (L1 , L2 ) ` x : (S1 , S2 ) : ( , x : (S3 , S4 )) is matched by four di↵erent cases. The rest of this section deals with the main properties of the algorithmic type system, namely soundness and completeness with respect to the original system. The following definition is used in the proof of soundness. Given a judgment 1 ` P : 2 ; N such that 2 ÷ N = 3 , we compute the used context closure of 1 w.r.t. 3 , notation 1 . 3 , as follows. S.S =S T .T =T lin p . lin p = end
.
un(S)
lin p . end = lin p
S.S =S
S1 . S10 = S100 S2 . S20 = S200 (S1 , S2 ) . (S10 , S20 ) = (S100 , S200 )
= ;.;=;
(
1. 2 = , 1 x : T1 ) . (
T = T1 . T 2 , x : T2 ) = 3 , x : T 2
3
Basically, the definition says that an end point which is linear both in the input and output environment is transformed into the type end, while an end point which is linear in the input environment and has type end in the output environment is left as is. Indeed in the first case the linear end point is not used, while in the second case it is. The first lemma describes the shape of the context returned by a call to the algorithm. Lemma 4.1 (Shape of the return context). Let 1 ` P : 2 ; N and 2 ÷ N defined, where x : (Sl , Sr ) 2 1 and x : (S 0 l , S 0 r ) 2 2 . The following cases arise for each i = l, r. 1 2
Si0 = Si and xi 62 N Si = lin p and un(Si0 ) and (Si0 6= end ) xi 2 N )
Proof. By induction on the length of the inference 1 ` P : 2 ; N . 1) follows straightforwardly by the I.H. In 2) we proceed by induction and use the fact that the environment returned in the I.H. of rules [A-InL],[A-InR],[A-OutL],[A-OutR] contains an unrestricted end point in correspondence to the end point used for linear input/output. This is because by hypothesis the environment of the conclusion is defined; since such environment has the form 1 , x : (Sl , Sr ), 2 ÷ N1 , xi , this holds if and only if for each i = l, r we have that Si is unrestricted. A simple but useful corollary of the lemma says that a used closure obtained by a call to the algorithm returning a consistent environment is defined. Corollary 4.2. If
1
`P:
2; N
and
2
÷N =
3
then
1
.
3
is defined.
M. Giunti and V.T. Vasconcelos
18
The next lemma is at the core of the proof of soundness. Note that in the statement of the lemma, the context 2 ÷ N can contain linear assumptions. This stronger result is needed to apply induction, since in typing a parallel process the output context produced by the the typing of the first process can contain linear typings which will be consumed by the subsequent process. Lemma 4.3. If
1
`P:
2; N
and
2
÷N =
3
then
1
.
3
` erase P .
Proof. By induction on the length of the judgment 1 ` P : 2 ; N . The interesting case is [A-Par]. Let 1 ` P1 | P2 : 3 ; N2 be inferred from 1 ` P1 : 2 ; N1 and 2 ÷ N1 ` P2 : 3 ; N2 , and assume that 2 ÷ N1 and 3 ÷ N2 are defined. By Corollary 4.2 the contexts 1 .( 2 ÷N1 ) and ( 2 ÷N1 ).( 3 ÷N2 ) are defined. The I.H. is (1) 1 .( 2 ÷N1 ) ` erase P1 and (2) ( 2 ÷ N1 ) . ( 3 ÷ N2 ) ` erase P2 . To close the proof, we need to show that ( 1 . 2 ÷ N1 ) (( 2 ÷ N1 ) . ( 3 ÷ N2 )) is defined and equal to 1 . ( 3 ÷ N2 ). Take x 2 dom( 1 ) and assume that 1 (x) = (A1 , S10 ), 2 (x) = (S2 , B2 ), 3 (x) = (C1 , C2 ); the case 1 (x) = bool is straightforward. It is sufficient to show the result for a single end point Ai , i = 1, 2, since the definitions of splitting, unrestricted closure and of context di↵erence are compositional. It is also convenient to assign the following labels: ( 1 .( 2 ÷N1 ))(x) = (S1 , S2 ), ( 2 ÷N1 )(x) = (B10 , B20 ), ( 2 ÷N1 ).( 3 ÷N2 )(x) = (S10 , S20 ), and ( 3 ÷ N2 )(x) = (C10 , C20 ). From Lemma 4.1 we infer that two cases arise for each Bi : Bi = Ai , or Bi = U and Ai = L and U 6= end ) xi 2 N1 . These correspond to three cases for each Si in (S1 , S2 ): (a) Si = L . Bi0 = L since Bi0 = end, or (b) Si = L . Bi0 = end since Bi0 = L, or (c) Si = U . Bi0 = U since Bi0 = U . Now we inspect the shape of an end point Si0 in (S10 , S20 ). In case a) we have Si0 = end . Ci0 = end because Ci0 = end, in case b) we have two sub-cases corresponding to (i) Si0 = L . Ci = L because Ci0 = end and (ii) Si0 = L . Ci = end because Ci0 = L, while in case c) we have Si0 = U . Ci0 = U because Ci0 = U . In all three cases we conclude that Si Si0 is defined and equal to Ai . Ci0 , which is the desired result since 1 . ( 3 ÷ N2 )(x) = (A1 . C10 , S10 . C20 ). Theorem 4.4 (Soundness). If
1
`P:
2; N
and un(
2)
then
1
` erase P .
Proof. Follows from un( 2 ), Corollary 4.2 and Lemma 4.3. First, when un( 2 ) we have that 2 ÷ N is defined. We apply Corollary 4.2 and infer 1 . ( 2 ÷ N ) defined. We apply Lemma 4.3 and infer 1 .( 2 ÷N ) ` erase P . Next, from un( 2 ) we infer 1 .( 2 ÷N ) = 1 . To see this, let x : (S1 , S10 ) 2 1 , x : (S2 , S20 ) 2 2 , and x : (S3 , S30 ) 2 2 ÷ N . We exploit Lemma 4.1.1 and deduce that when S1 = U then S2 = U and in turn S3 = U , which let us infer S1 = U = S1 . S3 . Otherwise, Lemma 4.1.2 does apply, because of the hypothesis un( 2 ): we have S1 = L and S2 = U . Consider the sub-case S2 = end. We have S3 = end and S1 = L = S1 . S3 , as desired. The other sub-case is S2 = U and U 6= end and xi 2 N . We have that S3 = end, and in turn S1 = L = S1 . S3 , and we are done. We now build towards completeness. The following lemma shows how we can weaken the algorithmic judgments by using context splitting. Lemma 4.5 (Algorithmic weakening). Let following hold.
=
1
2
and x : (S100 , S200 ) 2
. The
Linearity, Session Types and the Pi Calculus 1 If 2 If
1 1
19
` x : (S1 , S2 ) : 3 then ` x : (S1 , S2 ) : 3 ` P : 3 ; N then ` P : ( 3 ÷ N ) 2; N .
2;
Proof. 1) The proof follows by a case analysis of the table for typing of values. Take 00 00 0 , x : (S10 , S20 ). It is enough to show the result for a single 1 , x : (S1 , S1 ) ` x : (S1 , S2 ) : end point, since splitting is compositional. The case Si = un p and Si00 = un p and Si0 = un p is clear being un p = un p S for all defined rules. We can also have the case Si = un p and Si00 = end and Si0 = un p, which is also clear. The case Si = L and Si00 = L and Si0 = end is obtained by Si = Si S and S = Si0 S. The case Si = L and Si00 = end and Si0 = L is similar. The last case is Si = end and Si00 = end and Si0 = end, which for any S leads to Si = S, Si00 = end and Si0 = S, being S = end S. In both cases S = L, S = U , the results do hold, and we are done. We sketch 2). The proof is by induction on length of the judgment 0 ; N . Take case [A-InL]: 1 ` x(y).P : 3 ÷ {yl , yr } \ y; N \ {yl , yr } [ (if q = 1 ` P: lin then {xl } else ;) inferred from 1 ` x : (q?T.S1 , S2 ); 2 and ( 2 , y : T ) + x : (S1 , S2 ) ` P : 3 ; N . We rewrite the last judgment as 02 , y : T, x : T 0 ` P : 3 ; N where 2 = 02 , x : (S10 , S20 ) and T 0 = (S10 , S20 ) (S1 , S2 ). Assume that 1 1 is defined. A case analysis shows that there is 0 such that 0 = 02 , y : T, x : T 0 ( 1 , y : (end, end)). By induction we obtain 0 ` P : ( 3 ÷ N ) ( 1 , y : (end, end)); N . We apply (1) and infer the following judgment: 1 . Now by commutativity of splitting we can 1 ` x : (q?T.S1 , S2 ); 2 rewrite 0 as ( 2 1 ) + x : (S1 , S2 ), y : T . We can apply [A-InL] and infer the desired result: 1 ); N ÷ {yl , yr }. As a further example, 1 ` P : (( 3 ÷ N ) ÷ {yl , yr } \ y) take [A-Par]. Assume that 1 ` P1 | P2 : 3 ; N2 is inferred from (i) 1 ` P1 : 2 ; N1 and (ii) 2 ÷ N1 ` P2 : 3 ; N2 . Let 1 1 be defined. By induction we have that i) 1 1 ` P1 : ( 2 ÷ N 1 1 ); N1 and ii) 2 ÷ N1 1 ` P2 : ( 3 ÷ N 2 ) 1 ; N2 . We apply [A-Par] and infer the desired result, 1 ` P | P : ( ÷ N ) . 1 1 2 3 2 1 We are now in a position to show that the algorithm is complete. Theorem 4.6. If
` erase P then
`P:
0
; N 0 and un( 0 ).
Proof. By induction on the length of the inference ` erase P , relying on Lemma 4.5. We sketch the main cases. When the derivation ends with rule [T-InL], we have 1 2 ` erase x(y).P inferred from 1 ` x : (q?V.S, S1 ) and 2 + x : (S, S1 )), y : V ` erase P . The I.H. is that ( 2 + x : (S, S1 )), y : V ` erase P : 00 ; N 00 with un( 00 ). Let 1 = 0 , x : T . By the rule for typing values in Figure 4 we infer that 1 ` x : (q?V.S, S1 ) : 0 with 0 = 0 , x : (S 0 , S2 ). 0 We apply weakening for typing of values and infer 1 2 ` x : (q?V.S, S1 ) : 2; indeed by hypothesis ( 2 + x : (S, S1 )) is defined and S2 cannot be linear (*). Next, we apply weakening for typing of processes to the I.H., obtaining ( 2 + x : (S, S1 )) 0 0 , y : V ` erase P : ( 00 ÷ N 00 ) , y : T 0 ; N 00 . By applying [A-In] we obtain 1 2 ` 0 erase x(y).P : ( 00 ÷ N 00 ) ; N 00 \ {yl , yr }. Note that un( 0 \ x), because of [T-Var]. Moreover un( 0 (x)), because of (*). We conclude that the return context is unrestricted, as desired. When the inference ends with rule [T-Par], we have 1 2 ` erase P1 | P2 inferred from 0 ; N 0 and (2) 2 ` P2 : 00 ; N 00 1 ` erase P1 and 2 ` erase P2 . The I.H. is (1) 1 ` P1 :
M. Giunti and V.T. Vasconcelos
20
New syntactic forms (extends Figure 1) P ::= . . .
Processes:
xp xp .P
µa.S
output
p
x (x).P
S ::=
Session types: end
input
T ::=
recursive type termination
Types:
?T.S
receive
ˆT
shared type
!T.S
send
S
session type
a
a
type variable
type variable
µa.S
recursive type
P ! P New reduction rules (extends Figure 1) xp z q .P | xp (y).Q !p P | Q[z q /y] + x: T =
[R-Com]
Context update rules + xp : S = , x p : S + x: T = , x: T ( , x : ˆT ) + x : ˆT = , x : ˆT
if xp , x 62
if x, x+ , x 62
` P Typing rules `p P
completed `p 0 1
`p P 1 +
2
unlimited `p ⇤P
2 `p Q `p P | Q
, x : ˆT `p P ( , x : ˆT ) + y q : T `p xy q .P
, x : ˆT `p P , x+ : S, x : S `p P `p (⌫x)P `p (⌫x)P [T-Inact] [T-Repl] [T-New] [T-NewS]
, x : ˆT, y : T `p P , x : ˆT `p x(y).P (
, xp :
, xp : S, y : T `p P , xp : ?T.S `p xp (y).P [T-Par] [T-In] [T-InS]
, x p : S `p P !T.S) + y q : T `p xp y q .P
[T-Out] [T-OutS]
Fig. 5. Pi calculus with polarities
with un( 0 ), un( 00 ). We apply weakening for typings of processes to 1) and 2) and infer 0 0 0 0 (i) 1 ÷ N0 ÷ N 0 ` P2 : ( 00 ÷ N 00 ) ÷ N 0 ; N 00 . 2 ` P1 : 2 ; N and (ii) 2 0 Since 0 ÷ N 0 ÷ N 0 , we can apply [A-Par] and infer 1 2 = 2 2 ` P1 | 00 00 0 0 00 0 00 P2 : ( ÷ N ) ÷ N ; N . The result follows from un( ), un( ). 5. Embedding the Pi Calculus with Polarities This section shows that the polarity system introduced by Gay and Hole (GH05) can be embedded in our system. Since Gay and Hole show that the simply typed pi calculus can be embedded in the pi calculus with polarities; by transitivity the simply typed pi calculus can be embedded in our system as well. In Figure 5 we present the branch/select-free fragment of the pi calculus with polarities. Variables may be optionally polarized, occurring in processes as well as in typing contexts as x+ or x or simply as x. We write xp for a general polarized name, where p
Linearity, Session Types and the Pi Calculus
21
represents an optional polarity. Duality on polarities, written p exchanges + and . The new constructors of the language, input and output, are in Figure 5; the remaining are taken from Figure 1 (except for the conditional process which we do not consider); the syntactic category for values in Figure 1 does not contribute to the language. The reduction relation, denoted by !p , is defined inductively by the rules in Figure 1 with rule [R-Com] replaced by that in Figure 5 (rules [R-IfT], [R-IfF] excluded). It is easy to see that the two languages di↵er in the (optional) polarity annotation on (non-bound occurrences of) variables. We define an erase function that removes from a polarized processes all occurrences of + and , to yield a process generated by the grammar in Figure 1. There is an obvious operational correspondence between the two languages, stated in Theorem 5.1. The language of types includes a distinct category S for (linear) session types; unlike (GH05) we ignore subtyping as well as recursive types but take recursive session types into account. Duality is defined as in Section 2, with the appropriate changes which amount to erasing the qualifiers. Typing contexts now gather assumptions on polarized variables, in addition to simple variables as before. There is however one restriction on the variables occurring in a context: x and x+ (or x ) cannot occur simultaneously in a given context , even though x+ and x may. New assumptions are added to contexts by means of an update operation +, defined in Figure 5. This operation is stricter than context splitting in our system, for it does not take into account the “neutral” nature of type end. For example, we have x : (end, end) + x : (q!T.S, S 0 ) is defined in our case, whereas x : end + x : !T.S is not defined in the polarity system. We say that a context is unlimited if it contains no session types, and is completed if every session in it is end. The typing relation is inductively defined by the rules in Figure 5. The first thing to notice is that each of the rules for input, output and restriction in our system corresponds to a pair of rules in the system with polarities, one that takes care of shared types (unrestricted), whereas the other deals with session types (linear). Our use of type qualifiers and context splitting allows for a more concise formulation of the rules. Rules [T-In] and [T-InS] in Figure 5 have their counterpart in a single (left or right) rule in Figure 3, namely [T-InL] and [T-InR], thanks to type qualifiers and the context splitting operation. The same can be said of the relation between rules [T-Out],[T-OutS] and [T-OutL],[T-OutR]. Rule [T-NewS] introduces in the context two channel end points of dual types; contrast with rule [T-Res] in Figure 3: our system gathers the two end points in a single variable whose type contains the two dual end point types. From the above description it should be obvious that the two systems are quite close to each other. In order to define the typing correspondence we need to translate session types, types and contexts for the polarized language (as in Figure 5) into end point types, types and contexts in our language (Figure 1). Function {[S]} translates session types, [[T ]] translates types. The translation of session types is straightforward. For types, we translate ˆT into an unrestricted type capable of continuously inputting and outputting values of type [[T ]]; recall from Section 2 that we use ⇤?T as an abbreviation for µa.un?T.a, for some a not in T . A session type S, when interpreted as a type, is translated into a type containing {[S]} and end for its end points. To translate contexts we assume that if both x+ and x are in then they occur
M. Giunti and V.T. Vasconcelos
22
in contiguous positions (and in this order). If this is not the case, then the context can be rearranged since we work with contexts up to entry permutation. The translation of contexts is given by the rules below, which must be tried in the given order; the first rule for mapping non-empty contexts is for polarized pairs while the second rule is for single entries. {[!T.S]} = lin![[T ]].{[S]}
{[?T.S]} = lin?[[T ]].{[S]} {[end]} = end
{[a]} = a
[[ˆT ]] = (⇤?[[T ]], ⇤![[T ]]) [[S]] = ({[S]}, end)
{[µa.S]} = µa.{[S]}
[[;]] = ;
[[ , x : S, x : S 0 ]] = [[ ]], x : ({[S]}, {[S 0 ]}) +
[[ , xp : S]] = [[ ]], x : [[S]]
[[ , x : ˆT ]] = [[ ]], x : [[ˆT ]]
We are now in a position to state the main result of this section. The converse is clearly not true. Take for P the polarized process x+ y | x+ (z). Then erase(P ) = xy | x(z) reduces while P does not. Also erase(P ) is typable under context [[x : ˆend, y : end]] = x : (⇤?(end, end), ⇤!(end, end)), y : (end, end), whereas P is not typable under x : ˆend, y : end. Theorem 5.1 (Polarity-Pi to pi correspondence). The following hold. 1 If `p P then [[ ]] ` erase(P ). 2 If P !p Q, then erase(P ) ! erase(Q). Proof. (1). The proof is by induction on the derivation of `p P , and uses unrestricted weakening (Lemma 3.2) to add polarized variables at type (end, end) in order to make context splitting defined. As an example, we draw two interesting cases. For [T-InS] let , x : ?T.S `p x(y).P be inferred from , x : S, y : T `p P (the case for x+ is similar). Assume the induction hypothesis to be [[ , x : S, y : T ]] ` erase(P ). There are two cases corresponding to (i) = 0 , x+ : S 0 or (ii) x+ 62 . In case (i) we rewrite the induction hypothesis as [[ 0 ]], x : ({[S 0 ]}, {[S]}), y : [[T ]] ` erase(P ). We apply [T-InR] and infer [[ 0 ]], x : ({[S 0 ]}, lin ?[[T ]].{[S]}), y : [[T ]] ` erase(P ) as required. In case (ii), noticing that (end, end) ({[S]}, end) = [[S]], we rewrite the induction hypothesis as [[ ]], x : [[S]], y : [[T ]] ` erase(P ). We apply [T-InL] and infer [[ ]], x : (lin ?[[T ]].{[S]}, end) ` x(y). erase(P ). For [T-Out], let ( , x : ˆT ) + y q : T `p xy q .P be inferred from , x : ˆT `p P . The induction hypothesis is [[ , x : ˆT ]] ` erase(P ). If y q 62 dom( ), we use weakening and infer from the induction hypothesis the judgment [[ , x : ˆT ]], y : (end, end) ` erase(P ). In either case we complete the proof by applying [T-OutR]. (2). By a straightforward induction on the derivation of a reduction step !p . 6. Embedding the pi calculus with accept/request primitives This section shows that the pi calculus with accept and request primitives (HVK98) can be embedded in our system. With respect to the original formulation, the calculus considered here does not provide for label selection and branching. On the other hand it features process replication in place of recursion. The syntax of processes and types is in Figure 6. In addition to the set of variables introduced in Section 2, we consider a new (disjoint) countable set of
Linearity, Session Types and the Pi Calculus
23
New syntactic forms (extends Figures 1 and 5) P ::= . . .
Processes:
request x(k).P accept x(k).P
v ::= . . .
session request
k
session acceptance
kv.P
input
k(k).P
channel passing
(⌫k)P
channel restriction
channels
T ::=
Types: bool
output
k(x).P
Values:
boolean
S
session type
hS, Si
shared type
?S
used channel
P ! P New reduction rules (extends Figure 1) accept x(k).P | request x(k).Q !r (⌫k)(P | Q)
[R-Link]
kh.P | k(h).Q !r P | Q
[R-Pass]
kv.P | k(x).Q !r P | Q[v/x] = ;
[R-Com]
Linear context composition
=
`P .
if v = y, true, false
1
(
1, k :
S) (
2 2, k :
= 3 S) =
1 3, k :
?S
(
1, k :
= T)
2
3 2
=
k 62 2 3, k : T
Typing rules for processes ` x : hS, Si `r P . `r accept x(k).P .
,k: S
` x : hS, Si `r P . , k : S `r request x(k).P . [T-Acc] [T-Req]
`r v : T `r P . , k : S , x : T `r P . , k : S [T-Send] [T-Rcv] `r k(x).P . , k : ?T.S `r kv.P . , k : !T.S `r P . , k : S 2 `r P . , h : S 1 , k : S 2 [T-Thr] [T-Cat] `r k(h).P . , k : ?S1 .S2 `r kh.P . , k : !S1 .S2 , h : S1 completed `r P 1 . 1 `r P 2 . 2 `r P . completed `r 0 . `r P1 | P 2 . 1 `r !P . 2 [T-Inact] [T-Par] [T-Repl] , x : hS, Si `r P . `r (⌫x)P .
`r P . , k : ? S `r (⌫k)P .
[T-Res] [T-ResC]
Fig. 6. Accept/request pi calculus
channels, ranged over by h, k. Synchronization names are taken from the set of variables. The new process constructors are exactly accept and request: they allow to install new sessions via synchronization on names. We remove productions x(x).P and xv.P in the syntax of processes, and replace them by input/output processes on channels: k(x).P and kv.P . We also introduce a new restriction operator (⌫k)P for channels, in addition to that for variables (⌫x)P . The bindings in the language are introduced by the parenthetical constructs: accept, request, input and restriction. The set of free channels, as well as substitution of variables
M. Giunti and V.T. Vasconcelos
24
and boolean values for variables in a given process P [v/x], is defined as usual. Notice that substitution is not defined for channels. The reduction relation, denoted !r , is defined in Figure 6. Rule [R-Link] establishes a new session k when an accept process meets a request process on a given name x. Channel k, bound in both processes, becomes free in each process, but still bound in the parallel composition of both processes. Rule [R-Com] is taken from Figure 1, only that the subject of communication are channels and the objects values do not comprise channels. The last rule, [R-Pass], allows delegating a channel from an output process to an input process. The channel h in the output process must not be free in the input process, for no substitution is performed in channel passing. Types are (informally) divided in sorts and session types. Session types are as in Figure 5; the definition of the dual function, S, from session types to session types is defined in Section 5. Sorts include the type bool for boolean values as well as types for names of the form hS1 , S2 i. In such a type, session type S1 types the accept end of the name, whereas session type S2 types the request end. We are only interested in types where S1 is the dual of S2 . Type ?S denotes a channel on which no further interaction is possible. To guide our encoding, we decorate it with the type from which it was generated. We explain such mechanism below. The type system uses two kinds of contexts: shared contexts mapping variables x to sorts (types of the form bool and hS1 , S2 i), and linear contexts mapping channels k to session types S and to ?S . For linear contexts we define in Figure 6 an operation of composition that conjoins two contexts on the disjoint part, and assigns a ?S type to a channel that is typed at dual types S and S in the two incoming contexts. Composition is not defined when the types for a same channel in the two input contexts are not dual to each other. The typing system comprises the rules for value typing, ` v : T , taken from Figure 3, as well as the rules for process typing, ` P . , in Figure 6. The typing rule for accept reads the type hS, Si of value x from the shared context and places a new entry k : S in the linear context of the continuation process P . The rule for request is similar, only that that the dual type S is taken into consideration. The rules for channel passing, [T-Thr] and [T-Cat], are similar to their counterparts in the polarity system, namely rules [T-OutS] and [T-InS] in Figure 5. The rules for value passing, [T-Send] and [T-Rcv], are also similar, only that the value sent, v, or received, x, is read or written on the shared context . The rules for inaction and for replication are similar to those in Figure 5; predicate completed is defined in Section 5: it is true of contexts containing only end as session types. The rule for parallel composition makes use of the composition operator and marks as “used” (session type ?S ) those channels that can be found at type S in one thread and at type S in the other, thus preventing further interaction on such channels. Finally, the rules for scope restriction, [T-Res] and [T-ResC], introduce in the appropriate contexts types for the bound names: a name type hS, Si in the shared context for name binding, and the ?S type in the linear context for channel binding. In the latter case, we see that only channels that have been used to end can be restricted. We now look at the encoding. For processes we have to encode the constructors in Figure 6, plus those inherited from Figure 5. Given that both the sets of variables and
Linearity, Session Types and the Pi Calculus
25
channels are enumerable, we can easily map the two sets into the set of variables; we leave the application of these maps implicit in the sequel. Proceeding in this way, the only cases left are accept and request. We choose request to create a new channel k and use name x to convey its identity to potential accept parties. Accept processes, in turn, receive the newly created channel via a conventional input on name x. We could have chosen the accept party to create the channel; accept and request are symmetric. [[accept x(k).P ]] = x(k).[[P ]]
[[request x(k).P ]] = (⌫k)xk.[[P ]]
We also have to encode contexts, which we do, pointwise, by using an encoding for types. We use an auxiliary encoding {[S]} to map session types into session types. Types T are encoded using the [[T ]] function. A name type hS1 , S2 i is translated into a type describing the two channel ends; recall that ⇤?T abbreviates the recursive end point type µa?T.a, and similarly for ⇤!T . Session type ?S is translated into type ({[S]}, {[S]}). Note that the decoration of ?S is essential for the reconstruction of the type. A type ?S originates from types S and S in a process kv | x(y), say, and prevents its composition with, say, a process ku. In our system it is the linear nature of type ({[S]}, {[S]}) that prevents the composition. The input type is translated into a type where only the input end point can be used (the other is recorded as end, allowing no interaction); and conversely for the output. The four remaining cases are the identity function for end, bool, and the type variable a, and µa.[[S]] for [[µa.S]]. {[?T.S]} = lin?[[T ]].{[S]}
[[hS1 , S2 i]] = (⇤?[[S1 ]], ⇤![[S2 ]]) [[?T.S]] = ({[?T.S]}, end)
{[!T.S]} = lin![[T ]].{[S]}
[[?S ]] = ({[S]}, {[S]})
[[!T.S]] = (end, {[!T.S]})
We have the below correspondence result. The converse is not true. Take for P the process kh | k(l).(htrue.l(x)). It should be easy to see that P does not reduce, whereas [[P ]] = P does. Notice that the subprocess k(l).(htrue.l(x)) cannot be renamed into a process of the form k(h).Q, as required by rule [R-Pass], for h is free in htrue.l(x). It is also the case that [[P ]] is typable under context [[h : S, h : hS, Si]] where S is the type !bool.end, whereas P is not typable under context h : S, h : hS, Si. Theorem 6.1 (Accept/request-pi to pi correspondence). 1 If `r P . then [[ ]], [[ ]] ` [[P ]]; 2 If P !r Q then [[P ]] ! [[Q]]. Proof. (1) We proceed by induction on the length of the inference `r P . , using unrestricted weakening (Lemma 3.2) to add sessions typed with (end, end) whenever such sessions are in and not in a context of its derivation. To illustrate, we sketch a couple of cases. Assume that through [T-Req] we have ` request x(k).P . with a : hS, Si 2 and `r P . , k : S. Therefore [[ ]](a) = (⇤?[[S]], ⇤![[S]]). By I.H. [[ , , k : S]] ` [[P ]]. By applying [T-OutR] we infer [[ , ]], k : ({[S]}, {[S]}) ` ak.[[P ]]. An application of [T-Res] give us the desired result, [[ , ]] ` (⌫k)ak.[[P ]]. Take case [T-Thr] and let `r kk 0 .P . , k : !S.S 0 , k 0 : S inferred from `r P . , k : S 0 . By I.H. we have [[ , , k : S 0 ]] ` [[P ]]. We use unrestricted weakening (Lemma 3.2) and infer [[ , , k : S 0 ]], k 0 : (end, end) ` [[P ]]. We
M. Giunti and V.T. Vasconcelos
26
New syntactic forms (extends Figure 2) c ::=
Capabilities: i
T ::=
Types:
input
qcT
channel
o
output
bool
boolean
io
input and output
T + T = T Combination of types un c1 T + un c2 T = un (c1 [ c2 ) T
bool + bool = bool +
=
;+
=
lin i T + lin o T = lin io T
Combination of contexts 1
(
1, x :
T1 ) + (
+
2, x :
= 3 T2 ) =
2
1 3, x :
T1 + T2
(
+
1, x :
2 = T) +
3 2
=
x 62 2 3, x : T
` P Typing rules for processes (extends Figure 3) `l P 1 2 `l P2 + 2 `l P 1 | P 2 , y : T `l P + x : q iT `l x(y).P 1
1
, x : q io T `l P `l (⌫x)P `l P + x : q oT + v : T `l xv.P
[T-Par] [T-Res] [T-In] [T-Out]
Fig. 7. Linear pi calculus
apply [T-OutR] and infer [[ , ]], k : (end, lin ![[S]].{[S 0 ]}), k 0 : [[S]] ` kk 0 .[[P ]]. Lastly, take 0 case [T-Par], and let `r P | P 0 . inferred from `r P1 . 1 and `r P2 . 2 . By I.H. [[ , 1 ]] ` [[P ]]1 and [[ , 2 ]] ` [[P2 ]]. To conclude by applying [T-Par], two considerations need to be done. First, since [[ ]] is unrestricted, we have [[ ]] [[ ]] = [[ ]]. Second, we can make the domains of the contexts [[ 1 ]] and [[ 2 ]] equal by adding entries (end, end), thus generating two contexts 0 from [[ 1 ]] and 00 from [[ 2 ]]. Then, it is 00 easy to show that 0 is defined and equal to [[ ]]. We may apply [T-Par] and infer [[ , ]] ` [[P1 | P2 ]]. (2) By induction on the length of the inference P !r P 0 . The interesting case is [R-Link], and is established by a(k).[[P ]] | (⌫k)ak.[[Q]] ⌘ (⌫k)(a(k).[[P ]] | ak.[[Q]]), by [R-Com]: a(k).[[P ]] | ak.[[Q]] ! [[P ]][k/k] | [[Q]], by [R-Res]: (⌫k)(a(k).[[P ]] | ak.[[Q]]) ! (⌫k)([[P ]][k/k] | [[Q]]), and by [R-Struct]: a(k).[[P ]] | (⌫k)ak.[[Q]] ! (⌫k)([[P ]][k/k] | [[Q]]). The result then follows by noting that [[P ]][k/k] = [[P ]]. Cases [R-Com],[R-Pass] are analogous, the remaining cases follow straightforwardly from induction. 7. Embedding the Linear Pi Calculus In this section we analyze (a synchronous variant of) the linear pi calculus (KPT99) and provide a typing-preserving encoding into our system. The syntax of linear pi processes and the reduction relation are described in Figure 1. Figure 7 defines the syntax of types and the typing rules for processes. Types now have the form q c T where q is a lin/un qualifier introduced in Figure 2, and c is a capability describing the input, output or input-output nature of the type.
Linearity, Session Types and the Pi Calculus
27
The linear discipline is imposed by way of a type combination operation, defined in Figure 7. The combination of two unrestricted types conjoins the capabilities, by resorting to a set view these and defined as follows. i = {i}
o = {o}
io = {i, o}
The type combination operation is defined in Figure 7. The combination of un types is only defined for two types, of i and of o capabilities; the result is a type of io capability. There is also a rule symmetrical to the last, namely lin o T + lin i T = lin io T . The operator is then extended point-wise to typing contexts. The typing system for the linear pi-calculus is defined by the rules in Figure 3, where rules [T-Par], [T-Res], [T-In] and [T-Out] are replaced by those in Figure 7. Rule [T-Out] is an adaptation of that in (KPT99) to the synchronous setting: we let the continuation be typed with context while in the original paper the premise to the rule is un( ) since the (absent) continuation behaves as 0. We have also adapted rule [T-Res] to require that the restricted channel uses both capabilities; the original system allows processes of the form (⌫x)xtrue to be typed by assigning to channel x type lin o bool. Our system forces a linear behavior to be described by a type (lin !bool, lin ?bool) which cannot be used to type process xtrue, a process that never exercises the input capability. In order to obtain a typing correspondence result we therefore have aligned the rules in the two systems. A compositional encoding of linear types is defined below. Types are encoded using the auxiliary end point encoding {[T ]}. Unrestricted end points are encoded into recursive process; once again recall that ⇤!T abbreviates the type µa.!T.a, and similarly for ⇤?T . Linear end points are encoded into a linear output/input followed by end, meaning that the channel cannot be further used. An input type is encoded as a channel type composed of an input end point type and an end type. The output type is similar. Input/output types are encoded in channel types, one end for the output, the other for the input capability. {[lin iT ]} = lin?{[T ]}.end
{[un iT ]} = ⇤?{[T ]}
[[q iT ]] = ({[q iT ]}, end)
{[lin oT ]} = lin!{[T ]}.end
{[un oT ]} = ⇤!{[T ]}
[[q io T ]] = ({[q iT ]}, {[q oT ]})
[[q oT ]] = (end, {[q oT ]}) [[bool]] = bool
For instance, taking for T the type (⇤!bool, ⇤?bool), linear pi type lin i(lin io (un io bool)) is mapped into the type (lin ?(lin !T.end, lin ?T.end).end, end). The main result of this section establishes the correspondence between the two systems. Theorem 7.1 (Linear-pi to pi correspondence).
`l P if and only if [[ ]] ` P .
Proof. For the left to the right direction, we proceed by induction on the length of the inference `l P . The proof relies on a unrestricted weakening (Lemma 3.2). Indeed the rule for context combination in Figure 7 permits to combine two unrestricted types having opposite capabilities. We recover this by weakening each type with the missing capability, in order to make the context splitting operation of Figure 3 defined. To illustrate, consider
M. Giunti and V.T. Vasconcelos
28
case [T-In] and let + x : q iS `l x(y).P be inferred from , y : S `l P . The induction hypothesis is [[ , y : S]] ` P . We have are three cases corresponding to (i) x : lin oS 2 , (ii) x : un cS 2 , and (iii) x not in . In (i) we can directly apply [T-InR], since the splitting of [[lin oS]] and [[lin iS]] is defined. In (ii) we have two sub-cases corresponding to c = i or c 6= i. In the first case [[un cS]] [[un cS]] is defined, while in the second case it is not. We need to weaken the judgment [[ , y : S]] ` P to [[ , y : S]] \ x, x : (un oS, un iS) ` P . We can now apply [T-InR] and close the result. Case (iii) is analogous, while by weakening we infer the judgment [[ , y : S]], x : (un oS, un iS) ` P . In rule [T-Par] we use weakening and add entries x : (end, end) in order to make the domain of the environments 1 , 2 of the hypothesis equal, so that we can apply context splitting in rule [T-Par] of Figure 3. The remaining cases are similar. For the right to the left direction, we proceed by induction on the length of the inference [[ ]] ` P , by exploiting a result saying that [[ ]], x : (end, end) ` P implies [[ ]] ` P
(1)
Then [[ ]] ` P . To illustrate, we sketch a couple of cases. Assume that by using rule [A-InL] we have [[ 1 + 2 ]] ` x(y).P inferred from 0 ` x : ([[q iT ]], S 0 ) and , y : [[T ]] ` P 00 where = 00 + x : (S, S 0 )) and [[ 1 + 2 ]] = 0 . Moreover, we let S = end whenever q = lin, and S = [[un i T ]] otherwise. Take the sub-case x in 2 . When q = un we have x : (un iT , S 0 ) 2 and by I.H. we infer 2 , y : T `l P . From un( 0 \ x) and [T-In] we deduce 1 + 2 `l x(y).P . In the case q = lin we have x : (end, S 0 ) 2 and we proceed as above by exploiting the I.H. 2 , y : T `l P . Otherwise, assume that x not in 2 . Therefore x : (end, end) 2 . We use (1) and infer 00 \ x, y : [[T ]] ` P . By I.H. we infer 2 , y : T `l P . We conclude by applying [T-In]. Take case [T-Par] and let [[ 1 + 2 ]] ` P | Q be inferred 00 from 0 ` P and 00 ` Q such that [[ 1 + 2 ]] = 0 . We exploit (1) and rewrite the 0 00 judgments above as \I ` P and \I ` Q where we let \I be the di↵erence of and I, and we let I be the partition of induced by (z) = (end, end). By I.H. we obtain 1 `l P and 2 `l Q. We conclude by applying [T-Par]. 8. Related Work and Conclusions As mentioned in the introduction, the pi calculus equipped with a polarity-based typing system (GH05) and the double binder pi calculus equipped with lin/un qualified session types (Vas09) are the works closest to ours. Here we try to obtain the same results, relying on the traditional pi calculus. Towards this end we introduce a pair constructor denoting, at type level, the two ends of a same channel. Following (Vas09), and in order to distinguish linear from unrestricted variables we use type qualifiers applied to pre types, inspired by Walker’s presentation of substructural type systems (Wal05). This paper extends the results in (GV10; Giu11). In the first work we introduced a type system where channels can be either characterized by one session type (in case the process holds one end only), or by a pair of session types (when the process holds the two ends). Here we simplify the setting by forcing processes to always hold the two ends. The former case where a process holds one end at type S is characterized in the new system by a type of the form (S, end). It is then easy to see that the new system allows to type processes
Linearity, Session Types and the Pi Calculus
29
not typable in the former system, processes that use the “other” end of a channel for purposes allowed by an end type, that is purposes not related to communication. An algorithmic type system for (GV10) was proposed by one of the authors in (GV10). In this split-free algorithm, typing produces at output a context where the consumed linear capabilities are marked as unusable. As a consequence, the algorithm is incomplete when in presence of processes holding the two ends of a same channel. The algorithm in this paper solves this problem by using a di↵erent technique, resorting to backtracking when a particular type splitting turns out not to be the adequate one. We assess the expressivity of our typing system by providing for type-preserving encodings of the pi calculus with polarized variables of (GH05), the pi calculus with accept and request primitives of (HVK98), and the linear pi calculus of (KPT99). The linear pi calculus turns out to be a sublanguage of the language proposed in this paper. Reference (GV10) also presents an embedding of the linear lambda calculus (KPT99) which can easily be transposed to the current system. Demangeon and Honda proposed a linear type system for a polyadic asynchronous pi-calculus (DH11), together with an encoding of the pi calculus with accept/request primitives. The encoding takes advantage of the polyadic nature of the language, and of the lin/un qualifiers for input/output (denoted by 1 and w in the paper) to mimic the synchronous nature of the source language. The problem is simplified in our case since the target language is synchronous. A deeper comparison of the two systems remains as future work. Padovani defines the behavior of processes according to the channels they use (Pad12). Session types appear as the restriction of the behavior of processes with respect to a single channel. To describe the simultaneous access to a channel by more than one process, types include a form of parallel composition. Parallel composition of (session) types is quite close to our pair types. The system in (Pad12) guarantees that the two ends of a session are owned by independent processes, thus enjoying a progress result which is not among the aims of the present work. The ability to pass part of the functionality of a linear channel and retain the rest goes beyond what is usually available to session typing systems. In the realm of (binary) session types, it was first proposed by the authors (GHVY09). The method is however to be found in several works in the literature; we mention two, in addition to (Pad12) discussed above. Multiparty session types use a projection operator to extract session types for the global behavior of a system (HYC08). The conversation calculus includes a type splitting operation allowing to decompose the behavior of a process (CV10; BCVV11). In comparison with these systems, the splitting capabilities of our types are quite limited: from a linear (end point) type all we can do is to extract an end type. They are however in line with the expressivity of the type language, and still allow to type processes hitherto not typable. It should be noted that the choice of representing interaction on channels with types with two distinct components (representing the two ends of the channel) rules out some process that could be interesting. Consider a variant of the petition server that by norm signs all petitions: !(⌫p) . . . p(dueDate).(!p(signature).ProcessSignatures | phserverSignaturei)
M. Giunti and V.T. Vasconcelos
30
Our type system does not accept this process because in the unrestricted part of the process !p(signature).ProcessSignatures | phserverSignaturei both the input and the output capabilities are needed, and the output capability has been sent to the petition creator. It remains as future work the investigation of how to incorporate such behavior in our type system. References Pedro Baltazar, Lu´ıs Caires, Vasco T. Vasconcelos, and Hugo T. Vieira. Dynamic roles in multiparty communication. UNL-DI-7–2011, Departamento de Inform´ atica, Universidade Nova de Lisboa, 2011. Giuseppe Castagna, Mariangiola Dezani-Ciancaglini, Elena Giachino, and Luca Padovani. Foundations of session types. In PPDP, pages 219–230. ACM, 2009. Lu´ıs Caires and Hugo T. Vieira. Conversation types. Theoretical Computer Science, 411(51– 52):4399–4440, 2010. Mariangiola Dezani-Ciancaglini and Ugo de’Liguoro. Sessions and session types: an overview. In WS-FM’09, volume 6194 of LNCS, pages 1–28. Springer, 2010. Mariangiola Dezani-Ciancaglini, Sophia Drossopoulou, Dimitris Mostrous, and Nobuko Yoshida. Objects and session types. Information and Computation, 207(5):595 – 641, 2009. Romain Demangeon and Kohei Honda. Full abstraction in a subtyped pi-calculus with linear types. In CONCUR’11, volume 6901 of LNCS, pages 280–296. Springer, 2011. Simon J. Gay and Malcolm J. Hole. Subtyping for session types in the pi calculus. Acta Informatica, 42(2/3):191–225, 2005. Marco Giunti, Kohei Honda, Vasco T. Vasconcelos, and Nobuko Yoshida. Session-based type discipline for pi calculus with matching. In PLACES’09, 2009. Marco Giunti. A type checking algorithm for qualified session types. In WWV, volume 61 of EPTCS, pages 96–114, 2011. Marco Giunti and Vasco T. Vasconcelos. A linear account of session types in the pi calculus. In CONCUR’10, volume 6269 of LNCS, pages 432–446. Springer, 2010. Kohei Honda, Vasco T. Vasconcelos, and Makoto Kubo. Language primitives and type disciplines for structured communication-based programming. In ESOP’98, volume 1381 of LNCS, pages 22–138. Springer, 1998. K. Honda, N. Yoshida, and M. Carbone. Multiparty asynchronous session types. POPL’08, 43(1):273–284, 2008. Naoki Kobayashi, Benjamin C. Pierce, and David N. Turner. Linearity and the pi-calculus. ACM Transactions on Programming Languages and Systems, 21(5):914–947, 1999. R. Milner, J. Parrow, and D. Walker. A calculus of mobile processes, parts I and II. Information and Computation, 100(1):1–77, 1992. Luca Padovani. Session types at the mirror. In Interaction and Concurrency Experience, volume 12 of EPTCS, pages 71–86, 2009. Luca Padovani. On projecting processes into session types. Mathematical Structures in Computer Science, 2012. To appear. Benjamin C. Pierce. Types and Programming Languages. MIT Press, 2002. B. C. Pierce and D. Sangiorgi. Typing and subtyping for mobile processes. Mathematical Structures in Computer Science, 6(5):409–453, 1996. Kaku Takeuchi, Kohei Honda, and Makoto Kubo. An Interaction-based Language and its Typing System. In PARLE, volume 817 of LNCS, pages 398–413. Springer, 1994.
Linearity, Session Types and the Pi Calculus
31
Vasco T. Vasconcelos. SFM 2009, volume 5569 of LNCS, chapter Fundamentals of Session Types, pages 158–186. Springer, 2009. David Walker. Advanced Topics in Types and Programming Languages, chapter Substructural Type Systems. MIT Press, 2005. Nobuko Yoshida and Vasco T. Vasconcelos. Language primitives and type discipline for structured communication-based programming revisited: Two systems for higher-order session communication. In SecReT’07, volume 171(4) of ENTCS, pages 73–93. Elsevier, 2007.