Relating Functional and Imperative Session Types

Imperative session types provide an imperative interface to session-typed communication. In such an interface, channel references are first-class objects with operations that change the typestate of the channel. Compared to functional session type APIs, the program structure is simpler at the surface, but typestate is required to model the current state of communication throughout. Following an early work that explored the imperative approach, a significant body of work on session types has neglected the imperative approach and opts for a functional approach that uses linear types to manage channel references soundly. We demonstrate that the functional approach subsumes the early work on imperative session types by exhibiting a typing and semantics preserving translation into a system of linear functional session types. We further show that the untyped backwards translation from the functional to the imperative calculus is semantics preserving. We restrict the type system of the functional calculus such that the backwards translation becomes type preserving. Thus, we precisely capture the difference in expressiveness of the two calculi and conclude that the lack of expressiveness in the imperative calculus is largely due to restrictions imposed by its type system.


Introduction
Session types provide a type discipline for bidirectional communication protocols in concurrent programs.They originate with papers by Honda and others [Hon93,THK94], who proposed them as an expressive type system for binary communication in pi-calculus.Later work considered embeddings in functional and object-oriented languages, both theoretically and practically oriented [GV10, HKP + 10, SY16,Pad17b].
A typical incarnation of session types [GV10] embedded in a functional language supports a data type of channel ends, which are end points of communication channels.A session type s describes the communication behavior of a channel end and is governed by a grammar like this one: let server u = let (x , u ) = receive u in (* u : ?Int .? Int .! Int .s' *) let (y , u ) = receive u in (* u : ?Int .! Int .s' *) send ( x +y , u ) (* u : !Int .s' *) Listing 1: Example server in functional style continue according to s on a channel of type ?t.s.The internal choice type ⊕ . . .enables the sender to choose the continuation protocol s i by selecting its label i .The external choice & . . .requires the receiver to continue with s i if it receives i .The session type End marks the end of the conversation.
Functional vs Imperative Session Types.A significant number of embedded session type systems rely on a functional treatment of channel ends.That is, the communication operations consume a channel end at the type before the communication and conceptually produce a new channel end at the type after the communication.As an example we consider the receive operation which consumes a channel of type ?t.s and returns a pair of the received value of type t and the continuation channel of type s: receive ∶ ?t.s → (t ⊗ s) This design forces a programmer to explicitly thread channel references through the program.Moreover, every channel reference must be treated linearly because a repeated use at the same type would break the protocol.The typical programming pattern is to rebind a variable, say u, containing the channel end with a different type in every line as in Listing 1 (typings refer to the state before the operation in that line).Writing a program in this style feels like functional programming before the advent of monads, when programmers loudly complained about the need for "plumbing" as demonstrated with u.Moreover, this style is not safe for embedding session types into mainstream languages because most of them do not enforce the linearity needed to avoid aliasing of channel ends at compile time.A similar argument can be made for interfacing with dynamically typed languages.
There are techniques to ease the integration of linear functional APIs in mainstream languages.Embeddings in object-oriented languages make use of fluent interfaces, which favor the chaining of method calls [HY16].Embeddings in functional languages wrap channels into a monad [PT08], but this approach either does not scale well to programs that process multiple channels or it mimics an imperative approach similar to what we explore in this paper.Generally, much less work can be found that takes the alternative, imperative approach inspired by typestate-based programming [SY86].
Interestingly, in one of the early works on session types, Vasconcelos, Gay, and Ravara [VGR06] proposed a session type calculus embedded in a multithreaded functional language, which we call VGR.It is a bit of a mystery why VGR was not called imperative1 because it enables rewriting the functional program fragment in Listing 1 into the style shown Listing 2, which clearly has an imperative flavor.The parameter u of the server function is a reference to a communication channel.The operation receive takes a channel associated with session type ?Int.S and returns an integer2 .Executing receive changes the type of the channel referred to by u to S, which indicates that the VGR calculus is a typestate-based system [SY86].The function send_on_ takes an integer to transmit and a channel associated with session type !Int.S.It returns a unit value and updates the channel's type to S.
Taken together, the server function in Listing 2 expects that its argument u refers to a channel of type ?Int.?Int.!Int.S ′ , for some S ′ , and leaves it in a state corresponding to type S ′ on exit.This change of typestate is reflected in the shape of a function type in VGR: Σ 1 ; T 1 → T 2 ; Σ 2 .In this type, T 1 and T 2 are argument and return type of the function.The additional components Σ 1 and Σ 2 are environments that reflect the state (session type) of the channels before (Σ 1 ) and after (Σ 2 ) calling the function.The type of a channel, Chan α, serves as a pointer to the entry for α in the current channel environment Σ. Channels in T 1 refer to entries in Σ 1 and channels in T 2 refer to entries in Σ 2 , but both environments may refer to further channels that describe channel references captured by the function (Σ 1 ) or created by the function (Σ 2 ).In Listing 2, the type of server is {α ∶ ?Int.?Int.!Int.S}; Chan α → Unit; {α ∶ S}, (1.1) for some fixed channel name α and session type S.
Compared to other session type systems [GV10, FLMD19], VGR does not require linear handling of channel references, as can be seen by the multiple uses of variable u in Listing 2. Instead, it keeps track of the current state of every channel using the environment Σ, which is threaded linearly through the typing rules.
In Section 2 we give deeper insights into VGR, the kind of programs that it accepts, and the programs that fail to typecheck.To give a glimpse of its peculiarities, we examine the type of server in eq.(1.1) more closely.
First, the type Chan α of a channel reference refers to the name α.This name identifies a certain channel so that the function cannot be invoked on other channels.Second, a function of this type can be type-checked without knowledge of the channel names that are currently in use and their state.This property enables the definition of the server function in a library, say, but the type checker does not allow us to call the function on a channel named differently than α, even if its session type matches.Hence, the library may end up defining a function that cannot be called.
Consider the variation of the type in eq.(1.1) that replaces the argument type by Unit: {α ∶ ?Int.?Int.!Int.S}; Unit → Unit; {α ∶ S}. (1.2) This type can be assigned to a function like server' in Listing 3 that is closed over a reference to a channel of type Chan α.In this context, the fixation on a certain channel name α is required for soundness: While we might want to apply a function to different channels, it is not possible to replace a channel captured in a closure.A function of type as in eq.(1.2) may be called any time the channel α is in a state matching the "before" session type of the function.
Subsequently, Gay and Vasconcelos created a functional session type calculus based on a linear type system, which was later called LFST 3 [GV10].While LFST is still monomorphic, a function like server can be applied to several different channels with the same session type.In LFST, we can also close over a channel, but doing so turns a function like server' into a function that must be called exactly once.In contrast, server' can be called arbitrarily often (including zero times) in VGR provided the channel α is available at the right type in the caller's environment.Clearly, LFST lifts some restrictions of the VGR calculus, but it seems to impose other restrictions.In any case, the exact correspondence between the two calculi has never been studied.
There is another line of session-type research based on the Curry-Howard correspondence between fragments of linear logic and process calculi [CP10].Programs/processes in these systems may also be regarded as handling channels "imperatively", perhaps even more so than VGR.We discuss these approaches in Section 6 along with other related work.

Contributions.
• We show that LFST is at least as expressive as VGR by giving a typing-preserving translation that simulates VGR in LFST (Section 4).• We show that untyped VGR is at least as expressive as LFST by giving a backwards translation that simulates LFST in VGR (Section 5).• We exhibit a type system for LFST that characterizes the shortcomings of VGR exactly.The backwards translation becomes type preserving with respect to this system (Section 5.2).
In this paper we omit choice and recursion from session types because these features are straightforward to add and our results extend seamlessly.Compared to the conference version of this paper [ST21b], we added more explanations, we incorporated full rule sets and proofs, and we made the Agda proof script for Proposition 4.1 (translation preserves typing) available as a supplement [ST21a].

Motivation
In this section, we highlight the various shortcomings of VGR and discuss how they are solved in LFST.
2.1.Channel Identities.Our discussion of VGR's function type Σ 1 ; T 1 → T 2 ; Σ 2 in the introduction shows that a function that takes a channel as a parameter can only be applied to a single channel.A function like server (Listing 2) must be applied to the channel of type Chan α, for some fixed name α.
LFST sidesteps this restriction by not encoding the identity of a channel in the type.It rather posits that session types are linear so that channel references cannot be duplicated.In consequence, the operations of LFST's session API must consume a channel and return another channel to continue the protocol.
Vol. 18:3 RELATING FUNCTIONAL AND IMPERATIVE SESSION TYPES 33:5 2.2.Data Transmission vs Channel Transmission.In VGR, it is possible to pass channels from one thread to another.The session type !S ′ .S indicates a higher-order channel on which we can send a channel of type S ′ .The operation to send a channel has the following typing rule in VGR: ↦ Σ; Unit; α ∶ S The premises are value typings that indicate that v and v ′ are references to different, fixed channels β and α under variable environment Γ.The conclusion is an expression typing of the form Γ; Σ; e ↦ Σ 1 ; T ; Σ 2 where Σ is the incoming channel environment, Σ 1 is the part of Σ that is passed through without change, and Σ 2 is the outgoing channel environment after the operation indicated by expression e which returns a result of type T .The rule states that channels α and β have session type !S ′ .S and S ′ , respectively.Moreover, α and β are implicitly different (and different from all names in Σ) because a channel environment is only well-formed if all its bound names are different.The channel β is consumed (it is sent to the other end of channel α) and α gets updated to session type S.
Compared to the function type considered in the introduction (Section 1), sending a channel is more flexible.Any channel of type S ′ can be passed because β is not part of channel α's session type.Alas, if the sender holds references to channel β (i.e., values of type Chan β), then these references can no longer be exercised as β has been removed from Σ.So one can say that rule C-SendS passes ownership of channel β from the sender to the receiver.
However, there is another way to send a channel reference over a channel, namely if it is captured in a closure.To see what happens in this case, we look at VGR's typing rules for sending and receiving data of type D. Types of the form D comprise first-order types and function types, but not channels.Listing 5: With aliasing We conclude with the observation that abstracting over the send operation is not usefully possible in VGR because it would fix channel names in the function type.
None of these issues arise in LFST because channels have no identity.Hence, any value whatsoever can be sent over a channel, higher-order session types are possible, and there is just one typing rule for sending and another for receiving any kind of value.
2.3.Channel Aliasing.The VGR paper discusses the following function sendSend.fun sendSend u v = send 1 on u ; send 2 on v It takes two channels and sends a number on each.This use is reflected in the following typing.
Ignoring the types we observe that it would be semantically sound to pass a reference to the same channel w, say, of session type !Int.!Int.End for u and v.However, sendSend w w does not type check with the type in eq.(2.1) because w would have to have identity u and v at the same time, but environment formation mandates they must be different.
Another typing of sendSend in VGR would be With this typing, sendSend w w type checks.Indeed, the typing forces the two arguments to be aliases!In LFST, the invocation sendSend w w is not legal as it violates linearity.Indeed, to simulate the two differently typed flavors of sendSend requires two different expressions in LFST.As an illustration, we show LFST expressions as they are produced by our type-driven translation in Section 4, when applied to the sendSend function with the types in (2.1) and in (2.2).In the code fragment in Listing 4, u and v have unit type (translated from Chan u and Chan v) and sigma is a linear record with fields u and v that contain the respective channels.The dot operator performs field selection and * is disjoint record concatenation.The notation for record literals is standard.
In the translation of sendSend' in Listing 5, u and v also have unit type (translated from Chan w and Chan w), but the record sigma has only one field w containing the channel.
Figure 1: Syntax of VGR 2.4.Abstraction over Channel Creation.A server typically accepts many connections on the same access point and performs the same initialization (e.g., authentication) on each channel.Hence, it makes sense to abstract over the creation of a channel as in this code fragment.
fun acceptAdd () = let c = accept addService in // authenticate client on c ( omitted ) c Here, addService is an access point for sessions of type S. The function accept creates a channel end according to the access point type (a client would invoke the corresponding request function on the same access point.)The VGR typing rule for accepting a connection reads as follows: In this rule, v is an access point for creating connections of type S. According to the rule, the name of the newly created channel is fresh, i.e., it does not occur in any incoming environment or type.However, the freshness condition on this channel only applies inside the function body of acceptAdd.The actual VGR type of acceptAdd does not reflect freshness anymore but fixes a name α, say, in the function type: In consequence, VGR cannot invoke acceptAdd twice in a row as the second invocation would result in an ill-formed environment that contains two specifications for channel α.
LFST elides this issue, again, by not tracking channel identities.

Two Session Calculi
This section formally introduces the calculi VGR and LFST.It also explains the slight adjustments to the calculi that we made to obtain a smooth translation.
Evaluation contexts Reduction of expressions and processes Processes C are expression processes, parallel processes, protocol restrictions, and channel restrictions, in that order.Expressions t are in A-normal form, i.e., they are sequences of simple expressions e ending in a fork that creates new threads or in a value.A simple expression e restricts all its arguments to values, complex expressions must be sequentialized by using let-expressions.Simple expressions are function application, access point creation, accepting and requesting a connection, sending and receiving on a channel, and closing a channel.A value v is either a channel name α, a lambda abstraction, or a unit value.Channel names are either variables x or channel ends γ with a polarity p. Types distinguish between data types D and channels because two different sets of typing rules govern sending and receiving of data vs. sending and receiving a channel.We already used this syntax 33:9  We write ⋅ for the dual operator.It flips the polarity of a communication.On polarities, it is defined as + = − and − = +.On session types, ?T .S = !T .S and !T .S = ?T .S.In both cases the dual operator is an involution: S = S.
We omit choices as they present no significant problem and as they can be simulated using channel passing.We also omit the standard congruence rules for processes and silently apply reduction rules up to congruence: parallel composition is a commutative monoid, the ν-binders admit scope extrusion, and ν-binders can commute.
Figure 2 defines the semantics of VGR.We use a slightly different, but equivalent definition as in the literature.We define evaluation contexts for expressions E, F ∶∶= ◻ let x = E in t which are used in the expression rules.Our formulation avoids the commuting conversion rule R-Let in the literature and fixes an issue with the original reduction relation. 4  We distinguish between expression reduction ⇒ e and process reduction ⇒ p , both of which are tagged with a label .This label indicates the effect of the reduction and it ranges over ∶∶= accept send close new fork τ processes where τ stands for effect freedom and can be omitted.Labeled expression reductions are paired with their counterpart at the process level as familiar from process calculi [Mil99], that is, γ p ?v (γ p !v) stand for receiving (sending) v on γ p which resolves to label send at the process level (see reduction (3.6)).Similarly, accept γ p (request γ p ) stands for accepting (requesting) a connection on fresh channel γ p and resolves to label accept at the process level.Finally, γ p End stands for a close operation on γ p and resolves to label close at the process level.
Typing for VGR comes in three parts: value typing Γ; v ↦ T in Figure 3, expression typing Γ; Σ; e ↦ Σ ′ ; T ; Σ ′′ in Figure 4, and configuration typing Γ; Σ; C ↦ Σ ′ (Figure 5).The value typing judgment relates an environment Γ and a value v to a type T .The expression typing judgment is very similar to a type state system.It relates a typing environment Γ, an incoming channel environment Σ, and an expression to an environment Σ ′ ⊆ Σ which contains the channels not used by e, the type T , and the outgoing channel environment Σ ′′ .Σ ′′ contains typings for channels that have been used by e or created by e.The configuration typing relates Γ, incoming Σ, and configuration C with Σ ′ ⊆ Σ which contains the channels not used by C.
The static semantics of the VGR calculus is presented as in the literature [VGR06] except for the rule C-Fork.This change is unavoidable because the original rule is unsuitable for the translation: It states that t 1 processes channels in Σ, leaves the channels in Σ 1 ⊆ Σ unchanged, and consumes the remaining ones.The unchanged channels Σ 1 are then processed by t 2 .However, the translation of t 1 runs in a separate thread, so it is unable to return the untouched channels in Σ 1 .Hence, the rule C-Fork splits the channels into the ones in Σ 1 consumed by the new thread t 1 and the ones in Σ 2 consumed by the continuation t 2 .We also deviate in using a labeled transition system for the dynamic semantics to directly relate labeled reduction steps between the two systems.
3.2.Linear Functional Session Types.On the functional side, we consider an extension of a synchronous variant of the LFST calculus [GV10] by linear records with disjoint concatenation.Figure 6 gives the syntax of this calculus, which we call LFST-rec.The  The second line of the expression grammar adds the standard elimination of linear units and defines operations on linear records.We write {} for the empty record, {α = e} to construct a singleton record with field α given by e, e 1 ⋅ e 2 for the disjoint concatenation of records e 1 and e 2 , e.α to project field α out of the record e returning a pair of the contents of the field and the remaining record, and e.⃗ α for generalized projection to a list of names ⃗ α that returns a pair of two records, one with the fields ⃗ α and the other with the remaining fields.The extension with records can be regarded as syntactic sugar as it is well known how to compile records to nested pairs.Given that compilation, the typing rules for record operations are derived rules.We prefer the convenience of the record notation as it avoids the additional bookkeeping of this compilation step.
A configuration C can be a single thread, two configurations running in parallel, a channel abstraction binding the two ends to γ and δ, or an access point abstraction (νn)C.The latter is a straightforward addition to LFST, which assumes the existence of globally known access points.
The metavariable t ranges over types, s ranges over session types, and r ranges over rows, which are lists of bindings of names to types.A type t can be a session type s, a access point type [s], the unit type Unit, an unrestricted function type t → t, a single-use function type t − * t, a pair type t ⊗ t, or a record type {r} defined by a row r.A session type s is as before.A row r is a list of pairs of (row) names and types where all names are disjoint.
Figure 7 recalls the definition of the predicate unr t for unrestricted types, which we lift pointwise to typing environments.Intuitively, a type is unrestricted if it does not contain any linear components.A linear component is either a session type; a pair with at least one linear component; a record with at least one linear field; or a single-use function, which may close over a linear component in a free variable.In the literature [GV10], a channel of type End is unrestricted, so that no explicit close operation is needed.Here, we fully enforce linear handling of channels by adding the close operation.This addition requires a change in the unr t predicate.It splits environment Γ into Γ 1 and Γ 2 such that unrestricted bindings are duplicated and linear bindings end up either in Γ 1 or Γ 2 .In the typing rules, we write Γ 1 + Γ 2 for some Γ such that Γ = Γ 1 + Γ 2 .
Figure 7 splits the incoming environment Γ so that bindings to a linear type end up either in Γ 1 or in Γ 2 (also in Figure 7).Premise r 1 ♯ r 2 states that rows r 1 and r 2 are disjoint, which means they bind different field names.Under these assumptions the (disjoint) concatenation of records e 1 and e 2 is accepted.The rules for field access and splitting of the record generalize the elimination rule for linear pairs.Rule T-Field shows that a field access singles out the field named α.Its content is paired up with a record comprising the remaining fields.Linearity of the record's content is preserved as the pair is also linear.Rule T-SplitRecord is similar, but splits its subject e according to a list ⃗ α of names which must be present in e's type.The result is a linear pair of two records.We consider an empty record to be unrestricted so that we can drop it if needed.
The remaining typing rules are taken from the original paper [GV10].We modify the operational semantics to perform synchronous communication and to fit with the labeled transition style used for VGR in Section 3.1.Its formalization is omitted from the main text because of its similarity to VGR, but it is available in the appendix (Figures 14 and 15).

Translation: Imperative to Functional
As a first step, we discuss the translation of the imperative session type calculus VGR into the linear functional session type calculus LFST-rec.The extension with record types is not essential, but it makes the translation more accessible.All records could be elided by replacing them with suitably nested pairs and mapping record labels to indices.4.1.Specification of the Translation.The translation from VGR to LFST-rec is type driven, i.e., it is a translation of typing derivations.The gist of the approach is to translate VGR expressions into a parameterized linear state transformer monad.It is parameterized in the sense of Atkey [Atk09] because the type of the state changes with every non-trivial computation step (i.e., sending and receiving messages).We map derivations for VGR value typing, VGR expression typing, and VGR configuration typing to LFST-rec expressions and configurations.For brevity, we indicate the translation with ⟪e⟫ and ⟪C⟫ where the arguments are really the typing derivations for e
These statements are proved by mutual induction on the derivations of the VGR judgments in the premises.The VGR typing judgments for expressions and configurations pass through unused channels (in Σ 1 ) in the style of leftover typings [All17].While this style is convenient for some proofs, it cannot be used for the translation as it fails when trying to translate the term fork t 1 ; t 2 .The first premise of its typing rule C-Fork is Γ; Σ; t 1 ↦ Σ 1 ; T 1 ; {}, which says that executing t 1 consumes some of the incoming channels Σ and does not touch the ones in Σ 1 .The second premise Γ; Σ 1 ; t 2 ↦ Σ 2 ; T 2 ; {} picks up Σ 1 and demands that t 2 consumes all its channels.However, this pattern does not work for the translation, which is based on explicit channel passing: if we passed all channels in Σ to t 1 , which is forked as a new thread, there would be no way to obtain the leftover channels Σ 1 after thread t 1 has finished.Moreover, these channels have to be available for t 2 even before t 1 has finished!The same issue arises when translating the parallel composition of two configurations.For that reason, in LFST-rec the translated expressions and configurations are supplied with exactly the channels needed.
Figure 8 contains the details of the type translation, the translation of environments, and the translation of values.The only interesting case of the type translation is the one for function types, which maps a function to a Kleisli arrow in a linear, parameterized state monad.The incoming and outgoing channel environments are mapped to the incoming and outgoing state record types.The other observation is that any channel type is mapped to the unit type.
The translation of values has two interesting cases.A channel value is mapped to the unit value () because channels are handled on the type level and channel references are resolved by accessing the corresponding field of the state record.Functions obtain an extra argument σ for the incoming state record that contains the currently open channels.The body of a lambda is translated by the expression translation which is indexed by the incoming state record σ and returns a pair of the result and the outgoing state record.
Figure 9 shows select cases from the translation of expressions that demonstrate the role of the record operations.The conclusion of Preserve-Expression shows that an expression is correctly translated to a linear state transformer as in the translation of the function type.
Figure 10 contains the translation of the configuration typing rules.Of those, the most interesting case is the C-Thread configuration rule.Threads execute in a context that contains a list of access points with their types.The thread body may refer to channels in Σ.The translation rule reifies the channels that are used in the thread by collecting them in a record σ and injecting that record as the initial state of the state monad.This record is transformed by the expression translation that returns a pair of the return value of type ⟪T ⟫ and the final record of type {⟪∅⟫}.It is easy to see that this pair is unrestricted because the translation of a (non-session) type T is generally unrestricted and the empty record is also unrestricted.
The remaining rules are simple.In C-Par, we do not have to manipulate the channel environments as we do in the T-Fork rule because channels are only reified at the thread level in rule C-Thread.C-NewN creates a new access point, C-NewB compensates for the different handling of channel restriction in VGR and LFST-rec.C-NewC handles depleted channels.4.2.Simulation.We would like the translation to induce a simulation in that each step of a typed VGR configuration C gives rise to one or more steps in its translation ⟪C⟫ in LFST-rec.Unfortunately, the situation is not that simple because administrative reductions involving the state get in the way.

Translation: Functional to Imperative
For the backwards translation we consider LFST programs without records and we informally extend the expression language of VGR with pairs-analogous to LFST, but unrestricted.
We first define an untyped translation that demonstrates that the calculi are equally expressive.Then we define a restricted version of LFST's type system to characterize the subset of LFST on which the translation preserves typing.5.1.Untyped Translation.In a first approximation, the backwards translation, indicated by e for an LFST expression e, might map the send and receive operations naively as follows.
send e 1 on e 2 = let x = e 1 in let y = e 2 in let z = send x on y in y (5.1) receive e = let y = e in let x = receive y in (x, y) ( This mapping, extended analogously to the rest of LFST, yields a program in A-normal form that fits with VGR's syntactic restrictions.The functional send operation returns the updated channel, so we have to duplicate the channel reference y in its image in VGR. Similarly, the functional receive operation returns a pair of the received value and the updated channel, so the translation needs to construct a pair from the received value and the updated channel y.However, to prove a tight relation between reduction in LFST and VGR, we need to be more careful to avoid administrative reductions.For example, if e in (5.2) is already a value, then the inserted let y = e in . . . is gratuitous and results in an extra administrative reduction in VGR.
This phenomenon is known since Plotkin's treatise of the CPS translation [Plo75].Hence, we factor the backwards translation in two steps.The first step transforms the LFST program to A-normal form using an approach due to Sabry and Felleisen [SF93].This transformation is known to give rise to a strong operational correspondence (a reduction correspondence [SW97]), it is typing preserving, and it is applicable to LFST because it preserves linearity.The definition of this translation e is given in Appendix A.2.
This refined ANF translation is compatible with evaluation because it is compatible with values, evaluation contexts, and substitution.
Lemma 5.1 (Value preservation).v is a value in LFST.
Proof.Case analysis on values v. Lemma 5.2 (Evaluation preservation).If E is an LFST evaluation context, then so is E .
Proof.Induction on the definition of evaluation contexts (Figure 14) using the definition of the ANF translation for evaluation contexts (Figure 17).
Proof.Induction on e.The only interesting case arises for e = x: All other cases are immediate by the induction hypothesis.
The second step is the expression translation e from LFST-ANF to VGR.This translation is very simple because the source calculus is already in A-normal form.The idea of the translation as stated at the beginning of this section is clearly reflected in the first Proof.In LFST-ANF, the grammar of evaluation contexts is reduced to which clearly matches VGR evaluation contexts (cf. Figure 2).So, item 1 is immediate and item 2 holds by induction on E. (2)

Typed Backwards Translation.
To obtain a type preserving backwards translation from LFST to VGR, we have to add extra information to the type system of LFST.Unfortunately, this extra information makes the typing more restrictive.We start with an informal review of the requirements.
First, as VGR tracks channel identities, they have to be represented in the revised type system for LFST.Following Padovani [Pad17a], we tag session types as in s α consisting of a session type s tagged with an identity α.This change affects the following five preliminary typing rules: accept and request create new channel identities, sending and receiving continues on the same channel.
Second, the function type in VGR specifies a transformation on the channels that are implicitly or explicitly affected by the function.Hence, we must augment the LFST type system with tracking the identities of channels, on which the program performs an effect.To this end, we equip LFST with a suitable sequential effect system [Gor17].It distinguishes between incoming and outgoing channels, Σ i and Σ o , which are also reflected in the latent effect on the function arrow.
Hence, the resulting typing judgment reads like this: in typing environment Γ, expression e has type t and its evaluation processes channels according to Σ i and returns channels according to Σ o .We define tagged session types by adding an identity tag α to all session types and augmenting function types with a set of uniquely tagged sessions.We carve out a set of data types d, which can be transmitted in VGR programs.Hence, session types proper (denoted by s) are a subset of LFST's session types.Using mostly standard effect typing rules (see Figure 11 for select rules and Appendix A.4 for the full set of rules), we show that effect typing is a proper restriction of LFST typing.We write t for the erasure of an LFST-EFF type t, which is defined in Figure 12.Erasure extends pointwise to environments Γ.

Lemma 5.10 (Conservative Extension
Proof.Straightforward induction.The standard typing rules correspond to the erasure of the effect typing rules.
The translation to ANF does not affect LFST typing with effects.
Figure 13 contains the backwards translation for types.An α-tagged session type turns into the channel type Chan α and the effect annotation on function types gets mapped to the before and after environments in VGR function types.
This preparation enables us to prove the typing preservation of the backwards translation.

Related Work
Pucella and Tov [PT08] give an embedding of a session type calculus in Haskell.Like our translation, their embedding relies on a parameterized monad, which is layered on top of the IO monad using phantom types.Linearity is enforced by the monad abstraction.Multiple channels are implemented by stacking so that channel names are de Bruijn indices.
Stacking only happens at the (phantom) type level, so that stack rearrangement has no operational consequences.The paper comes with a formalization and a soundness proof of the implementation.Sackman and Eisenbach [SE08] also encode session types for a single channel in Haskell using an indexed (parameterized) monad.Imai and coworkers [IYY19] propose an encoding of binary session-based communication as a library in OCaml.This library is based on an indexed state monad that maintains the current state of a set of channels in a tuple.Channel names are encoded by lenses operating on this state and operations an a channel change the index type at the position indicated by the lens.The programming style resembles VGR, but it is explicitly monadic.The monad and its type indexing are closely related to our encoding, which is linear by typing.
Another line of work on session types is based on process calculi obtained through the Curry-Howard correspondence applied to fragments of linear logic [CP10, BTP19, DP20].The resulting programs have an imperative flavor as they are based on process calculus.The correspondence structures communication as a string of interactions on a channel name.This channel name "changes type" by rebinding at each communication operation.There is a monadic embedding of this approach into a pure functional language [TCP13].In this stratified language, processes are snippets of imperative code encapsulated as first-class monadic values into the functional language.These values can be plugged into a process term by a suitable adaptation of the monadic bind operation.Processes may transmit channel names or values from the functional stratum.Processes have the imperative flavor as already mentioned.It would be interesting future work to relate this line of work with the correspondence developed in the present paper.
Alias types [SWM00] presents a type system for a low-level language where the type of a function expresses the shape of the store on which the function operates.Function types can abstract over store locations α and the shape of the store is described by aliasing constraints of the form {α ↦ T }.Constraint composition resembles separating conjunction [Rey02] and ensures that locations are unique.Analogous to our channel types, pointers in the alias types system can be duplicated and have a singleton type indicating their store location.Alias types also include non-linear constraints, which are not required in our system.

Conclusion
Disregarding types, the imperative and functional session calculi are equally powerful.But typing is the essence of a session calculus so that the imperative calculus is strictly less expressive.Two issues are responsible for the limitations.
(1) Identity tracking for channels restricts the usability of functional abstraction.As soon as types represent channel identities, functions are fixed to specific channels in a simply typed system.(2) Having different typing rules for sending channels and sending (other) data impedes abstraction and modularity.Higher-order channel passing has subtle problems that limit the usefulness of a transmitted channel.
Our results suggest that the simple nature of VGR's type system is the culprit for the severe restrictions on expressiveness.On the other hand, the conciseness of VGR programs is appealing to many (imperative) programmers.Hence, it is an interesting future work to extend VGR's type system such that there are type and semantics preserving translations in both directions.As demonstrated by the work on Alias Types [SWM00], polymorphism over identities is one required ingredient, but more work is needed to clarify all issues involved in such a system.which is similar to the semantics of context-free session types [TV16].Figure 15 defines the standard process congruence rules that make processes into a commutative semigroup.

Values
A.2. Translation to ANF. Figure 16 contains the definition of the translation of LFST to LFST in A-normal form.It is defined by induction on LFST expressions with the additional twist that it distinguishes between non-value terms n and value terms v (see Figure 14).The idea is that intermediate let-expressions are only introduced if the current term is a non-value.Variables that only appear on the right hand side in the translation are assumed to be fresh.
receive u in let y = receive u in send x + y on u Listing 2: Example server fun server ' () = let x = receive u in let y = receive u in send x + y on u Listing 3: Example server with capture

Figure 7 :
Figure 7: Typing rules of LFST Figure 7 also recalls the splitting judgment Γ = Γ 1 + Γ 2 .It splits environment Γ into Γ 1 and Γ 2 such that unrestricted bindings are duplicated and linear bindings end up either in Γ 1 or Γ 2 .In the typing rules, we write Γ 1 + Γ 2 for some Γ such that Γ = Γ 1 + Γ 2 .Figure7also contains the well-known typing rules for the communication primitives as well as the (derived) rules for the record fragment of LFST.The rule T-Emp typechecks Figure 8: Type translation

Figure 9 :
Figure 9: Translation of expressions and threads (excerpt)

Figure 10 :
Figure 10: Translation of configurations Proposition 5.4 (ANF Simulation).(1) If e → e e ′ , then e → + e e ′ .( the expression translation e .The remaining cases of the translation proceed homomorphically (see Figure 18 in Appendix A.3). send v on w = let z = send v on w in w receive v = let x = receive v in (x, v ) fork e = fork e ; () This setup establishes a tight connection between LFST-ANF and VGR, because the translation preserves values, evaluation contexts, and substitution.Lemma 5.5 (Value preservation).For each value v of LFST-ANF, v is a VGR value.Proof.Simple case analysis.Lemma 5.6 (Evaluation preservation).(1) For each evaluation context E of LFST-ANF, E is a VGR evaluation context.(2) For each expression e of LFST-ANF, E[e] = E [ e ].

Lemma 5. 7 (
Backwards substitution).For each LFST-ANF expression e and value v, e [ v x] = e[v x] .Proof.Induction on e using Lemma 5.5 for the case e = x.Proposition 5.8 (Backwards simulation).Let e, e ′ and C, C ′ be expressions and configurations in LFST-ANF.(1) If e → e e ′ , then e ⇒ e e ′ .(2)IfC → p C ′ , then C ⇒ + p C ′ .Proof.See Appendix A.5.3.Putting the results for the two steps together, we obtain the desired tight simulation result by composing Propositions 5.4 and 5.8.Proposition 5.9 (Full Backwards Simulation).Suppose that e, e ′ and C, C ′ are expressions and configurations in LFST.(1)If e → e e ′ , then e ⇒ + e e ′ .