Type-Directed Concurrency

. We introduce a novel way to integrate functional and concurrent programming based on intuitionistic linear logic. The functional core arises from interpreting proof reduction as computation. The concurrent core arises from interpreting proof search as computation. The two are tightly integrated via a monad that permits both sides to share the same logical meaning for the linear connectives while preserving their different computational paradigms. For example, concurrent computation synthesizes proofs which can be evaluated as functional programs. We illustrate our design with some small examples, including an encoding of the pi-calculus.


Introduction
At the core of functional programming lies the beautiful Curry-Howard isomorphism which identifies intuitionistic proofs with functional programs and propositions with types.In this paradigm, computation arises from proof reduction.One of the most striking consequences is that we can write functions and reason logically about their behavior in an integrated manner.
Concurrent computation has resisted a similarly deep, elegant, and practical analysis with logical tools, despite several explorations in this direction (see, for example, [4,15]).We believe the lack of a satisfactory Curry-Howard isomorphism is due to the limits inherent in complete proofs: they provide an analysis of constructive truth but not of the dynamics of interaction.
An alternative logical foundation for concurrency is to view computation as proof search [6].In this paper we show that the two views of computation, via proof reduction and via proof search, are not inherently incompatible, but can coexist harmoniously in a language that combines functional and concurrent computation.We retain the strong guarantees for functional computation without unduly restricting the dynamism of concurrent computation.
In order to achieve this synthesis, we employ several advanced building blocks.The first is linearity: as has been observed [12], the evolution and communication of processes maps naturally to the single-use semantics of assumptions in linear logic.The second is dependency: we use dependent types to model communication channels and also to retain the precision of functional specifications for transmitted values.The third is monads: we use monadic types to encapsulate concurrent computation, so that the linear connectives can retain the same logical meaning on the functional and concurrent side without interference.The fourth is focusing [5]: we use it to enforce the atomicity of concurrent interactions during proof search.
The result is a tightly integrated language in which functional computation proceeds by reduction and concurrent computation proceeds by proof search.Concurrent computation thereby synthesizes proofs which can be evaluated as functional programs.We illustrate the design with some small examples, including an encoding of the π-calculus to help gauge its expressive power.
There has been significant prior work in combining functional and concurrent programming.One class of languages, including Facile [11], Concurrent ML [18,19], JOCaml [9], and Concurrent Haskell [13], adds concurrency primitives to a language with functional abstractions.While we share some ideas (such as the use of monadic encapsulation in Concurrent Haskell), the concurrent features in these languages are motivated operationally rather than logically and are only faintly reflected in the type system.Another class of languages start from a rich concurrent formalism such as the π-calculus and either add or encode some features of functional languages [17].While operationally adequate, these encodings generally do not have a strong logical component.An interesting intermediate point is the applied π-calculus [2] where algebraic equations are added to the π-calculus.However, it is intended for reasoning about specifications rather than as a programming language.
Perhaps most closely related to our work is CLF [21] and the logic programming language LolliMon [14] based on its first-order fragment.Our type system is based on the common logic underlying both these systems.However, these systems are intended as a logical framework and concurrent logic programming language respectively and differ significantly from our language in the operational semantics.Another closely related line of work is Abramsky's computational interpretations of linear logic [3], but the discussion of concurrency there is based on classical rather than intuitionistic linear logic and lacks functional features.
The principal contributions of this paper are conceptual and foundational, although a simple prototype [1] indicates that there is at least some practical merit to the work.Owing to space constraints we omit the linear type constructors & and ⊕, recursive types and all proofs from this paper.These details can be found in the companion technical report [10].
In the remainder of the paper we present our language (called CLL) in three steps.First, we present the functional core (f CLL) which integrates linearity and a monad.Second, we present the concurrent core (l CLL), which is based on proof search, and which can call upon functional computation.Third, we complete the integration with one additional construct to allow functional computation to call upon concurrent computation.We call the complete language full-CLL.We conclude with some remarks about the limitations of our work.
Our main technical results are as follows.For the functional core f CLL, we prove type soundness by proving preservation and progress.For the concurrent core l CLL, we only formulate and prove a suitable notion of preservation.For full-CLL, we prove both preservation and progress, but the progress theorem is weaker than that of f CLL.This is because in full-CLL concurrent computations started during functional computation can deadlock.
2 f CLL: Functional core of CLL Syntax.The functional core of CLL is a first-order dependently typed linear functional language called f CLL.It is an extension of a linear lambda calculus with first-order dependent types from DML [22] and a monad.Its type and term syntax is based largely on that of CLF [21].The syntax of f CLL is summarized in figure 1. Types in f CLL can depend on index terms (denoted by s, t) that are divided into a number of disjoint sorts (γ).Index terms contain index variables (i, j, k, . ..) and uninterpreted function symbols (f, g, h, . ..).We assume the existence of a sorting judgment Σ t ∈ γ, where Σ is a context that mentions the sorts of all free index variables in t.
Type constructors (denoted by C) are classified into kinds.For every f CLL program we assume the existence of an implicit signature that mentions the kinds of all type constructors used in the program.An atomic type is formed by applying a type constructor C to index terms t 1 , . . ., t n .If C has kind γ 1 → . . .→ γ n → Type, we say that the atomic type C t 1 . . .t n is well-formed in the index variable context Σ iff for 1 ≤ i ≤ n, Σ t i ∈ γ i .In the following we assume that all atomic types in f CLL programs are well-formed.
Following CLF, types in f CLL are divided into two classes -asynchronous (A, B) and synchronous (S).Asynchronous types can be freely used as synchronous types.However, synchronous types must be coerced explicitly into asynchronous types using a monad {. ..}, which is presented in a judgmental style [16].
Programs (P ) are divided into three syntactic classes -terms (N ), monadicterms (M ) and expressions (E).This classification is reminiscent of a similar classification in CLF's objects.Under the Curry-Howard isomorphism, terms are proofs of asynchronous types whereas monadic-terms and expressions are proofs of synchronous types that end with introduction rules and elimination rules respectively.A f CLL program is called closed if it does not contain any free term variables.Closed programs may contain free index variables.
Typing.Programs in f CLL are type-checked using four contexts -a context of index variables Σ, a context of linear variables ∆, a context of unrestricted variables Γ and a context of patterns Ψ .Only the last of these contexts is ordered.There are four typing judgments in the type system.We use the notation N : A, M S and E ÷ S for typing relations.Some interesting rules from these judgments are shown in figure 2. Type-checking for f CLL is decidable.
Operational Semantics.We use a call-by-value reduction semantics for f CLL.
Figure 3 shows the definition of values in f CLL and some interesting reduction rules.The substitution relation P [M V /p] substitutes the monadic-value M V for a pattern p in the program P .It is defined by induction on the pattern p. P [V /x] and P [t/i] are the usual capture avoiding substitutions for term and index variables respectively.In f CLL, the monad {E} is a value because after we extend the language in section 4, expressions have effects.Reduction of the two components of a ⊗ can be interleaved arbitrarily, or it may performed in parallel.
Expressions are reduced in a context of index variables Σ.This context plays no role in f CLL, but when we extend f CLL to full-CLL in section 4, the context Σ becomes computationally significant.We state preservation and progress theorems for f CLL below.
Example 1 (Fibonacci numbers).As a simple example of programming in f CLL, we describe a function for computing Fibonacci numbers.These numbers are defined inductively as follows.
For implementing this definition as a function in f CLL, we assume that f CLL terms have been extended with integers having type int, named recursive functions and a conditional if-then-else construct.These can be added to f CLL in a straightforward manner.Figure 4 shows the f CLL function fib that computes the nth Fibonacci number.It has the type int → {!int}.It is possible to write this function in a manner simpler than the one presented here, but we write it this way to highlight specific features of f CLL.
The most interesting computation in fib, including recursive calls, occurs inside the monad.Since the monad is evaluated lazily in f CLL, computation in fib will actually occur only when the caller of fib eliminates the monad from the returned value of type {!int}.Syntactically, elimination of the monadic constructor can occur only in expressions at the let construct.Hence the program that calls fib must be an expression.Here is an example of such a top level program that prints the 5th Fibonacci number: let {!x} = fib 5 in print(x).

