A Concurrent Lambda Calculus with Futures Joachim Niehren
Jan Schwinghammer
Gert Smolka
Programming Systems Lab Universitat ¨ des Saarlandes Saarbrucken, ¨ Germany
School of Cognitive and Computing Sciences University of Sussex Brighton, UK
Programming Systems Lab Universitat ¨ des Saarlandes Saarbrucken, ¨ Germany
ABSTRACT We introdu e a new on urrent lambda al ulus with futures, (fut), to model the operational semanti s of on urrent extensions of ML. (fut) an safely express a variety of high-level on urren y onstru ts, in luding hannels, semaphores, or ports. Safe implementations of these
onstru ts in (fut) annot be orrupted in any well-typed
ontext. We prove safety on basis of a linear type system. Categories and Subject Descriptors D.3.1 [Programming languages℄: formal de nitions and theory|operational semanti s, types ; D.3.3 [Programming languages℄: language onstru ts and features| on urren y. General Terms Programming languages, operational semanti s, typing. Keywords Fun tional programming, on urren y, lambda al ulus, futures, linear types.
Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. Copyright 2002 ACM X-XXXXX-XX-X/XX/XX ...$5.00.
1. INTRODUCTION We introdu e a new on urrent lambda al ulus with futures, (fut), to model the operational semanti s of on urrent extensions of ML [14℄. Most on urrent extensions of Standard ML so far are based on hannels [18, 17℄. Only re ently, a new on urrent extension of ML was proposed [1℄ where all syn hronisation is based on futures. A future is a transparent pla eholder for a value; it disappears on e its value be omes available [4, 7℄. Operations may blo k until the value of a future be omes known. This form of data driven syn hronisation is invoked automati ally and as late as possible, so that the potential for on urrent
omputation is maximised. Several lambda al uli with futures were studied previously [6, 15℄, mainly in order to model parallel exe ution of purely fun tional programs. These al uli are all untyped. They add an operator to the lambda al ulus modeling the future operator of MultiLisp [7℄. This operator introdu es futures whose values will be omputed in independent on urrent threads. Con urrent fun tional omputation with indeterministi
ommuni ation annot be modeled by these lambda al uli with future, as they are restri ted to preserve on uen e [6℄. In order to solve this problem, we propose a new operator for (fut) that an reate handled futures. These model the I-stru tures of Id [3℄ and are losely related to the promises of [11℄. A handled future omes with a handle that an eventully assign a value to the future. Handled futures provide single assignment. Any attempt to use the same handle a se ond time raises a programming error. Handle errors are problemati in a strongly typed environment. They should be ex luded by the type system, but it is not entirely lear how to do so in an ML-like programming language with stati typing and type inferen e. In the presen e of ells, handled futures enable (fut) to express diverse on urren y onstru ts su h as hannels, ports, or semaphores. They an be implemented safely, so that well-typed (fut) programs that use these onstru ts
an never raise any handle errors. We prove this form of safety for several on urren y onstru ts on basis of a linear type system [20, 19, 9℄. The al ulus (fut) thus yields a solid basis for type safe
on urrent programming languages with futures. A prototypi al example for ML-like programming languages of this
lass is Ali e [1℄. Sin e various on urren y abstra tions
an be expressed and proved safe by the linear type system presented in this paper, it is onsequently not ne essary to ex lude handle errors through the type system of the pro-
gramming language. In order to omplement our results, we extend (fut) by lazy threads. We obtain a new and elegant model for mixed
all-by-value and all-by-need omputation [10, 2, 12℄ whi h naturally in ludes ( y li ) re ursive de nitions, unlike most previous approa hes. Finally, we investigate strong normalization and on uen e for fragments of (fut). Strong normalization holds for programs of (fut) without re ursive de nitions and relies on simple typing. Uniform on uen e [16℄ is valid for programs without ells and errors. This result formalizes the intuition that ells (in ombination with threads) provide the only sour e of indeterminism in (fut). Plan. We rst introdu e futures (Se t. 2) and then present the lambda al ulus with futures (fut) in Se t. 3. Handle
and other programming errors are dis ussed in Se t. 4. A linear type system for (fut) that ex ludes handle errors is given in Se t. 5. We then express diverse on urren y onstru ts in (fut) (Se . 6), and prove their safety (Se t. 7). Finally, we dis uss uniform on uen e (Se t. 8), strong normalization (Se t. 9), the extension by lazy futures (Se t. 10), and implementation issues (Se t. 11).
2. FUTURES Futures are variables that will eventually be identi ed with some value. The value of a on urrent future is omputed by a on urrent threads, while the value of a handled future will be assigned by handle appli ation. Threads and Configurations. We onsider a on urrent thread as a dire ted equation x(e between a future x and a lambda term e, whose value will eventually be assigned to x. Con gurations of on urrent omputation then ontain
sets of on urrent threads:
x1 (e1 | | xn (en
Con gurations are thus equation systems. We assume that the futures x1 ; : : : ; xn on the left hand sides of the equations of a on guration are pairwise distin t. Cyclic Dependencies. We allow for (mutually) re ursive
equations in ontrast to previously presented lambda al uli with futures [6, 15℄. We annot simply avoid y li dependen ies in on gurations sin e we assume referen e ells. This phenomenon is well known. Handled futures, nally, raise the same problem even in the absen e of ells (as we will see). Cy li dependen ies impose a number of te hni al onstraints on the design spa e of lambda al uli. The base ma hinery of previous lambda al uli with futures, for instan e, annot be extended in any straightforward manner. Concurrent Futures. Con urrent futures in (fut) are re-
ated by the thread operation:
thread : (A ! A) ! A Evaluating an appli ation thread x:A:e has the following ee ts:
a new on urrent future x of type A is reated,
a new thread x(e is spawned whi h evaluates the ex-
pression e of type A on urrently and eventually assigns its value to x,
the on urrent future x is returned instantaneously in
the original thread. As an example onsider an appli ation f e of some fun tion f , where the evaluation of the argument e takes onsiderable time, e.g., a ommuni ation with a remote pro ess or an expensive internal omputation. In this ase it may be advantageous to use instead f (thread x:e) whi h applies f to a fresh future x and delegates the evaluation of e to a on urrent thread x(e. The point here is that f will only blo k on x if it really needs the value of its argument, so that the latest possible syn hronisation is obtained automati ally. The only way we an simulate this ee t with hannels is by rewriting the fun tion f (even the argument type of f hanges). So what futures buy us is maximal on urren y without the need to rewrite existing
ode. Recursive Definitions. The reader will have noti ed that thread : (A ! A) ! A has the type of a x point op-
erator. In fa t it provides for re ursive de nitions by introdu ing the equation x(e, with x possibly o
urring free in e. Our interpretation of this somewhat surprising fa t is that the minimal infrastru ture for futures subsumes what is needed for re ursion. We an express the MultiLisp expression future(e) as thread x:e where x is a fresh variable, but
learly our thread operator is more general by not imposing x 62 fv(e). Handled Futures. Handled futures appeared before as the
promises of [11℄ and the I-stru tures of [3℄. They are in-
trodu ed together with a handle by an operator handle of type handle : (A ! (A ! unit) ! B ) ! B An appli ation handle x:y:e reates an asso iation x is handled by y introdu ing a new future x of type A and a new handle y : A ! unit taking s ope over some ontinuation e of type B whose value is returned. Handles an be used on e only; handle appli ation binds the asso iated future to the value of the appli ation argument. Multiple appli ations of handles raise handle errors.
3. LAMBDA CALCULUS WITH FUTURES We now present a lambda al ulus with futures (fut). We start from the simply typed lambda al ulus and add
onstants for future reation and referen e ells. 3.1 Syntax The syntax of our al ulus is build on the types, terms, and on gurations presented in Fig. 1. Types and Expressions. Types are fun tion types A ! B , the type A ref of referen e ells ontaining elements of type A, and the single base type unit.
Types
A; B 2 Type
::=
unit
j
A!B
j
` : TypeOf( )
A ref
Terms
; x:A ` x : A
x; y; z 2 Var
2 Const
v 2 Val
::= x
e 2 Exp
::= v
Con gurations p 2 Perm
C
2 Con g
; x:A ` e : B ` x:e : A ! B ` e1 : A ! B ` e 2 : A ` e1 e2 : B
::= unit : unit j thread : (A ! A) ! A j handle : (A ! (A ! unit) ! B) ! B j ref ell : A ! (A ref ) j ex h : A ref ! A ! A
j j
x:e
j j ex h v
e 1 e2
j1 ::= x(e j xRv j xHp y j C1 | C2 j (x)C ::= 0
Figure 1: Syntax of (fut) Expressions are built from a ountably in nite set of variables ranged over by x; y; z . Our al ulus provides ve onstants that are ranged over by . The only element of type unit is written unit. Constants thread and handle serve for introdu ing on urrent and handled futures respe tively. The onstants ref ell and ex h provide referen e ells and an atomi ex hange operation, respe tively. The expressions e of our al ulus are traditional lambdaterms over variables and onstants. The sets of free and bound variables of an expression are de ned as usual, and we identify expressions up to onsistent renaming of bound variables. We write e[ e0=x℄ for ( apture-free) substitution of e0 for x in e. Typing. We restri t our al ulus to be simply typed. The
onstant thread has type (A ! A) ! A for any type A Its argument must be a fun tion that maps a future of type A to a value of type A. The operation thread then returns the future of type A. The onstant handle has type (A ! (A ! unit) ! B ) ! B . Arguments to handle are fun tions that map a future of type A and a handle of type A ! unit to a value of some other type B , whi h the appli ation of handle returns. A handle of type A ! unit an bind the future that it handles to a value of type A. The onstant ref ell takes a value of type A and returns the lo ation of a new storage ell of type A ref ontaining this value. ex h takes su h a ell and a value of type A
as argument and performs an (atomi ) ex hange operation, pla ing the argument value in the ell and returning the previously stored value. Let and range over type environments x1 :A1 : : : xn :An , i.e. nite fun tional relations between Var and Type. In writing 1 ; 2 we assume that the respe tive domains are disjoint. Writing TypeOf( ) for the type of onstant given in Figure 1, we have the usual type inferen e rules for simply typed lambda al ulus (Fig. 2). Configurations. Threads, ells and asso iations xH1 y be-
tween handled futures and their respe tive handles form
Figure 2: Typing rules
omponents. We write x(e for the thread e with on urrent future x and xRv for the ell at lo ation x ontaining v. A
on guration is a olle tion of omponents, where C1 | C2 is parallel omposition. The omponent x(e introdu es the future x to a on guration. xRv introdu e the lo ation x and xHp y introdu es future x and handle y to the on guration. We use the permission p to re ord whether the handle has already been used to bind its asso iated future. (x)C restri ts the s ope of x to C .
For instan e, in the on guration ((y)(xRv | y(e1 )) | z (e2 the left omponent xRv introdu es a referen e ell x that
an be used in all omponents of the on guration (i.e., v, e1 and e2 ). The middle omponent introdu es the on urrent future y that an be used in the expressions v and e1 . However, y annot be used in the right omponent (i.e., e2 ), sin e its s ope is restri ted. In ontrast, the right omponent introdu es another on urrent future z that an be used everywhere in the on guration. Every future in a on guration is either on urrent or handled, i.e., its status is unique. Moreover, the binding of a
on urrent future must be unique, and a handle must give referen e to a unique future, so the following two on gurations are ill-typed: x(e1 | x(e2
or x1 H1 y | x2 H1 y
Therefore, the type system requires that the variables introdu ed by C1 and C2 are disjoint in on urrent ompositions C1 | C2 . Formally, we de ne the sets of exported and free variables of a on guration indu tively as follows. Exported Variables var(x(e) = var(xRv ) = fxg p var(xH y ) = fx; y g var(C1 | C2 ) = var(C1 ) ℄ var(C2 ) var((x)C ) = var(C ) fxg
Free Variables fv(x(e) = fv(xRe) = fv(e) fxg p fv(xH y ) == ; fv(C1 | C2 ) = (fv(C1 ) var(C2 )) [ (fv(C2 ) var(C1 )) fv((x)C ) = fv(C ) We do not distinguish on gurations that dier only in the names of lo al variables, so (x)C and (y)(C [ y=x℄) denote
C1 | (C2 | C3 ) C1 | C2 C2 | C1 (x)(y)C (y)(x)C ((x)C0 ) | C1 (x)(C0 | C1 ) if x not free in C1 (C1 | C2 ) | C3
Figure 3: Stru tural ongruen e
;
; x:A ` e : A ` x(e : (x:A) ; x:A ref ` v : A ` xRv : (x:A ref ) x; y 2= dom( ) ` xHp y : (x:A; y:A ! unit) `C: 0 ` (x)C : 0 x ; 2 ` C2 : 1 1 ` C1 : 2 ` C 1 | C2 : 1 ; 2
Figure 4: Typing rules for (fut) on gurations the same on guration, provided y does not o
ur in C . Also we do not want the order in whi h omponents appear in a on guration to matter. Following the presentation of - al ulus in [13℄ we use a stru tural ongruen e relation to simplify the statement of the operational semanti s. Let stru tural ongruen e be the least ongruen e relation losed under the rules in Figure 3. The rst two rules render parallel omposition asso iative and ommutative. The third rule expresses that the order of restri ting names does not matter. The nal rule is known as s ope extrusion in - al ulus and allows to extend the s ope of a lo al variable. Sin e we an always rename bound variables, these rules let us move all s ope restri tions to the top level. Hen e, any on guration C is stru turally ongruent to a
on guration in normal form, C
(x1 ) : : : (xk )(C1 | | Cn )
where ea h Ci is a simple omponent, i.e. of the form x(e, xRv or xHp y. Configuration Types. Types are lifted to on gurations a
ording to the inferen e rules in Fig. 4. A judgment
`C:
0
means that given type assumptions the on guration C is well-typed. The type environment 0 keeps tra k of the variables introdu ed by C . In fa t, the rules guarantee that 0 0 fv(C ) dom( ), var(C ) = dom( ) and dom( ) \ dom( ) = ;. To type a thread x(e we an use the environment as well as the binding x:A that is introdu ed by the omponent. Similarly, when typing a referen e ell xRv both and the assumption x:A ref an be used to derive that the ontents v of the ell has type A. The typing rule for a handle omponent xH1 y takes are that the types of the handled future x and its handle y are ompatible.
A restri tion (x)C is well-typed under assumptions if the on guration C is. The name x is kept lo al by removing any x:A from 0 , whi h we write 0 x. The typing rule for parallel omposition C1 | C2 ensures that the on guration is well-formed sin e it only applies if the variables 1 and 2 , introdu ed by C2 and C1 respe tively, are disjoint. Moreover, by typing C1 in the extended environment ( ; 1 ) the rule allows variables introdu ed by C2 to be used in C1 , and vi e versa. We have Lemma
3.1. If
` C1 :
0
and C1 C2 then
` C2 :
0
.
3.2 Operational Semantics The axioms and inferen e rules for the operational semanti s are given in Fig. 5 and Fig. 6, respe tively. Call-By-Value. Con urrent threads are always redu ed allby-value. This means that all arguments of a fun tion are evaluated before the fun tion is applied. This is expressed through the hoi e of evaluation ontexts E and the usual
all-by-value beta redu tion rule (beta) in Fig. 5. Evaluation ontexts: E ::= [ ℄ j E e j v E An evaluation ontext E is a term ontaining a single hole [ ℄. We write E [e℄ for the term obtained from E by repla ing the hole with an expression e. The rule (beta) is side ee t free in that it only involves a single omponent. Concurrent Futures. Con urrent futures are reated when redu ing an expression thread v. The rule (thread.new)
reates a new on urrent thread y(v y that eventually binds its value to y. By restri ting the s ope of y it is ensured that y is fresh even in a surrounding larger on guration. Appli ation is pla eholder stri t in its left argument, i.e. the evaluation of an expression E [y v℄ needs to evaluate the
on urrent future y and repla e it by an a tual fun tion. This is done by applying the rule (future.deref) that looks up the value v of y in the urrent on guration. The rule syn hronizes on urrent threads on that the expression e in y(e gets evaluated. The a ting thread must suspend until the value of x be omes available. In the same way, ex h is pla eholder stri t in its rst argument, and so we use stri t evaluation ontexts S in the rule (future.deref) to express this uniformly. Stri t ontexts: S ::= E [[ ℄ v℄ j E [ex h [ ℄ v℄ As dis ussed in [6℄, an implementation must perform a tou h operation whenever a pla eholder stri t position is en ountered in order to test if a future must be dereferen ed (see Se . 11). Handled Futures. A handled future is introdu ed jointly with a handle. Rule (handle.new) does this by evaluating an expression handle v whi h generates a new asso iation
omponent yH1 z for a fresh future y and handle z , and returns v y z . The permission 1 in the omponent indi ates that the handle an be used on e. A handle z an be applied to some value v, whi h has the ee t of binding the future y with yH1 z to the value v. This
onsumes the handle y, i.e., the handle an be used only on e to bind a future. In the rule (handle.bind) this is modelled by removing the permission 1 from the handle omponent yH1 z and repla ing it by 0, indi ating that the handle annot
x(E [(y:e) v℄
(beta)
!
x(E [thread v℄
(thread.new)
x(S [y℄ | y(v
(future.deref) (handle.new)
x(E [handle v℄
(handle.bind)
x(E [z v℄ | yH1 z
( ell.new)
x(E [ref ell v℄
( ell.ex h)
x(E [ex h y v1 ℄ | yRv2
x(E [e[ v=y℄℄
! (y) (x(E [y℄ | y(v y) ! x(S [v℄ | y(v
(y 2= fv(E [v℄))
! (y) (z) (x(E [v y z℄ | yH1 z) ! x(E [unit℄ | y(v | yH0 z
(y; z 2= fv(E [v℄))
! (y) (x(E [y℄ | yRv) ! x(E [v2℄ | yRv1
(y 2= fv(E [v℄))
Figure 5: Axioms for redu tion C1 ! C2
C1 ! C2 C1 | C ! C2 | C C1 ! C 2 C1 ! C2
rently:
(x)C1 ! (x)C2
x1 ((thread(x2 :(y:y) (z:z ))) ((z:z ) unit) ! (x2 )(x1(x2 ((z:z) unit) | x2 ((x2 :(y:y) (z:z)) x2 )
Figure 6: Contextual rules be used again. Note, however, that the simple type system does not prevent us from writing ode that ontains multiple o
urren es of this binding operation whi h therefore may introdu e ra e onditions and indeterminism. Cells. A new ell is reated by ref ell v, introdu ing a new
ell omponent with ontents v. For simpli ity, we do not distinguish between variable names and heap lo ations. The ex hange operation ex h y v writes v to the ell and returns the previous ontents. This ex hange is atomi , i.e. no other thread an interfere. Observe that this rule introdu es indeterminism to the al ulus sin e two threads might want to a
ess the ell and the nal result depends on the s heduling. As we will show below, if programs are error free in the sense that no attempt is made to bind a future twi e, then the relation ! restri ted to omponents without ex h is
on uent, and so the rule ( ell.ex h) is the sole sour e of indeterminism. Reduction. Fig. 6 des ribes the inferen e rules for the redu tion relation ! between on gurations: We an redu e below restri tion and parallel omposition, and we an use stru turally ongruent on gurations to derive redu tions. Let ! denotes the transitive and re exive losure of !. We an show that redu tion respe ts typing. 0
Proposition 3.2
and C1 ! C2 then
(Subje t Redu tion). C : 0.
`
2
If
` C1 :
3.3 Simple Examples Concurrent Threads. For example, we an use a on urrent future to evaluate a fun tion and its argument on ur-
At this point, we have a hoi e of redu ing the left or right thread next. One possible redu tion sequen e would be (x2 )(x1 (x2 ((z:z ) unit) | x2 ((x2 :(y:y) (z:z )) x2 ) ! (x2 )(x1(x2 ((z:z) unit) | x2 ((y:y) (z:z)) ! (x2 )(x1(x2 unit | x2 ((y:y) (z:z)) ! (x2 )(x1(x2 unit | x2 (z:z) ! (x2 )(x1((z:z) unit | x2 (z:z) All of these redu tions are justi ed by (beta) and the ontextual rules, ex ept for the last redu tion that is li ensed by rule (future.deref). Now we an apply (beta) again, and using stru tural ongruen e we obtain the on guration x1 (unit | (x2 )(x2 (z:z ) In fa t, any other redu tion sequen e would have given the same result in this ase. Explicit Recursion. As indi ated in Se tion 2, the onstant thread an be used as a xed point operator. In parti ular, it is possible to simulate the all-by-value xed point operator with unfolding (unfold) x f:x:e ! x:e[ x f:x:e=f ℄ by (thread f:x:e). The evaluation of this expression introdu es a on urrent thread f (x:e. Sin e this thread
annot do any omputation the program remains sequential. When applying f , any o
urren e of f met in e leads to a redu tion by (future.deref), repla ing the o
urren e by x:e. In fa t, (unfold) orresponds exa tly to a redu tion by (future.deref) in this ase.
4. PROGRAM ERRORS Program errors are a notorious problem even for a stati ally typed programming language. In (fut) we distinguish two kinds of errors apart from type errors that we have already ex luded. We will not dis uss how to handle errors in a on rete programming language but only spe ify error situations in our al ulus.
Irreducible Expressions. In our al ulus, errors lead to
irredu ible on urrent threads in on gurations (that may still be redu ible). We all a thread in a on guration C irredu ible if C annot be redu ed by applying a redu tion rule using this thread. Lemma
x(S [y℄.
4.1. Irredu ible threads have the form x(v or
Deadlock. Con gurations an deadlo k. This may be wanted
but ould also arise as a onsequen e of some programming error. The on guration: C x(y (z:z ) | y((u:v:v) (x unit) for instan e is irredu ible, even though well-typed: ` C : (x:unit ! unit; y:(unit ! unit) ! (unit ! unit)) Ea h thread is syn hronizing on that the other redu es to a value. In this paper, we do not deal with deadlo ks.
Handle Errors. A handled future an be bound to a value using its handle. Clearly, on e this has happened the handle
annot be used a se ond time. In our al ulus this is modeled in the rule (handle.bind) by rewriting a handle omponent yH1 z with permission into a omponent without permission yH0 z . Con guration C of the following form ontains handle errors : C (x1 ) : : : (xn )(C 0 | x(S [z v℄ | yH0 z ) Handle errors are serious sin e they may raise unwanted indeterminism. For example, the on guration x1 (y v1 | x2 (y v2 | xH1 y
may redu e to either of the following two on gurations, both of whi h ontain a handle error. x(v1 | x1 (unit | x2 (y v2 | xH0 y x(v2 | x1 (y v1 | x2 (unit | xH0 y Error freeness. We all a on guration C error-free if it
annot be redu ed to an erroneous on guration, i.e., if none of its redu ts C 0 with C ! C 0 ontains an error.
5. LINEAR TYPES FOR HANDLES We now re ne the type system to prevent handle errors. We do not argue that the linear types should be used in pra ti e. Rather, we see the system as a proof tool to fa ilitate reasoning about the absen e of handle errors. We demonstrate the expressiveness of the system in Se t. 6, by showing that for a variety of on urren y abstra tions we
an derive the expe ted (non-linear) types. This means the linear types of the handles are en apsulated, and a user of these abstra tions need not know about the linear types at all. Linear Types. We annotate types with usage information in the sense of [20℄. In our ase it is suÆ ient to distinguish between linear (i.e., exa tly one) and nonlinear (i.e., any number of times) uses: Uses ::= 1 j !
!j j ` : TypeOf( ) !j j ; x:A ` x : A ; x:A ` e : B j j ` x:e : A ! B 2 ` e2 : A 1 ` e1 : A ! B 1 2 ` e1 e2 : B
Figure 7: Linear typing rules with ordering 1 !. For our purposes we annotate only fun tion types, other types an always be used non-linearly.
Types A; B 2 Type ::=
unit
j
A
! B j
A ref
In parti ular, A ! B denotes fun tions from A to B that
an be used times. Correspondingly, we write jAj for the use atta hed to a type A, de ned by junitj = ! jA ! B j = jA ref j = !
The ordering on uses is extended to ontexts, writing j j i jAj for all x:A 2 Note that 1 j j holds va uously, whereas ! j j implies that all types in are non-linear. The types of the term
onstants are now re ned to re e t that handles must be used linearly. Constants unit : unit thread : (A ! A) ! A where jAj = ! 1 handle : (A ! (A ! unit) ! B ) ! B where jAj = ! ref ell : A ! (A ref ) ex h : A ref ! A ! A Restri ting the types of thread and handle by the ondition jAj = ! essentially says that futures an be used nonlinearly as before. On the other hand, note that no su h restri tion is made for ells whi h may ontain values of linear or non-linear type. Intuitively this is sound be ause ells an be a
essed only with the ex hange operation. Sin e there is no dereferen ing the ontents of a ell annot be opied through ell a
ess. We write 1 2 for the type environment with 1 [ 2 = and 1 \ 2 = fx:A 2 j jAj = !g in ase this exists. In other words, an be split into two parts 1 , 2 that both
ontain all the nonlinear variables of and a partition of the linear ones. The type rules for expressions are given in Fig. 7. The rules guarantee that every variable with linear type in appears exa tly on e in the term: In the rules for onstants and variables, the side- ondition ! j j expresses that
ontains only variables with use !. In the rule for abstra tion, the ondition j j allows us to derive a non-linear ! type A ! B only if e does not ontain any linear variables free. However, it is always possible to derive a linear type. 0
0
0
00
; x:A ` e : A jAj = ! ` x(e : (x:A) ; x:A ref ` v : A ` xRv : (x:A ref ) x; y 2= dom( ) jAj = ! 1 ` xH1 y : (x:A; y:A ! unit) y 2= dom( ) ` xH0 y : ;
`C:
Corollary 5.9 (Absen e of Handle Errors). 0 then C is error-free.
C:
0
Figure 8: Linear typing rules for on gurations Finally, the rule for appli ation splits the linear variables of the type environment. The annotation is irrelevant here, but the type of fun tion and argument must mat h exa tly. The rules for on gurations (Fig. 8) are almost the same as before, with some subtle ex eptions: The rules for typing thread and handle omponents now ontain the side ondition jAj = ! re e ting the type restri tion of the orresponding onstants. Moreover, the type of y in xH1 y must have use 1, and in xH0 y it is not exported anymore, i.e., it annot be used at all. Finally, the rule for parallel omposition splits the linear assumptions as well as the linear variables exported by ea h of the two onstituent on gurations. In parti ular, a linear variable of C1 an either be used in C2 or exported, but not both. Subject Reduction. We an prove a subje t redu tion theo-
rem in the standard way. We start with a number of lemmas relating to substitution. Lemma 5.1. If ` v : A then jAj j j.
` e : A and jBj = ! then ; x:B ` e : A. Lemma 5.3. Suppose ` e : A. If x does not o
ur in then x is not free in e. If x:A 2 with jAj = 1 then there 5.2. If
is exa tly one o
urren e of x in e. 0
Lemma 5.4
(Substitution). 0 e[ v= ℄ : A.
Lemma 5.5
(Context).
` v : B then `
x
ist 1 ; 2 and B su h that and 2 ` e : B .
=
If 1
If
; x:B
`
e : A and
` E [e℄ : A then there ex2 and 1 ; x:B ` E [x℄ : A
Lemma 5.6. Suppose ` C : . If x does not o
ur in then x is not free in C , and if x:A 2 with jAj = 1 then there is exa tly one o
urren e of x in C . Lemma 5.7
then 0
` C2 :
0
.
(Congruen e).
Proposition 5.8
and C1 ! C2 then
If
` C1 :
0
(Subje t Redu tion). C : 0.
`
2
and C1 C2 If
`
6. CONCURRENCY CONSTRUCTS We now show how to express various on urren y onstru ts in (fut). This demonstrates the power of handled futures in (fut). We use some synta ti sugar, writing let x1 =e1 x2 =e2 xn =en in e for (x1 :(x2 : : : : (xn :e) en : : : ) e2 ) e1 and :e for x:e where x is not free in e. Also we write e1 ; e2 for ( :e2 ) e1
` (x)C : 0 x 0 0 1 ; 1 ` C1 : 2 2 2 ; 2 ` C2 : 1 1 0 0 1 2 ` C 1 | C2 : 1 ; 2
Lemma
If
` C1 :
It is now easy to prove error freeness of well-typed on gurations, by ombining the absen e of handle errors in the immediate on guration and Subje t Redu tion.
Mutual Exclusion. When on urrent threads a
ess shared data it is ne essary that they do not interfere in order to prevent any in onsisten ies. We an implement an operation mutex of type (unit ! A) ! A that applies its argument under mutual ex lusion. We use a stri t ontext to syn hronize several threads wishing to a
ess a riti al region.
ref ell (y:y) handle(xbindx : (ex h r x) (unit); (let v =a (unit) in bindx (y:y ); v )) Before running the fun tion a that is given as argument (the riti al region), a handled future (of type unit ! unit) is stored in the referen e ell r. This future is bound (to the identity fun tion) only after the argument is evaluated. Moreover, before this happens, the previous ontents of the
ell r annot be an unbound future anymore sin e fun tion appli ation is stri t in its arguments. Consequently, threads
annot interfere when evaluating a. let r = in a:
Ports. We assume that there are pairs and a list data type, and write v :: l for the list with rst element v, followed by the list l. A stream is a list v1 :: ::vn ::x where x is a (handled) future. The stream an be extended arbitrarily often by using the handle of the future, provided ea h new element is again of the form v::x0 , with x0 a handled future. We all the elements v1 ; : : : ; vn on a stream messages. A fun tion newPort that reates a new port an be implemented as follows. :handle(sbinds : let in
putr = ref ell binds put = x:handle(sbinds :(ex h putr binds ) (x :: s)) (s; put))
The port onsists of a stream s and an operation put to put new messages onto the stream. The stream is ended by a handled future, whi h in the beginning is s itself. Its handle bind s is stored in the ell putr and used in put to send the next message to the port. put introdu es a new handled future before writing the new value to the end of the stream. Again, the new handle is stored in the ell. Channels. By extending ports with a re eive operation of type unit ! A we obtain hannels, whi h provide for indeterministi many to many ommuni ation. A fun tion newChannel that generates hannels is :handle(initbind : let
putr getr
init
= =
ref ell bind ref ell init
init
put get in
= =
x:handle(nbindn :(ex h putr bindn ) (x :: n)) :handle(nbindn : ase(ex h getr n)) of x :: ) bindn ( ); x)
(put; get))
Given a stream, applying get yields the next message on the stream. If the stream ontains no further messages, get blo ks: We assume that the mat hing against the pattern x :: is stri t. Note how get uses a handled future in the same way as the mutual ex lusion above to make the implementation thread-safe. Safety. The de nition of all three abstra tions is safe, in the
sense that no handle errors are raised by using them. For instan e, we an always send to the port without running into an error. Intuitively, this holds sin e nobody an a
ess the (lo al) handle to the future at the end of the stream s, and the implementation itself uses ea h handle only on e. The type system in the next se tion makes this intuition formal.
7. PROVING SAFETY We an now show that the on urren y onstru ts presented in Se t. 6 are typable in the linear type system. By the results of Se t. 5 this guarantees the absen e of handle errors when using them. In fa t, they an be given non-linear types, showing that the use of handled futures is properly en apsulated and not observable from the types. We use the derived typing rules 1 ` e1 : B 2 ; x:B ` e2 : A ` let x = e1 in e2 : A 1 2 and 1
` e1 : B 1
2
` e2 : A jBj = !
2 ` e1 ; e 2 : A
for lo al de larations and sequential omposition below. Mutual Exclusion. The mutual ex lusion implementation
mutex
an be given the type
! ` mutex : (unit ! A) ! A
A derivation is shown in Fig. 9: Let! B abbreviate the type of the handled future, i.e. B = (unit ! unit), and let 1 denote the type environment r:B ref ; x:B . If junit ! Aj = ! then let 1 also ontain a:unit ! A. In the se ond part, let 2 denote r:B ref ; x:B; a:unit ! A, and let 3 be 2 extended with v:A in ase jAj = !. In fa t, in this derivation there is no onstraint on the use 0 : When the abstra tion in derivation (3) is introdu ed, the type environment only ontains r:B ref whi h has use jB ref j = !. In parti ular, 0 an be hosen as ! whi h allows mutex to be used any number of times. Ports and Channels. We only sket h how to extend the
linear type system to deal with pairs and lists. The details of su h an extension are quite standard (e.g., [20℄). Just as with fun tion types these new types are annotated with uses, so
Types A; B 2 Type ::= : : :
j A B j
A list
whi h must additionally satisfy the well-formedness onstraints min(jAj; jB j) and jAj respe tively. The following inferen e rules an be devised for the new onstru ts (subje t to well-formedness).
` e1 : A 2 ` e2 : B 2 ` (e1 ; e2 ) : A B 1 ` e1 : A B 2 ; x:A; y :B ` e2 : B 1 2 ` ase e1 of (x; y ) ) e2 : B 1 ` e1 : A 2 ` e2 : A list 1 2 ` e1 ::e2 : A list 1 ` e1 : A list 2 ; x:A; y :A list ` e2 : B 1 2 ` ase e1 of x::y ) e2 : B 1
1
If these onstu ts are given the usual operational semanti s, the subje t redu tion theorem an be extended, as an Corollary 5.9. It is possible to derive ! ! ` newPort : unit ! (A list A ! unit) with the onstraint jAj. In parti ular, both newPort it-
self and the put operation (the se ond omponent of the result pair) an be used unrestri tedly. The use of the stream (the rst omponent) depends on the type A: Only if jAj = 1 it must be used linearly. Similarly, ! ! ! ! ` newChannel : unit ! ((A ! unit) (unit ! A))
an be derived for the implementation of hannels.
8. UNIFORM CONFLUENCE Assuming programs are error free, in the sense that they will never redu e to an error, we an establish a very strong notion of on uen e alled uniform on uen e [16℄. Definition
whenever C1 that C1 ! C 0
! is uniformly on uent if, C ! C2 and C1 6 C2 , there exists C 0 su h C2 .
8.1. A relation
s? This is depi ted on the right. Uni ??? form on uen e implies on uen e. More ?? remarkably, if ! is uniformly on u s 6 1 s2 ent then all maximal ! sequen es be? ? ginning from C have the same length, ? whi h may be nite or in nite. s0 Con uen e of ! is omparatively easy to establish, basi ally be ause redu tion within ea h thread is deterministi . Moreover, redu tions aused by dierent threads do not interfere, assuming C is error free and no ex h is used. Proposition 8.2 (Uniform Confluen e). The redu tion relation ! of (fut) restri ted to error-free on gurations not ontaining ex h is uniformly on uent.
Uniform on uen e has been established for a number of
on urrent al uli [16, 9, 8, 5℄.
1
` ex h : B
ref
1
!
! B !! B
1
`r:B
ref
` ex h r : B ! B ! ! 1 ` ex h r x : 1 ` (ex h r x) unit : !
unit
`x:B
1
1
unit
1 !
unit
unit
unit
`a:
! A unit : 2 ` a unit : A
unit
(1)
unit
1 ` bindx : B ! 2 ` u:u : B 1 ; bind : B ! ` bind ( y:y ) : x x 2 1 ; v :A ` bindx (y:y ); v : A 2 ; bindx :B ! 1 1 ` v:bindx (y:y); v : A ! A 2 ; bindx :B !
2 ; bindx :B
2
` unit :
unit
unit
2 ; v :A
`v:A
unit
unit
unit
2 ; bindx :B
1 !
unit
`
let
v =a (unit) in bindx (y:y ); v : A
(2)
(2)
(1)
1 ` (ex h r x) unit : ` v a (unit) bindx (y:y); v : A 2 ; bindx :B ! 1 ` (ex h r x) unit v a (unit) bindx (y:y); v : A 1 2 ; bindx :B ! 1 1 ` bind : ( ex h r x ) unit v a (unit) bindx (y:y ); v : (B ! )! A x 1 2 1 1 1 r:B ; a: ! A ` x:bindx :(ex h r x) unit v a (unit) bindx (y:y); v : B ! (B ! ) ! A r:B ; a: ! A ` handle x:bindx :(ex h r x) unit v a (unit) bindx (y:y); v : A r:B ` a:handle x:bindx :(ex h r x) unit v a (unit) bindx (y:y ); v : ( ! A) ! A 1
unit
unit
unit
; let
; let
ref
unit ref
=
; let
let
=
=
in
in
in
=
unit
in
unit
unit
; let
=
in
0
ref
; let
=
in
y: `y: ! ` ref ell : B ! B ` y:y : B ` ref ell (y:y) : B unit
unit
ref
ref
(4) ` ref ell (y:y) : B ref
`
let
(3)
unit
(4)
(3)
0 r:B ref ` a:handle x:bindx :(ex h r x) unit; let v =a (unit) in bindx (y:y ); v : (unit ! A) ! A
0 r=ref ell (y:y ) in a:handle x:bindx :(ex h r x) unit; let v =a (unit) in bindx (y:y ); v : (unit ! A) ! A
Figure 9: Type derivation for the mutual ex lusion example
(5)
9. STRONG NORMALIZATION We now investigate strong normalization for (fut). We show that strong normalization holds for re ursion-free programs be ause of simple typing. Our proof relies on uniform
on uen e and a simulation of parallel programs in (fut) through sequential programs in the simply typed lambda
al ulus, whi h is well-known to be strongly normalizing. Definition
9.1. An expression e is re ursion-free if
no ells are used in e, no handled futures are used in e, any o
urren e of thread in e is in a subterm of the form thread x:e where x 2= fv(e).
Note that the model of futures presented in [6℄ gives pre isely re ursion-free programs without simple typing. Furthermore, a simulation of parallel programs by sequential ones is investigated there, but for dierent reasons. Evaluating re ursion-free expressions leads to a y li on gurations C , in the sense that the futures xi of on urrent threads in C
(y1) : : : (yk )(x1(e1 | | xn (en )
an be linearly ordered su h that the free variables of ei are
ontained in fxj j xj > xi g. Theorem 9.2 (Strong Normalization). Redu tion of re ursion-free expressions of (fut) is strongly normalizing.
The idea of the proof is to simulate redu tion by beta redu tion ! in the simply typed lambda al ulus. Essentially, an a y li on guration x1 (e1 | | xn (en
with order x1 < < xn on the variables an be en oded as lambda term let
x1 =e1 : : : xn =en
in
xn
Not every redu tion sequen e of the on guration C an be simulated on the en oding. However, by uniform on uen e all maximal redu tion sequen es have the same length. Therefore it is suÆ ient to simulate any one parti ular maximal sequen e. This an easily be done by onsidering the sequen e orresponding to all-by-value in a natural sense.
10. LAZY FUTURES Demand-driven evaluation delays the start of an evaluation until the result is needed. Halstead [7℄ observed that futures provide a natural means for in orporating demanddriven evaluation into a all-by-value language. Having a language that ombines eager and lazy omputation the notion of uniform on uen e allows to establish a omplexity omparison between the two strategies. Sin e (fut) is base on the lambda al ulus, all result from [16℄
ould be derived more easily than in the pi al ulus. To this end we onsider lazy futures, introdu ed by an operation lazy that introdu es lazy futures in an analogous way to on urrent futures. Terms 2 Const ::= : : : j lazy : (A ! A) ! A
We need a new omponent in on gurations that represents a suspended omputations: Con gurations C 2 Con g ::= : : : j xLe Lazy futures have the following redu tions. Creation of lazy futures is done as for on urrent futures, (lazy.new) x(E [lazy v℄ ! (y)(x(E [y℄ | yLv y) where y is not free in E or v. In ontrast to a thread y(e, a lazy omponent yLe does not allow for omputations of e. In order to obtain the value asso iated with the lazy future y, another thread must rst suspend on y, thereby triggering the lazy omputation. We model this by turning the lazy
omponent into a thread. (lazy.trigger) x(S [y℄ | yLe ! x(S [y℄ | y(e Note that the (lazy.trigger) rule annot be applied repeatedly to y sin e the rst su h a tion removes y from the set of lazy futures. Consider the following example whi h demonstrates that the evaluation of a fun tion arguments may be on demand. Sin e we have expli it re ursion in the al ulus, there exists some nonterminating expression . So rule (lazy.new) admits the (unique) redu tion x((y:unit) (lazy z: ) ! (z)(x((y:unit) z | zL(z: ) z) Now the se ond omponent does not allow for any immediate redu tions and there is just the redu tion by (beta) leading to the on guration x(unit | (z )(z L(z: ) z ) whi h annot be redu ed further. In parti ular, this demonstrates that the evaluation of the argument is on demand.
11. IMPLEMENTATION VIEW An implementation of futures has to deal with pla eholder obje ts and dereferen ing to obtain the value asso iated with a future. Further, it must perform the triggering of lazy futures. All these aspe ts are visible on the level of the ompiler only; futures are transparent from the programmer's point of view. Therefore, these tou h operations are introdu ed by the ompiler rather than the programmer. With an expli it tou h operator ?:A!A the expression ?x waits for the value of the future x (both have type A), for es its evaluation if ne essary, and returns the value on e available. To improve eÆ ien y, a ompiler should be able to remove as many redundant tou hes as possible. That this an be done by stri tness analysis was an important a hievement of previous work on futures by Felleisen and Flanagan [6℄. In this paper, we do not deal with tou hes and their optimization. We expe t that the analysis of [6℄ an be extended to our al ulus, but leave this for future work. 12. CONCLUSION We have presented the lambda al ulus with futures (fut) whi h serves as a semanti s for on urrent extensions of ML where all syn hronization is based on futures. We assumed
all-by-value evaluation, stati typing, and state. We shown how to express various on urren y abstra tions in (fut) by using handled futures. We have proved the safety of these implementations on basis of a linear type system. Hen e, handle errors annot arise when using handles only through safe libraries. As a onsequen e, handled futures an be safely in orporated into a strongly typed ML-style programming language without imposing serious hanges in the type system. An ML extension alled Ali e [1℄ along these lines is available. We have proved on basis on uniform on uen e that ells are the only onstru t of (fut) that an import indeterminsm, when used in on urrent threads. We have shown that programs of (fut) without re ursive de nitions are strongly normalizing due to simple typing. These proofs were based on the notion of uniform on uen e. We have also shown that (fut) an naturally model mixed eager and lazy omputation. In future work, we intend to devellop a stri tness analysis for improving the eÆ ien y of implementations of (fut).
13. REFERENCES [1℄ The Ali e Proje t. Web site at the Programming Systems Lab, Universitat des Saarlandes, http://www.ps.uni-sb.de/ali e, 2002. [2℄ Z. M. Ariola and M. Felleisen. The all-by-need lambda al ulus. Journal of Fun tional Programming, 7(3):265{301, May 1997. [3℄ Arvind, R. S. Nikhil, and K. K. Pingali. I-stru tures: Data stru tures for parallel omputing. ACM Transa tions on Programming Languages and Systems, 11(4):598{632, O t. 1989.
[4℄ H. Baker and C. Hewitt. The in remental garbage
olle tion of pro esses. ACM Sigplan Noti es, 12:55{59, Aug. 1977. [5℄ G. Boudol. The - al ulus in dire t style. In 24th
ACM SIGPLAN-SIGACT Symposium on Prin iples of Programming Languages, pages 228{241, Jan. 1997.
[6℄ C. Flanagan and M. Felleisen. The semanti s of future and an appli ation. Journal of Fun tional Programming, 9(1):1{31, Jan. 1999. [7℄ R. H. Halstead, Jr. Multilisp: A Language for Con urrent Symboli Computation. ACM Transa tions on Programming Languages and Systems, 7(4):501{538, O t. 1985.
[8℄ A. Jerey and J. Rathke. A fully abstra t may testing semanti s for on urrent obje ts. In Pro . Li s 2002, 17th Annual Symposium on Logi in Computer S ien e, pages 101{112, 2002.
[9℄ N. Kobayashi, B. C. Pier e, and D. N. Turner. Linearity and the Pi-Cal ulus. ACM Transa tions on Programming Languages and Systems, 21(5):914{947, Sept. 1999. [10℄ J. Laun hbury. A natural semanti s for lazy evaluation. In SIGPLAN-SIGACT Symposium on Prin iples of Programming Languages, pages 144{154. The ACM Press, 1993. [11℄ B. Liskov and L. Shrira. Promises: Linguisti support for eÆ ient asyn hronous pro edure alls in distributed systems. Pro eedings of the SIGPLAN '88 Conferen e on Programming Language Design and Implementation, 23(7):260{268, June 1988.
[12℄ J. Maraist, M. Odersky, and P. Wadler. The
all-by-need lambda al ulus. Journal of Fun tional Programming, 8(3):275{317, May 1998. [13℄ R. Milner. The polyadi - al ulus: A tutorial. In F. L. Bauer, W. Brauer, and H. S hwi htenberg, editors, Logi and Algebra of Spe i ation, Pro eedings of International NATO Summer S hool (Marktoberdorf, Germany, 1991), volume 94. Springer,
1993. [14℄ R. Milner, M. Tofte, R. Harper, and D. B. Ma Queen. The Standard ML Programming Language (Revised). MIT Press, 1997. [15℄ L. Moreau. The semanti s of s heme with future. In International Conferen e on Fun tional Programming, pages 146{156, 1996. [16℄ J. Niehren. Uniform on uen e in on urrent
omputation. Journal of Fun tional Programming, 10(5):453{499, Sept. 2000. [17℄ F. Nielson, editor. ML with Con urren y: Design, Analysis, Implementation, and Appli ation. Monographs in Computer S ien e. Springer-Verlag, 1997. [18℄ J. H. Reppy. Con urrent Programming in ML. Cambridge University Press, 1999. [19℄ D. N. Turner and P. Wadler. Operational interpretations of linear logi . Theoreti al Computer S ien e, 227:231{248, 1999. Spe ial issue on linear logi . [20℄ D. N. Turner, P. Wadler, and C. Mossin. On e upon a type. In 7th International Conferen e on Fun tional Programming and Computer Ar hite ture, pages 1{11, La Jolla, California, June 1995. ACM Press.