l CLL: Concurrent core of CLL
The concurrent core of CLL is called l CLL.It embeds the functional language f CLL directly.In the structure of concurrent computations l CLL is similar to the π-calculus.However it is different in other respects.First, it allows a direct representation of functional computation inside concurrent ones, as opposed to the use of complex encodings for doing the same in the π-calculus [20].Second, the semantics of l CLL are directed by types, not terms.This, we believe, is a new idea that has not been explored before.
Syntax.We present l CLL as a chemical abstract machine (CHAM) [7].l CLL programs are called configurations, denoted by C. Figure 5 shows the syntax of l CLL configurations.Each configuration is made of four components, written Σ is a context of index variables, as defined in section 2. σ is a sorted substitution mapping index variables to index terms.Γ is a set of closed f CLL term values along with their types.∆ is a multiset of closed f CLL programs together with their types.We require that whenever N : A ∈ ∆, N have the type A[σ], where A[σ] is the result of applying the substitution σ to the type A. Similar conditions hold for monadic-terms and expressions in ∆ and term values in Γ .Formally, a configuration Σ; σ Γ | | | ∆ is said to be well-formed if it satisfies the following conditions.
We assume that all our configurations are well-formed.Programs in ∆ and values in Γ are collectively called processes.Intuitively, we view programs in ∆ as concurrent processes that are executing simultaneously.∆ is called a linear solution because these processes are single-use in the sense that they can neither be replicated, nor destroyed.Term values in Γ are viewed as irreducible processes (like functional abstractions) that are replicable.For this reason Γ is also called an unrestricted solution.The context Σ can be viewed as a set of global index names, that are known to have specific sorts.The domain of the substitution σ can be viewed as a set of local (private) index names that are created during the evaluation of the configuration.The substitution σ maps these local index names to index terms that depend only on the global names (see condition (1) for well-formedness above).

Semantics of l CLL
The semantics of l CLL are rewrite rules that allow a configuration to step to other configuration(s).The specific rules that apply to a particular configuration are determined by the types of processes in that configuration.In this sense, these rules are type-directed.We classify rewrite rules into three classes -functional, structural and synchronization.
Functional rules.Functional rules allow reduction of programs in the linear solution ∆.We denote them using the arrow .Figure 6 shows the functional rewrite rules for l CLL configurations.There are three rules, one for reducing programs in each of the three syntactic classes of f CLL.Reductions of different programs in ∆ can be performed in parallel.This supports the idea that programs in ∆ can be viewed as processes executing simultaneously.
Structural rules.Structural rules apply to those irreducible programs in ∆ that have synchronous types.These are exactly the monadic values M V .A structural rule decomposes a monadic value into smaller monadic values.We denote structural rules with the arrow .All structural rules for rewriting l CLL configurations are shown in figure 7. Unlike most CHAMs, our structural rules are not reversible.
Fig. 6.Functional rewrite rules for l CLL configurations The rule ⊗ splits the monadic value M V1 ⊗ M V2 of type S 1 ⊗ S 2 into two monadic values M V1 and M V2 of types S 1 and S 2 respectively.Intuitively, we can view M V1 ⊗ M V2 as a parallel composition of the processes M V1 and M V2 .The rule ⊗ splits this parallel composition into its components, allowing each component to rewrite separately.
In the rule ∃, there is a side condition that i must be fresh i.e. it must not occur anywhere except in S(i).Some α-renaming may have to be performed to enforce this.In l CLL, the ∃ type acts as a local index name creator.The rule ∃ creates the new index name i and records the fact that i is actually bound to the index term t in the substitution σ.
The rule !moves a program of type !A to the unrestricted solution, thus allowing multiple uses of this program.For this reason, the type !A serves as a replication construct in l CLL.The rules and ÷ change the type ascription for programs that have been coerced from one syntactic class to another.Synchronization Rules.Synchronization rules act on values in Γ and ∆ having asynchronous types.These are exactly the term values V .Synchronization rules are denoted by the arrow −→.We call this process synchronization.Synchronization uses values in ∆ exactly once, while those in Γ may be used zero or more times.

Synchronization rules, Σ
In the rule −→=⇒ shown in figure 8, ∆ denotes a subset of the linear solution that participates in the synchronization.The remaining solution ∆ is kept as is.Some backward reasoning is performed in the judgment =⇒ to produce the linked program N of type {S}.This is the essential point here -the result of a synchronization must be of type {S}.
The semantic rewriting relation for l CLL is defined as ⇒ = ∪ ∪ −→.It satisfies the following type preservation theorem.More specifically, each use of −→=⇒ corresponds to a single focusing step for eliminating asynchronous constructors from a proposition that has {S} in the head position.For a detailed description of this see [10].
Example 2 (Client-Server Communication).We illustrate concurrent programming in l CLL with an example of a client-server interaction.The server described here listens to client requests to compute Fibonacci numbers.Each request contains an integer n.Given a request, the server computes the nth Fibonacci number and returns this value to the client.
We model communication through asynchronous message passing.Assume that all clients and the server have unique identities, which are index names from a special sort called procid.The identity of the server is serv.A message from one process to another contains three parts -the identity of the sender, the identity of the recipient and an integer, which is the content of the message.Messages are modeled using a type constructor mess and a term constructor message having the kind and type shown in figure 9.For every pair of index terms i and j of sort procid and every integer n, we view the value (message [i] [j] n) of type (mess i j) as a message having content n from the process with identity i to the process with identity j.In order to extract the integer content of a message, we use the destructor fetchmessage that has the reduction rule fetchmessage {!n}.The server program called fibserver is shown in figure 9.It waits for a message m from any client i.Then it extracts the content n from the message, computes the nth Fibonacci number using the function fib defined in example 1 and returns this computed value to the client i as a message.fibserver has the type fibservtype = ∀i : procid.mess i serv {mess serv i}.A sequence of rewrite steps in l CLL using fibserver is shown in figure 9.The initial configuration contains fibserver and a message to fibserver containing the integer 6 from a client having identity k.For brevity, we omit the client process.The crucial rewrite in this sequence is the first one, where the synchronization rule −→=⇒ is used to link the fibserver program with the message for it.Rewriting ends with a message containing the value of the 6th Fibonacci number (namely 13) from fibserver to the requesting client k.

An encoding of the π-calculus in l CLL
We describe a translation of a variant of the asynchronous π-calculus [8] to l CLL.The syntax and semantics of this variant are shown in figure 10.It extends the asynchronous π-calculus with a nil process 0. The replication operator ! is restricted to actions only.
Two translations • and • are shown in figure 11.They map π-calculus entities to programs and types of fCLL respectively.We model channels as index terms of a specific sort chan.In order to translate xy, which is an output message, we introduce a type constructor out and a related term constructor output, whose kind and type are shown in figure 11.The translations of xy to terms and types are output [x] [y] and out x y respectively.
Additional Signature procid: sort serv : procid mess: procid → procid → Type message: ∀i : procid.∀j : procid.int → mess i j fetchmessage: ∀i : procid.∀j : procid.mess i j {!n} Fibonacci Server fibservtype = ∀i : procid.mess i serv {mess serv i} fibserver: fibservtype = Λi : procid.λm : To translate x(y).P , we introduce a term destructor destroyout corresponding to the constructor output.Its type and reduction rule are shown in figure 11.The translation x(y).P waits for two inputs -the channel name y and a mes-  Translations of !A, P 1 |P 2 and 0 are straightforward.We translate νx.P to the type ∃x : chan.P .To translate νx.P to a program, we assume that there is an index constant c chan of sort chan.Then we translate νx.P to [c chan , ( P [c chan /x])], which has the type ∃x : chan.P .
For any π-calculus process P , fn(P ) : chan; •; • P P .The translation of a π-calculus process P to l CLL is defined as the configuration P = fn(P ) : chan; Fig. 12. Full-CLL syntax and semantics then link E ÷ S to G evaluates to .All these conditions are summarized in figure 12.If none of these conditions hold, evaluation of the link construct fails and computation deadlocks.We call this condition link failure.Since expressions are coerced into terms through a monad, link failure never occurs during evaluation of terms and monadic-terms.As a result, full-CLL has the following progress theorem.Link failure is easy to detect at runtime and can be handled, for example, by throwing an exception.For all practical problems that we encountered, we found it possible to write programs in which link failure never occurs.f CLL's preservation theorem (theorem 1) holds for full-CLL also.
Example 3 (Fibonacci numbers in full-CLL).Figure 13 shows a concurrent implementation of Fibonacci numbers in full-CLL.The function fibc uses the additional signature from example 2 and assumes that the sort procid contains at least three constants k 1 , k 2 and k. fibc has the type int → {!int}.Given an input integer n ≥ 2, fibc computes the nth Fibonacci number using a link construct that starts concurrent computation with a tensor of three processes having identities k 1 , k 2 and k respectively.The first two processes recursively compute f ib(n − 1) and f ib(n − 2) and send these values as messages to the third process.The third process waits for these messages (m 1 and m 2 ), extracts their integer contents and adds them together to obtain f ib(n).This becomes the result of evaluation of the link construct.
During the evaluation of fibc, each of the two recursive calls can encounter a link construct and create a nested l CLL concurrent computation.Since the two recursive calls can be executed simultaneously, there may actually be more than one nested l CLL configuration at the same time.However, these configurations are distinct -processes in one configuration cannot synchronize with those in another.In general, full-CLL programs can spawn several nested concurrent computations that are completely disjoint from each other.

Conclusion
We have presented a language that combines functional and concurrent computation in a logically motivated manner.It requires linearity, a restricted form of dependent types, a monad, and focusing, in order to retain the desirable properties of each paradigm in their combination.Perhaps the biggest limitation of our work is that the logic underlying the type system is not strong enough to express many useful properties of concurrent programs like deadlock freedom.This is clearly visible in the fact that full-CLL does not have a progress theorem as strong as that of its functional core f CLL.Our types represent only basic structural properties of concurrent processes.At the same time, due to the presence of dependent and linear types, the type system can be used to express very strong functional guarantees about various components of a concurrent program.Finding a logic that can express useful properties of both functional and concurrent computation and converting it to a programming language using the Curry-Howard isomorphism is a challenge at present.Another challenge is to build a realistic implementation of CLL, including a more complete functional language and type reconstruction to see if our ideas scale in practice.Since concurrency in CLL is somewhat low-level, it will be important to build up libraries of common idioms in order to write large programs conveniently.

Figure 8
shows the two synchronization rules.The rule −→ {} eliminates the monadic constructor {} from values {E} of asynchronous type {S}.The second rule −→=⇒ performs synchronization of several term values at the same time.It uses an auxiliary judgment Σ; σ Γ | | | ∆ =⇒ N : A, which we call the sync judgment.The rules of this judgment are also shown in figure 8.The sync judgment links values in Γ and ∆ to form a more complex program N .

Theorem 3 (
Preservation for l CLL).If C is a well-formed configuration and C ⇒ C , then C is also well-formed.Concurrent computation asproof search.Given a l CLL configuration C = Σ; σ Γ | | | ∆, types in ∆[σ]and Γ [σ] can be viewed as propositions that are simultaneously true, in a linear and unrestricted sense respectively.Using the Curry-Howard isomorphism, the corresponding programs in ∆[σ] and Γ [σ] can be seen as specific proofs of these propositions.The sync judgment (figure8) is actually a linear entailment judgment -if Σ; σ Γ | | | ∆ =⇒ N : A, then from the unrestricted assumptions in Γ [σ] and linear assumptions in ∆[σ], A[σ] can be proved in linear logic.The term N synthesized by this judgment is a proof of the proposition A[σ].As a result, each use of the synchronization rule −→=⇒ can be viewed as a step of proof search in linear logic that uses several known facts to conclude a new fact, together with its proof term.By the Curry-Howard isomorphism, the proof term is a well-typed program that can be functionally reduced again.

Fig. 11 .
Fig. 11.Translation of the π-calculus sage m that corresponds to the translation of xy.It then discards the message m and starts the process P .Translations of !A, P 1 |P 2 and 0 are straightforward.We translate νx.P to the type ∃x : chan.P .To translate νx.P to a program, we assume that there is an index constant c chan of sort chan.Then we translate νx.P to [c chan , ( P [c chan /x])], which has the type ∃x : chan.P .For any π-calculus process P , fn(P ) : chan; •; • P P .The translation of a π-calculus process P to l CLL is defined as the configuration P = fn(P ) : chan; • • | | | P P .Although we have not formally proved it, we believe that the following correctness result holds for this translation: P → * P iff there is a l CLL configuration C such that P ⇒ * C and P * C.

Theorem 4 (
Progress for full-CLL).1.If Σ; •; • N : A then either N = V or N N for some N .2. If Σ; •; • M S then either M = M V or M → M for some M .3. If Σ; •; • E ÷ S then either E = E V or Σ; E → Σ; E for some E or reduction of Σ; E deadlocks due to link failure.

Fig. 13 .
fibc = λn : int.if (n = 0 or n = 1) then {!1} else { link ( {let {!n1} = fibc (n − 1) in (message [k1] [k] n1)} ⊗ {let {!n2} = fibc (n − 2) in (message [k2] [k] n2)} ⊗ λm1 : mess k1 k. λm2 : mess k2 k. { let {!x} = fetchmessage [k1] [k] ˆm1 in let {!y} = fetchmessage [k2] [k] ˆm2 in !(x + y) } ) ÷ {mess k1 k} ⊗ {mess k2 k} ⊗ (mess k1 k mess k2 k {!int}) to !int } The function fibc in full-CLL P iff there is a l CLL configuration C such that P ⇒ * C and P Full-CLL is an extension of f CLL that allows l CLL's concurrent computations inside functional ones.This is done by extending f CLL expressions by a single constructlink E ÷ S to G. G ∈ {A, !A, 1} is called a goal type.Additional syntax and semantics for this construct are shown in figure12.Other than the link construct, full-CLL inherits all of f CLL's syntax, typing rules and semantics.linkE÷S to G is evaluated in a context of index variables Σ as follows.First, the l CLL configurationC = Σ; • • | | | E ÷ S iscreated and allowed to rewrite according to the relation ⇒ till it reaches a quiescent configuration C .By quiescent we mean that no rewrite rule applies to C i.e.C is in ⇒-normal form.After C is obtained, the result of evaluating link E ÷ S to G depends on the goal type G.