Type Inference and Optimisation for an Impure World.


 Gyles Moody
 1 years ago
 Views:
Transcription
1 Typ Infrnc and Optimisation for an Impur World. Bn Lippmir DRAFT Jun, 2009 A thsis submittd for th dgr of Doctor of Philosophy of th Australian National Univrsity
2 2
3 Dclaration Th work in this thsis is my own xcpt whr othrwis statd. Bn Lippmir
4 4
5 Thanks Thanks to my family and frinds for putting up with m and my occasional disapparancs. Sincr thanks to my suprvisor Clm BakrFinch, to Simon Marlow for an intrnship at GHC HQ, and to Brni Pop for rading draft vrsions of this thsis. Shouts out to th fpsyd crw, for plasant monthly divrsions whn I probably should hav bn writing up instad. Thanks to th Gnral, th Particular and FRATER PERDURABO, who taught m that grat truths ar also grat lis. Thanks to th popl who rciv no thanks. All Hail Discordia. May our larning curvs always b a mil high. 5
6 6
7 Abstract W addrss th problm of rasoning about th bhaviour of functional programs that us dstructiv updat and othr sid ffcting actions. All gnral purpos languags must support such actions, but adding thm in an undisciplind mannr dstroys th nic algbraic proprtis that compilr writrs dpnd on to transform cod. W prsnt a typ basd mutability, ffct and data sharing analysis for rasoning about such programs. Our analysis is basd on a combination of Talpin and Jouvlot s typ and ffct disciplin, and Lroy s closur typing systm. Th xtra information is addd to our SystmF styl cor languag and w us it to guid cod transformation optimisations similar to thos implmntd in GHC. W us a typ classing mchanism to xprss constraints on rgions, ffcts and closurs and show how ths constraints can b rprsntd in th sam way as th typ quality constraints of SystmFc. W us typ dirctd projctions to xprss rcords and to liminat nd for ML styl mutabl rfrncs. Our typ infrnc algorithm xtracts typ constraints from th dsugard sourc program, thn solvs thm by building a typ graph. This multistagd approach is similar to that usd by th Hlium Haskll compilr, and th typ graph hlps to manag th ffct and closur constraints of rcursiv functions. Our languag uss callbyvalu valuation by dfault, but allows th samlss intgration of callbynd. W us our analysis to dtct whn th combination of sid ffcts and callbynd valuation would yild a rsult diffrnt from th callbyvalu cas. W contrast our approach with svral othr systms, and argu that it is mor important for a compilr to b abl to rason about th bhaviour of a program, than for th languag to b purly functional in a formal sns. As opposd to using sourc lvl stat monads, ffct typing allows th programmr to offload th task of maintaining th intndd squnc of ffcts onto th compilr. This hlps to sparat th concptually orthogonal notions of valu and ffct, and rducs th nd to rfactor xisting cod whn dvloping programs. W discuss th Disciplind Discipl Compilr (DDC), which implmnts our systm, along with xampl programs and opportunitis for futur work. 7
8 8
9 Layout Th layout and formatting of this thsis was influncd by th work of Edward R. Tuft, spcially his book Visual Explanations. To rduc th nd for th radr to flip pags back and forth whn progrssing through th matrial, I hav avoidd using floating figurs, and hav trid to kp rlatd diagrams and discussion on th sam two pag sprad. For this rason som diagrams hav bn rpatd, and som sctions contain xtra whit spac. 9
10 10
11 Contnts Thanks 5 Abstract 7 Layout 9 1 Introduction Prlud Th Problm Why dstructiv updat mattrs Efficint data structurs rquir dstructiv updat Dstructiv updat hlps to broadcast nw valus What is purity? Linar and uniqunss typing Stat monads Rf typs invit larg rfactorisation xrciss Practical limitations of lazy valuation A way forward Typ Systm Updat without imprativ variabls Rgion Typing Rgions and aliasing Rgion classs Functions, allocation and nonmatrial rgions Updating data rquirs it to b mutabl Primary rgions and algbraic data Thinking about rgions Effct typing
12 12 CONTENTS Effcts and intrfrnc Effct information in typs Effcts and currying Top lvl ffcts Effcts in highr ordr functions Constraint strngthning and highr ordr functions Obsrvabl ffcts and masking Rcursiv ffcts Constant rgions and ffct purification Purification in highr ordr functions Strict, spin lazy and lmnt lazy lists Lazy and Dirct rgions Liftdnss is not a capability Th problm with polymorphic updat Fighting th valu rstriction Gnralisation rducs data sharing in SystmF Typ rasur incrass data sharing (again) Don t gnralis variabls fr in th stor typing Rstricting gnralisation with ffct typing Obsrvation critria Effct typing vrsus arbitrary updat Closur typing Dangrous typ variabls Closur typing and hiddn communication Matrial rgions and sharing Matrial rgions and algbraic data typs Strong, mixd and absnt rgion variabls Pur ffcts and mpty closurs Closur trimming Typ classing Copy and counting Typ classs for copy and updat Shap and partial application Shap constraints and rigid typ variabls Shap constraints and immatrial rgions
13 CONTENTS Typ dirctd projctions Dfault projctions Ambiguous projctions and typ signaturs Pull back projctions Custom projctions Comparisons with othr work FX Gifford, Lucassn, Jouvlot and Talpin C Bjarn Stroustrup Haskll and unsafprformio Simon Pyton Jons t al Bhaviors and Trac Effcts Nilson and Nilson t al λ var Odrsky, Rabin, Hudak, Chn MLKit Toft, Talpin, Birkdal Functional Encapsulation Gupta Objctiv Caml Lroy, Doligz, Garrigu, Rémy and Jérôuillon Calculus of Capabilitis and Cyclon Crary, Walkr, Grossman, Hicks, Jim, and Morristt BitC Shapiro, Sridhar, Smith, Dorri Monadic Rgions Flut, Morristt, Kislyov, Shan Typ Infrnc Binding ordr and constraint basd infrnc Sourc languag and constraint slurping Normal typs Fr variabls of typs Dangrous variabls Matrial and immatrial variabls Th map xampl Annotatd sourc languag Exampl: annotatd syntax tr Slurping and constraint trs
14 14 CONTENTS Typs of programs and dclarations Kinds of typs and constraints Typs of trms Exampl: typ constraints Constraint sts and quivalnc classs Exampl: typ graph Constraint rduction Constraint ntailmnt Unification Had rad Gnralisation Tracing Loop chcking Packing Loop braking Clan boring ffct and closur variabls Quantification Lat constraints and postinfrnc chcking Projctions Exampl: vctors Ambiguous projctions and typ signaturs Constraint ordring and mutual rcursion Comparison with Hlium Hrn, Hag, Swirstra Typ Classs Dp Rad/Writ Dp Mutabl/Const Purification Shap Error Rporting Constraint justifications Tracking purity rrors
15 CONTENTS 15 4 Cor Languag Constraints and vidnc Witnss passing Dpndnt kinds Witnsss of mutability Witnsss of purity Simplifid cor languag Symbol Classs Kinds Typs Trms Wak valus and lazy valuation Stors, machin stats and rgion handls Rgion allocation vrsus lazy valuation Stor typings Rgion similarity Duplication of rgion variabls during valuation Witnss production Transitions Kinds of kinds Kinds of typs Similarity Subsumption Typs of trms Soundnss of typing ruls Extnsions to th simplifid languag Masking nonobsrvabl ffcts Masking ffcts on frsh rgions Masking pur ffcts Boundd quantification Effct joining in valu typs Optimisations Local transforms Floating at th sam lvl Effcts and rgion aliasing
16 16 CONTENTS Floating into altrnativs Floating outsid lambda abstractions Comparisons Monadic intrmdiat languags Tolmach, Bnton, Knndy, Russll SystmFc Sulzmann, Chakravarty, Pyton Jons, Donnlly Conclusion Implmntation Implmnting thunks and lazinss Limitations and possibl improvmnts Masking mutability constraints Blockd rgions and rgion sums Boundd quantification and ffct strngthning Polymorphism, data sharing, and constraint masking Witnsss of no aliasing Should w trat toplvl ffcts as intrfring? Add witnsss to writ ffcts A bttr typ for forc Summary of Contributions Th Hair Shirt A Proofs of Languag Proprtis 259
17 Chaptr 1 Introduction 1.1 Prlud I am thinking of a data structur for managing collctions of objcts. It provids O(1) insrt and updat oprations. It has nativ hardwar support on all modrn platforms. It has a long history of us. It s provn, and it s lightning fast. Unfortunatly, support for it in my favourit languag, Haskll [PJ03a], appars to b somwhat lacking. Thr ar popl that would tll m that it s not ndd [PJW92], that thr ar othr options [Oka98b], that it s bad for paralllism [Can91] and bad for computr scinc in gnral [Bac78]. Thy say that without it, programs ar asir to undrstand and rason about. Yt, it sms that vry tim I start to writ a program I find myslf wanting for it. It s calld th stor. Th mutabl stor, that is. I want for ral dstructiv updat in a ral functional languag (for my own, particular, subjctiv dfinition of ral ). I wantd it for long nough that I dcidd I should tak a PhD position and spnd th nxt svral yars of my lif trying to gt it. Soon aftr starting I cam to ralis two things: 1) That th problm was ral, and that many popl wr awar of it. 2) That this was not a nw problm. 17
18 18 CHAPTER 1. INTRODUCTION 1.2 Th Problm Functional programming is many things to many popl, but at th hart of it is on cntral ida. Programs should b xprssd in trms of highr ordr functions, rfrrd to as combining forms in Backus s sminal papr [Bac78], instad of as imprativ squncs of commands which updat a global stor. Th folklor promiss that as functional programs admit mor algbraic laws than thir imprativ countrparts, thy will b asir to xprss and rason about. It also promiss that functional programs hav th potntial to run fastr, with th imagind spdup bing partly du to frdom from th von Numann bottlnck, that is squntial accss to th global stor, and partly du to optimising transforms which can b carrid out du to th algbraic laws [dms95]. Aftr 30 yars of intns rsarch, svral industry strngth compilrs [PJ94, NSvEP91, TBE + 06, Mac91], and countlss rsarch paprs, both of ths promiss hav bn dlivrd on yt curiously, functional languags hav not rplacd imprativ ons in mainstram softwar nginring. Thr ar a myriad of ndlssly dbatd rasons for this apparnt lack of us, and most will b quit familiar to th popl likly to b rading this thsis. Oftn toutd candidats includ organisational inrtia and markting prssur xrtd by larg corporations sking to cmnt thir own particular languag into th psych of th industry programmr [GJSB05]. It is no doubt asy to form ths opinions, spcially if on is a rsarchr or acadmic in th fild of programming languags. Almost by dfinition, w spnd th majority of our tim working with our own systms and attnding confrncs whr th prsntations ar givn by popl in similar circumstancs. In rcnt yars this situation has bn rcognisd by th functional programming community itslf, hnc th cration of forums that sk to collct rports of industry xprinc with its languags [Wad04]. Th conclusion of many of ths prsntations simply ritrats what w hav known all along that functional programming is wondrful and th application of highr ordr functions, pattrn matching and strong typing (for som) lads to shortr dvlopmnt tims and mor rliabl softwar. By all accounts th community is thriving and much softwar is bing writtn, yt th majority of it continus to b from graduat studnts and rsarchrs in th fild of programming languag thory. Of this fact on can asily b convincd by visiting an arbitrary wbbasd job placmnt agncy and comparing sarch rsults for Haskll or O Caml vrsus any on of Java, Prl, Ruby, C++ or Python. Ar Haskll and O Caml dstind to b Th Vlvt Undrground of programming languags, whr hardly anyon has hard thm, but vryon who dos forms a band? 1 1 Aftr a quot attributd to Brian Eno. Th Vlvt Undrground wr a rock music group activ in th lat 60 s, arly 70 s. Thy wr highly influntial, yt initially unsuccssful in a commrcial sns.
19 1.2. THE PROBLEM 19 Somthing s missing? What if w wr to tak a stp back from th glory of functional programming, and instad focus on what might b missing? Aftr all, if functional languags could do vrything that imprativ languags could, as wll as having strong typing, pattrn matching, highr ordr functions and associatd goodnss, thn at last thr would b no tchnically basd rason not to us thm. With this in mind, this thsis taks th position that an important missing fatur from all currnt functional languags is ral dstructiv updat. A programmr should b fr to updat an arbitrary data structur in thir program, with minimal runtim ovrhad, and with minimal intrfrnc from th typ systm or languag dsign. Not th us of th word intrfrnc. In on sns, a languag is a structur for formulating and communicating idas, but in anothr it is a barrir to a tru xprssion of intnt. In an imprativ languag th programmr can updat thir data whn and whr thy s fit, whras in a typical functional languag, thy cannot. W sk to rmov this barrir. This work is mbodid in th Disciplind Discipl Compilr (DDC) 2. Discipl bing th nam of th languag it compils, and Disciplind invoking th typ and ffct disciplin [TJ92b] of Talpin and Jouvlot which forms th basis of our typ systm. Whrvr possibl, w hav avoidd crating yt anothr functional languag (YAFL) that noon is likly to us. Discipl s syntax is basd on Haskll, and DDC itslf is writtn in Haskll. This allows us to lvrag a hug body of xisting popl, idas and cod. Kping th sourc and implmntation languags similar will also mak it asy to bootstrap DDC in futur work. As dstructiv updat is th sourc of all our problms, w start with a discussion of why it should b includd in a languag in th first plac. Having convincd ourslvs that it is rally ndd, w will xamin how it is supportd in xisting functional languags, and argu that this support is inadquat. W will discuss th notion of purity and how it bnfits a languag. W will also considr what it mans for a languag supporting dstructiv updat and othr sid ffcts to b pur, and whthr th formal notion of purity is usful in practic. Discipl allows arbitrary structurs to b updatd, and functions to hav arbitrary sid ffcts. Instad of rlying on stat monads, w us a typ basd analysis to rcovr mutability, ffct and data sharing information from th program bing compild. W us an intrmdiat languag similar to Systm Fc [SCPJD07] and our analysis rcovrs nough information to do th sam cod transformation styl optimisations as a highly optimising compilr such as GHC [PJ94]. W will discuss som of th practical problms with using lazy valuation as th dfault mthod, and why spac laks ar so common in lazy programs. Discipl uss strict valuation by dfault, but allows th programmr to introduc lazinss whn dsird. W us th typ systm to nsur that th combination of dstructiv updat and lazinss dos not chang th maning of th program compard with th strict cas. This chaptr outlins our approach and th rasons w hav chosn it. Chaptr 2 discusss th typ systm in dtail, and Chaptr 3 outlins th infrnc 2 Whn daling with a fild that sparats languags into pur and impur, th rligious connotations ar alrady prsnt. W mak no apologis for th nam.
20 20 CHAPTER 1. INTRODUCTION algorithm. Chaptr 4 dscribs our cor languag and givs a proof of soundnss for its typ systm. Chaptr 5 summariss what w hav larnd so far and suggsts avnus for futur work. 1.3 Why dstructiv updat mattrs Dstructiv updat is th procss of changing th valu of an objct inplac, by ovrwriting and hnc dstroying its old valu. Without dstructiv updat w cannot chang th valus of xisting objcts, only allocat nw ons. With dfrnc to Turing compltnss, dstructiv updat is simply not rquird to writ programs. Likwis, almost vry fatur of a particular languag can b shown to b suprfluous. Tiny systms such as th Lambda Calculus, Conway s gam of lif, and th Rul 30 cllular automata ar Turing complt [Rn02, Coo04], and hnc capabl of univrsal computation. On th othr hand, no on writs programs in thm, at last not dirctly. Whn considring languag faturs w must always start from a practical, and thrfor subjctiv viwpoint. Whn w say dstructiv updat mattrs, w man that a larg nough subst of programmrs find it usful that it warrants considration by all. W suggst that dstructiv updat furnishs th programmr with two important and powrful tools, and that ths tools ar ithr too cumbrsom or too infficint to crat without it. Th first tool is a st of fficint arraylik data structurs for managing collctions of objcts, and th scond is th ability to broadcast a nw valu to all parts of a program with minimal burdn on th programmr Efficint data structurs rquir dstructiv updat For a mchanical dvic such as an intrnal combustion ngin, fficincy is dfind as th ratio of usful work output to th amount of nrgy input to th dvic [Gia00]. For a computational dvic such as a collction structur, w could rasonably dfin its fficincy as bing th numbr of insrt and updat oprations that can b compltd pr hardwar clock cycl. W pay no attntion to th difficulty of dsigning th structur in th first plac. Lik intrnal combustion ngins, th dvlopmnt of common data structurs is bst lft to tams of xprts, prmitting th nd usr to focus on thir own spcific tasks. Whn th numbr of objcts to b managd is known bforhand, th simplst collction structur is th array. In a typical garbag collctd runtim systm, th allocation of an array rquirs just thr machin oprations. W tst th topofhap pointr to nsur nough spac is availabl, writ th objct hadr word, and thn advanc th pointr. Th initialisation or updat of a particular valu in th array an also straight forward. Assuming w hav thr rgistrs containing a pointr to th start of th array, th nw valu, and th indx of th valu to b updatd, many procssors can implmnt th updat with just on or two instructions [Sun02, Int06].
21 1.3. WHY DESTRUCTIVE UPDATE MATTERS 21 R1: A v 0 v v v v v v v v v R2: R3: v 4 4 Of cours, du to piplining and cach ffcts, th numbr of machin instructions xcutd for an opration dos not rlat dirctly to th numbr of clock cycls usd [HP96]. Howvr, it is a usabl approximation for this discussion, and w will considr th cas of updating a flat array as approaching 100% fficincy for arraylik structurs. Prfct fficincy would b achivd if vry updat opration compltd in th minimum numbr of clock cycls possibl on th availabl hardwar. For most applications, prfct fficincy is unlikly to vr b achivd by a statically compild program, as it is too difficult to accuratly simulat piplin stats and data hazards in a multitasking systm. Ignoring cach ffcts, th fficincy of an array is indpndnt of how many lmnts it containts. It costs no mor to updat a valu in a 1000 lmnt array than to updat on in a 10 lmnt array. Functional arrays ar unaccptably slow Without dstructiv updat w cannot chang an array objct onc it is allocatd, but w can sidstp this problm by crating a nw objct instad of updating th old on. A simpl mthod is to allocat a whol nw array and copy th old valus into it, with th nw valu in plac of th on that is bing updatd. This works, but is a disastr for prformanc. Assuming w nd on machin instruction for ach valu copid, prforming an updat on a 10 lmnt array now rquirs 10 instructions, plus thr to do th allocation. This rprsnts a misrabl 7.7% fficincy compard with a singl instruction dstructiv updat. For a 1000 lmnt array w nd at last 1003 instructions, rprsnting approximatly 0.1% fficincy. This is clarly unaccptabl. Tr structurs ar only a partial solution W can rcovr som of this ground by using a tr structur instad of a flat array. If w stor valus in th intrnal nods of a balancd binary tr thn w nd n nods for n valus, and th tr is cil(log 2 (n)) lvls dp. Unfortunatly, to chang a valu in th tr w must still allocat a nw nod. As this nw nod will b at a diffrnt addrss from th old on, w must thn rbuild all of its parnts so that th tr rfrncs th nw nod instad of th old on. For xampl, in th tr on th nxt pag, to updat v 7 w must rallocat th nod that contains it as wll as th nods of v 6, v 8 and v 5.
22 22 CHAPTER 1. INTRODUCTION N v 5 N v N v 2 8 N v 6 N v 9 N v 7 For a small numbr of valus, using a binary tr is wors than copying th whol array for ach updat, bcaus ach nod contains an objct hadr and two pointrs instad of just a valu. A balancd tr of 1000 lmnts is 10 lvls dp, and as a rough approximation, half of th nods li at th bottom of th tr. If w wr to updat on of ths nods thn w would nd to rallocat all of its parnts, which quats to 9 * 4 = 36 words of spac. Not all nods ar at this lvl, but w havn t accountd for finding th nod to b updatd in th first plac ithr. For a backofnvlop calculation w could xpct an avrag of at last 50 machin instructions to b rquird to updat a nod in this tr. This quats to 2% fficincy whn compard with dstructiv array updat of a similarly sizd array. Anothr option is to us trs of a highr ordr, prhaps a quadtr or a Btr structur lik th on shown in th following diagram. Adding mor valus pr nod rducs th dpth of th tr. It also rducs th numbr of nods w must rbuild whn prforming an updat, but at th cost of making ach nod largr. N v 3 v 6 N v v N v v N v v For a full (2,3)tr with two kys and thr branchs pr nod, ach nod is 6 words long including th objct hadr. Evry xtra lvl provids thr tims th numbr of nods prsnt in th prvious lvl, and for 1000 valus w nd a littl mor than 6 lvls. If w say that ach nod to b updatd has an avrag of 5 parnt nods, this quats to 5 * 6 = 30 words of spac to b rinitialisd whn updating a nod. This isn t much bttr than th prvious cas. Many algorithms naturally us an array as thir primary collction structur. If, for th lack of dstructiv updat, w ar forcd to a tr instad, thn w automatically impos a log(n) slowdown on our algorithm s run tim. To accss an lmnt in a tr w must travrs its structur, but array accss can b prformd in constant tim. This slowdown is in addition to a substantial constant factor du to th xtra bookkping data that must b maintaind, such as objct hadrs and branch pointrs that ar not ndd whn using arrays. In [PMN88] Pondr givs a list of algorithms for which no quivalnt, arraylss algorithm of similar complxity is known.
23 1.3. WHY DESTRUCTIVE UPDATE MATTERS 23 Th limit Thr ar an infinit varity of possibl structurs for simulating arrays, and trs rprsnt just a fw. By this stag, an astut radr may b thinking about all thir own favourit structurs and how much bttr thy ar than th ons outlind hr [Oka98b, OG98]. As w ar talking about machin instructions and constant factors, not just algorithmic complxity, thr ar also a hug varity of low lvl dtails to considr. Dtails includ instruction slction, caching, data layout, pointr comprssion [LA05], and using diff arrays which rly on dstructiv updat bhind th scns for fficincy, whilst prsnting a functionally pur intrfac. An xampl of pointr comprssion is to rplac ach of th pointrs in an objct by offsts from a bas pointr, instad of including th stor addrss in full. This can rsult in substantial spac savings for pointr havy programs on 64 bit machins, whr th siz of a particular data structur is only a tiny fraction of th availabl addrss spac. Diff arrays us a dstructivly updatabl array for th currnt stat of th structur, and updats to th structur ar implmntd by physically updating this array. Old stats of th array ar rprsntd by a list of diffrncs to apply to th currnt stat, so old stats bcom slowr and slowr to accss as th program progrsss. Thr ar many avnus for improvmnt, but without dstructiv updat w ar still hamstrung by th nd to allocat objcts to rprsnt nw program stats. Considr a maximally fficint structur which rquirs only a singl, tiny objct to b allocatd for ach updat. At th last, w could xpct this nw objct to contain a hadr word, th nw valu, and a pointr to th rst of th structur: H v Howvr, th allocation and initialisation of this objct will still rquir at last fiv machin instructions, thr for allocation and two to writ th nw valu and pointr. For som applications a constant fivfold slow down is of no consqunc, but for othrs it is a dal brakr.
24 24 CHAPTER 1. INTRODUCTION Tupls and rcords ar also arrays At th machin lvl, tupls and rcord objcts ar oftn vry similar to arrays. W can implmnt rcords by rprsnting ach fild as a pointr to th objct containing its valu, so at this lvl th rcord is simply an array of pointrs. A rcord objct with 5 filds would contain a hadr word and fiv pointrs. Considr thn th following rcord typ from DDC: data SquidS = SquidS { stattrac :: Mayb Handl, stattracindnt :: Int, staterrors :: [Error], statstop :: Bool, statargs :: St Arg, statsigmatabl :: Map Var Var, statvsboundtoplvl :: St Var, statvargn :: Map NamSpac VarBind, statvarsub :: Map Var Var, statgraph :: Graph, statdfs :: Map Var Typ, statpath :: [CBind], statcontains :: Map CBind (St CBind), statinstantiats :: Map CBind ( St CBind), statgnsusp :: St Var, statgndon :: St Var, statinst :: Map Var (InstancInfo Var Typ), statquantifidvars :: Map Var (Kind, Mayb Typ), statdatafilds :: Map Var ([Var], [(Var, Typ)]), statprojct :: Map Var (Typ, Map Var Var), statprojctrsolv :: Map Var Var, statclassinst :: Map Var [Fttr] } This rcord rprsnts th stat of our typ infrncr whil it is rducing constraints. Th maning of th filds is not important for this discussion. W includ this data typ to mak th point that ral rcords can contain upwards of 22 sparat filds. No mattr how fficintly th intrnal sts, maps and graphs ar implmntd, without dstructiv updat w cannot chang th valu of a fild without rbuilding at last part of th rcord objct. If w must rbuild it all, thn this is at last 22 tims slowr than using dstructiv updat. In a languag without dstructiv updat w must allocat and initializ nw objcts to rprsnt nw program stats. This a drastically lss fficint altrnativ. In practic, vn if a languag dos not support th dstructiv updat of arbitrary structurs, attmpts ar mad to introduc it in a mor rstrictd form. In [SCA93] Sastry prsnts an analysis to dtrmin an ordr of valuation for array accss and updat oprations, that allows th updats to b implmntd dstructivly. Bsids bing first ordr only, th troubl with many such analyss is that whn thy fail to introduc an updat at an important point in th program, th programmr is lft with littl rcours to add it manually. Thr is also th problm of dtrmining which updats should hav bn implmntd dstructivly, but wrn t. As discussd in 1.6, Haskll includs a monadic sublanguag that supports th dstructiv updat of slct structurs such as arrays. Howvr, this sublanguag introducs its own problms, and algbraic data such as rcords and
25 1.3. WHY DESTRUCTIVE UPDATE MATTERS 25 lists cannot b similarly updatd. In [San94] Sansom dscribs th tim profil of an arly vrsion of GHC, and mntions that th us of a monadic mutabl array ovr an association list improvd th prformanc of typ substitution by a factor of 10. Whn combind with othr improvmnts, this rsultd in a 20x spdup of th typ chckr as a whol. If a particular programmr dos not us functional arrays or larg rcords in thir programs, thn thy may not b awar of th runtim cost of using thm. Howvr, thos who do ar looking down th barrl of a fiv fold slowdown, or wors, compard with othr languags Dstructiv updat hlps to broadcast nw valus Thr is an oftn rharsd argumnt that th xprssivnss of a languag is mor important than fficincy, bcaus improvmnts to procssor spd will quickly rcovr any lost ground. Th standard countr is to say that th common man wants thir nw and fastr computrs to do nw and fastr things, not th original things lss fficintly. Ths argumnts can also b applid to dstructiv updat. Surly, th antagonist offrs, a fiv fold slowdown is not that bad. Moor s law says w ll hav that back in four yars, and look at all th xtra compilr optimisations w can do now that th languag is pur!. Computational fficincy may or may not mattr to a particular programmr, but th lvl of abstraction offrd by th languag should mattr to all. W will now mov away from concrns ovr run tim spd, and instad focus on th xprssivnss of th languag itslf. Considr a st of program moduls which all rfrnc a singl, shard valu. This valu could b a cursor position or timing valu, somthing that changs oftn and is of intrst to many sparat moduls. W will rfr to this valu as X. In a languag with dstructiv updat w can plac X in a containr structur and hav ach modul accss it via a pointr: Modul 1 Modul 2 RRR X Modul 3 Modul 4 Using dstructiv updat, on modul can modify X and th nw vrsion is immdiatly visibl to othrs. Notic that modul 1 has a rfrnc to th top of th containr structur as wll as a dscription of how to find th valu of intrst. In this xampl th containr is a binary tr and th valu is accssabl by following thr right branchs from th root nod. On th othr sid, moduls 2, 3, and 4 do not nd to know how to locat X within its containr bcaus thy hav a pointr dirctly to it. This scond group of moduls is not intrstd in th containr or any othr valu containd within.
26 26 CHAPTER 1. INTRODUCTION Without dstructiv updat, a modul cannot chang X dirctly, nor can it chang th pointrs within clint moduls so that thy rfrnc any nw objcts it might crat. Th programmr is forcd to rwrit all moduls so that thy rfrnc th top lvl of th containr structur, and includ a dscription of how to find th valu of intrst. Modul 1 Modul 2 RRR RRR Modul 3 RRR X Modul 4 RRR By doing this w hav rducd th lvl of abstraction in th program. Whras moduls 2, 3, and 4 ar only intrstd in th valu X, thy must now also concrn thmslvs with th containr structur and how to find and updat lmnts containd within. This problm is compoundd whn a shard valu is logically part of svral containrs. Prhaps X is also prsnt in a graph structur, and th tr is usd to rprsnt a st of objcts which must b writtn to disk whn th program finishs. Th moduls that wish to updat th shard valu must hav knowldg of all structurs which contain it. Shard valus lik th on dscribd hr ar oftn ndd to writ intractiv programs such as Frag [Ch05]. In Haskll, variabls holding timing valus, mous positions and othr usr intrfac stats ar typically bundld up into a rcord of IORfs. This in turn rquirs all cod which accsss ths valus to b writtn in th IO monad, a point w will rturn to in 1.6. Updating nstd rcords in Haskll is painful Haskll 98 has an conspicuously poor rcord systm. In itslf this is not a nw obsrvation, but w paus to discuss it bcaus w fl th problm ariss in part from th lack of dstructiv updat in th ambint languag. Standard complaints includ th rcords not bing light wight, not bing xtnsibl, and that all fild nams ar in th top lvl scop [JPJ99]. In addition, w considr th syntax for updating nstd rcords to b unusabl. Th following cod dfins thr rcord typs with two filds ach. Typ R1 contains typ R2, and typ R2 contains typ R3. Notic th prfixs r1, r2 and r3 on ach fild nam. In Haskll, fild nams pollut th top lvl nam spac, so w can t hav a fild namd fild1 in R1 as wll as in R2 without crating a nam clash.
27 1.3. WHY DESTRUCTIVE UPDATE MATTERS 27 data R1 = R1 { r1fild1 :: Int, r1fild2 :: R2 } data R2 = R2 { r2fild1 :: Char, r2fild2 :: R3 } data R3 = R3 { r3fild1 :: Bool, r3count :: Int } W will crat a rcord valu of typr1 as an xampl. Similarly to th prvious sction, w trat th fildr3count as a shard valu that many program moduls will b intrstd in. Whn th rcord is cratd w will initialis this fild to zro. Th xact valus usd for th othr filds ar not important for this xampl. rcord1 = R1 { r1fild1 = 5, r1fild2 = R2 { r2fild1 = a, r2fild2 = R3 { r3fild1 = Fals, r3count = 0 }}} Extracting th countr fild from th structur is straight forward. Each fild nam bcoms a projction function which taks th rcord and producs th fild valu, for xampl r1fild1 :: R1 > Int. W can mak us of th function composition oprator to xtract th count fild using a plasing syntax: count = (r3count. r2fild2. r1fild2) rcord1 Updating th countr is anothr mattr ntirly. As w do not wish to modify th othr filds in th structur, w must unpack and rpack ach lvl in turn. This procss corrsponds to rallocating parnts whn updating a nod in a tr. Unfortunatly, this tim w cannot writ a cut rcursiv function to do so bcaus th rcords at ach lvl hav diffrnt typs. Th following diagram shows th structur of th nstd rcords: R1 fild1 fild2 I 5 R2 fild1 fild2 C a R3 fild1 count B fals I 0
28 28 CHAPTER 1. INTRODUCTION R1 fild1 fild2 I 5 R2 fild1 fild2 C a R3 fild1 count B fals I 0 If w wish to chang th count fild in this structur to th valu 1, w must allocat a nw objct containing this valu. W must thn rbuild th R3, R2 and R1 nods so that th structur rfrncs this nw objct whil rtaining th pointrs to th othr nods. Hr is th gory Haskll xprssion: rcord2 = rcord1 { r1fild2 = (r1fild2 rcord1) { r2fild2 = ((r2fild2. r1fild2) rcord1) { r3count = 1 }}} Clarly this is not somthing a typical programmr would njoy writing. Th fild nams and th variabl rcord1 ar rpatd twic ach, th lin must b brokn into fragmnts to fit on th pag, it dos not indnt wll, and thr is much visual nois. It is wors whn w nd to updat this fild with a nontrivial xprssion. Considr th simpl act of incrmnting r3count. W can us layout to rduc th nois, but it is still quit bad: rcord3 = rcord2 { r1fild2 = (r1fild2 rcord2) { r2fild2 = ((r2fild2. r1fild2) rcord2) { r3count = (r3count. r2fild2. r1fild2) rcord2 + 1 }}} Th nd to writ such tdious cod to prform such a simpl updat would b a dal brakr for many programmrs. 3 Considr an quivalnt statmnt in an imprativ languag, such as C++. rcord2.fild2.fild2.count += 1 Dstructiv updat allows th programmr to focus solly on th lmnt of intrst, whil laving th othrs untouchd. Grantd, th abov statmnt dos not hav th sam smantics as th Haskll vrsion bcaus it modifis th original objct instad crating a nw on. If this bhaviour is rquird thn many imprativ, objct orintd languags support a fragmnt such as: rcord3 = rcord2.copy() rcord3.fild2.fild2.count += 1 3 It crtainly is for th author.
29 1.3. WHY DESTRUCTIVE UPDATE MATTERS 29 To th surrounding program ths two simpl statmnts hav th sam ffct as th Haskll xprssion shown abov, with th addd advantag that th concpts of copy and updat ar clarly sparatd. In C++ w can mak lif vn asir for th programmr. W can crat a rfrnc to th fild of intrst and incrmnt it without any knowldg of th surrounding rcord structur: int* countrf = &(rcord.fild2.fild2.count) (*countrf) += 1; Admittdly, rfrncs and dstructiv updat can b usd for vil as wll as for good. Many confusing programs can b constructd in which diffrnt program moduls communicat via shard mutabl objcts in a way which is ntirly nonobvious to th casual obsrvr, and almost impossibl to dbug. Th countr to this argumnt is to say that confusing programs can b writtn in any languag, and a good carpntr can hammr a nail into a wall without smashing thir own fingrs. W should not that th problm of updating nstd rcords in Haskll can b mad asir by gnric programming libraris such as Scrap Your Boilrplat [APJ03] (SYB) and DriFT [HJL06]. Although ths systms can hlp, w fl thy ar not complt solutions as thy lack th fficincy and as of us of dstructiv updat. SYB styl systms tnd to travrs unintrsting parts of a structur whn prforming an updat, rsulting in a significant prformanc pnalty [Mit07]. DriFT is a prprocssor which can automatically gnrat updat functions for ach of th filds in a rcord, though it dos not support nstd updat as pr th prvious xampl. Whn implmnting DDC w dfind tupls of gt and st functions for ach fild, along with combinators to compos ths functions and to updat filds dp within nstd rcords. W hav found this to b a srvicabl yt tdious approach, as w hav not yt writtn a prprocssor to gnrat th tupls. This approach also dos not solv th problm of fild nams bing in top lvl scop.
30 30 CHAPTER 1. INTRODUCTION 1.4 What is purity? Although th word purity has many varid manings, most would agr that th following xprssion is pur: (λx. doubl x) (succ 5) To rduc this xprssion callbyvalu, w first valuat th argumnt and thn substitut into th body of th function. (λx. doubl x) (succ 5) (λx.doubl x) 6 doubl 6 12 Whn w rduc th sam xprssion callbynam, w substitut th argumnt first, yilding th sam rsult. (λx. doubl x) (succ 5) doubl (succ 5) doubl 6 12 In th simply typd lambda calculus, th ordr in which function applications ar valuatd dos not affct th nd rsult. This bhavior is also known as th ChurchRossr proprty [Ros84], or conflunc. Purity is of trmndous hlp to compilr writrs bcaus it givs us th frdom to rordr function applications during compilation, whilst prsrving th maning of th program. By rordring function applications w can xpos many usful compilr optimisations [dms95], and this wll known idntity of th map function is on such xampl: map f (map g xs) map (f g) xs Th first xprssion applis g to ach lmnt of th list xs yilding an intrmdiat list. It thn applis f to ach lmnt of this list, yilding th rsult. In th scond xprssion, th composition of f and g is applid to ach lmnt dirctly, without rquiring th construction of an intrmdiat list. As long as w ar fr to rordr function applications, w can optimis a arbitrary program by rwriting xprssions of th first form into th scond. Th Glasgow Haskll Compilr includs a myriad of similar optimisations. Simpl, frquntly invokd rwrits ar bakdin to th compilr propr, whras mor spcific idntitis such th on abov ar part of th standard libraris, or ar dfind by th programmr dirctly. Th rcnt work on stram fusion [CLS07] is a prim xampl of library dfind rwrits which dpnd on purity. In contrast, th following xprssion is dciddly not pur: choos (introubl ()) (launchmissils 5) (atcak 23) Th nd rsult of this xprssion dpnds vry much on th ordr of valuation. Th intntion is for th first argumnt to xcut first, bfor choosing on of th othrs. This ordring must b prsrvd in th compild program, ls th maning of th program will b changd.
31 1.4. WHAT IS PURITY? 31 Th concpt of purity can also b applid to a languag as a whol. With th ChurchRossr proprty in mind, Sabry dfins a purly functional languag to b on that satisfis th following critria [Sab98]: 1. it is a consrvativ xtnsion of th simply typd λcalculus. 2. it has a wlldfind callbyvalu, callbynd, and callbynam valuation functions (implmntations), and 3. all thr valuation functions (implmntations) ar wakly quivalnt. W will considr th finr points of ths critria in a momnt. Sparat from Sabry s dfinition, th functional programming community gnrally rcogniss Haskll to b pur, whil SML, Schm, Fortran and C++ ar said to b impur languags. Howvr, not that Fortran and C++ ar not xtnsions of th λ calculus, so ar not functional ithr. Pur and impur ar loadd trms Sabry s dfinition contains svral subtl points, not last of which ar th words bing dfind. Th Oxford English Dictionary (OED) givs svral manings for th word impur. In rgards to a languag or styl, th word has th maning of containing forign idioms or grammatical blmishs. In this contxt, th forign idioms would includ intractions with th outsid world such as launching missils or ating cak. Ths actions ar not part of th formal dfinition of th lambda calculus, and it is not obvious what th rsult will b from th function nams alon. Th othr maning offrd by th OED is along th lins of not pur crmonially; unhallowd, or containing som dfiling or offnsiv mattr; dirty, unclan. This is unfortunat trminology. In contrast, mathmatical disciplins ar somtims sparatd into groups labld pur and applid. Th intntion is that th mor pur disciplins hav no immdiat practical applications, but ar considrd worthy of study bcaus thy incras our undrstanding of mathmatics as a whol. On th othr hand, th applid filds focus on using mathmatics to achiv goals in othr disciplins, such as physics. What was onc considrd a pur fild may bcom mor applid whn a concrt application is found. For xampl, abstract algbra is now an intgral part of th rror control coding systms that w rly on for lctronic communication [LDJC83]. Computational sid ffcts Grantd, impur languags can b much hardr to rason about, and th bulk of this thsis is about doing just that. Actions which affct th outsid world must b implmntd in th appropriat ordr, ls th program may not yild th intndd rsult. Othr intrnal actions such as dstructivly updating data and thn rading it back must also b squncd appropriatly. Whn th nd rsult of two xprssions dpnds on th ordr in which thy ar valuatd, thos xprssions ar said to hav computational ffcts, or to intrfr [Ry78]. Computational ffcts ar also known as sid ffcts, bcaus an xprssion can rturn a valu as wll as doing somthing ls. This is anothr unfortunat
32 32 CHAPTER 1. INTRODUCTION trm. Whn a pharmacutical product has a sid ffct, this is usually takn to b a bad thing. A pharmacutical sid ffct is an undsirabl rsult, but a computational sid ffct is oftn th ntir rason for running a program in th first plac. Do w rally nd thr implmntations? W rturn to Sabry s scond and third critria for a purly functional languag: 2. it has a wlldfind callbyvalu, callbynd, and callbynam valuation functions (implmntations) 3. all thr valuation functions (implmntations) ar wakly quivalnt. At th tim of writing, Haskll is callbynd, and thr is no formal dfinition of its implmntation. Th Haskll 98 rport [PJ03a] contains a dscription of th syntax and English languag nots on th intndd maning, but no formal oprational or natural smantics. Thr ar formal smantics for fragmnts such as th lazy lambda calculus [Abr90, Lau93b], but not th complt languag. Whthr this counts as having thr wll dfind implmntations is dbatabl. SML has a formal smantics [MTHM97], yt it is callbyvalu only. Thr is a lazy vrsion of ML [Aug84], but not all faturs of SML ar supportd, notably xcptions and mutabl rfrncs. On th othr hand, GHC includs th sq combinator which can b usd to turn a nativly callbynd application into a callbyvalu on, within th sam implmntation. For xampl, th following application will valuat callbynd as dfault: f xp... Howvr, w can forc th argumnt to b valuatd in an approximatly callbyvalu mannr by writing: lt x = xp... in sq x (f x) By binding xp... to th variabl x and thn passing this as th first argumnt to sq, w forc it to b rducd to had normal form 4 [PJ87, PJ92] bfor substitution into f. This simulats callbyvalu valuation. Howvr, in a lazy languag th dfinition of valu usually includs xprssions that contain rdxs, as long as thr is no rdx at top lvl. If w dsir hyprstrict valuation, whr all possibl rdxs ar rducd bfor application, thn w nd to mak mor judicious us of sq. W will rturn to this point in In th STG machin on which GHC is basd, function application is btwn variabls and atoms. For this implmntation an xprssion cannot b in wak had normal form without also bing in had normal form.
33 1.4. WHAT IS PURITY? 33 Wak quivalnc Considr th following function application, whr is a divrging xprssion. A divrging xprssion is on that aborts th program with an rror, or nvr trminats. (λz. 5) Whn w valuat this xprssion callbynd, th variabl z is not prsnt in th body of th function, so w can simply discard th argumnt. Howvr, if w us callbyvalu, or th rwrit using sq from th prvious sction, thn th valuation of this xprssion will divrg. Sabry s dfinition of wak quivalnc accounts for this: Lt P b a st of programs, B b a st of obsrvabls and val 1 and val 2 b two partial functions (implmntations) from programs to obsrvabls. W say val 1 is wakly quivalnt to val 2 whn th following conditions hold: If val 1 (P) = B thn ithr val 2 (P) = B or val 2 (P) is undfind If val 2 (P) = B thn ithr val 1 (P) = B or val 1 (P) is undfind Whn discussing th obsrvabls of a program w will omit th tim takn for it to valuat. W will considr only th final valu rturnd, and th IO actions prformd, as bing its rsult. If on implmntation valuats mor slowly than anothr, but othrwis rturns th sam valu and prforms th sam actions, thn by th abov dfinition thy ar still quivalnt. If this wr not th cas thn most compilr optimisations would chang th maning of th program. In fact, if thy didn t chang its maning, by making it fastr, thn thy would b uslss. If valuation tim is not obsrvabl thn, by rights, divrgnc should not b obsrvabl ithr. In a practical sns, th only way w can obsrv that a program divrgs is by waiting an infinit tim for it to complt. If it dosn t, thn w ll know it divrgd. For this rason w tak divrgnc as bing part of th undfind in th dfinition of wak quivalnc. Undr this dfinition, if w valuat a program with on implmntation and it divrgs, but in anothr it dosn t, th implmntations ar still wakly quivalnt. As divrgnc is not obsrvabl, by xtnsion it is also not an action, nor dos it corrspond to a sid ffct. W also tak undfind to man that th program would not compil du to a typ rror. Discipl is callbyvalu by dfault, but also supports callbynd valuation. W shall s in that if w attmpt to suspnd a function application that has an obsrvabl ffct, somthing that would othrwis chang th maning of th program with rspct to th callbyvalu cas, th compilr will dtct this and rport a typ rror. By Sabry s dfinition w argu that this maks Discipl a purly functional languag vn though arbitrary structurs can b dstructivly updatd, and functions can hav arbitrary sid ffcts. W considr Trauchi and Aikn s systm of witnssing sidffcts [TA05] to b pur for th sam rason. Lik ours, thir systm supports th updat of mutabl rfrncs at arbitrary points in th program. It also provids a typ
34 34 CHAPTER 1. INTRODUCTION systm to nsur witnss rac frdom, which mans thr ar nough data dpndncis in th program to prvnt a paralll rduction of it from having an indtrminat rsult. Exprssiv powr and oprational quivalncs Of cours, Sabry s dfinition of what a purly functional languag is may or may not corrspond to th informal undrstanding of it by th functional programming community at larg. Thr is also th qustion of whthr purly functional should man th sam thing as pur, as in our xprinc ths trms ar usd intrchangably. Whthr or not purly functional languags ar somhow intrinsically bttr than impur ons is a moot point. Sabry s discussion of why Haskll is purly functional hings on th fact that monadic programs can b tratd as producing a dscription of th IO actions to b prformd, instad of xcuting thm dirctly. Th actual xcution only happns whn computing th obsrvabl rsult of th dscription, a procss concptually sparat from valuation. Howvr, as GHC uss monads to support mutabl rfrncs, and ths rfrncs can contain lambda trms, th valuation and obsrvation functions would nd to b dfind as coroutins. As only th valuation part adhrs to Sabry s dfinition, w fl that th trm purly functional, whn applid to a languag as a whol, is a dscription of th formalisation of that languag, and not of th fatur st prsntd to th usr. It is not about th lack of sid ffcts or lack of mutabl stat, bcaus Haskll provids both of ths. On th othr hand, th trm pur whn applid to a singl xprssion has a mor widly accptd maning. A pur xprssion has no sid ffcts and its valuation can b rordrd with any othr xprssion without affcting its rsult. If th valuation cannot b safly rordrd with anothr thn w will call th xprssion impur. Th ability to rordr xprssions is an oprational quivalnc. In [Fl91] Fllisn nots that: an incras in xprssiv powr is rlatd to a dcras in th st of natural (mathmatically appaling) oprational quivalncs. In 1.3 w saw that th omission of dstructiv updat from a languag rducs its xprssivnss bcaus it mans thr is no asy way to updat shard valus containd within data structurs. By no asy way w man that if w had a program that dstructivly updatd a shard valu, and w had to rwrit that program without using updat, thn w would nd to prform far raching changs to th cod. Our languag, Discipl, is basd on Haskll and is xtndd to support th dstructiv updat of arbitrary structurs, and som othr impur faturs. W add ths faturs to incras th xprssiv powr of th languag, but by doing so w los crtain oprational quivalncs. Th gam is thn to win a high dgr of xprssivnss whil losing only a small numbr of oprational quivalncs. Exprssivnss is not asy to quantify, but w touchd on it in our discussion of why dstructiv updat mattrs. In Chaptr 4 w discuss how w hav organisd our cor languag so that only th parts of th program that us impur faturs los oprational quivalncs. This allows th full gamut of program optimisations to b applid to th pur parts, which w fl is a fair compromis.
35 1.4. WHAT IS PURITY? 35 Divrgnc is not an ffct In Discipl, th tim takn for a program to valuat is not formally obsrvabl, though w do not considr this approach to b th only valid option. For xampl, in a hard ral tim systm th tim takn to valuat a program is just as important as its final rsult (by dfinition). If a program writtn in such a systm cannot produc its rsult in th rquird tim, thn th program is wrong. In Discipl w hav no formal support for such rquirmnts, othr than good intntions. As w lav run tim unobsrvabl, thn it follows that divrgnc should not b obsrvabl ithr. This is a diffrnc to Tolmach s systm [Tol98] which has spcific support for pur but potntially nontrminating computations. W will rturn to this in Although divrgnc is not obsrvabl, w crtainly don t want to introduc it into an othrwis trminating program. By th dfinition of wak quivalnc, introducing divrgnc would not chang a program s maning, but it would crtainly aggravat th programmr. DDC is a gnral purpos compilr and its rol is to produc a binary that runs fast nough to satisfy th programmr. This fast nough is not wll dfind, though th gnral rul is th fastr th bttr. This has implications for our handling of divrgnc. Whil compiling a program, if w s an xprssion of th form ((λz. 5) ) thn w will b fr to prform a compil tim βrduction and rwrit this to 5, or not. Rwriting it rducs th run tim of th program, from infinit to somthing finit, which w will tak as bing a good thing. Howvr, this tratmnt of divrgnc it at odds with som styls of imprativ programming that us functions lik: void loop () { whil (tru) ; } Although this function appars to do nothing, as part of a largr program it may b doing nothing for a particular purpos. For xampl, programs in mbddd systms ar oftn basd around intrrupt srvic routins (ISRs). Such programs typically us th main routin to st up a numbr of ISRs, and thn ntr an ndlss loop. Whn a hardwar dvic rquirs srvic, or a timr xpirs, th procssor calls th ISR, dos som computation and rturns to th main loop. In this cas th program divrgs for a purpos, and it would b wrong to improv it by liminating th loop. In DDC w handl this by rquiring ndlss loops to contain a sid ffcting function. For xampl: loop () = lt = slp 1 in loop () Th typ of slp will includ an ffct that signals to th compilr that th function is valuatd for som rason othr than to gain its rturn valu. W discuss ffct typs in 2.3. Rfrntial Transparncy Purity is rlatd to th notion of rfrntial transparncy. A languag is said to b rfrntially transparnt if any subxprssion can b rplacd by any othr
36 36 CHAPTER 1. INTRODUCTION that is qual in valu, without affcting th nd rsult of th program [SS90]. Rusing our prvious xampl: (λx. doubl x) (succ 5) If w tak (succ 5) to hav th valu 6 thn w ar fr to rplac any instanc of (succ 5) with this valu, without changing th rsult of th program: (λx. doubl x) 6 This is clarly valid, bcaus it is th rsult w would hav obtaind whn rducing th xprssion callbyvalu anyway, and w know that th lambda calculus is pur. For contrast, considr th following xprssion which rads a charactr from th consol: gtchar () Is this xprssion rfrntially transparnt? If w wr to say that th valu of gtchar () is a charactr, thn th answr would b no. Th charactr rturnd will dpnd on which ky th usr prsss, and could b diffrnt vry tim. W cannot tak th first charactr that th usr ntrs and us this to rplac all othr instancs of gtchar () in th program without changing its maning. W could qually say that this xprssion dos not in fact hav a valu sparat from th contxt in which it is valuatd. Knowldg of th rturn valu is inxtricably linkd to knowldg of what ky th usr will prss. Saying that th valu of gtchar () is a just charactr is a gross ovrsimplification. Anothr way of looking at this is to say that th xprssion gtchar (), and th charactr valu, ar not obsrvationally quivalnt [Gun92]. Th obsrvd rsult of valuating a charactr is just th charactr, but th valuation of gtchar () also changs (or xamins) th stat of th outsid world. If dsird, w could dal with this problm by simply mbdding th notion of th outsid world dirctly into th spac of valus. Onc this is don w might thn prtnd that th languag was rfrntially transparnt all along. In Haskll syntax, w could giv gtchar th following typ: gtchar :: World (Char,World) This function taks th prvious stat of th world and rturns a charactr along with th nw world. Th tchniqu of thrading th world through IO functions gos back to at last FL [AWW91], though th stat paramtr was namd th history instad of th world. To construct a usful xampl, w would also lik to hav a function which prints charactrs back to th consol: putchar :: Char World World Th problm of manufacturing th initial world can b solvd by introducing a primitiv function which xcuts th program, similarly to th main function in C or Haskll. runprog :: (World World) ()
37 1.4. WHAT IS PURITY? 37 Now w can can writ a program which rads a charactr and prints it back to th usr: lt prog world = (lt (c, world2) = gtchar world world3 = putchar c world2 in world3) in runprog prog Whthr w chos to swallow ths dfinitions would likly dpnd on whthr w had constructivist or intuitionistic tndncis. As it is impossibl to actually construct a valu of World typ, w cannot rplac an xprssion such as (gtchar world) with its rsulting valu, lik w did with (succ 5). W could rplac it with an xprssion such as (id (gtchar world)), but that sms pointlss. Nvrthlss, programming in this styl has an important advantag. W can writ our compilr as though th languag wr indd pur and rfrntially transparnt, bcaus th act of passing around th world xplicitly introducs th data dpndncis ndd to nforc th dsird squnc of ffcts. In addition, w do not actually nd to construct th world valu at all. At runtim can w can simply pass around a dummy valu, or liminat th world passing ntirly during compilation, onc it has srvd its purpos. This allows th programmr to manag th problm, but th burdn of corrctnss is thirs. For som programs, failing to supply adquat data dpndncis can caus unxpctd rsults at runtim. Data Dpndncis Considr th following xprssion: f (putstr hllo ) (putstr world ) In what ordr should ths two strings b printd? If w rad this as a currid, callbyvalu application, thn th xprssion is quivalnt to: (f (putstr hllo )) (putstr world ) In this cas th output would b: worldhllo. On th othr hand, if th compilr did a lft to right convrsion to administrativ normal form during dsugaring, thn w could also rad th xprssion as: lt x = putstr hllo y = putstr world in f x y If th runtim systm thn valuatd ths bindings top to bottom, in a callbyvalu mannr, thn th output would instad b: hlloworld. If valuation was callbynam thn it would dpnd on which ordr f usd its argumnts, if at all. If w instad convrtd th xprssion to C99, its rsult would b undfind by th languag standard [C05]. In C99, sid ffcts ar only guarantd to b compltd at ach squnc point, bfor moving onto th nxt on. Thr is a squnc point just bfor th call to a function, but only aftr all argumnts
38 38 CHAPTER 1. INTRODUCTION ar valuatd. Each argumnt dos not hav its own squnc point, so th compilr is fr to call th putstr functions in any ordr. If w do not wish to rly on th ordr spcifid (or not) by th languag standard, w could instad us our world passing mchanism to nforc a particular squnc: lt prog world = (lt (x, world2) = putstr hllo world (y,world3) = putstr world world2 in fun x y world3) in runprog prog Now thr thr is no ambiguity. 5 Assuming that putstr is an atomic, primitiv opration which is strict in both argumnts, th first occurrnc must b valuatd bfor th scond bcaus w nd to pass th tokn bound to world2 to th nxt occurrnc. Unfortunatly, this mchanism falls apart if w mix up th variabls binding th world tokn, such as world and world2. Our program can also giv unxpctd rsults if w accidntally rus thm: lt prog world = (lt (x, ) = putstr hllo world (y, ) = putstr world world in fun x y world) in runprog prog In this cas w hav passd th sam tokn to ach instanc of putstr. In a callbynd languag such as Haskll, and in th absnc of data dpndncis, th ordr in which lt bindings ar valuatd dpnds on th ordr thir valus ar dmandd by th surrounding program. 1.5 Linar and uniqunss typing Linar typing is a way to nforc that particular valus in a program, lik our world tokn, ar usd in a singl thradd mannr. Linar valus can b usd onc, and onc only, and cannot b discardd [Wad90b]. Uniqunss typing combins convntional typing with linar typing so that nonlinar valus, capabl of bing shard and discardd, can xist in th sam program as linar valus [BS94]. This can b don by adding subtyping and corcion constraints btwn uniqunss variabls as in Clan [BS93], or mor rcntly, by using boolan algbra and unification as in Morrow [dvpa07]. With uniqunss typing w can giv putstr th following typ: putstr :: String World World Th first annotation indicats that whn w apply this function, th world tokn passd to it must not b shard with any othr xprssion. On th right of th arrow, th indicats that whn th function rturns, thr will b no othr rfrncs to th tokn bar this on. This forcs th world tokn to b usd in 5 Or at last lss ambiguity, w r still glossing ovr th actual oprational smantics of th languag.
39 1.5. LINEAR AND UNIQUENESS TYPING 39 a singl thradd mannr, and not duplicatd. In contrast, th annotation indicats that th String and function valus may b shard with othr parts of th program. Using this nw typ xplicitly disallows sharing th world as pr th xampl from th prvious sction: lt prog world = (lt (x, ) = putstr hllo world (y, ) = putstr world world in fun x y world) in runprog prog Hr, th world tokn passd to putstr is nonuniqu bcaus thr ar thr sparat occurrncs of this variabl. On an oprational lvl, w can imagin that in a callbynd implmntation, a thunk is cratd for ach of th lt bindings, and ach of thos thunks will hold a pointr to it until thy ar forcd. Uniqunss typing can also b usd to introduc dstructiv updat into a languag whilst maintaining th illusion of purity. From this point on w will lid annotations on function constructors to mak th typs clarr. Using th Morrow [dvpa07] systm w could dfin: nwarray :: Int (Int a u ) Array a u updat :: Array a u Int a u Array a u nwarray taks th siz of th array, a function to crat ach initial lmnt, and producs a uniqu array. Th u annotation on th typ variabl a is a uniqunss variabl, and indicats that th array lmnts ar polymorphic in uniqunss. Th updat function taks an array, th indx of th lmnt to b updatd, th nw lmnt valu, and rturns th updatd array. Notic th uniqunss annotations on th two right most function arrows of updat. As w allow partial application w must prvnt th possibility of just th array argumnt bing supplid and th rsulting function additionally shard. Whn applying a primitiv function lik updat to a singl argumnt, many implmntations will build a thunk containing a pointr to th argumnt, along with a pointr to th cod for updat. If w wr to shar th thunk thn w would also shar th argumnt pointr, violating uniqunss. Making th array uniqu forcs it to b usd in a singl thradd mannr. This in turn allows th runtim systm to us dstructiv updat instad of copy whn modifying it. W can do this whilst maintaining purity, as uniqunss nsurs that only a singl function application will b abl to obsrv th array s stat bfor it is updatd. To rad back an lmnt from th array w can us th slct function: slct :: Array a Int (a, Array a ) slct taks an array, th indx of th lmnt of intrst and rturns th lmnt and th original array. As th tupl rturnd by th function contains a uniqu array it must also b uniqu. This is known as uniqunss propagation[bs93]. Similarly to th partial application cas, if th tupl could b shard by many xprssions thn ach would also hav a rfrnc to th array, ruining uniqunss.
40 40 CHAPTER 1. INTRODUCTION Notic that it is only possibl to slct nonuniqu lmnts with this function. Aftr slct rturns thr will always b two rfrncs to th lmnt, th on rturnd dirctly in th tupl and th on still in th array. On way to work around this problm is to rplac th lmnt of intrst with a dummy at th sam momnt w do th slction. Of cours, onc w hav finishd with th lmnt w must rmmbr to swap it back into th array. By doing this w can prsrv uniqunss, but at th cost of rquiring a diffrnt styl of programming for uniqu and nonuniqu lmnts. rplac :: Array a Int a (a, Array a ) Uniqunss typing gos a long way towards introducing dstructiv updat into a languag, whil maintining th bnfits of purity. Unfortunatly, bsids th addd complxity to th typ systm, programs using it can bcom quit vrbos. Having th rquird data dpndncis in on s cod is all wll and good, but manually plumbing vry uniqu objct around th program can bcom tdious. W will tak a momnt to mditat on th following typ signatur, from th analtyps modul of th Clan 2.2 compilr sourc cod: chckkindsofcommondfsandfunctions ::!Indx!Indx!NumbrSt![IndxRang]!{#CommonDfs}!u:{# FunDf}!v:{#DclModul}!* TypDfInfos!* ClassDfInfos!* TypVarHap!* ExprssionHap!* GnricHap!* ErrorAdmin > (!u:{# FunDf},!v:{#DclModul},!*TypDfInfos,!* TypVarHap,!* ExprssionHap,!* GnricHap,!*ErrorAdmin) This function has thirtn argumnts, and th rturnd tupl contains 7 componnts. Th!, # and * ar strictnss, unboxdnss and uniqunss annotations rspctivly, and {a} dnots an array of lmnts of typ a. Admittdly, w did spnd a fw minuts looking for a good xampl, but th vrbosity of this signatur is not uniqu among its brthrn. W ar crtainly not implying that th Clan implmntr s coding abilitis ar anything lss than first rat. Howvr, w do suggst that th rquirmnt to manually plumb stat information around a program must b allviatd bfor such a languag is likly to b adoptd by th community at larg. With this point in mind, w prss on to th nxt sction. 1.6 Stat monads In th contxt of functional programming, a monad is an abstract data typ for rprsnting objcts which includ a notion of squnc. Introducd by Moggi [Mog89] and laboratd by Wadlr and othrs [Wad90a, PJW92, Lau93a, LHJ95], thy ar a highly gnral structur and hav bn usd for divrs applications such as IO, xcptions, strictnss, continuations and parsrs [LM01, HM98]. In Haskll, th primary us of th gnral monad structur is to hid th plumbing of stat information such as world tokns, and th dstructivly updatabl
41 1.6. STATE MONADS 41 arrays from th prvious sction. For xampl, in thradthworld styl, a function to rad an Int from th consol would hav typ: gtint :: World (Int,World) This signatur has two sparat aspcts. Th Int trm in th tupl givs th typ of th valu of intrst, whil th two occurrncs of World show that this function also altrs th outsid world. W can sparat ths two aspcts by dfining a nw typ synonym: typ IO a = World (a, World) W can thn rwrit th typ of gtint as: gtint :: IO Int This nw typ is rad: gtint has th typ of an IO action which rturns an Int. Not that w hav not altrd th undrlying typ of gtint, only writtn it in a mor plasing form. W can also dfin a function printint, which prints an Int back to th consol: printint :: Int IO () By applying th IO typ synonym w can rcovr its thradthworld vrsion: printint :: Int World ((), World) Th magic bgins whn w introduc th bind combinator, which is usd to squnc two actions: bindio :: IO a (a IO b) IO b bindio m f = λ world. cas m world of (a,world ) f a world bindio taks an IO action m, a function f which producs th nxt action in th squnc, and combins thm into a nw action which dos both. In a lazy languag such as Haskll w us a casxprssion to forc th first action to complt bfor moving onto th scond. In a dfaultstrict languag lik Discipl w could writ bind using a ltxprssion, which would hav th sam maning: bindio :: IO a (a IO b) IO b bindio m f = λ world. lt (a, world ) = m world in f a world W also nd a toplvl function to run th whol program, similar to runprog from bfor: runio :: IO a a runio m = m ThWorld In this dfinition, ThWorld is th actual world tokn valu and is th sol mmbr of typ World. In a ral implmntation, World could b mad an
42 42 CHAPTER 1. INTRODUCTION abstract data typ so that clint moduls ar unabl to manufactur thir own worlds and spoil th intndd singlthraddnss of th program. W would also nd to nsur that only a singl instanc of runio was usd. Hr is a combinator that crats an action that dos nothing xcpt rturn a valu: rturnio :: a IO a rturnio x = λworld. (x,world) Now w can writ a program to rad two intgrs and rturn thir sum, without nding to mntion th world tokn xplicitly: runio (bindio gtint (λx. bindio gtint (λy. rturnio (x + y)))) In Haskll w can us any function of two argumnts infix by surrounding it with backquots. W can also us th function composition oprator $ to liminat th outr parnthsis: runio $ gtint bindio λx. gtint bindio λy. rturnio (x + y) Finally, by using donotation and th monad constructor class [Jon93] w can hid th uss of bindio and writ this program in a mor familiar styl: runio $ do x gtint y gtint rturnio (x + y) Rprsnting ffcts in valu typs is a doubl dgd sword Th us of stat monads in this way has svral bnfits. First and formost, by using bindio w hav liminatd th nd to manually plumb th world tokn around our programs. W can also us stat monads to manag intrnal stat by rplacing th world tokn with rfrncs to ths structurs. Additionally, bcaus monads ar a gnral data typ whos application is not rstrictd to just IO and stat, w can dfin combinators which work on all monads including lists, xcptions, continuations and parsrs. Including ffct information in typs also aids program documntation. Programmrs oftn writ cod commnts to rcord whthr crtain functions prform IO actions or us intrnal stat. By including this information dirctly in typ signaturs w lvrag th compilr to chck that this documntation rmains valid whil th program is dvlopd. Howvr, th fact that ffct information is rprsntd in th spac of valus and valu typs is a doubl dgd sword. On on hand, w did not nd any spcific support from th languag to dfin our IO monad. On th othr hand, functions which prform IO actions (still) hav diffrnt structural typs compard to ons that do not.
43 1.6. STATE MONADS 43 For xampl, a function which doubls an intgr and rturns th rsult would hav typ: doubl :: Int Int A function which doubls an intgr as wll as printing its rsult to th consol would hav typ: doublio :: Int IO Int Imagin that during th dvlopmnt of a program w wrot a function that uss th first vrsion, doubl: fun :: Int Int fun x = lt... =... x = doubl x y =... in x + y Suppos that aftr writing half our program w thn dcid that fun should b using doublio instad. Th dfinition of fun w alrady hav uss a ltxprssion for intrmdiat bindings, but now w must rfactor this dfinition to us th donotation, or an xplicit bind combinator to plumb th world through. For th donotation, w must chang th binding oprator for our monadic xprssion to, as wll as adding a lt kyword to ach of th nonmonadic bindings: fun :: Int IO Int fun x = do lt... =... x doublio x lt... =... x + y Th typ of fun has also changd bcaus now it prforms an IO action as wll. W must now go back and rfactor all othr parts of our program that rfrnc fun. In this way th IO monad bgins to infct our ntir program, a condition colloquially known as monad crp [Lou08] or monaditis [Kar08]. Although w hav hiddn th world tokn bhind a fw layrs of syntactic sugar, it is still thr, and it still prturbs th styl of our programs. Th spac of valus and th spac of ffcts ar concptually orthogonal, but by rprsnting ffcts as valus w hav muddld th two togthr. On could argu that in a wll writtn program, cod which prforms IO should b clarly sparatd from cod which dos th ral procssing. If this wr possibl thn th rfactoring problm outlind abov should not aris too oftn. Howvr, as monads ar also usd for managing intrnal stat, and such stat is usd in so may nontrivial programs, all srious Haskll programmrs will hav suffrd from this problm at som point. In practic, th rfactoring of programs btwn monadic and nonmonadic styls can b a substantial amount of work [LNSW01].
44 44 CHAPTER 1. INTRODUCTION Haskll has fracturd into monadic and nonmonadic sublanguags Bing a functional languag, programs writtn in Haskll tnd to mak havy us of highrordr functions. Highrordr functions srv as control structurs similar to th for and switch statmnts in C, with th advantag that nw ons can b dfind dirctly in th sourc languag. This havy us of highrordr functions aggravats th disconnct btwn th monadic and nonmonadic styls of programming. Evry gnral purpos highrordr function nds both vrsions bcaus monads ar so oftn usd to manag intrnal stat. Considr th map function which applis a workr to all lmnts of a list, yilding a nw list: map :: (a b) [a] [b] map f [ ] = [ ] map f (x : xs) = f x : map f xs This dfinition is fin for nonmonadic workrs, but if th workr also prforms an IO action or uss monadic stat thn w must us th monadic vrsion of map instad: mapm :: Monad m (a m b) [a] m [b] mapm f [ ] = rturn [ ] mapm f (x : xs) = do x f x xs mapm f xs rturn (x : xs ) Intrstingly, w can mak th nonmonadic dfinition of map rdundant by driving it from this monadic on. W will us th idntity monad, which contains no stat and dos not allow accss to th outsid world. This monad is just an mpty shll which satisfis th dfinition: map :: (a b) [a] [b] map f xx = runidntity (mapm (λx.rturn (f x)) xx Although w hav no proof, w bliv that it is possibl to transform at last all scond ordr monadic functions to similar nonmonadic vrsions in this way. It is a pity thn that th standard Haskll libraris ar missing so many monadic vrsions. For xampl, th Data. Map packag of GHC , rlasd in Novmbr 2008, dfins a finit map collction typ that includs th functions map, mapwithky and mapaccum among othrs. Th typs of ths functions ar: map :: (a b) Map k a Map k b mapwithky :: (k a b) Map k a Map k b mapaccum :: (a b (a, c)) a Map k b (a,map k c) Thr ar no quivalnt mapm, mapwithkym and mapaccumm functions in this library. In fact, thr ar no monadic vrsions for any of th Data.Map functions. Th Map data typ is also abstract, so if th programmr wants to apply a monadic workr function to all of its lmnts thn lif bcoms troublsom. On solution is to convrt th ntir structur to a list and us mapm discussd arlir. Of cours, doing this will incur a prformanc pnalty if th compilr is unabl to optimis away th intrmdiat lists.
45 1.6. STATE MONADS 45 Th lack of monadic vrsions of functions is not confind to th Data.Map library. GHC also lacks monadic vrsions of th list functions find, any and span. If monads wr mostly usd for domain spcific applications, thn th lack of library functions may not hurt in practic. For xampl, w hav usd th Parsc monadic parsr combinator library [LM01] in th implmntation of DDC. During dvlopmnt w mainly usd th parsr spcific combinators providd by th library, and doubt that w could vn think of a snsibl us for mapaccumm in this contxt. On th othr hand, th managmnt of IO and intrnal stat is not a domain spcific problm. Stat monads prmat th sourc cod for many wll known Haskll applications such as darcs and th aptly namd XMonad window managr [SJ07]. W do not fl that th lack of monadic library functions is du to poor prformanc on th part of library dvloprs. Similarly, th lack of a standard linkd list library in C99 can asily b blamd on th absnc of a polymorphic typ systm in th languag. In C99 thr is no way to xprss a typ such as lngth :: [a] Int, so programmrs tnd to roll thir own list structurs vry tim. A list of intgrs could b dfind as: struct ListInt { int x; struct ListInt* xs; }; In C99, functions ovr lists can b succinctly writtn as forloops: int lngthlistint ( struct ListInt* list) { int ln = 0; for (struct ListInt* nod = list; nod!= 0; nod = nod>xs) ln ++; rturn ln; } This works, but th programmr must thn dfin a sparat vrsion of ach list function for vry lmnt typ in thir program. Eithr that or abus th void* typ. Mor commonly, th dfinitions of simpl list functions ar typd out again and again, and mor th complx ons ar dfind with macros. A library writr cannot hop to crat functions for vry possibl lmnt typ, so w ar lft with no standard list library at all. Similarly, Haskll dos not provid a convnint way to gnrat both monadic and nonmonadic vrsions of a function, nor dos it provid an asy way to abstract ovr th diffrnc. Programmrs ar taught not to cut and past cod, so w ar lft with on vrsion of ach function but not th othr. Monad transformrs produc a layrd structur Monad transformrs [LHJ95] offr a convnint way of constructing a monad from svral smallr componnts, ach providing a diffrnt fact of its computational bhavior. Th rsulting data typ is known as a monad stack, du to
46 46 CHAPTER 1. INTRODUCTION th layrd way of constructing it. For xampl, vrsion 0.8 of th XMonad window managr uss a stack providing configuration information, intrnal stat and IO: nwtyp X a = X (RadrT XConf (StatT XStat IO) a) This typ is constructd by applying two monad transformrs, RadrT and StatT to th innr monad, IO. StatT xtnds IO with th ability to accss th XStat rcord typ, whil RadrT xtnds it with th ability to accss configuration information stord in th XConf rcord typ. Th implmntation of DDC s typ infrncr also uss a monad stack built with StatT and IO. In this cas, StatT supplis accss to th currnt stat of th algorithm whil IO provids a dstructivly updatabl array usd to rprsnt th typ graph. Monad transformrs sav th programmr from th nd to manually dfin thir own monads. Without such a mchanism thy would b forcd to rdfin primitiv functions lik bind and rturn ach tim a nw monad was ndd. As mntiond by Filinski [Fil94], th structur cratd by monad transformrs is distinctly hirarchical. In th X typ abov, IO is on th bottom, followd by StatT, followd by RadrT. This fact is rflctd in programs using it, as xplicit lifting functions must b usd to mbd computations xprssd in lowr monads into th highr structur. For xampl, th liftio function taks an IO action and convrts it into an quivalnt action in a monad which supports IO: liftio :: MonadIO m IO a m a For both XMonad and th DDC typ infrncr, th fact that monad transformrs produc a layrd structur is of no bnfit. Actions which supply configuration information, altr th intrnal stat of th program, and intrfac with th outsid world ar all commutabl with ach othr. On th othr hand, monads which xprss computational bhaviors such as backtracking and xcptions ar not similarly commutabl [Fil94]. Th XMonad sourc cod of Novmbr 2008 includs a binding which rnams liftio into th shortr io. A hand count by th author yildd 57 sparat uss of this lifting function, vrsus 65 occurrncs of th kyword do. If it wr possibl to collaps th monad stack into a singl layr thn w could avoid this xplicit lifting of IO actions. Of cours, w would want to achiv this without losing th bhavioral information prsnt in thir typs. Th ffct typing systm w shall discuss in th nxt chaptr dos just this. Intrstingly, from th high occurrnc of IO lifting functions and th prvasivnss of th X typ, w s that XMonad is in fact an imprativ program. It is imprativ in th sns that its procssing is wll mixd with IO, though not in th sns that it is basd around th dstructiv updat of a global stor. Although it is writtn in a purly functional languag, this dos not chang th fact that th construction of a window managr is an inhrntly statful and IO drivn problm, with a statful and IO drivn solution.
47 1.7. REF TYPES INVITE LARGE REFACTORISATION EXERCISES Rf typs invit larg rfactorisation xrciss SML obstinatly supports dstructiv updat, though its us is rstrictd to arrays and to data structurs that incorporat th spcial Rf typ. Th following functions ar usd to program with Rf. W us Haskll syntax for consistncy. nwrf :: a Rf a radrf :: Rf a a writrf :: Rf a a () nwrf taks an objct and rturns a frsh mutabl rfrnc to that objct. radrf taks a rfrnc to an objct and rturns th objct. writrf taks a mutabl rfrnc, a nw objct, and updats th rfrnc to point to th nw objct. Although srvicabl, tying updat to a particular typ constructor forcs th programmr to dcid which parts of thir structurs should b updatabl whn thir typs ar dfind. On th surfac this may sm rasonabl, but considr th dsign of a simpl library for a conslist. W start with th data typ: data List a = Nil Cons a (List a) W would now lik to dfin a st of functions which oprat on valus of this typ. On such function is indx, which rturns th lmnt at a particular position in th list: indx :: Int List a a indx 0 (Cons xxs) = x indx n (Cons xxs) = indx (n 1) xs indx Nil = rror... Suppos that onc w hav finishd this dfinition w thn want a function rplac that dstructivly rplacs th lmnt at a crtain position in th list. This rquirs th had of th Cons cll to b updatabl, so w insrt a Rf constructor into th data typ: data List a = Nil Cons (Rf a) (List a) Th dfinition of rplac is thn: rplac 0 (Cons rx xs) rplac n (Cons rx xs) = writrf rx = rplac (n 1) xs This is all wll and good, but as th List typ has changd w nd to go back and chang th dfinition of indx to rad th lmnt out of th rfrnc bfor rturning it. W must also inspct vry othr function w v dfind that uss th List typ. If a function accsss th had of a Cons cll thn it nds a call to radrf as wll. indx :: Int List a a indx 0 (Cons x xs) = radrf x indx n (Cons x xs) = indx (n 1) xs indx Nil = rror...
48 48 CHAPTER 1. INTRODUCTION Concptually, th opration of indx hasn t changd at all. indx still rcursivly stps through th list until it finds th dsird lmnt, thn rturns it. Howvr, w had to modify its dfinition bcaus w addd a function to th library which rquirs a crtain proprty (mutability) of th data structur, vn though indx itslf dosn t mak us of that proprty. Notic that th modifications rquird ar purly mchanical in natur, and that this problm is vry similar to monad crp discussd in th prvious sction. Suppos that aftr dfining a fw mor functions, w dsir a nw on calld insrtat. This function will mak us of dstructiv updat to insrt a nw lmnt at a particular position in th list. This rquirs th tail of ach Cons cll to b mutabl as wll, so w hav to chang th data typ onc again: data List a = Nil Cons (Rf a) (Rf (List a)) Th dfinition for insrtat is: insrtat :: Int a List a () insrtat Nil = rror... insrtat 0 (Cons r rxs) = lt xs = radrf rxs in writrf rxs (Cons (Rf ) (Rf xs)) insrtat n (Cons r rxs) = lt xs = radrf rxs in insrtat (n 1) xs Onc again, w must go back and inspct vry function w hav dfind so far to mak sur that all accsss to th tail of a Cons cll first rad th rfrnc. Our indx function is now: indx :: Int List a a indx 0 (Cons x xs) = radrf x indx n (Cons x xs) = indx (n 1) (radrf xs) indx Nil = rror... Mor mchanical modifications hav wastd mor programming tim. What can b don to allviat this problm? Th cntral activity of programming is dfining data structurs and writing functions which oprat on thm. Unlss a programmr is simply rplicating a program thy hav writtn bfor thn thy ar unlikly to know xactly which parts of thir structur should b wrappd in Rf and which can b lft bar. If w dfin all structurs to b mutabl from th start thn w can avoid having to rinspct xisting functions as th data typ volvs, though this would rquir many suprfluous calls to radrf. In addition, a naiv implmntation of Rf would simply insrt rfrnc objcts into th runtim data structur, so w would pay a prformanc pnalty as wll: C R C R R R I 1 I 2
49 1.8. PRACTICAL LIMITATIONS OF LAZY EVALUATION 49 On th othr hand, if w dfin our data typs without using Rf, thn structurs of that typ can not b updatd vr. If thos structurs ar providd by a library and a clint programmr dcids thy actually do want to prform an updat, thn it is likly that th only practical solution will b to dfin thir own typs and writ cod that duplicats functionality alrady prsnt in th original library. This is xactly th cas with SML lists and tupls, which ar all immutabl. Although som cod duplication can b allviatd by using similar modul signaturs for mutabl and immutabl objcts, th fact that th two hav fundamntally diffrnt typs only srvs to ncourag it. If only th immutabl vrsions ar providd in bas libraris, thn usrs ar ncouragd to us ths structurs in cass whr a mutabl on would b mor appropriat. This in turn rlgats mutabl structurs to b scond class citizns of th languag. 1.8 Practical limitations of lazy valuation Th following xampl from [GS01] dmonstrats th subtlty of spac usag in lazy languags: lt xs x y in x + y = [1..n] = had xs = last xs W will us GHC as a rfrnc point for th bhavior of a ral implmntation. Whn compild with no optimisations, th xcution of this program will crat a thunk for ach ltbinding bfor valuating th addition [PJ92]. If w assum that addition dmands its argumnts lft to right, th thunk for x will b forcd first, rsulting in th valu 1. This thunk will thn b ovrwrittn with its valu, which liminats th containd rfrnc to xs. Th valuation of y ntails th construction and travrsal of th list [1..n] until w rach its last lmnt. In a garbag collctd implmntation this can b don in constant spac bcaus last dos not hold a rfrnc to a list cll onc it has travrsd it. Howvr, if w chang th ordr of argumnts to addition th program consums spac proportional to th lngth of th list: lt xs x y in y + x = [1..n] = had xs = last xs In this cas, th valuation of y ntails th construction of th ntir list. Th list cannot b garbag collctd until th thunk for had xs has bn forcd, bcaus it contains a rfrnc to its first lmnt. This xampl shows that only slight modifications to a program can rsult in dramatic diffrncs in spac usag. All strictnss analyss ar incomplt Th run tim prformanc of many lazy programs can b improvd by xploiting th strictnss proprtis of functions. A function f is strict if and only if
50 50 CHAPTER 1. INTRODUCTION f [PJ87]. This can aris for two rasons. If f inspcts th valu of its argumnt whn it valuats, thn it will divrg if its argumnt dos. Also, if f rturns its argumnt uninspctd, thn th rsult will b if th argumnt is. If nithr is th cas thn th function is nonstrict. For xampl, th choos function is strict in its first argumnt but not th othrs: choos b x y = if b thn x ls y Whn this function is applid to its thr argumnts, it will always rquir th valu of b. On th othr hand, ithr x or y may b rturnd, but not both. A similar xampl is th first function which rturns just its first argumnt whil discarding th scond: first x y = x As x is passd through to th rsult, it is strict in this argumnt. As th function body maks no rfrnc to y, it is nonstrict in that on. Strictnss analysis [BHA85, WH87, SR95] is usd to rcovr th strictnss proprtis of functions. A compilr can us this information to convrt a callbynd program into a mor callbyvalu vrsion without changing its maning. For an implmntation such as GHC, this amounts to idntifying th ltbound variabls which ar passd to strict functions, and valuating thos bindings as soon as thy ar ncountrd, instad of building thunks. For many lazy programs, spcially thos prforming lots of numric computation, valuating strict bindings arly can rsult in substantial prformanc improvmnts. Early valuation savs th allocation and initialisation of thunks, as wll th nd to updat and garbag collct thm onc thir valus ar dmandd. In practic, a compilr should rduc strict bindings to wak had normal form (whnf) [PJ87] only. Rduction to whnf liminats outr rdxs whil allowing thunks to b prsnt dp within data structurs, such as at th tail position of lists. To s why, considr our first xampl again: lt xs x y in x + y = [1..n] = had xs = last xs Th fact that addition and had ar strict in thir argumnts implis that th xs, x, and y bindings can b valuatd as soon as thy ar ncountrd. If w valuat [1..n] to whnf w construct just th outr Cons cll and th program runs in constant spac. Howvr, if w wr to fully valuat [1..n] bfor taking its had, thn th program will consum spac proportional to this list. Lik all compil tim analyss, strictnss analysis is ncssarily incomplt. This is plainly obvious from our choos xampl: choos x y z = if x thn y ls z Suppos w writ an xprssion which uss choos to print on of two rsults: putstr (choos b xp1 xp2)
51 1.8. PRACTICAL LIMITATIONS OF LAZY EVALUATION 51 putstr is strict in its argumnt, yt th qustion of whthr it prints xp1 or xp2 can only b answrd by knowing th valu of b. In gnral, th valu of b cannot b dtrmind at compil tim. Apart from bumping up against th halting problm, this fact is obvious if w considr a situation whr b is drivd from usr input. In a typical Haskll program, many functions ar concrnd with procssing algbraic data. Such functions ar usually writtn with pattrn matching, or with a casxprssion that xamins th outr constructor of th input valu. casxprssions ar a gnralisation of ifxprssions, so w hav th sam problm as with th choos xampl abov. In gnral, for a particular function call w can not know what th outr constructor of its argumnt will b, which dfats strictnss analysis in a similar mannr. Spac laks can b lgantly cratd with mapaccuml In a lazy functional program, a spac lak is cratd whn unvaluatd thunks rfrnc a larg amount of data, prvnting it from bing rclaimd by th garbag collctor. This can b countr intuitiv at first glanc. How can an unvaluatd xprssion us mor spac than its actual rsult? Considr th xprssion (rang 1 100) which builds th list [1..100]. W would xpct a thunk rprsnting th application of rang to its argumnts 1 and 100 to us much lss spac than a fully valuatd list of 100 lmnts. Howvr, considr th cas whr on of th argumnts is a variabl instad of an intgr valu. A thunk which rprsnts th application (rang 1 n) contains a rfrnc to th objct n, and as long as th thunk is liv this objct cannot b garbag collctd. Suppos n is also a thunk, and that it rfrncs a larg amount of data. Whil our original list rmains unvaluatd, this data rmains liv. It may b that th program s prformanc would b improvd by forcing th list to b fully valuatd as soon as possibl. This would allow th garbag collctor to rclaim spac usd by thunks and objcts that ar no longr rfrncd. Of cours, whthr this would work in practic is vry application spcific. Factors to considr includ th siz of th rsulting list vrsus th siz of th rtaind data, whthr th ntir list valu will actually b usd by th program, whthr th liv data is also hld liv by othr xprssions, cach and main mmory sizs, and so on. Spac laks ar spcially common in lazy programs which ar basd around stat and stat transformrs. For ths programs, xcution is dividd into a squnc of stps, with a wlldfind stat bfor and aftr ach stp. Th function f taks th old stat, som input x and producs th nxt stat and som output y: x0 x1 stat 0 f stat 1 f stat2 y 0 y 1
52 52 CHAPTER 1. INTRODUCTION In Haskll, this pattrn of computation is xprssd by th function mapaccuml which has typ: mapaccuml :: (stat x (stat, y)) stat [x] (stat, [y]) mapaccuml taks a transition function, an initial stat, a list of inputs and producs th final stat and th list of outputs. Many programs us a similar pattrn of computation, though not all xprss it with mapaccuml. Considr an intractiv program such as a computr gam. W could imag that stat is a dscription of th gam world, x is th usr input, y is a dscription of th usr display, and f is th gam logic which computs a nw stat and display basd on th input. For a computr gam, th stat could consist of th playr s position, surrounding trrain, currnt nmy positions, rmaining ammo, and so on. A spac lak is cratd whn th program fails to dmand th ntir y valu aftr ach stp. Suppos that y includs th playr s scor at ach stp of th gam, but this information is not displayd in ral tim. Although th scor at ach stp might b xprssd by a singl intgr, as it dpnds on th currnt gam stat at last past of this structur must b kpt liv until th intgr is fully valuatd. If a usr plays th gam for an hour, with a nw stat gnratd 30 tims a scond, thn this can quat to a substantial amount of rtaind data. Additionally, whn th scor is a nontrivial function of th currnt stat, rasoning about th amount of spac wastd bcoms intractabl. In Haskll, th only practical way to dal with a complx lak is to writ so calld dpsq functions that manually travrs ovr an ntir structur to nsur it is fully valuatd. Othr tchniqus can hlp, such as having th garbag collctor prform lak avoiding projctions [Wad87], but to fully cur laks th programmr must nsur that all structurs which should b valuatd actually ar. Most dpsq functions ar writtn to liminat all rdxs in a structur, and ar thrfor quivalnt to th rduc to normal form stratgy from [THLPJ98]. A builtin dpsq function was proposd for Haskll, th succssor standard to Haskll 98 [Has08], but as of Novmbr 2008 it has not bn implmntd in GHC. It is also possibl to add strictnss annotations to usr dfind data typs. Ths annotations prvnt thunks bing cratd at crtain positions in th structur, but cannot b asily b addd to library dfind typs such as Map and List. Cas study of a spac lak A stat basd spac lak was ncountrd whil th author was dvloping a graph coloring rgistr allocator [Cha04, SRH04] for GHC 6.7. Th algorithm is basd around a graph whr ach nod rprsnts a program variabl. An dg btwn two nods rprsnts a constraint that thos two variabls can not b assignd to th sam rgistr. Th goal is to assign rgistrs, visualisd as colors, to ach of th nods in a way that satisfis th constraints, whilst using only th availabl st of rgistrs. Th algorithm procds by xtracting a constraint graph from th cod undrgoing rgistr allocation, and thn attmpting to color it. If this is not possibl with th availabl colors (rgistrs) thn th algorithm modifis th cod to stor som variabls on th stack instad of rgistrs, and tris again. For nonpathological programs this procss should convrg within thr or four itrations.
53 1.8. PRACTICAL LIMITATIONS OF LAZY EVALUATION 53 Graph coloring rgistr allocation is a stat basd algorithm. Th stat consists of th currnt vrsion of th cod undrgoing allocation, along with th constraint graph. As opposd to th mapaccuml function, thr is no xtra prstp input to th stat transition function corrsponding to th x valus in th prvious diagram. Th output y valus corrspond to graph profiling information, such as th numbr of colord vrsus uncolord nods rmaining aftr ach stp. Whn th allocator was bing dvlopd w wr wll awar of spac laks and thir causs. Th intndd opration of th algorithm was to build a complt constraint graph, attmpt to color it, and if that faild to build a nw graph and lav th old on for th garbag collctor. W knw that if th program rtaind any rfrncs to th profiling information for old graphs, thn this would prvnt thos graphs from bing garbag collctd. If this happnd w would hav a spac lak, so w mad considrabl ffort not to rtain profiling information unlss it was xplicitly rqustd. W rasond that if th usr rqustd profiling information thn thy would not mind if th allocator ran a littl slowr du to rtaind data, as this was not a common opration. Howvr, onc it was writtn, an xamination of hap spac [SPJ95] usd by th allocator rvald th following: ghc B/hom/tbnl/dvl/ghcHEADprof fhardwirlibpaths O2 fr 72,787,117 byts x sconds Mon Sp 24 11: byts 22M 20M 18M 16M 14M 12M 10M 8M 6M 4M 2M 0M sconds (906)/BuildGraph/RgAlloc/... (848)TypchckRnam (893)CorToStg (853)/bin_tycldclsTypch... (863)/SimplTopBinds/Simpli... MAIN (887)CorTidy (904)/RgAlloc/NativCodG... (905)/ColorGraph/RgAlloc/... (896)CodGn (892)CorPrp (862)/OccAnal/SimplifyCor... (856)/bin_rulsTypchckR... (895)/ProfMassag/Stg2StgC... (850)/bin_xportsTypchck... (613)PrlInfo.CAF (908)/gnMachCod/NativCo... (527)Parsr.CAF (882)/StranalCor2Cor OTHER Th two larg spiks in spac usag that appar around 6 and 7 svn sconds ar dirctly attributabl to th rgistr allocator. This is whn prforming allocation for th SHA1.hs modul from th darcs sourc cod. Objct typ profiling rvald that most of th spac was takn up by thunks rprsnting function applications. As to th xact caus of th lak, w ar not sur. W could imagin that whn th compilr mits a particular compild machin instruction, this action dmands th rsult of rgistr allocation for that instruction. Th rgistrs allocatd to a particular instruction dpnd on what othr rgistrs ar assignd to surrounding instructions. W could thn imagin a sction of graph in th final stat of th allocator bing dmandd. This in turn might dmand largr sctions of graph from prvious stats, along with parts of th various intrmdiat vrsions of assmbly cod that w trid to find allocation solutions for.
54 54 CHAPTER 1. INTRODUCTION Good rsarch has bn don on formally analysing th spac usag of callbynd programs [GS01, BR00]. Howvr, trying to rason about th xact spac bhavior of a thr thousand lin program, compild with a production compilr that incorporats tns, if not hundrds of individual optimisations is anothr mattr ntirly. W plainly admit that our rasoning is littl but inspird guss work. What w do know is that using a dpsq function to forc th graph to b fully constructd bfor coloring curd th worst of th problm. This rsult was obtaind through xprimntation and frqunt consultation with th hap usag profil. Th following profil is for th final vrsion: ghc B/hom/tbnl/dvl/ghcHEADprof fhardwirlibpaths O2 fr 54,421,971 byts x sconds Mon Sp 24 11: byts 10M 8M 6M 4M 2M 0M sconds (848)TypchckRnam (893)CorToStg (906)/BuildGraph/RgAlloc/... (853)/bin_tycldclsTypch... (863)/SimplTopBinds/Simpli... MAIN (887)CorTidy (904)/RgAlloc/NativCodG... (905)/ColorGraph/RgAlloc/... (896)CodGn (892)CorPrp (862)/OccAnal/SimplifyCor... (856)/bin_rulsTypchckR... (895)/ProfMassag/Stg2StgC... (908)/gnMachCod/NativCo... (850)/bin_xportsTypchck... (613)PrlInfo.CAF (907)/rgLivnss/NativCo... (873)/FloatInwardsCor2Cor OTHER In this vrsion th larg spiks in spac usag hav bn rducd, rsulting in a pak usag around half of th unforcd vrsion. W conjctur that th rmaining cost attributd to(906)/buildgraph/rgalloc is mostly du to th lgitimat construction of th graph during allocation, though onc again w can not b sur. W dmd th profil accptabl, and movd on to othr things. W glan svral points from this xprinc. Firstly, although a programmr may writ what thy fl is a stat basd program, if it is xprssd in a lazy languag thn it may not bhav that way at runtim. Scondly, th xact caus of spac laks in larg lazy programs can b vry hard to rason about. That bing said, although th problm may b hard to charactris, th solution is wll undrstood. Forcing thunks to valus liminats thir containd rfrncs and frs up objcts for th garbag collctor. On a philosophical not, w fl thr is an immns practical diffrnc btwn optimisation and control. Having a larg numbr of optimisations in a compilr is all wll and good, but if th compild cod still dosn t run fast nough thn th languag (and/or compilr) must provid nough additional control for th programmr to stp in and fix th problm. If this is not possibl thn th programmr will b forcd to us a diffrnt languag, and if that happns mor than onc thn thy will b unlikly to choos th sam systm for thir nxt projct.
55 1.9. A WAY FORWARD 55 In this cas w wr abl to fix th problm. Howvr, w do not th irony of writing xtra cod to manually forc th valuation of xprssions that w did not intnd to b suspndd in th first plac. W cannot, off hand, think of a singl plac in th rgistr allocator cod whr lazy valuation was usd for a usful purpos. W ar not suggsting that lazinss is nvr usful, mor that it dpnds on th application. For a slction of programs from th nofib bnchmark suit [Par92], Harris [HS07] givs th prcntag of allocatd thunks that wr actually valuatd at runtim. In th 20 programs considrd, 9 ndd up valuating at last 99% of thir thunks, 14 valuatd at last 90%, whil only on valuatd lss than 80%. Th fact that a program valuats almost all of its thunks dos not imply it dos not mak us of lazinss. For xampl, if w us lazinss to valuat th xprssion sum [0..100] in constant spac, thn all th thunks in th list will b forcd. Th application of sum to a Cons cll dmands th lmnt valu as wll as th tail of th cll. Howvr, th fact that a program valuats 99% of its thunks would suggst that it is not crating lazy lists whr th spin is valuatd but th majority of th lmnts ar not. It would also suggst that th program is not using th sxir lazy structurs, such as infinit gam trs [Hug89]. 1.9 A way forward Discipl allows dstructiv updat and lazy valuation to b prsnt in th sam languag. W do this whil prsrving th ovrall structur of typs, and whil kping most of th nic algbraic proprtis associatd with purly functional languags. By prsrving th structur of typs w hop to avoid th rfactoring xrciss discussd arlir. W do not rul out support for stat monads or Rf typs, rathr w dsir a systm which dos not rquir thm to writ most programs. W us a typ basd mutability and ffct analysis. Th analysis dtrmins which objcts in th program might b dstructivly updatd, and which ar guarantd to rmain constant. Using this information, th compilr can prform optimisations on th pur parts of th program whil laving xprssions with intrfring computational ffcts in thir original ordr. This stratgy is similar to that takn by Tolmach [Tol98] though w us a SystmF styl cor languag instad of a monadic on. Th cor languag uss a witnss passing mchanism to manag mutability and ffct constraints, similar to that usd to manag typ quality constraints in SystmFc [SCPJD07]. Although th xtra mutability and ffct information is visibl in sourc typs, it can usually b lidd by th programmr, and is thrfor not an undu burdn. Th dfault valuation mthod is callbyvalu. This maks it asir to construct an fficint implmntation on currnt hardwar, as wll as liminating an important sourc of spac laks. Th programmr may manually suspnd function applications whn dsird, and th runtim systm will automatically forc thm as ndd. This is unlik library basd implmntations of lazinss in languags such as O Caml. Ths implmntations rquir th us of xplicit forcing functions, as wll as changing th typs of lazy valus.
56 56 CHAPTER 1. INTRODUCTION W also us our analysis to dtct whn an objct is guarantd not to b a thunk. Our implmntation of lazy valuation is likly to b slowr than a nativly lazy systm such as GHC. Howvr, nonlazy cod should not suffr a substantial prformanc pnalty compard with othr dfault strict languags such as ML and C. Our typ systm uss a typ class basd mchanism to attach purity, mutability, constancy, lazinss and othr constraints to data typs. This allows functions to b polymorphic in thos attributs and not rquir th ovrall structur of typs to b changd. W also us this mchanism to dtct whn th combination of lazinss and dstructiv updat in th sam program might giv a rsult diffrnt to th callbyvalu cas. W flag ths as typ rrors and assrt that our languag is still pur by Sabry s dfinition [Sab98]. Our languag includs support for rcord typs, and w us typ dirctd fild projctions which prmit fild nams to b in rcordlocal scop. W would lik for it to b possibl and practical to writ fficint programs in our languag. Finally, w would lik it to b attractiv to popl who don t actually car that much about th philosophy of functional programming. W follow Stl and Sussman [SS76], and Knuth [Knu74] in that a languag dsignr s mphasis should b on hlping th programmr solv thir particular problms. Our aim is not to sparat languag faturs into good and bad, only to offr sharp tools in a hop thy will b usful.
57 Chaptr 2 Typ Systm W hav sn that ML styl rfrncs ar clumsy to work with bcaus thir us changs th structur of typs. This causs mutabl valus to b typincompatibl with constant valus, and invits larg rfactorisation fforts whn writing cod. Could thr b a bttr way? In a traditional imprativ languag such as C, Pascal or Java, th programmr is fr to updat data as thy s fit, and th typ of mutabl data is not rquird to b structurally diffrnt from that which rmains constant. Howvr, if w wr to allow th programmr to updat any objct in th systm, without tracking it carfully, thn w would hav to assum that vry objct was mutabl. This would dramatically limit our ability to prform optimisations on th intrmdiat cod. With this in mind, w first considr th form of updat w wish to support, and thn sk a way of tracking which objcts it is applid to. W intnd this chaptr to srv as a gntl introduction to our typ systm, and to th concpts involvd. For this rason w hav rfraind from starting with a formal dscription of our languag or its typing ruls. This information is givn in
58 58 CHAPTER 2. TYPE SYSTEM 2.1 Updat without imprativ variabls In a typical imprativ languag th syntax to bind a variabl is th sam as that usd to updat it. This conflats th two issus. Considr th smantics of th following program fragmnt: x = 5 Radrs with a mor functional background would likly rad this as x has valu 5. Radrs with a mor imprativ background could qually rply x is bing updatd to valu 5. With th diffrnc btwn boxd and unboxd intgrs in mind, th fragmnt could also man x is a pointr to an objct, and it is th pointr which is bing updatd or prhaps x points to an objct, and it is th objct which is bing updatd. Ths thr radings for updat ar shown in th following diagram, whr th valu is bing updatd from 3 to 5. x unboxd updat rdirction boxd updat : x : : 5 x 3 5 x := 5 In th first two cass it is th local valu of x that is bing changd. In ths cass w call x an imprativ variabl, and w do not support this form of updat in our languag. Howvr, in th last cas only th objct pointd to by x changs. W support this option and writ x := 5 to distinguish it from th syntax for binding which is simply x = 5. Why do it this way? Firstly, w intnd to support updat by th inclusion of functions such as: updatint :: Int Int () updatchar :: Char Char () Th first paramtr of ths functions is th objct to b updatd, and th scond is th sourc of th nw valu. W us (:=) as an ovrloadd updat oprator, so x := 5 can b rwrittn as updatint x 5. In light of this, w rstrict updat to objcts for two main rasons. Th first is that in our implmntation w us local unboxing [Lr97] to support fficint numric computation, and w dsir intrmdiat rsults to b hld in th rgistr st whrvr possibl. If w prmit local valus to b updatd, thn w would also want to pass thm by rfrnc, so that calld functions could updat thm via this rfrnc.
59 2.1. UPDATE WITHOUT IMPERATIVE VARIABLES 59 Considr thn an unboxd vrsion of updatint, and som C cod that uss it: void troubl(void) { int x, y; }... x = 3; y = 5; updatintunboxd (&x, y);... This cod is valid, though dply troubling to a C compilr. As x is passd by rfrnc, its valu must b hld on th stack instad of in th rgistr st, othrwis w couldn t construct a pointr to it. Mor sriously, in rgards to sparat compilation, a C compilr would b unabl to guarant that this pointr bcoms unrachabl bfor troubl rturns, losing th stack fram and th storag for x. As in [Hn02] w hav obsrvd GCC to disabl a numbr of lowlvl optimisations whn compiling cod which uss pointrs to automatic variabls. W could prhaps implmnt local updat as a primitiv of th languag, but w avoid this option du to th xtra complxity and concptual mismatch rlativ to objct updat. Anothr rason for not supporting imprativ variabls, and prhaps a mor convincing on for radrs who don t spnd all thir tim writing compilrs, is that it simplifis th typ systm. If w only support updat of th objcts pointd to by our variabls thn w only nd to rason about th mutability of ths objcts, and not of th variabls as wll. This can b contrastd with [Od91] and [SSD08b] which rason about both.
60 60 CHAPTER 2. TYPE SYSTEM 2.2 Rgion Typing Rgions and aliasing A rgion is th st of stor locations whr a particular objct may b prsnt at runtim. W us rgions to rason about th mutability and aliasing of objcts. Th following diagram shows a stor containing a numbr of objcts, dividd into two rgions. This diagram is intndd to b suggstiv only. Many systms bsids our own mak us of rgions, and a particular systm may allow thm to b disjoint aras of th stor, includ fr spac, grow with tim, b hirarchical, includ only subcomponnts of an objct, and so on obj1 obj2 obj3 obj4 } ρ obj5 obj6 } ρ 2 W us ρ n to dnot rgion handls. A rgion handl can b thought of as a runtim idntifir for a particular rgion, or prhaps an indx into a tabl that dscribs th xtnt of a rgion. For th simpl systm in th diagram, w could trat a rgion as a st of alignd, 4byt words. In this cas our rgion handls could b dfind as: ρ 1 = {1234, 1238, 1246, 1250} ρ 2 = {1682, 1690} At compil tim w will not ncssarily know how th objcts in th stor will b arrangd, or how to dfin th rgion handls. W would lik to writ functions that oprat on objcts from any rgion, indpndntly of how thy ar arrangd. For this purpos w introduc rgion variabls, which w us to bind rgion handls. Rgion variabls ar idntifid as r n in this txt. Thr ar concptual similaritis btwn rgion and valu information. Considr th following statmnts of valu: 23 < > a = 23 In th first statmnt, th numral 23 rprsnts an objct in th stor that includs a particular bit string. In th scond statmnt w hav usd a valu variabl to bind th numral 23. W can think of rgions as bing akin to th objcts in th stor, rgion handls bing akin to numrals, and rgion variabls bing lik valu variabls. In this sns, rgions ar physical things,
61 2.2. REGION TYPING 61 rgion handls ar dscriptions of thm, and rgion variabls ar plac holdrs for th handls. Clarly though, rgions and valus ar diffrnt kinds of things. As pr tradition w us a star * to dnot th kind of valu typs. Rgion kinds ar dnotd by a prcnt sign % 1. In th concrt syntax w also us % as a namspac qualifir, writing %rn in plac of r n. This hlps th parsr, as wll as bing convnint for syntax highlighting txt ditors. Unlik th systm of Toft and Birkdal [TB98], ours dals only with rgion variabls and not with th dfinition of rgion handls, or th layout of th stor. Thir systm uss rgions to manag th allocation of fr spac at run tim, whr ours uss rgions as part of an analysis to guid compil tim cod optimisations. Our analysis is typ basd. W add rgion variabls to all typ constructors which corrspond to data objcts that can b usfully updatd. This includs constructors lik Int, Bool and List, but not th function constructor ( ) or th unit constructor (). Th function constructor dos not nd on bcaus th valu of a function cannot b updatd at runtim. Th unit constructor dos not nd on bcaus thr is only on possibl unit valu. For xampl, a list of charactr pairs could hav typ: pairs :: List r 1 (Pair r 2 (Char r 3 ) (Char r 4 )) pairs = [MkPair g o, MkPair b y,...] In a top lvl signatur such as this, if two typ constructors hav diffrnt rgion variabls, such as Char r 3 and Char r 4, thn th corrsponding valus ar guarantd to b rprsntd by diffrnt runtim objcts. Howvr, in gnral ths objcts may alias. For xampl, hr is a function which crats a pair of intgrs: intpair :: r 1 r 2 r 3. Int r 1 Int r 2 Pair r 3 (Int r 1 ) (Int r 2 ) intpair x y = MkPair x y As th rgion variabls r 1, r 2 and r 3 ar quantifid in th typ signatur, w may pass th sam intgr objct for both argumnts of th function: fiv :: Int r 5 fiv = 5 pairoffivs :: Pair r 4 (Int r 5 ) (Int r 5 ) pairoffivs = intpair fiv fiv Hr, th rgion variabls r 1 and r 2 of intpair hav bn instantiatd to r 5. This tlls us that both lmnts of th pair may rfr to th sam hap objct, and thy will in this cas. Not that in th body of intpair, th valu variabls x and y may also rfr to th sam objct bcaus w can pass th sam on for both argumnts. In th typ of pairoffivs, th rgion variabl r 4 is frsh bcaus th valuation of intpair will allocat a nw objct to rprsnt th pair. Frshly allocatd objcts do not alias any xisting objcts. Aliasing information is of fundamntal importanc whn rasoning about dstructiv updat, as any rad or writ actions prformd on objcts in on rgion 1 Pictorially, % is two circls sparatd by a lin, a mnmonic for this, or that
62 62 CHAPTER 2. TYPE SYSTEM will not b visibl to th parts of a program that only dal with anothr. To us th languag of [Ry78], actions prformd on disjoint rgions do not intrfr. In many cass th rgion variabls attachd to diffrntly namd typ constructors will b distinct, but this is not rquird in gnral. In our pairs xampl, all th list constructor clls ar in on rgion, and all th pair clls ar in anothr: r r r r C C... P P g b o y Stting r 1 = r 2 would b quivalnt to placing th list clls in th sam rgion as th pair clls. Lik Talpin and Jouvlot s original work [TJ92b], our concpt of a rgion is simply a nam for a st of locations. W somtims find it usful to visualis rgions as colours of paint, which w apply to data objcts stord in th hap. Stting r 1 = r 2 corrsponds to painting all th list and pair clls th sam colour. Thy will b hardr to distinguish aftrwards, corrsponding to a wakning of our analysis, but it will caus thm no harm. As rgion variabls ar providd as paramtrs to typ constructors, th kinds of th constructors rflct this. Char taks a rgion and producs a typ, whil List and Pair both tak a rgion, a typ and produc a nw typ: Char List Pair :: % :: % :: % Rgion classs Whn a valu is mutabl w add mutability constraints to th rgion variabls in its typ. For xampl, if w wantd to updat th charactrs in a string w would giv it typ: str :: Mutabl r 2 List r 1 (Char r 2 ) Th constraint Mutabl r 2 is a rgion class. Rgion classs ar similar to th valu typ classs in Haskll [HHPJW96], such as Show and Eq. With valu typ classs, th typ constraint Eq a rquirs a to b a typ that supports quality. Similarly, th rgion constraint Mutabl r 2 rquirs r 2 to corrspond with a rgion that supports updat. Whn discussing our systm w us th word typ to rfr to all th information in a signatur, including valu typ information such as List and Char, any constraints on variabls, rgion information, as wll as th ffct and closur information w will discuss latr. For this rason w also rfr to both
63 2.2. REGION TYPING 63 rgion classs and valu typ classs as simply typ classs. Not that th programmr usually dosn t hav to provid this additional information in typ signaturs. Most can b rconstructd by th typ infrncr. This is discussd furthr in and Rturning to th signatur of str, w call trm on th right of th, th body of th typ. W call th valu portion of th body is its shap, bcaus this information dscribs th ovrall structur of th objct in th stor. As our typs oftn contain a larg numbr of constraints, w usually writ thm aftr th body, instad of bfor it as in Haskll: str :: List r 1 (Char r 2 ) Mutabl r 2 Th is pronouncd with, and is writtn as : in th concrt syntax. Th diffrnc btwn th abov typ and th original prfix form is purly syntactic, and our compilr accpts both. In th abov typ, no constraint has bn placd on r 1. If w wish to updat th spin of th list as wll as its charactrs, thn this rgion must also b mutabl. Multipl constraints ar sparatd by commas: str :: List r 1 (Char r 2 ) Mutabl r 1, Mutabl r 2 Bing abl to updat th spin of a list is usful for oprations such as insrting a nw lmnt into th middl of th list, as it allows us to chang th tail pointrs of xisting cons clls. On th othr hand, if w wish to prvnt updats to th spin w could us th constraint Const r 1 to nforc this: str :: List r 1 (Char r 2 ) Const r 1, Mutabl r 2 As thr ar two rgion variabls in this typ, both th spin and lmnts can hav diffring mutabilitis. Attmpting to constrain a rgion variabl to b both Mutabl and Const rsults in a compil tim typ rror Functions, allocation and nonmatrial rgions In our systm th succssor function has th following signatur: succ :: (r 1 :: %) (r 2 :: %). Int r 1 Int r 2 In this typ w hav includd th kind of ach rgion variabl, but as in Haskll w can omit this information if it can b asily infrrd. Th variabls r 1 and r 2 must hav rgion kind bcaus thy ar usd as paramtrs to th Int constructor, so w instad writ: succ :: r 1 r 2. Int r 1 Int r 2 Starting with th Int r 1 trm on th lft of th arrow, th fact that r 1 is quantifid indicats that succ can oprat on valus from any rgion. On th
64 64 CHAPTER 2. TYPE SYSTEM right of th arrow, th fact that r 2 is quantifid indicats that succ can produc its output into any rgion. This is possibl bcaus th function allocats a nw Int objct ach tim it is calld, and frshly allocatd objcts do not alias xisting objcts. Altrnativly, if a function dos not allocat its rturn valu, thn th rgion variabls in its rturn typ will not b quantifid: x :: Int r 3 x = 5 samx :: () Int r 3 samx () = x In this xampl, samx rturns th sam objct vry tim it is calld. This objct coms from its nvironmnt, and is shard btwn all calls to it, hnc r 3 must rmain unquantifid. Unquantifid rgion variabls can also appar on th lft of an arrow. This happns whn a function conflats its argumnts with valus from th nvironmnt: y :: Int r 4 y = 23 choosy :: Int r 4 Int r 4 choosy z = if... thn y ls z Th objct rturnd by choosy could b ithr its argumnt z, or th shard objct y. Our systm cannot rprsnt th fact that th rturnd objct might b in on rgion or anothr, so w us th sam variabl for both. This limitation is discussd in In this xampl, r 4 is also prsnt in th nvironmnt, so it cannot b quantifid in th typ of choosy. Although r 4 appars in th typs of both y and choosy, ach occurrnc has a slightly diffrnt maning. In th typ of y, it rprsnts a particular st of locations in th hap, and on of thos locations contains th intgr objct of valu 23. On th othr hand, th us of r 4 in th typ of choosy dos not man that choosy also contains an intgr objct. Instad, ths occurrncs rprsnt locations in th stor whr th function s argumnt and rturn valus li. W distinguish btwn ths two cass by saying that r 4 in th typ of y is in a matrial position, whras in th typ of choosy is not. Th diffrnc btwn th matrial and immatrial positions of typ constructors is discussd mor fully in Updating data rquirs it to b mutabl Whn a function can updat its argumnt, w add a constraint to its typ that rquirs th argumnt to b mutabl. For xampl, th inc function dstructivly incrmnts its argumnt and has typ: inc :: r 1. Int r 1 () Mutabl r 1 This typ indicats that inc can oprat on intgrs in any rgion, as long as that rgion is mutabl. W trat mutability as a capability providd by th objcts in our systm, and th rquirmnt for this capability flows from th functions that mak us of it. An altrnativ stup would b to xplicitly prmit updat by rquiring th programmr to supply typ signaturs and mutability constraints for vry objct that is to b updatd, or to us a spcial kyword
65 2.2. REGION TYPING 65 whn allocating thm. W fl that th us of a spcial kyword would crat cluttr in th program, though w will somtims rquir mutability constraints to b givn in a typ signatur. W will rturn to this in During typ infrnc, th compilr compars all th constraints placd on th rgion variabls in th program. In th absnc of an xplicit typ signatur, if a particular rgion is not constraind to b mutabl, thn at runtim th objcts containd within that rgion will nvr b passd to a function that can updat thm. For this rason, matrial rgion variabls that ar not constraind to b mutabl ar considrd to b constant. This dos not apply to quantifid, immatrial rgions in th typs of functions. In this cas th thr options: mutabl, constant, and unconstraind, hav distinct manings. For xampl, in th following typ signatur: foo :: r 1. Int r 1 () As r 1 is unconstraind w may apply this function to intgrs which ar ithr mutabl or constant, whras with: foo :: r 1. Int r 1 () Const r 1 W can only apply this function to intgrs which ar constant Primary rgions and algbraic data In all xampls so far, th typ constructors usd hav had only on rgion paramtr. This is typical for simpl typs with a small amount of intrnal structur, but w nd mor whn dfining algbraic data. Considr a vctor of two intgrs: data IntVctor r 1 r 2 r 3 = IV (Int r 2 ) (Int r 3 ) Th first rgion variabl r 1 corrsponds to th rgion containing th outr IV constructor. This is calld th primary rgion variabl. Th variabls r 2 and r 3 appar in th body of th dfinition and rprsnt th rgions containing th intgr componnts. For xampl, th valu (IV 2 3) would b rprsntd as: r 1 IV r r 3 Ths thr sparat rgion variabls provid thr dgrs of frdom whn dciding which parts of th objct should b mutabl and which should b constant. Allowing r 2 and/or r 3 to b mutabl prmits th componnts to b updatd, and whn r 1 is mutabl w can updat th pointrs in th outr constructor. Th tag of th outr constructor is also containd in th primary rgion. Updats to th tag prmit th valu of numrations such as Bool to b changd.
66 66 CHAPTER 2. TYPE SYSTEM Not that with this systm it is not possibl to giv th pointrs to th two componnts sparat rgion variabls. W omit this capability to rduc th complxity of th systm, though w s no fundamntal barrir to supporting it if rquird in th futur Thinking about rgions Thr ar svral ways to concptualis what a rgion actually is, and w hav mntiond two so far. Firstly, a rgion is an ara of th hap whr objcts can b stord at runtim. For systms that us rgions to manag allocation and dallocation [TBE + 06], this is th most natural. Frsh objcts ar allocatd into a particular rgion, and th whol rgion is rclaimd by th storag managr whn th objcts containd ar no longr ndd by th running program. Such systms us rgion allocation to augmnt or rplac th standard garbag collction mchanism. At an oprational lvl, th rgions in such systms ar usually contiguous, or ar constructd with a linkd list of contiguous mmory pags. Howvr, DDC dos not us rgions to manag allocation, it rlis on a traditional garbag collctor. W can still imagin a rgion to b a spcific ara of th hap, but th parts of th hap that mak up th rgion ar scattrd throughout, and do not form a contiguous block. Scondly, a rgion is a labl for a collction of objcts in th stor. Earlir w suggstd imagining ths labls to b lik colours of paint. Whn a program is compild, th compilr dcids on a fixd st of colours (rgions). It thn prtnds that at runtim, vry objct allocatd by th program will b paintd with on of ths colours. Th colours hlp it to rason about what th program is prmittd to do with a crtain objct. For xampl, w could paint all th mutabl objcts with shads of pink, and all th constant objcts with shads of blu. Importantly though, th colours ar just prtnd. Our analysis is static, so w do not rcord what rgion an objct blongs to in th objct itslf, or maintain any rgion information at runtim. Finally, a rgion is a labl for a st of program points which prform allocation [Pi05]. If w know that a particular objct is in rgion r 1, thn it must hav bn allocatd by on of th points corrsponding to r 1. Evry objct is allocatd by on program point, and an allocation point can allocat zro or mor objcts. Allocation points xist within functions, so whthr or not an allocation point vr allocats dpnds on whthr th function is vr calld. Howvr, during valuation th objcts tnd to gt mixd up, such as whn choosing btwn two objcts in an ifxprssion. This mans that th compilr will usually los track of th xact point whr a particular objct was allocatd. It can only hop to rduc it to a small st of possibilitis. Using this ida w can imagin that if a rgion variabl is constraind to b Const, som part of th program rquirs an allocation point to produc a constant objct. Likwis, if a rgion variabl is constraind to b Mutabl, som part of th program rquirs a mutabl objct. A mutability conflict ariss whn a particular allocation point must produc an objct that is both mutabl and constant. This is not possibl, so w rport an rror. W will xploit this lin of rasoning furthr whn w com to prov th soundnss of our cor languag in
67 2.3. EFFECT TYPING Effct typing Effcts and intrfrnc Whn th valuation of an xprssion prforms rad or writ actions on mutabl data, th compilr must nsur that ths actions occur in th corrct ordr, ls th maning of th program will chang. W hav sn how rgion variabls ar usd to rason about th mutability of data, and w now discuss how to rason about th actions. Following Talpin and Jouvlot [TJ92b] w us ffct typing to annotat function typs with a dscription of th actions ach function prforms. For xampl, th inc function rads its argumnt, computs th succssor, and writs th nw valu back to its argumnt. Adding this information to th typ givs us: inc :: Rad r r 1. Int r 1 Writ r 1 1 () Mutabl r 1 Th ffct annotation on th function arrow tlls us which rgions in th stor will b accssd whn it valuats. Whn th ffct trm bcoms larg this syntax is hard to rad. For this rason w usually introduc an ffct variabl, and add a constraint to th typ that contains th original ffct trm: inc :: r 1. Int r 1 1 () 1 = Rad r 1 Writ r 1, Mutabl r 1 Effct variabls ar idntifid as n in this txt, and as variabls prcdd by an xclamation mark 2!n in th concrt syntax. Th xclamation mark is usd as both a namspac qualifir and as th symbol for ffct kinds. In th concrt syntax, ffct constructors such as!rad and!writ ar also prcdd by this namspac qualifir. Akin to valu typ constructors, th ffct constructors hav spcific kinds. Both Rad and Writ tak a rgion and produc an ffct, so w hav: Rad :: %! Writ :: %! Trating th function constructor as a gnral typ constructor, w can rad th infix application a b as shorthand for th prfix application ( ) a b. This will hlp whn prsnting th typing ruls of th cor languag, as w can us gnral typ application to build function typs instad of rquiring a rul spcific to functions. Singl, atomic ffcts such as Rad r 1 and Writ r 1 ar gathrd togthr with th join oprator. Effcts form a lattic ordrd by st inclusion on atomic ffcts. W us σ 1 σ 2 to man ffct σ 1 is no gratr than ffct σ 2, for xampl: Rad r 1 Rad r 1 Writ r 1 Th oprator corrsponds to st union. W us (bottom) to rprsnt th ffct of an xprssion which prforms no visibl actions, and a function arrow 2 a mnmonic for: somthing s happning!
68 68 CHAPTER 2. TYPE SYSTEM with no annotation is takn to hav this ffct. Convrsly, w us (top) to rprsnt th ffct of an xprssion which could prform all possibl actions. This top lmnt is usful bcaus w can ras any ffct trm in our program by rplacing it with, without loss of safty. W can also us whn th tru ffct of an xprssion is unknown. As w dsir a top lmnt in our ffct structur, w us a lattic to gathr ffcts instad of using sts dirctly. W also find th lattic notation mor convnint, as w can writ σ Rad r 1 instad of σ {Rad r 1 }, whr σ is an arbitrary ffct. Th original ffct systm of Gifford and Lucassn [GL86] is also prsntd as a lattic, though thy do not us an xplicit top lmnt. Th notion of ffct is intimatly rlatd to th notion of intrfrnc [Ry78], which rlats to how th valuation of on xprssion may affct th outcom of anothr. For xampl, if on xprssion has th ffct Rad r 1 and anothr has Writ r 1, thn thy may b accssing th sam hap objct. In this cas our compilr must worry about th ordr in which ths two xprssions ar valuatd, and in particular, it must prsrv this ordr whn prforming optimisations. Importantly, th notion of intrfrnc is sparat from th usual mthod of propagating information btwn xprssions via data dpndncis. For xampl: y = doubl x z = succ y Th valuation of th first statmnt is most crtainly going to affct th outcom of th scond, but w don t count this as intrfrnc, bcaus changing thir ordr would violat th scoping ruls of th languag and prvnt th program from bing compild. On th othr hand, if w had: y = succ x inc z Ths two statmnts may or may not intrfr, dpnding on whthr x, y or z ar aliass for th sam objct. Whn spaking of ffcts, w pronounc as pur, bcaus th valuation of an xprssion with this ffct can b safly rordrd with rspct to any othr. W pronounc as sync bcaus an xprssion with this ffct may intrfr with all othr impur xprssions, so it must b synchronisd with rspct to thm all Effct information in typs Hr is th typ of updatint, which ovrwrits th valu of its first argumnt with th scond: updatint :: r 1 r 2. Int r 1 Int r 1 2 () 1 = Writ r 1 Rad r 2, Mutabl r 1
69 2.3. EFFECT TYPING 69 Whn typst, ffct variabls ar writtn abov th function arrow. Howvr, in th concrt syntax w combin thm with th arrow: updatint :: forall %r1 %r2. Int %r1 > Int %r2 (!1)> () :!1 =!{!Writ %r1;!rad %r2 }, Mutabl % r1 Th syntax!{!1;!2;... } is quivalnt to All functions that writ to a particular rgion also rquir that rgion to b mutabl. Whn w xprss typ signaturs, w can lav out mutability constraints so long as w includ th appropriat writ ffct. On th othr hand, th inclusion of a mutability constraint dos not imply that a function is ncssarily capabl of writing to th associatd rgion. Th ffct information in a typ givs an uppr bound on th particular actions a function may prform at runtim. For xampl, th following typ signatur is valid, but som of th information containd dos not corrspond to an actual proprty of th function: rturnfiv :: r 1 r 2. Int r 1 1 Int r2, 1 = Writ r 1 Mutabl r 1 rturnfiv x = 5 This is an xampl of ffct wakning. It is always saf to trat a particular function (or xprssion) as having a largr ffct than it ncssarily dos. With rgard to intrfrnc, wakning th ffct of an xprssion corrsponds to synchronising its valuation with othr parts of th program, mor than w would strictly nd to. Rturning to th typ of updatint, th ffct trm w us for 1 could rally b anything w lik, as long as it includs Writ r 1 Rad r 2. Indd, w could wakn its typ by quantifying 1 and making this fact xplicit: updatint :: r 1 r 2 1. Int r 1 Int r 1 2 () 1 Writ r 1 Rad r 2, Mutabl r 1 Writing this anothr way, w could plac th 1 Writ r 1 Rad r 2 constraint dirctly on th quantifir: updatint :: r 1 r 2 ( 1 Writ r 1 Rad r 2 ). Int r 1 Int r 1 2 () Mutabl r 1 This nw constraint givs a lowr bound on th ffct with which 1 can b instantiatd as. W will rturn to th practical diffrncs btwn th strong and wak forms of updatint in Not that although atomic ffcts hav a txtual ordring whn collctd togthr with, thr is no corrsponding information in th analysis. In th typ of updatint, th ffct trm Writ r 1 appars bfor Rad r 1 on th pag, yt clarly th function must rad th sourc argumnt bfor it writs to th dstination. Th oprator is commutativ so σ 1 σ 2 is quivalnt to σ 2 σ 1. For comparison, in th bhavior typs of Nilson and Nilson [NN93, NN99], th ordr of actions is prsrvd.
70 70 CHAPTER 2. TYPE SYSTEM Effcts and currying In our xampls, usually only th rightmost function arrow will hav an ffct annotation, though this is not rquird in gnral. Our primitiv updatint function nds both argumnts bfor it can procd, hnc both Rad r 2 and Writ r 1 appar on th sam arrow. If w partially apply updatint by supplying just th first argumnt, thn th runtim systm will build a thunk. This thunk holds a pointr to th objct cod for th ral primitiv updat function, along with a pointr to th supplid argumnt. Building a thunk has no visibl ffct on th rst of th program, so this partial application is pur. Only whn w apply th scond and final argumnt will th runtim systm b in a position to call th primitiv function to carry out th updat action. In contrast, w could dfin a slightly diffrnt function that rads th sourc argumnt as soon as it is applid: whr radthnupdatint :: r 1 r 2. Int r 1 1 Int 2 r2 () 1 = Rad r 1, 2 = Writ r 2, Mutabl r 2 radthnupdatint src = do src = copyint src (λdst updatint dst src ) copyint :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1 Not that unlik in Haskll, th Discipl doxprssion is not monadic. A doxprssion consists of a squnc of statmnts or bindings, trminatd with a statmnt. Th valu of th whol xprssion is th valu of th last statmnt. W trat dobinds;xpr as bing sugar for ltbinds inxpr, whr th lt is nonrcursiv. In radthnupdatint w mak a copy of th sourc argumnt as soon as it is availabl. Th variabl src binds this copy and is fr in th innr function. If w partially apply radthnupdatint to just its first argumnt, thn th runtim systm will build a thunk which rfrncs th copy. At this point w ar fr to updat th original sourc objct, without affcting th rsult of th innr function. W can s this bhavior in th typ signatur for radthnupdatint. Onc th first argumnt is applid th function dos not caus any mor visibl rad ffcts Top lvl ffcts So far w hav only considrd actions that modify th intrnal stat of th program, that is, rads and writs to mutabl data. For a gnral purpos
71 2.3. EFFECT TYPING 71 languag w must also b abl to prform IO. Th ordr of ths actions must b maintaind during compilation, and w can us th ffct mchanism to do so. W rfr to ffcts which rprsnt actions on xtrnal stat as toplvl ffcts. Ths ffcts xist in th top lvl scop and cannot b safly maskd. Although th Rad and Writ ffct constructors ar bakdin to th languag, w allow th programmr to dfin thir own constructors to rprsnt top lvl ffcts. For instanc, for a typical intractiv application w could dfin th following: ffct Consol ffct FilSystm ffct Ntwork Th primitiv functions that accss th outsid world includ ths constructors in thir ffct trms. For xampl: putstr :: r 1. String r 1 1 () 1 = Rad r 1 Consol Th typ of putstr tlls us that it will rad its argumnt and prform an action on th consol. DDC nsurs that th ordrings of calls to putstr ar maintaind with rspct to all functions that hav top lvl ffcts. In particular, if w dfin a function with a diffrnt toplvl ffct: radfil :: r 1 r 2. FilPath r 1 1 String r2 1 = Rad r 1 FilSystm W must still synchronis uss of radfil with putstr, bcaus in gnral, consol and fil actions may intrfr. This point is discussd furthr in
72 72 CHAPTER 2. TYPE SYSTEM Effcts in highr ordr functions Whn w mov to highr ordr functions, w bgin to s ffct variabls in th typs of thir paramtrs. For xampl, th typ of map is: map :: a b r 1 r 2 1. (a 1 b) List r 1 a 2 List r 2 b 2 = 1 Rad r 1 map f [ ] = [ ] map f (x : xs) = f x : map f xs Th map function applis its first paramtr to vry lmnt of a list, yilding a nw list. It must inspct th list to dtrmin whthr it is mpty or a cons cll, hnc th Rad r 1 ffct. Whn it applis its paramtr, that function invoks its actions, hnc th variabl 1 also appars in th ffct trm for 2. Th actual ffct bound to 1 dpnds on how map is applid. For xampl, w could us partial application to dfin a nw function which will tak th succssor of a list of intgrs: succ :: r 3 r 4. Int r 3 3 Int r4 3 = Rad r 3 mapsucc :: r 5 r 6 r 7 r 8. List r 5 (Int r 6 ) 4 List r 7 (Int r 8 ) 4 = Rad r 6 Rad r 5 mapsucc = map succ Du to th application map succ, th rad ffct of succ is bound to 1 in th typ of map. This ffct trm is thn substitutd into th constraint for 2. Accounting for typ gnralisation, this rad ffct bcoms th Rad r 6 trm in th typ of mapsucc. From th typ of mapsucc w s that it will rad th list clls from th rgion namd r 5, as wll as rading th lmnt clls (via succ) from th rgion namd r Constraint strngthning and highr ordr functions Th cor of our typ infrnc algorithm is modld aftr th Typ and Effct Disciplin [TJ92b]. It rturns a typ trm and a st of ffct constraints for vry xprssion in th program. This combination of typ trm and constraints corrsponds to th wak vrsion from For xampl, th infrrd typ of succ would b: succ :: r 1 r 2 1. Int r 1 1 Int r2 1 Rad r 1 W rad this typ as: a function which taks an Int in a rgion namd r 1, rturns an Int in a rgion namd r 2, and whos valuation causs an ffct that includs Rad r 1. W us in th constraint bcaus w can trat succ as having any ffct, as long as it includs Rad r 1. Howvr, as th function
73 2.3. EFFECT TYPING 73 itslf only has th Rad r 1 ffct, w will not los any information if w rplac by = and strngthn this typ to: succ :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1 W could also substitut th constraint into th body of th typ, yilding th flat vrsion: Rad r succ :: r 1 r 2. Int r 1 1 Int r2 W gain two immdiat bnfits whn strngthning typs in this way. Firstly, th typs of most common library functions can b xprssd without using th unfamiliar oprator, which rducs th numbr of symbols that bginnrs nd to worry about, and is a bnfit not to b undrratd. Th scond is that it rducs th nd for a larg numbr of ffct applications in programs which hav bn translatd to our cor languag. Our cor languag discussd in 4 is an xtnsion of SystmF, similar in spirit to th cor languag usd in GHC. As usual, th instantiation of typ schms corrsponds to typ application in th cor languag. An application of succ using th wak vrsion of its typ would rquir an xprssion such as: succ r a r b (Rad r 1 ) x Hr, r a, r b and Rad r 1 satisfy th r 1 r 2 1. portion of th typ schm. Both r a and r b ar tru paramtrs. Thy supply information rgarding th location of th argumnt and rturn valu, and ar likly to b diffrnt for ach us of succ. On th othr hand, th fact that succ has th ffct (Rad r 1 ) is obvious from its typ, and supplying this information vry tim it is calld ndlssly incrass th vrbosity of th cor program. This bcoms problmatic whn w apply functions that hav a mor intrsting bhaviour. It is not uncommon for typs in typical programs to hav upwards of 20 atomic ffct trms. By strngthning th typ of succ w can lid th ffct application and apply th function with th smallr xprssion: succ r a r b x This is possibl unlss th application of succ gnuinly nds to b tratd as having a largr ffct. This can occur for two rasons. Firstly, whn choosing btwn two functions on th right of an if or casxprssion, w must wakn thir ffct trms so that thir typs match. W discuss this furthr in 4.3. Scondly, it is not obvious how to strngthn th typs of highr ordr functions, or if this is vn possibl in gnral. 3 Ths typs can includ constraints on ffct variabls that appar in paramtr typs. Such constraints rquir function paramtrs to hav at last a crtain ffct, but as w can trat any function as having mor ffcts than it is actually abl to caus, thy don t provid any usful information to th compilr. Th fact that w hav constraints of this form is an artfact of th bidirctional natur of th typing ruls, and th HindlyMilnr styl unification algorithm usd to prform infrnc. Th ffct of a function can includ th ffct of its paramtr, as pr th map xampl, but also th othr way around. W will s an xampl of this in a momnt. 3 I do not know how to do this, but do not hav a proof that it is impossibl.
74 74 CHAPTER 2. TYPE SYSTEM First Ordr W start with a simpl first ordr function, id: id :: a 1. a 1 a 1 id = λx. x If an ffct trm corrsponds to an action that could b carrid out if th function wr valuatd, thn w call it a manifst ffct of th function. In this xampl, 1 is a manifst ffct, albit it is. Clarly, id is pur so thr is nothing prvnting us from dropping th quantifir for 1 and substituting for 1 in th body of th typ: id :: a. a a Notic that in th original typ, 1 is manifst, and dos not appar in th paramtr portion of th typ, that is, on th lft of a function arrow. Scond Ordr Hr is an xampl scond ordr function: appfiv :: a r 1 1. (Int r 1 1 a) 1 a 1 appfiv = λg. g 5 appfiv accpts a function paramtr and applis it to th intgr 5. Th ffct causd by th us of appfiv will b th sam as th ffct causd by th paramtr function. This information is rprsntd by th fact that 1 appars in both th paramtr typ and as a manifst ffct on right most function arrow. Although w hav th constraint 1, unlik th cas for id, w cannot safly strngthn this typ and substitut for 1 : appfiv bad :: a r 1. (Int r 1 a) a This nw typ is strictly lss gnral than th original bcaus w can only apply it to paramtr functions that ar pur. Howvr, 1 is a statmnt that is always tru, so w can drop it from th signatur and writ: appfiv :: a r 1 1. (Int r 1 1 a) 1 a In futur w will always lid trivial constraints such as 1. To mak things slightly mor intrsting, w will add anothr ffct to appfiv: succfiv :: r 1 r 2 r (Int r 1 1 Int r2 ) 2 Int r Rad r 2 succfiv g = succ (g 5) succfiv is similar to appfiv, xcpt that it passs th rsult of its paramtr function to succ. This introducs th nw ffct Rad r 2. Not that th ffct of th paramtr, 1, and th manifst ffct of th ovrall function ar now linkd
75 2.3. EFFECT TYPING 75 via th constraint on 2. This is in contrast to appfiv, whr thy wr linkd via a singl variabl. Whn w strngthn th ffct constraint and substitut it into th body of th typ w gt: succfiv strong :: r 1 r 2 r 3 1. (Int r 1 1 Int r2 ) 1 Rad r 2 Int r3 Prforming this substitution has not lost any information. W can s that th ffct of valuating succfiv is to apply th paramtr function and rad its rsult. If dsird, w could introduc a nw ffct variabl for th 1 Rad r 2 trm, and convrt th strong form back to th original wak vrsion. In this cas th two ar quivalnt. For comparison, hr is a scond ordr function whr strngthning dos not work: choosfiv :: r 1 r 2 1. (Int r 1 1 Int r2 ) 1 Int r 2 1 Rad r 1 choosfiv g = lt f = if... thn g ls succ in f 5 Not that th ifxprssion is choosing btwn th paramtr function g and and succ. Th typ infrnc algorithm uss unification to nsur that both ths xprssions hav th sam typ. succ rads its argumnt, so g is tratd as though it rads its argumnt also. This is th rason for th Rad r 1 constraint on th variabl 1, which nams th ffct of th paramtr function. It is important to not that th function paramtr passd to choosfiv is now rquird to hav th Rad r 1 ffct. If w wantd to apply choosfiv to th pur function id, thn w would nd to instantiat id with a wakr ffct, so that it also contains Rad r 1. This laking of a function s ral, manifst ffct into th typ of its paramtr is th othr half of th bidirctional information flow discussd arlir. Intrstd partis ar rfrrd to th litratur on intrsction and union typs as a possibl way around this problm [CF04, DP03]. Such typ systms can xprss mor dtaild proprtis of programs, but full typ infrnc is oftn undcidabl. Prhaps a union typing systm guidd by typ annotations could giv a mor plasing typ to choosfiv. Howvr, w hav bn primarily intrstd in compil tim optimisation and ar unconvincd of th bnfits of a mor complx systm, so hav not lookd into this furthr. Also, such constraints only sm to aris in programs that choos btwn functions, or us collction structurs that contain functions. W havn t writtn many Discipl programs which do this, and ar not sur if having constraints on ffct variabls in paramtr typs rprsnts a ral problm in th languag. W cannot strngthn th typ of choosfiv and rmov th constraint as w did prviously. Substituting Rad r 1 for 1 in th body would brak th link btwn th ffct of th paramtr and th manifst ffct of th ovrall function: choosfiv bad :: r 1 r 2 Rad r. (Int r 1 1 Int r2 ) Rad r 1 Int r 2
76 76 CHAPTER 2. TYPE SYSTEM For this rason w must includ boundd quantification in both our sourc and cor languags. W strngthn constraints to = constraints only whn th variabl dos not appar in a paramtr typ (to th lft of a function arrow). This simpl rul allows us to lid th majority of ffct applications that would othrwis appar onc th program has bn translatd to th cor languag. As w shall s, thr ar cass whr w could strngthn but don t, but thy ar rar in practic. On mor scond ordr function follows. This tim w hav applid succ to th rsult of f to yild an additional rad ffct: choossuccfiv :: r 1 r 2 r (Int r 1 1 Int r2 ) 2 Int r 3 1 Rad r 1, 2 1 Rad r 2 choossuccfiv g = lt f = if... thn g ls succ in succ (f 5) Th point to notic hr is that th constraind ffct variabl 1 also appars in th constraint for 2. This mans that whn w convrt th typ to us boundd quantifirs w must b carful about thir ordr. For xampl, writing ach quantifir sparatly givs: choossuccfiv :: r 1. r 2. r 3. ( 1 Rad r 1 ). ( 2 1 Rad r 2 ). (Int r 1 1 Int r2 ) 2 Int r 3 Unlik th first thr rgion quantifirs, w cannot chang th ordr of th two ffct quantifirs, ls 1 would b out of scop in th scond constraint. This has two important implications for our implmntation. Th first is that although our typ infrnc algorithm rturns a typ which includs a constraint st using, th cor languag uss individual boundd quantifirs as abov. This mans that whn convrting typs to th cor rprsntation w must do a dpndncy walk ovr th constraint st to nsur th quantifirs ar introducd in th corrct ordr. Th scond is that w hav no way of rprsnting graphical or rcursiv ffct constraints in th cor languag, so w must brak ths loops during translation. This procss is covrd in and 3.4. Third Ordr Moving up th chain, w now considr a third ordr function foo. W will rus appfiv in this xampl, so rpat its dfinition. W admit that foo is a constructd xampl, but mak th point that a typ systm must handl such xampls anyway. Th radr is invitd to analys thir own favourit third ordr function. 4 foo = λf. succ (f succ) appfiv = λg. g 5 4 W had nough troubl coming up with this on.
77 2.3. EFFECT TYPING 77 As th opration of foo is prhaps nonobvious to th casual obsrvr, w offr an xampl callbyvalu rduction of th trm (foo appfiv): foo appfiv Th typ of foo infrrd by our systm is: foo :: r 1 r 2 r 3 r (λf. succ (f succ)) appfiv (λf. succ (f succ)) (λg. g 5) (succ ((λg. g 5) succ)) (succ (succ 5)) 7. ((Int r 1 1 Int r2 ) 2 Int r 3 ) 3 Int r 4 1 Rad r 1, 3 2 Rad r 3 foo taks a scond ordr function as its paramtr. In th sourc, foo s paramtr is applid to succ, hnc th (Int r 1 1 Int r2 ) componnt of its typ. As th rsult of this application is passd again to succ, th rsult has typ Int r 3. Th function foo itslf rturns th rsult of this final application, giving th rturn typ Int r 4. Not th smantic diffrnc btwn th two ffct constraints. Th constraint on 3 givs th manifst ffct of valuating th function, whras th constraint on 1 says that foo s paramtr will b passd a function which has a rad ffct. In this typ, as 1 dos not xprss a link btwn th paramtr and th manifst ffct of th function, w could strngthn it to: foo :: r 1 r 2 r 3 r 4 2 Rad r. ((Int r 1 1 Int r2 ) 2 Int r 3 ) 2 Rad r 3 Int r4 Howvr, functions of ordr thr and highr ar rar, so in our currnt implmntation w stick with th simplr strngthning rul. Highr ordr functions in practic Whn rsarching th matrial in this sction w had difficulty finding xampls of usful functions of ordr thr or gratr. In [Oka98a] Okasaki suggsts that in th domain of parsr combinators, functions up to sixth ordr can b usful in practic. Howvr, th signaturs h prsnts us typ synonyms, and th principl typs of th combinators ar of lowr ordr. For xampl, using th ML syntax of th papr th bind combinator is: fun bind (p, f) sc = p (fn x f x sc) If w limit our slf to simpl typs thn this is a third ordr function: bind : (( ), ) Yt its intndd typ signatur, givn as a commnt in th ML cod is: ( bind : a Parsr ( a b Parsr) b Parsr ) Although Parsr is a typ synonym for a third ordr function, it could b argud that this dos not mak bind fifth ordr.
78 78 CHAPTER 2. TYPE SYSTEM Obsrvabl ffcts and masking Considr th following function: slowsucc x = do y = 0 y := y + 1 x + y W hav usd th oprator (:=) as sugar for th updatint function from This function has six atomic ffcts. Th two addition xprssions rad both thir argumnts, and th updat function rads th rsult of (y + 1) thn ovrwrits th old valu of y. If w includd all of ths ffcts in th typ for slowsucc thn w would hav: slowsucc :: r 1 r 2 r 3 r 4 r 5. Int r 1 1 Int r5 1 = Rad r 1 Rad r 2 Rad r 3 Rad r 4 Writ r 2, Mutabl r 2 Hr is a vrsion of slowsucc whr th variabls and constants hav bn annotatd with th rgions thy ar in, rlativ to th abov typ signatur. slowsucc x r 1 = do y r 2 = 0 r 2 y r 2 := (y r r 3 ) r 4 (x r 1 + y r 2 ) r 5 Th point to not is that much of th information in th typ of slowsucc won t b of intrst to a function that calls it. Th constants 0 and 1, th valu of y, and th rsult of th addition (y + 1) ar ntirly local to th dfinition of slowsucc. If w so dsird, spac to hold ths valus could b allocatd on th stack whn calling th function, and thn frd whn rturning from it. Th fact that slowsucc maks us of ths valus is not obsrvabl from any calling contxt. Th only way a callr can communicat with a particular function is via its argumnt and rturn valus, as wll as via its fr variabls. A callr can pass an argumnt, rciv a rsult, and in a languag with dstructiv updat th calld function could modify valus accssabl via its fr variabls. From th typ signatur for slowsucc w s that its argumnt is passd in a rgion namd r 1, and its rturn valu is producd into a rgion namd r 5. Othr than th addition and updat oprators, this particular function has no fr variabls. As rgions r 2, r 3 and r 4 ar not fr in th body of th typ, that is th Int r 1 1 Int r5 trm, th ffcts and constraints on ths rgions can b rasd. W call this procss masking thos ffcts and constraints. This givs: slowsucc :: r 1 r 5. Int r 1 1 Int r5 1 = Rad r 1 Not that slowsucc has a pur intrfac. Although it uss dstructiv updat intrnally, a calling function cannot obsrv this. This form of ffct masking
79 2.3. EFFECT TYPING 79 achivs a similar rsult to monadic ncapsulation of ffcts in th ST monad [LPJ94], with th advantag of bing prformd automatically by th compilr. Hr is anothr xampl: lngth xs = do n = 0 map (λ. n := n + 1) xs n This imprativ vrsion of th list lngth function initialiss a countr to zro, uss map to incrmnt th countr for vry lmnt of th list, thn rturns th countr. map is similar to th standard map function, xcpt that it discards its rturn valu. Whn using map th paramtr function is only xcutd for its ffct. In this way map is similar to mapm from Haskll. If w usd just th masking rul from th prvious xampl thn w would hav th following typ for lngth: lngth :: a r 1 r 2. List r 1 a 1 Int r 2 Rad r 1 Writ r 2, Mutabl r 2 Th map function rads its argumnt list, so w hav Rad r 1 in th typ of lngth. Th xprssion n := n + 1 updats th valu of n, which is finally rturnd. This givs Int r 2 as th rturn typ, along with Writ r 2 and Mutabl r 2 as ffcts and constraints of th function. Not that th rturn valu of lngth is frshly allocatd, so th calling function cannot hav a rfrnc to it bforhand. Bcaus of this, th fact that th rturn valu was cratd via dstructiv updat is unimportant. W can us an additional masking rul: if a rgion variabl is quantifid, not prsnt in a paramtr typ, and not prsnt in th closur of th function, thn ffcts and constraints on that rgion can b maskd. W will discuss closurs in 2.5. Masking th typ of lngth abov givs: lngth :: a r 1 r 2. List r 1 a 1 Int r 2 Rad r 1 Onc again, w s that although lngth uss dstructiv updat intrnally, it has a pur intrfac. W will now sadly admit that although our currnt implmntation of DDC masks th Writ r 2 ffct in th typ of lngth it dos not also mask th Mutabl r 2 constraint. Although w can plainly s that this is a valid opration in th sourc languag, w do not yt hav a systm in plac to mask th corrsponding constraint in th cor languag. In futur work w plan to us th systm outlind by Gupta [Gup95] to do so. This is discussd furthr in and
80 80 CHAPTER 2. TYPE SYSTEM Rcursiv ffcts Considr th following function: fac n = cas n of 0 1 n fac (n 1) This function also contains six sparat sourcs of ffcts. Firstly, whn th casxprssion valuats it must rad th valu of n to dtrmin which altrnativ to tak. Th multiplication and subtraction xprssions must rad thir oprands. Finally, valuation of th rcursiv call to fac causs all of ths ffcts again. Just as th rcursiv function fac is dfind in trms of itslf, th ffct of fac includs itslf. With this in mind w could giv fac th following typ: fac :: r 1 r 2 1. Int r 1 1 Int r2 1 Rad r 1 1 Th ffct trm Rad r 1 is du to th cas, multiply and subtraction xprssions, and 1 is du to th rcursiv call. As pr th prvious sction, w hav maskd th ffct of rading th two 1 constants. Now, although th ffct 1 is constraind to includ itslf, th fact that 1 is rcursiv is not usd by our subsqunt analysis. Du to this, w will simplify this typ by braking th rcursiv loop. W do this by first dcomposing th constraint 1 Rad r 1 1 into two parts: 1 Rad r Th scond part, 1 1 is trivially satisfid, so w can writ th typ of fac in a simplr form: fac :: r 1 r 2 1. Int r 1 1 Int r2 1 Rad r 1 W can also apply th ffct strngthning rul to liminat th quantifir for 1 and chang th constraint oprator from to =. This givs us our final typ: fac :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1 Not that as our cor languag cannot rprsnt rcursiv ffct typs, w must always prform this loop braking simplification. Othr systms basd on bhaviors and trac ffcts [NN93, SSh08] xprss ths loops using a fix point oprator, but w ar not awar of any way to us this information to optimis th program Constant rgions and ffct purification Rcall from that th constraint Mutabl r 1 indicats that rgion r 1 may b updatd, whil Const r 1 indicats that it will nvr b updatd. During
81 2.3. EFFECT TYPING 81 typ infrnc, onc all th rgion constraints from a sourc program hav bn procssd, any rgions that hav not bn constraind to b mutabl ar assumd to b constant. This is th first sourc of Const constraints in our systm. Th scond sourc is th us of lazy valuation. In Discipl, lazy valuation is introducd by suspnding particular function applications. W do this with th suspnsion For xampl: six = 5 This syntax is dsugard into an application of th primitiv arity1 suspnd function: six = suspnd1 succ 5 Whr suspnd1 has typ: suspnd1 :: a b 1. (a 1 b) a b Pur 1 Not that as th two right most function arrows hav no ffct annotations, thy ar takn to b (pur). suspnd1 taks a paramtr of typ a 1 b, an argumnt of typ a and dfrs th application by building a thunk at runtim. Whn th valu of this thunk is dmandd, th function paramtr will b applid to its argumnt, yilding th rsult of typ b. Clarly, th function paramtr must not caus visibl sid ffcts. If it did thn th valu of its rsult would dpnd on whn th thunk is forcd, which usually won t b what th programmr had intndd. For this rason, th ffct constraint Pur 1 rquirs th visibl ffct of th function paramtr to b. W now considr th typ of succ including rgion and ffct information: succ :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1 Th typ of succ includs an ffct Rad r 1, and whn suspnd1 is applid to succ w gt th constraint Pur (Rad r 1 ). Now, Rad r 1 is not th which this constraint rquirs. Howvr, suppos r 1 was constant. Rad ffcts on constant rgions can b safly ignord bcaus it dos not mattr whn a particular rad taks plac, th sam valu will b rturnd vry tim. During typ infrnc, purity constraints on rad ffcts ar dischargd by forcing th rgions rad to b constant. W call this ffct purification. If th rgion happns to alrady b mutabl thn it cannot additionally b mad constant. In this cas th systm rports a purity conflict and givs an rror mssag that includs th trm in th program that causd th rgion to b markd as mutabl, along with th suspnsion that rquirs it to b constant.
82 82 CHAPTER 2. TYPE SYSTEM For xampl: succdlay () = do x = 5 y = x... x := In this program w hav suspndd th application of succ, which will rad th intgr bound to x. Latr in th program, this intgr will b updatd to hav a nw valu, 23. Th troubl is that th vntual valu of y will dpnd on whn this rsult is dmandd by th surrounding program. If it is dmandd bfor th updat thn it will valuat to 6, but if it is dmandd aftr it will valuat to 24. Th usual sns of an rronous program is on that cannot b rducd to a valu bcaus th rduction rachs a point whr no furthr rul applis, such as with Tru +42. Although succdlay dos not hav this problm, w argu that its bhaviour is nonobvious nough to justify rjction by th typ systm. This is akin to compilr warnings about uninitialisd variabls in C programs. Uninitialisd variabls pr s will not crash a program, but th bhavior of a program which uss thm can b so confusing that it is bst to rjct it outright. Of cours, in a particular implmntation w can always add a trapdoor. Our suspnd1 function is primitiv, but is not bakd into th typ systm. In our runtim systm w hav implmntd suspnd1 in C. W import it with th forign function intrfac, lik any othr primitiv function. To allow succdlay w would simply import th C implmntation of suspnd1 again with a diffrnt nam and lav th Pur 1 constraint out of th nw typ signatur. This would b akin to using th unsafprformio function with GHC. unsafprformio allows a sidffcting function to b usd in a contxt that dmands a pur on, laving th burdn of corrctnss on th programmr instad of th compilr and typ systm Purification in highr ordr functions Purity constraints can also b applid to th ffcts of function paramtrs. This is common for highr ordr functions that work on lazy data structurs. For xampl, hr is a dfinition of th lazy map function, which rads lmnts of th input list only whn th corrsponding lmnt of th output is dmandd. mapl f [ ] = [ ] mapl f (x : xs) = f x : mapl xs W will dsugar th pattrn match into a casxprssion, us Nil and Cons in plac of [ ] and :, as wll as using th quivalnt suspnd function in plac mapl f xx = cas xx of Nil Cons x xs Nil Cons (f x) (suspnd1 (mapl f) xs) Th ffct of mapl includs th ffct of inspcting th valu of xx in th casxprssion, as wll as th ffct of valuating th application f x. On th othr
83 2.3. EFFECT TYPING 83 hand, th us of suspnd1 rquirs (mapl f) to b a pur function. Th fact that mapl suspnds its rcursiv call forcs it to b pur. W can purify th ffct of th casxprssion by rquiring th cons clls of th list to b in a constant rgion. W cannot purify th ffct of f x locally, bcaus f is an unknown function, but w can rquir that callrs of mapl provid a guarant of purity thmslvs. W do this by placing a purity constraint on th ffct of f, which givs mapl th following typ: mapl :: a b r 1 r 2 1. (a 1 b) List r 1 a 2 List r 2 b 2 = 1 Rad r 1, Pur 1, Const r 1 This says that w can only us mapl with pur paramtr functions, and with constant lists. Ths constraints ar sufficint to guarant that th valu rturnd will not dpnd on whn it is dmandd. Th abov typ is th on producd by our currnt implmntation. Not that vn though Rad r 1 and 1 ar pur, w hav rtaind ths ffcts in th constraint for 2. It would b nicr to ras thm, but w hav not yt implmntd a mchanism to prform th corrsponding ffct masking in th cor languag, which is discussd in Altrnativly, rasing ths ffcts would produc th following typ: mapl :: a b r 1 r 2 1. (a 1 b) List r 1 a List r 2 b, Pur 1, Const r 1 Th two constraints Pur 1 and Const r 1 xprss th implicit constraints on functions and data prsnt in lazy languags such as Haskll. In Haskll, all functions ar pur 5 and all data is constant. 6 By adding a oprator to our strict vrsion of map w hav cratd th lazy vrsion. This nw vrsion is typ compatibl with th strict vrsion, xcpt for th addd constraints that nsur rfrntial transparncy. 5 Bar som hacks whn implmnting IO. 6 Though, not as far as th runtim systm is concrnd.
84 84 CHAPTER 2. TYPE SYSTEM Strict, spin lazy and lmnt lazy lists Rturning to th sugard vrsion of mapl, not that this function is spin lazy. mapl f [ ] = [ ] mapl f (x : xs) = f x : mapl xs A spin lazy map is on that only allocats cons clls for th output list whn thy ar dmandd. Altrnativly, w could mov oprator and crat a vrsion that allocatd all of th cons clls as soon as it was calld, but dfrrd th valuation of th actual list lmnts: maple f [ ] = [ ] maple f (x : xs) = x : maple f xs W mntion this bcaus in our introduction w discussd th fact that in Haskll, th functions map and mapm ar concptually similar, but rquir diffrnt dfinitions and hav diffrnt typs. W argud that this cratd a nd to rfactor lots of xisting cod whn dvloping programs. Although w hav now introducd thr diffrnt Discipl vrsions, map, mapl, maple which ar strict, spin lazy, and lmnt lazy rspctivly, this is a diffrnt situation. In th typs of ths thr functions, th valu typ portion rmains th sam. If w covr up th rgion, ffct and constraint information, w ar lft with an idntical typ in ach cas: map :: (a b) List a List b Th thr vrsions map, mapl, maple ar all intrchangabl as far as thir valu typs ar concrnd. This is comparabl to th diffrnc btwn foldl and foldl in th standard Haskll libraris. foldl is a strictr vrsion of foldl, but it has th sam typ. Of cours, in Discipl w still want mapm whn using monads such as parsrs. Th fact that w can xprss sid ffcting programs without nding stat monads dos not imply th monad abstraction is not usful for othr purposs Lazy and Dirct rgions Rgion classs ar a gnral mchanism that allows us to xprss spcific proprtis of data. W hav alrady discussd th Mutabl and Const classs that ar usd to xprss whthr an objct may b updatd or must rmain constant. W us th additional classs Lazy, LazyH and Dirct to track th cration of thunks du to th us of suspnd functions. A Lazy constraint applid to th primary rgion of a data typ indicats that valus of that typ may b rprsntd as thunks. LazyH applid to a typ variabl indicats that th top lvl (had) rgion of that typ may b a thunk. On th othr hand Dirct applid to a primary rgion variabl indicats that th objct is guarantd not to b a thunk. This allows us to optimis th handling of boxd valus in th cor languag, as wll as improv cod gnration for cas xprssions in th back nd. Not that th concpts of dirctnss and strictnss ar quit diffrnt. Whn a function is strict in its argumnt, th rsult of th function will always dpnd
85 2.3. EFFECT TYPING 85 on th argumnt. On th othr hand, whn a function is dirct in its argumnt, it will not accpt valus rprsntd by thunks, and whn it is dirct in its rsult, it will not produc thunks. Hr is a vrsion of suspnd1 that uss a LazyH constraint to indicat that this function producs thunks: suspnd1 :: a b 1. (a 1 b) a b Pur 1, LazyH b W will suspnd an application of succ as an xampl: x = suspnd1 succ 5 To work out th typ of x, w first instantiat th typs of suspnd1 and succ. W hav usd primd variabls for th instantiatd nams: suspnd1 inst :: (a 1 b ) a b Pur 1, LazyH b succ inst :: Int r 1 2 Int r 2 2 = Rad r 1 Applying suspnd1 inst to succ inst givs: (suspnd1 succ) :: Int r 1 Int r 2 Pur (Rad r 1 ), LazyH (Int r 2 ) By assigning th constant 5 th typ Int r 1 w gt: (suspnd1 succ 5) :: Int r 2 Pur (Rad r 1 ), LazyH (Int r 2 ) W rduc th Pur (Rad r 1 ) constraint by rquiring that r 1 is constant. Th constraint LazyH (Int r 2 ) tlls us that r 2 may contain a thunk, so w rduc it to Lazy r 2 : (suspnd1 succ 5) :: Int r 2 Const r 1, Lazy r 2 Although this typ includs th constraint Const r 1, th rgion variabl r 1 is not prsnt in its body. Th rgion r 1 rlats to th constant valu 5, not to th rsulting valu x, so w can drop it and gt: (suspnd1 succ 5) :: Int r 2 Lazy r 2 Th rgion variabl r 2 cannot b quantifid bcaus it is matrial in this typ. Th final typ of x is: x :: Int r 2 Lazy r 2 This says that th outrmost constructor of this objct may b a thunk, and it crtainly will b aftr th call to suspnd1: r 2 cod for succ I 5 r 1
86 86 CHAPTER 2. TYPE SYSTEM r 2 cod for succ I 5 r 1 As th application thunk rprsnts a valu of typ Int r 2 w draw it as blonging to th rgion r 2. This is opposd to thunks that rprsnt partial applications. Ths thunks hav no rgions bcaus thy rprsnt objcts of function typ, and function typs ar not annotatd with rgion variabls. Whn th valu of x is forcd, th application succ 5 will b valuatd. Following lazy valuation, th thunk will thn b ovrwrittn by an indirction nod pointing to th rsult: x: I 6 r 2 During back nd cod gnration, w must account for th fact that x may point to a thunk or indirction. To xtract th unboxd intgr from x w must first load th tag of th objct pointd to. This allows us to idntify th sort of objct it is, and dcid whthr to forc th thunk, follow th indirction, or load th valu as rquird. On th othr hand, if w knw that x was dirct, as with: x :: Int r 2 Dirct r 2 Thn w would b sur that x only pointd to a boxd intgr. This would sav us from having to load th tag and do th tst. Similarly to th way nonmutabl rgions dfault to bing constant, nonlazy rgions dfault to bing dirct Liftdnss is not a capability W should not that th constraint nams Lazy and Dirct hav an oprational flavour bcaus DDC uss this information to guid optimisations. W could prhaps rnam thm to Liftd and Unliftd, which would rflct th fact that a Liftd valu rprsnts a computation that may divrg. A similar approach is takn in [LP96] and [PJSLT98], though thy distinguish btwn pointd and liftd typs. In [LP96], th typ of unliftd intgrs is writtn Int #. Th typ of liftd intgrs is dfind to b Int #, with th in th subscript acting as a typ oprator that allows th bottom lmnt to b on of th valus rprsntd by th typ. Not that with this formulation, monotyps such as intgrs must b ithr liftd or unliftd. Our mthod of attaching constraints to rgion variabls allows us to rus th typ class machinry to ncod a similar proprty. Howvr, typ class constraints xprss a supports rlationship, which dosn t quit match up with th concpt of liftdnss. For xampl, th constraint Eq a mans that a is a typ whos valus support bing tstd for quality. Th constraint Mutabl r mans that th objcts in rgion r support bing updatd. Likwis, Const r
87 2.4. THE PROBLEM WITH POLYMORPHIC UPDATE 87 mans that th objcts in r can b safly rad by a suspndd computation, that is, thy support lazinss. If an objct is constraind to b nithr Mutabl nor Const thn w cannot assum it is saf to do ithr of ths things. Extnsionally, if a typ is compltly unconstraind thn w know nothing about th valus that inhabit that typ. Each nw constraint provids a nw pic of information, and that information givs us th capability to do somthing nw with th corrsponding valus. If an objct is Dirct thn w can gnrat fastr cod to rad its valu, bcaus it is guarantd not to b rprsntd by a thunk. Howvr, th fact that an objct is Lazy dosn t provid us with an addd capability. Th Lazy constraint only srvs to nsur that an objct is not also tratd as Dirct. For xampl, considr th following typ: fun :: r 1 r 2. Int r 1 Int r 2 As r 1 is not constraind to b Dirct, thn objcts passd to this function may b rprsntd by thunks. On th othr hand, if w had: fun :: r 1 r 2. Int r 1 Int r 2 Lazy r 1 This Lazy constraint also xprsss th fact that objcts passd to this function may b rprsntd by thunks, but that isn t nw information. Howvr, during typ infrnc, if w discovr that a trm has typ: Int r 1 Lazy r 1, Dirct r 1 Thn this could man that a lazy objct was passd to a function that was xpcting a dirct on, which is invalid. 2.4 Th problm with polymorphic updat A wll known problm can aris whn dstructiv updat is addd to a languag with a HindlyMilnr styl polymorphic typ systm. Th classic xampl is as follows: id succ :: a. a a :: Int Int brokn () = do rf = nwrf id writrf rf succ (radrf rf ) Tru If w tratd this function as though it wr writtn in Standard ML, w could argu that it is not typ saf and would likly crash at runtim. Th first lin crats a rfrnc to a polymorphic function id, whil th scond updats it to hold a lss gnral function succ. This invalidats th original typ of rf. Th problm appars to cntr on th typ infrrd for rf : rf :: a. Rf (a a) Th quantifir allows us to instantiat this typ diffrntly for ach us of rf. Howvr, our static typ systm is unabl to track th fact that onc w updat th rfrnc w can no longr trat it has having this gnral typ.
88 88 CHAPTER 2. TYPE SYSTEM Fighting th valu rstriction Aftr winning out ovr svral othr systms [Gar02] th standard way of addrssing th problm with polymorphic updat is to apply th valu rstriction [Wri96]. Th valu rstriction stats that th typ of a ltbound variabl should only b gnralisd if th right of th binding is a syntactic valu, such as a variabl, litral, lambda abstraction, or application of a data constructor to anothr valu. Ths xprssions ar calld nonxpansiv bcaus thir valuation will nithr gnrat an xcption or xtnd th domain of th stor [MTHM97, Tof90]. Th valu rstriction has th advantags that it is simpl, asy to implmnt, and dos not rquir xtra information to b attachd to th structur of typs. This last point is spcially important for MLstyl languags in which th programmr must writ full typ signaturs whn dfining modul intrfacs. Th down sid is that a class of xprssions that wr prviously assignd polymorphic typs los thir polymorphism. For xampl: f = map id Th typ of f is not gnralisd bcaus th right of th binding is not a syntactic valu. To rgain polymorphism w must ηxpand it to giv: f = λx. map id x or quivalntly, writ it as a function binding: f x = map id x In [Wri96] it was argud that as th numbr of modifications nding to b prformd to xisting ML programs was small compard to th ovrall siz of th cod, th valu rstriction dos not plac an undu burdn on th programmr in practic. Howvr, in light of mor rcnt languags such as Haskll [PJ03a], th valu rstriction would intrfr with applications such as parsr combinator libraris, which mak havy us of polymorphic valus [LM01]. Mor rcntly, a variant namd th rlaxd valu rstriction [Gar02] uss a subtyping basd approach to rcovr som of th polymorphism lost by th simplr rstriction. Unfortunatly, straightforward xampls lik (map id) rmain monomorphic Gnralisation rducs data sharing in SystmF Th valu rstriction dos not solv th fundamntal problm of a static analysis bing unabl to track runtim changs in th typ of data. What it dos is to limit polymorphism, and to prvnt th usr from writing a crtain class of programs. Issus of soundnss can only aris in rlation to a wll dfind smantics. Th usual formulation bing Soundnss = Progrss + Prsrvation [Pi02], maning that a wlltypd xprssion must ithr b a valu or b abl to progrss to th nxt stp in its valuation; and that its wlltyping is prsrvd during valuation.
89 2.4. THE PROBLEM WITH POLYMORPHIC UPDATE 89 With an ML styl smantics, if w fail to dal adquatly with th issu of polymorphic updat thn th last lin in brokn rducs as: (radrf rf ) Tru succ Tru (λx. x + 1) Tru Tru +1 This trm is not a valu and cannot b valuatd furthr as thr is no rduction rul spcifying how to add on to a boolan valu. It is th combination of oprational and static smantics which is unsound. On th othr hand, if w considr a SystmF styl translation of brokn which has bn typd without rstricting gnralisation thn w would hav: brokn = λ (). lt rf = Λb. nwrf {b b} (id {b}) in lt = writrf {Int Int} (rf {Int}) succ in radrf {Bool Bool} (rf {Bool}) Tru W hav insrtd typ lambdas Λ and typ argumnts {} at gnralisation and instantiation points rspctivly. Notic that rf now binds a function valu instad of an application xprssion. From th oprational smantics of DDC s cor languag w hav: H ; t 1 H ; t 1 H ; lt x = t 1 in t 2 H ; lt x = t 1 in t 2 H ; lt x = v in t H ; t[v /x] (EvLt1) (EvLt) Whn combind, ths two ruls say that to valuat a ltxprssion w should first rduc th right of th binding to a (wak) valu and thn substitut this valu into th body. Whil valuating brokn, as th right of th rf binding is alrady a valu w substitut and nd up with: lt = writrf {Int Int} ((Λb. nwrf...) {Int}) succ in radrf {Bool Bool} ((Λb. nwrf...) {Bool}) Tru Not th duplication of th trm involving nwrf and th fact that a nw rfrnc containing id will b allocatd at ach occurrnc. Th rvaluation of polymorphic trms corrsponds with polymorphismbynam [Lr93]. Also not that th first rfrnc will b updatd, but only th scond on will b rad. Admittdly, th bhavior of this xprssion could b confusing to th programmr, but allowing it dos not mak our systm unsound. Dmonstration of unsoundnss would rquir that an xprssion was wll typd, not a valu, and could not b rducd furthr. This xprssion can b rducd to Tru, and is not a problm in this rspct Typ rasur incrass data sharing (again) Although polymorphismbynam maks our SystmF styl cor languag sound in th prsnc of polymorphic updat, w still nd to rstrict gnralisation.
90 90 CHAPTER 2. TYPE SYSTEM Th rduction in data sharing w gt from th translation from sourc to cor is rintroducd by typ rasur during th convrsion to our backnd abstract C languag. Whn w ras th typ lambdas and argumnts from th translation of brokn, rf binds a valu again. This lavs us with our original problm. As in [GL86] w rstrict gnralisation to prsrv th data sharing proprtis of programs during translation to and from cor. W shall s in 2.5 that w us closur typing instad of th valu rstriction to achiv this Don t gnralis variabls fr in th stor typing In [Tof90] Toft uncovrs th crux of th problm with polymorphic updat by attmpting to prov th soundnss of an MLstyl typ systm with mutabl rfrncs, and showing whr th proof braks down. Unsurprisingly, th offnding cas is th on for ltbindings. Th dynamic rul is as follows: s ; E t 1 v 1 ; s 1 s 1 ; E + {x v 1 } t 2 v ; s s ; E lt x = t 1 in t 2 v ; s (MLEvLt) Th judgmnt form s ; E t v ; s is rad: starting with stor s and nvironmnt E, th xprssion t valuats to valu v and a (prhaps changd) stor s. Th stor s maps locations to valus whil th nvironmnt E maps variabls to valus. Stor locations ar cratd whn w allocat a nw rfrnc cll, and modifying th contnts of a rfrnc cll corrsponds to changing th valu bound to a particular location. Th corrsponding typ rul is: Γ t 1 :: τ 1 Γ, x : Gn(Γ, τ 1 ) t 2 :: τ Γ lt x = t 1 in t 2 :: τ (MLTyLt) Hr, Gn(Γ, τ 1 ) prforms gnralisation and is short for a 1..a n. τ 1, whr a 1...a n ar th typ variabls in τ 1 that ar not fr in Γ. In gnral, t 1 may contain location variabls, so w nd to know th typs of th valus bound to ths locations bfor w can chck th typ of th whol xprssion. This information is hld in th stor typing which maps locations to typs. If w hav an xprssion t 1 of typ τ 1, thn rducing it rlativ to a particular stor s 1 should yild a valu v 1. W dsir this valu to hav th sam typ as th original xprssion, and xprss this fact with th statmnt: s 1 :: ST 1 = v 1 :: τ 1 This statmnt rads: in stor s 1 with typing ST 1, v 1 has typ τ 1. Now th troubl starts. Although w know that v 1 has typ τ 1, whn valuating a ltxprssion w must satisfy th th scond prmis of (MLTyLt). This rquirs that w strngthn th abov statmnt to: s 1 :: ST 1 = v 1 :: Gn(Γ, τ 1 )
91 2.4. THE PROBLEM WITH POLYMORPHIC UPDATE 91 This says that w r now considring th valu to hav a mor gnral typ than it usd to. An xampl of this would b to first trat th trm (λx. x) as having th monomorphic typ b b, and thn latr dciding that it has th mor gnral, polymorphic typ b. b b. In a languag without rfrncs, as long as b is not fr in th typ nvironmnt thn this gnralisation is justifid. If b is not fr in th typ nvironmnt, thn thr is nothing stopping us from αconvrting any local uss of it, and thus liminating all mntion of this particular variabl from our typing statmnts. By doing this w could b sur that no othr parts of th program ar trating b as bing any spcific, concrt typ, bcaus thy hav no information about it. Howvr, whn w introduc mutabl rfrncs w must also introduc th concpt of a stor and its associatd stor typing. This stor typing includs typ variabls, and whn w try to strngthn th original statmnt th proof falls apart. Considr again our brokn xampl that crats a rfrnc to th polymorphic function id. Expanding out th dfinition of id givs: lt rf = nwrf (λx. x) in... Onc nwrf (λx. x) has bn rducd to a valu, th statmnt w nd to strngthn is: {loc 1 λx. x} :: {loc 1 (a a)} = loc 1 :: a a Notic how th rduction of nwrf (λx. x) has cratd a nw location in th stor and bound th idntity function to it. In th stor typing this function has th typ (a a) which includs th fr variabl a. Howvr, during gnralisation this fact is ignord and w nd up with: {loc 1 λx. x} :: {loc 1 (a a)} = loc 1 :: a. a a This statmnt is clarly suspct bcaus th typ assignd to loc 1 no longr modls its typ in th stor. Whn w updat th rfrnc to hold succ, th typ of th binding in th stor changs. Unfortunatly, th static typing ruls still trat loc 1 as having th mor gnral typ: {loc 1 succ} :: {loc 1 (Int Int)} = loc 1 :: a. a a If w wr to thn rad th succ function back from th stor and apply it to a nonint valu lik Tru, th runtim rsult would b undfind. Toft sums up th problm with th following obsrvation: Th naiv xtnsion of th polymorphic typ disciplin [with mutabl rfrncs] fails bcaus it admits gnralisation on typ variabls that occur fr in th stor typing Rstricting gnralisation with ffct typing As w don t want to rly on th valu rstriction to control gnralisation, w must find anothr way of idntifying variabls that ar fr in th stor typing. In a languag with MLstyl rfrncs, th sol mans of xtnding th stor is by xplicitly allocating thm with a function such as nwrf. In this cas, th problm of idntifying variabls fr in th stor typing rducs to idntifying
92 92 CHAPTER 2. TYPE SYSTEM calls to nwrf and collcting th typs of valus passd to it. If w trat rfrnc allocation as a computational ffct, thn w can us ffct infrnc to prform th collction [Wri92]. Th ruls for th polymorphic typ and ffct systm [TJ92a, TJ92b] ar as follows: Γ t :: τ ; σ Γ, x : τ x :: Inst(τ) ; (Var) Γ, x : τ 1 t 2 :: τ 2 ; σ Γ λ(x : τ 1 ). t 2 :: τ 1 σ τ2 ; (Abs) Γ t 1 :: τ 11 σ τ12 ; σ 1 Γ t 2 :: τ 11 ; σ 2 Γ t 1 t 2 :: τ 12 ; σ 1 σ 2 σ (App) Γ t 1 :: τ 1 ; σ 1 Γ, x : Gn(σ 1, Γ, τ 1 ) t 2 :: τ 2 ; σ 2 Γ lt x = t 1 in t 2 :: τ 2 ; σ 1 σ 2 (Lt) Γ t :: τ ; σ 1 σ 1 σ 2 Γ t :: τ ; σ 2 (Sub) Th judgmnt Γ :: τ ; σ rads: In th nvironmnt Γ th xprssion has typ τ and ffct σ. Th nvironmnt Γ maps variabls to typs. In this prsntation ffcts ar gathrd togthr with th st union oprator and a pur xprssion is assignd th ffct. Also not th trm Gn(σ 1, Γ, τ 1 ) in th rul (Lt). Gnralisation is rstrictd to variabls that ar not fr in ithr th typ nvironmnt or th ffct causd by valuating th body of a ltbinding. Ths ruls dscrib th plumbing of how ffcts ar attachd to typs. What s missing is a dscription of how atomic ffcts ar introducd to th systm via nwrf. In Wright s systm [Wri92], nwrf is givn th typ: nwrf :: a. a a Rf a Hr, a is a typ variabl and its prsnc on th function arrow indicats that it has th ffct of allocating a nw rfrnc containing a valu of that typ. Th ffct variabl combind with th subsumption rul (Sub) allows th function to b tratd as causing any ffct so long as it includs a. This is usd whn passing argumnts to highr ordr functions, which is discussd in Although this systm collcts th rquisit typ variabls, it is limitd by th fact that all th ffcts causd by th allocation of rfrncs appar in a function s typ, vn if thy ar usd ntirly locally to that function.
93 2.4. THE PROBLEM WITH POLYMORPHIC UPDATE 93 For xampl, with th following program: id id :: a. a a = λx. x idrf :: b b b idrf = (λx. lt rf = nwrf x in radrf rf ) In th typ for id, w can gnralis a bcaus it dos not appar fr in ithr th typ nvironmnt or th ffct causd by th function. Th scond function idrf bhavs idntically to id, xcpt that it crats a rfrnc to its argumnt bfor rturning it. Evn though this rfrnc is not accssibl onc idrf rturns, th ffct causd by allocating it appars in its typ, which prvnts b from bing gnralisd. Although ths two functions bhav idntically from a callrs point of viw, thy cannot b usd intrchangably as thy hav diffrnt typs Obsrvation critria In [TJ92b] Talpin and Jouvlot xtnd Wright s ffct systm with rgions. As in Discipl, thir rgions dnot sts of locations which may alias, but thy attach rgion variabls to rfrnc typs only. In thir systm, ffcts ar causd whn rfrncs ar rad and writtn to, but also whn thy ar allocatd. Each ffct carris with it th typ of th rfrnc bing actd upon, as wll as th rgion it is containd within. Th typs of th primitiv oprators ar: nwrf :: a r. (a Rf r a) Init r a radrf :: a r. (Rf r a a) Rad r a writrf :: a r. (Rf r a 1 a 2 ()) 2 Writ r a Similarly to Wright s systm, nwrf can b tratd has having any ffct, so long as that ffct includs Init r a. Th ffct Init r a rcords that a rfrnc in rgion r was initialisd to contain a valu of typ a. Howvr, in this systm th subsumption rul (Sub) is modifid to includ an obsrvation critrion which allows ffcts which ar not visibl to a callr to b maskd. Γ :: τ ; σ 1 σ 2 Obsrv(Γ, σ 1, τ) Γ :: τ ; σ 2 (SubObs) whr Obsrv(Γ, τ, ) = { Init r τ 1, Rad r τ 1, Writ r τ 1 σ r fr(γ) fr(τ) } { ς σ ς fv(γ) fv(τ) } Th function fv computs th fr typ, rgion and ffct variabls in its argumnt, whil fr rturns fr rgion variabls only.
94 94 CHAPTER 2. TYPE SYSTEM With this systm, whn w typ chck th dfinition of idrf th body of th λxprssion yilds th statmnt: Γ, x :: a (lt rf = nwrf x in radrf r) :: a ; Init r 1 a Rad r 1 a Not that although th right of th ltbinding allocats and thn rads a rfrnc, th rgion into which th rfrnc is allocatd is ntirly local to th binding. Applying (SubObs) yilds: Γ, x :: a (lt rf = nwrf x in radrf r) :: a ; This allows us to infr th sam typ for id as w do for idrf. Laving th formal proof of soundnss in [TJ92b], w can s why th obsrvation critria works by inspcting our original statmnt: Γ, x :: a (lt rf = nwrf x in radrf r) :: a ; Init r 1 a Rad r 1 a Notic that r 1 is not prsnt in th typ nvironmnt, and is thrfor not visibl to th xprssion s calling contxt. Also, as th typ of th xprssion dos includ r 1 thr will b no handl on this rgion aftr th xprssion has finishd valuating. Indd, as th allocatd rfrnc is unrachabl aftr this valuation, it could b safly garbag collctd. Rturning to Toft s (un)proof in 2.4.4, this garbag collction corrsponds to rmoving th associatd binding from th stor and its stor typing, which allows a to b safly gnralisd Effct typing vrsus arbitrary updat Talpin and Jouvlot s systm works wll for a languag with MLstyl rfrncs. As updat is limitd to a distinguishd Rf typ, it is asy for th typ systm to dcid whn to introduc Rad, Writ and Init ffcts. Howvr, in Discipl, updat is not rstrictd to data of a spcial typ. In our systm all data has th potntial to b updatd. For xampl th simpl data typ Mayb is dfind as follows: data Mayb r a = Nothing Just a Dfining this typ furnishs us with a data constructor which can b usd to allocat a Just. Just :: a r. a Mayb r a Onc a Just has bn allocatd, w can thn us th fild projction syntax of 2.7 to updat it, or not, as w s fit. If w wr to us an ffct systm to control gnralisation, how would w know whthr this constructor should caus an Init ffct? Only th allocation of a mutabl valu should caus an ffct, but mutability dpnds on whthr or not th valu may vr b updatd, not vic vrsa. Th mutability of th objct will b infrrd by our typ systm, but this proprty is not immdiatly visibl at th point whr th objct is allocatd.
95 2.5. CLOSURE TYPING Closur typing Lroy s closurtyping [LW91, Lr92] is a systm for modling data sharing du to th inclusion of fr variabls in th bodis of functions. W us closur typing as an altrnat solution to th problm of polymorphic updat, as wll as to rason about th sharing proprtis of rgions. Considr th following function: addt = λx. λy. (x + y, x) If w tak addition (+) to oprat on valus of typ Int, thn w could giv addt th following typ: addt :: Int Int Pair Int Int If w thn partially apply addt to th valu 5, th first argumnt of its typ is satisfid and w nd up with a function that accpts an intgr and producs a pair: addfiv :: Int Pair Int Int addfiv = addt 5 addfiv can b furthr applid to yild th pair, but what happnd to th first valu w providd? Assum valuation procds via tmplat instantiation aftr th pur lambda calculus. In this cas w could rason that th argumnt 5 was bound to th formal paramtr x and thn substitutd into th body of th outr lambda abstraction, that is: addfiv addt 5 (λx. λy. (x + y, x)) 5 λy. (5 + y, 5) This callbynam rasoning is applicabl to a pur languag such as Haskll, but as w intnd to us dstructiv updat w must tak a mor oprational approach. If w instad considr an implmntation basd on suprcombinators [Hug83], w would trat addt as a singl suprcombinator, and th partial application (addt 5) as th construction of a thunk containing pointrs to th suprcombinator cod and argumnt valu: cod for addt I 5 Whn addfiv is applid to its final argumnt, th cod for addt is calld dirctly. addt s first argumnt coms from th thunk, and th scond is supplid by th application. This is how DDC oprats. With this systm, vry us of addfiv shars th sam 5 objct. Using rgion annotations on data typs and closur annotations on functions 7, w giv addfiv a typ which maks th sharing xplicit. 7 W modify Lroy s syntax for closurs to b similar to th on usd for ffcts.
96 96 CHAPTER 2. TYPE SYSTEM addfiv :: r 1 r 2 r 3. c Int r 1 1 Pair r2 (Int r 3 ) (Int r 4 ) c 1 = x : Int r 4 On th lft of th function arrow, th argumnt typ Int r 1 says that addfiv accpts an intgr from a rgion which w nam r 1. On th right of th arrow, w s that th function producs a pair of two intgr componnts. As r 3 is quantifid, w infr that th first componnt has bn frshly allocatd into a nw rgion (addition rturns a frsh rsult). Th data constructor rprsnting th pair is also frsh, so r 2 is quantifid as wll. On th othr hand, r 4 is not quantifid, which indicats that th scond componnt of th pair will b in th sam rgion ach tim addfiv is calld. Th closur variabl c 1 attachd to th function arrow indicats that th dfinition of addfiv crats a shard valu, and th trm x : Int r 4 rcords its typ. W includ valu variabl nams such as x in closur trms for notational convninc, and trat th x : portion of x : Int r 4 as an oprator that lifts th typ trm Int r 4 into a closur trm. In this xampl, th variabl x corrsponds to th occurrnc that is fr in th innrmost lambdaabstraction in th dfinition of addfiv. Whn a function has a larg numbr of fr variabls it is hlpful for thm to b includd in th typs prsntd to th usr. Our typ systm collcts this information but dos not mak us of it for chcking purposs. If dsird w could rplac all occurrncs of ths variabls with an undrscor to indicat thy ar ignord by th typ systm propr Dangrous typ variabls In [Lr92] Lroy dfins dangrous variabls to b th ons that ar fr in a liv rfrnc typ. For Discipl this is quivalnt to bing fr undr a mutabl typ constructor. Considr th following typ: thing :: Mayb r 1 (a a) Mutabl r 1 with data Mayb r 1 a = Nothing Just {x :: a} In th typ of thing, a is dangrous bcaus it corrsponds to a valu that w ar abl to updat at runtim. For xampl, th following cod crats a Just constructor containing th function id, updats it to hold th lss gnral function succ, thn tris to apply that function to a string. This xampl is similar to on from 2.4, xcpt that w ar using th Discipl projction syntax to updat th mutabl objct. Th trm thing # x crats a rfrnc to th x fild in th Just constructor. If w viw rfrncs as bing akin to pointrs, thn thing # x has a similar maning to th C xprssion &(thing.x). Projctions ar discussd furthr in 2.7.
97 2.5. CLOSURE TYPING 97 Onc th rfrnc is cratd, w us th := # oprator to updat th fild (via th rfrnc): do thing thing # x troubl = Just id := # succ = cas thing of Just f f di! Whn gnralising th typ of thing w must hold a monomorphic. If w wr to giv it th following polymorphic typ, thn th abov cod would pass th typ chckr, but would hav an undfind rsult at runtim. thing bad :: a. Mayb r 1 (a a) Mutabl r 1 In gnral, to dtrmin th dangrous variabls in a typ w must inspct th dfinitions of th data typs involvd. For xampl, th following typ has thr sparat rgion variabls, which givs us thr placs to attach mutability constraints: data TwoThings r 1 r 2 r 3 a b = Thing1 (Mayb r 2 a) Thing2 (Mayb r 3 b) Hr is an xampl signatur that uss TwoThings: foo :: TwoThings r 4 r 5 r 6 (d Int r 7 ) (Char r 8 ) Const r 4, Mutabl r 5, Const r 6 In this cas, as r 5 is mutabl w must hold d and r 7 monomorphic. Not that rgion, ffct and closur variabls can b dangrous as wll. As r 5 is mutabl w cannot gnralis r 7 bcaus th associatd Mayb objct might b updatd to hold a function that dos not allocat a frsh rturn valu. On th othr hand, w can allow r 8 to b polymorphic as r 6 is constant. If r 4 was mutabl thn all of r 5, r 6, d, r 7 and r 8 would hav to b monomorphic, bcaus this would lt us updat ithr of th Thing objcts to hold a diffrnt Mayb. A formal dscription of which variabls ar dangrous is givn in Closur typing and hiddn communication Considr th following function, also from [Lr92]: makgtst x do rf = nwrf x gt () = radrf rf st z = writrf rf z Pair gt st This function allocats a rfrnc to th supplid valu x, and thn rturns a pair of functions to gt and st th valu in th rfrnc.
98 98 CHAPTER 2. TYPE SYSTEM In Discipl, without closur information and bfor gnralisation, th typ of makgtst is: makgtst :: a Pair r 1 (() 1 a) (a 2 ()) 1 Rad r 2, 2 Writ r 2, Mutabl r 2 Thr ar two problms with this typ. Firstly, as r 2 is not mntiond in th body (or th typ nvironmnt), th rad and writ ffcts will b maskd as pr This is invalid bcaus th ordr in which ths applications tak plac at runtim crtainly mattrs, so thy must rtain thir ffct trms. Scondly, if w wr to allow a to b gnralisd thn w would hav an unsound systm onc again. For xampl: makgtst bad :: a r 1. a Pair r 1 (() a) (a ()) brokn () do gtst = makgtst bad id st2 = snd gtst st2 succ gt2 = fst gtst gt2 () di! By allowing th mutabl objct rf to b fr in th closur of th gt and st functions, w hav cratd a communication channl btwn thm that is not visibl in thir typs. This is not a problm in itslf, but th addition of ltpolymorphism allows ach function to gain a diffrnt undrstanding of what typ of data is bing snt across th channl. Not that with th bad typ for makgtst, th infrrd typ of gtst includs a quantifir for b: gtst :: b. Pair r 1 (() (b b)) ((b b) ()) As w hav usd a ltbinding to dfin gt2 and st2, th typs of th two componnts ar rgnralisd and w nd up with: gt2 :: c. () (c c) st2 :: d. (d d) () Th us of st2 updats th shard rfrnc to contain a function, succ, that only accpts intgrs. Unfortunatly, with gt2 w can thn rad it back and prtnd that it accpts a string. Adding closur information to our typs rmdis this problm. Hr is th nw typ of makgtst, with closur information, and bfor gnralisation: makgtst :: a Pair r 1 (() 1 c 1 a) (a 2 c 2 ()) 1 Rad r 2, 2 Writ r 2, c 1 rf : Rf r 2 a, c 2 rf : Rf r 2 a, Mutabl r 2 Th constraints on c 1 and c 2 show that th gt and st functions rturnd in th pair can accss a shard mutabl valu, and that th typ of this valu
99 2.5. CLOSURE TYPING 99 contains a variabl a. Not that th lattic structur for closurs is idntical to that for ffcts, which was discussd in For closurs w tak as bing a synonym for th suprst oprator, and us as a synonym for. Thr is no lmnt for closurs, but w stick with th lattic notation for consistncy with ffct typs. Rturning to makgtst, not that this function allocats th rfrnc itslf. This can b dtrmind from th fact that th primary rgion variabl of th rfrnc, r 2, is not rachabl from th closur annotation on th outrmost (lftmost) function arrow. Onc w apply makgtst to its argumnt, th rfrnc is cratd and subsquntly shard. In our xampl this is don in th binding for gtst. Aftr gnralisation, th nw typ of gtst is: gtst :: 1 2 c 1 c 2. Pair r 1 (() 1 c 1 (b b)) ((b b) 2 c 2 ()) 1 Rad r 2, 2 Writ r 2, c 1 rf : Rf r 2 (b b), c 2 rf : Rf r 2 (b b), Mutabl r 2 In this typ w hav two outrmost function arrows, which ar th two in th Pair. Th typ (b b) is in th closur of ths outrmost functions, and th typ variabl b lis undrnath a rgion variabl r 2 that is constraind to b Mutabl. This mans that b is dangrous and cannot b gnralisd. Not that r 2 is not gnralisd ithr, though this rstriction is du to th fact that r 2 is prsnt in th outrmost closur. This point is discussd in th nxt sction. Rturning to our xampl, aftr prforming th fst and snd projctions, our nw typs for gt2 and st2 ar: gt2 :: 1 c 1. () 1 c 1 (b b) 1 Rad r 2, c 1 rf : Rf r 2 (b b), Mutabl r 2 st2 :: 2 c 2. (b b) 2 c 2 () 2 Writ r 2, c 2 rf : Rf r 2 (b b), Mutabl r 2 Th ffct information in th typs of ths functions nsur that uss of thm will not b rordrd during optimisation. Th closur annotations captur th fact that thy can communicat via a shard mutabl valu, and nsur that both functions agr on its typ.
100 100 CHAPTER 2. TYPE SYSTEM Matrial rgions and sharing Rcall from sction that matrial rgion variabls ar th ons that rprsnt objcts that ar shard btwn all uss of a bound variabl. For xampl: fiv :: Int r fiv = 5 Hr, r is clarly matrial, bcaus vry us of fiv rfrncs th sam 5 objct. On th othr hand, considr: addtwo :: r 1 r 2. Int r 1 Int r 2 addtwo x = succ (succ x) Nithr r 1 or r 2 ar matrial in th typ of addtwo. Ths variabls rprsnt th locations of objcts passd to, and rturnd from, th function. Thy do not rprsnt locations of objcts that ar shard btwn uss of it. Without furthr information, w tak rgions in th argumnt positions of function typs to b immatrial. Not that with th constructors at hand, w cannot b sur that no function objcts ar shard btwn calls to addtwo. If succ was dfind as th partial application of som mor primitiv function, thn vry us of succ would rfr to th sam thunk. Howvr, for our purposs sharing only mattrs if th shard objctd has th potntial to b dstructivly updatd, and thunks cannot b updatd. 8 Th following xampl dfins a function that rfrncs a shard data objct: makfiv () = do x = 5 rtfiv () = x rtfiv If w wrot down a typ for makfiv which includd rgion variabls but not closur information thn w would hav: makfiv :: r. () () Int r As r is quantifid, makfiv should rturn a frshly allocatd Int objct ach tim it is calld. This is crtainly tru if w apply both argumnts, but w can invalidat th maning of th quantifir by supplying only on. To s this mor clarly, considr th suprcombinator translation: makfiv () = do x = 5 rtfiv x rtfiv x () = x makfiv and rtfiv ar th rsult of lambdalifting [Joh85] our original function. Not that th fr variabl in th dfinition of rtfiv is passd xplicitly to its liftd vrsion. As makfiv rturns th valu rtfiv x, which valuats to a thunk, th sam 5 objct will b rturnd ach tim makfiv is providd with its final argumnt. 8 Thy can b ovrwrittn by th runtim systm during lazy valuation, but this is not visibl in th programming modl.
101 2.5. CLOSURE TYPING 101 Considr thn a binding that partially applis makfiv: makfivunit :: r. () Int r makfivunit = makfiv () Although th typ of makfivunit says that its rturn valu should b frshly allocatd, w hav just sn that th valuation of makfiv () will produc a function that rturns th sam 5 objct vry tim. Following th standard rstriction for gnralisation, w hav not quantifid ovr variabls fr in th typ nvironmnt. This nvironmnt consists of th typ of makfiv, which has no fr variabls, so that dos not hlp us hr. Th standard rstriction prvnts typs from bcoming out of sync with thir contxt, but it dos not modl sharing du to fr variabls in th body of function dfinitions. Onc again, closur typing coms to our rscu. Whn w includ closur information, th typs of makfiv and makfivunit bcom: makfiv :: r. () () c Int r c = x : Int r makfivunit :: () c Int r c = x : Int r Th typ of makfiv now includs th fact that whn th first () is applid, it allocats an objct in a rgion it nams r, and this objct is shard by all calls to th rturnd function. Th typ of makfivunit prsrvs this sharing information. Rgion variabls that ar rachabl from th closur annotation on th outr most function arrow of a typ ar matrial, and matrial rgion variabls ar not gnralisd Matrial rgions and algbraic data typs Whn w com to gnralis th typ of a binding, and th typ contains only simpl constructors lik Int and, thn w can dtrmin which rgion variabls ar matrial dirctly from th typ. Howvr, whn daling with algbraic data typs, w also nd thir dfinitions. Considr th following: data IntFun r c 1 = SInt (Int r 2 ) SFun (Int r 1 c 1 3 Int r4 ) This dfinition implicitly gnrats th following constructors. Not that w us r 1..r 4. as shorthand for r 1 r 2 r 3 r 4. Also, r 1 is usd as th primary rgion variabl of th typ, but is not prsnt in th typs of th constructor argumnts. SInt :: r c 1. Int r 2 IntFun r c 1 SFun :: r c 1. (Int r 1 c 1 3 Int r4 ) IntFun r c 1 Th SInt constructor crats an objct containing a pointr to an Int. Th rgion variabl r 1 is primary as it is first in th list, so w tak th outr SInt
102 102 CHAPTER 2. TYPE SYSTEM constructor to b in this rgion. Th Int componnt is in rgion r 2, so an application of SInt would produc: somfiv = SInt 5 somfiv: SInt r 1 Int 5 r 2 As th outr constructor always appars in th primary rgion, th primary rgion variabl is matrial. Bcaus an SInt objct contains an Int in a rgion namd r 2, this variabl is also matrial. On th othr hand, whn w us SFun, th constructd objct will contain a pointr to ithr th cod for th function argumnt, or a thunk, dpnding on whthr th argumnt was partially applid: somsucc = SFun succ somadd = SFun ((+) 2) somsucc: SFun r somadd: SFun r 1 1 cod for cod for (+) Int 2 r 5 Not that with th constructors at hand, thr no way to crat an IntFun objct that actually includs data in th r 3 or r 4 rgions. Bcaus of this, thy ar immatrial, and th gnralisation of immatrial rgions is not rstrictd as pr th prvious sction. Th typ of somsucc abov is: somsucc :: r 3 r 4 1. IntFun r Rad r 3 Not that although our somsucc objct dos not includ data in rgion r 2, that rgion is not quantifid hr. In gnral, if a particular valu has typ IntFun r c 1 thn w will not know what data constructor was usd to crat it. W must rly on th data typ dfinition to dtrmin which rgions ar matrial. Th typ of somadd is similar, xcpt that its closur variabl is constraind to contain th typ of th argumnt in th partial application of (+): somadd :: r 3 r 4 1 c 1. IntFun r c 1 1 Rad r 3 Rad r 5, c 1 Int r 5 Th matrial rgions of a typ ar dfind formally in
103 2.5. CLOSURE TYPING Strong, mixd and absnt rgion variabls Whn an algbraic data typ is dfind w do not rstrict th ways in which rgion variabls ar usd. Du to this, a particular variabl may occur in both a matrial and immatrial position. For xampl: data IntFunMixd r c 1 = SIntX (Int r 2 ) SCharX (Int r 4 ) SFunX (Int r 1 c 1 2 Int r3 ) In th first constructor, r 2 is usd as th primary rgion variabl of Int, which maks it matrial. In th third constructor, r 2 is usd as part of th typ of a function paramtr, so it is also immatrial. In this situation w say that r 2 is mixd matrial. If a rgion variabl is only vr usd in a matrial position, thn it is strongly matrial. In th abov dfinition, r 1 is strongly matrial bcaus it is usd as th primary rgion variabl for IntFunMixd, and not in th typ of a function paramtr. Th variabl r 4 is also strongly matrial. W will us this concpt whn w discuss th polymorphic copy function in 2.6. If a rgion variabl is prsnt as a paramtr of th typ constructor bing dfind, but not on of th data constructors, thn w say it is absnt. Th variabl r 5 is absnt in th abov dfinition. As absnt rgion variabls cannot corrspond to ral rgions in th stor, all absnt variabls ar also immatrial. Th rvrs is not tru, as r 3 is immatrial, but not absnt Pur ffcts and mpty closurs In th prvious two sctions, th dfinitions of IntFun and IntFunMixd includ ffct and closur variabls as argumnts to th typ constructor. This allows ths data typs to b polymorphic in th ffct and closur of th containd function. Altrnativly, w could omit ths variabls as long as w constraind th typs of SFun and SFunX so that th ffct of th containd function was pur, and its closur containd no lmnts. A closur that has no lmnts is said to b mpty. Emptinss of closurs is rlatd to purity of ffcts. Rcall from that a pur ffct is writtn and w can rquir an ffct to b pur with th Pur constraint. Likwis, w writ mpty closurs as and rquir a closur to b mpty with th Empty constraint. W somtims annotat with its kind, such as! and $ to distinguish btwn its two radings, but th kind is usually clar from contxt. By omitting ffct and closur variabls, and rstricting ourslvs to a singl rgion w will now dfin a dit vrsion of IntFun that has a singl paramtr instad of six. This nw data typ can still contain an Int or function valu, but th st of functions it could hold is rducd: data IntFunDit r 1 = SIntD (Int r 1 ) SFunD (Int r 1 Int r 1 )
104 104 CHAPTER 2. TYPE SYSTEM data IntFunDit r 1 = SIntD (Int r 1 ) SFunD (Int r 1 Int r 1 ) This modifid data typ dfinition gnrats th following constructors: SIntD :: r 1. Int r 1 IntFunDit r 1 SFunD :: r 1 1 c 1. (Int r 1 c 1 1 Int r1 ) IntFunDit r 1 Pur 1, Empty c 1 Not that although r 1 is rpatd in th first paramtr of SFunD, this dosn t rquir its argumnt to b a function which simply passs th Int through unchangd. Th typ of a function lik succ can b instantiatd so that both its rgion variabls ar th sam. Du to this w can still construct (SFunD succ) as pr th figur in 2.5.4, though th singl rgion will b forcd Const du to purification of th function s Rad ffct. On th othr hand, w can no longr construct (SFunD ((+) 2)) as its typ would includ a closur trm du to th partial application, rndring it nonmpty. S for a possibl way of addrssing this limitation Closur trimming Th closur annotation attachd to a function typ lists th typs of all fr variabls in that function s dfinition. Howvr, not all of this information is usful to our analysis. As w only rstrict th gnralisation of matrial rgion variabls, w only nd to rtain closur trms that contain thm. Th rst of th closur information can b trimmd out, and doing so is an important optimisation in practic. Considr th following program: x = 5 fun () = x + 1 fun2 () = fun fun3 () = fun2 fun4 () = fun3 This is a simpl program, but as ach succssiv binding rfrs to th binding abov it, th closur trms in thir typs can bcom vry larg. If x has typ Int r 1, thn fun has th following signatur: fun :: r 2. () 1 c 1 Int r2 1 = Rad r 1, c 1 = x : Int r 1 This says that fun accpts a unit valu and producs a frshly allocatd intgr. Th closur constraint c 1 = x : Int r 1 says that th function rfrs to this objct via th fr variabl x. Whn it valuats, th addition oprator rads th intgr bound to x, hnc th Rad r 1 ffct. It also rads th constant intgr 1, but as this constant is local to th function th ffct is maskd.
105 2.6. TYPE CLASSING 105 Hr is th typ for fun2 : fun2 :: r 2. () c 2 () 1 c 1 Int r2 1 = Rad r 1, c 1 = x : Int r 1, c 2 = (fun : r 3. () 3 c 3 Int r3 3 = Rad r 1, c 3 = x : Int r 1 ) Not that fun2 rfrs to fun, so th full typ of fun appars in its closur. Howvr, as w only us closur trms to rason about th sharing proprtis of data, w gain no bnfit from carrying around information about th ffcts associatd with a variabl lik fun. W also gain no bnfit from rtaining its argumnt and rturn typs. W xtnd th concpt of matriality to valu typs, and say that th argumnt and rturn positions of functions ar immatrial bcaus thy do not rprsnt objcts in th stor. Lastly, if w ras th rturn typ Int r 3 thn w do not nd th quantifir r 3. Th only information about fun that w do nd to kp is that it rfrncs a matrial objct of typ Int r 1. Using ths obsrvations w trim th typ of fun2 to gt: fun2 :: r 2. () c 2 () 1 c 1 Int r2 1 = Rad r 1, c 1 = x : Int r 1, c 2 = fun : Int r 1 Trimming closurs prvnts th typs of functions from blowing up. Without closur trimming th closur trm of a top lvl function lik main would includ all th typs of all functions usd in th program. In practic, most closur trms can b rasd totally. For xampl, th dfinition of our addtwo function rfrncs th fr variabl succ. As succ contains no matrial closur componnts, nithr dos addtwo. addtwo :: r 1 r 2. Int r 1 Int r 2 addtwo x = succ (succ x) In our currnt implmntation w only trim out closur information concrning immatrial rgion variabls. Sction prsnts som idas for also trimming out information concrning rgion variabls that ar constraind to b constant. 2.6 Typ classing In this sction w discuss valu typ classs in Discipl. Th gnral mchanism is similar to that usd in Haskll, xcpt that w nd a spcial Shap constraint on typs to b abl to writ usful class dclarations. As our currnt implmntation dos not implmnt dictionary passing, w limit ourslvs to situations whr th ovrloading can b rsolvd at compil tim. For this rason, non of our class dclarations hav suprclasss, and w do not support valu typ classs bing prsnt in th constraint list of a typ. This in turn allows us to avoid considring most of th subtl issus discussd in [PJJM97]. W hav mad this rstriction bcaus w ar primarily intrstd in using th typ class mchanism to manag our rgion, ffct and closur information. Exploring th possibilitis for intraction btwn th various
106 106 CHAPTER 2. TYPE SYSTEM kinds of constraints rprsnts an intrsting opportunity for futur work. Thr is also th possibility of dfining multiparamtr typ classs that constrain typs of varying kinds Copy and counting Th nd for a Shap constraint ariss naturally whn w considr functions that copy data. For xampl, th copyint function which copis an intgr valu has typ: copyint :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1 W will assum that this function is dfind as a primitiv. As r 2 is quantifid w know that copyint allocats th objct bing rturnd, which is what w xpct from a copy function. In Discipl programs, copyint can b usd to initialis mutabl countrs. For xampl: startvalu :: Int r 1 Const r 1 startvalu = 5 fun () = do count = copyint startvalu... count := count 1... startvalu is dfind at top lvl. In Discipl, if a top lvl valu is not xplicitly constraind to b Mutabl thn Const constraints ar addd automatically. W hav includd this on manually for th sak of xampl. In th dfinition fun w hav a countr that is dstructivly dcrmntd as th function valuats. As th typ of (:=) (sugar for updatint) rquirs its argumnt to b mutabl, w cannot simply initialis th countr with th binding count = startvalu. This would mak th variabl count an alias for th objct bound to startvalu. This in turn would rquir both count and startvalu to hav th sam typ, crating a conflict btwn th mutability constraint on count and th constancy constraint on startvalu. W instad us copyint to mak a frsh copy of startvalu, and this us objct to initialis count Typ classs for copy and updat Aftr intgrs, anothr common data typ in functional programs is th list. In Discipl w can dclar th list typ as: data List r 1 a = Nil Cons a (List r 1 a) This dclaration introducs th data constructors Nil and Cons which hav th following typs:
107 2.6. TYPE CLASSING 107 Nil :: r 1 a. List r 1 a Cons :: r 1 a. a List r 1 a c 1 List r 1 a c 1 = x : a Not that in th typ of Nil, th rgion variabl r 1 is quantifid. This indicats that Nil bhavs as though it allocats a frsh objct at ach occurrnc. 9 On th othr hand, in th typ of Cons th rgion variabl r 1 is shard btwn th scond argumnt and th rturn typ. This indicats that th rturnd objct will contain a rfrnc to this argumnt. Using our list constructors, and th copyint function from th prvious sction, w dfin copylistint which copis a list of intgrs: copylistint :: r 1 r 2 r 3 r 4. List r 1 (Int r 2 ) 1 List r 3 (Int r 4 ) 1 = Rad r 1 Rad r 2 copylistint xx = cas xx of Nil Cons x xs Nil Cons (copyint x) (copylistint xs) Onc again, th fact that both r 3 and r 4 ar quantifid indicats that th rturnd objct is frshly allocatd. Not that 1 includs an ffct Rad r 1 du to inspcting th spin of th list, as wll as Rad r 2 from copying its lmnts. As copyint and copylistint prform similar oprations, w would lik dfin a typ class that abstracts thm. If w ignor ffct information for th momnt, w could try somthing lik: class Copy a whr copy :: a a Unfortunatly, this signatur for copy dos not rspct th fact that th rturnd objct should b frsh. Our copyint function producs a frshly allocatd objct, but Int instanc of th typ in th class dclaration would b: copy Int :: r 1. Int r 1 Int r 1 This would prvnt us from using our ovrloadd copy function to mak local, mutabl copis of constant intgrs as pr th prvious sction. As th argumnt and rturn typs includ th sam rgion variabl, any constraints placd on on must b compatibl with th othr. On th othr hand, th following class dclaration is too wak: class Copy a whr copy :: b. a b If th argumnt of copy is an intgr, thn w xpct th rturn valu to also b an intgr. What w nd is for th argumnt and rturn typs of copy to hav th sam ovrall shap, whil allowing thir containd rgion variabls to vary. 9 Howvr, if th rturnd objct is constraind to b constant thn th compilr can rus th sam on ach tim and avoid th actual allocation.
108 108 CHAPTER 2. TYPE SYSTEM W nforc this with th Shap constraint: class Copy a whr copy :: b. a b Shap a b Shap a b can b viwd as functional dpndncy [Jon00] btwn th two typs a and b. Th functional dpndncy is bidirctional, so if a is an Int thn b must also b an Int, and if b is an Int thn so must a. As w do not provid any mchanism for dfining Shap from a mor primitiv structur, it is bakd into th languag. This handls th argumnt and rturn typs, though w still nd to account for th ffct of rading th argumnt. W do this with th RadT (rad typ) ffct: class Copy a whr copy :: b. a 1 b 1 = RadT a, Shap a b In th class dclaration, RadT a says that instancs of th copy function ar prmittd to rad any rgion variabl prsnt in th typ a. Onc this dclaration is in plac, w can add th instancs for ach of our copy functions: instanc Copy (Int r 1 ) whr copy = copyint instanc Copy (List r 1 (Int r 2 )) whr copy = copylistint Along with RadT, thr is a rlatd WritT that allows a function to hav a writ ffct on any rgion variabl in a typ. Similarly, MutablT and ConstT plac constraints on all th rgion variabls in a typ. Nxt, w will us WritT and MutablT to dfin th typ class of objcts that can b dstructivly updatd: class Updat a whr (:=) :: b. a b c 1 1 () 1 = WritT a RadT b, c 1 = x : a, Shap a b, MutablT a This dclaration says that instancs of (:=) may writ to th first argumnt, rad th scond argumnt, hold a rfrnc to th first argumnt during partial application, rquir both argumnts to hav th sam ovrall shap, and rquir rgions in th first argumnt to b mutabl. Not that th typs in class dclarations ar uppr bounds of th possibl typs of th instancs. Instancs of (:=) must hav a typ which is at last as polymorphic as th on in th class dclaration, and may not hav an ffct that is not implid by WritT a RadT b. Nor may thy plac constraints on thir argumnts othr than Shap a b and MutablT a. Importantly, aftr a partial application of just thir first argumnts, thy may not hold rfrncs to any matrial valus othr than ths argumnts. This last point is dtrmind by th closur trm x : a.
109 2.6. TYPE CLASSING Shap and partial application W now discuss how th Shap constraint works during partial application. W will us th ovrloadd quality function as an xampl. Hr is th Eq class dclaration: class Eq a whr (==) :: b r 1. a b 1 c 1 Bool r1 1 = RadT a RadT b, c 1 = x : a, Shap a b This dclaration says that instancs of (==) accpt two argumnts, and rturn a frsh boolan. Instancs ar prmittd to rad thir argumnts and hold a rfrnc to th first on whn partially applid. Th argumnts may also b rquird to hav th sam shap. Considr th following binding: isempty = (==) [ ] This binding partially applis (==), rsulting in a function that tsts whthr a list is mpty. To dtrmin th typ of isempty w first instantiat th typ of (==): (==) :: a b 1 c 1 Bool r 1 1 = RadT a RadT b, c 1 = x : a, Shap a b Taking [ ] to hav th typ List r 2 c, w bind it to a and liminat th outr function constructor: ((==) [ ]) :: b 1 c 1 Bool r 1 1 = RadT (List r 2 c) RadT b, c 1 = x : List r 2 c, Shap (List r 2 c) b Th Shap (List r 2 c) b constraint rquirs b to hav th sam shap as List r 2 c. W satisfy this by giving b th typ List r 3 d, whr r 3 and d ar frsh: ((==) [ ]) :: List r 3 d 1 c 1 Bool r 1 1 = RadT (List r 2 c) RadT (List r 3 d), c 1 = x : List r 2 c, Shap (List r 2 c) (List r 3 d) Th ffct RadT xprsss a rad on all rgion variabls in its argumnt typ. As w now know what this argumnt typ is w can rduc th RadT ffct to a simplr form. Hr, RadT (List r 2 c) can b rducd to Rad r 2 RadT c and RadT (List r 3 d) can b rducd to Rad r 3 RadT d. As both argumnts to our Shap constraint ar list typs, this constraint is partially satisfid, though w still nd to nsur that c has th sam shap as d: ((==) [ ]) :: List r 3 d 1 c 1 Bool r 1 1 = Rad r 2 RadT c Rad r 3 RadT d, c 1 = x : List r 2 c, Shap c d
110 110 CHAPTER 2. TYPE SYSTEM This typ can b rducd no furthr, so w will gnralis it to crat th schm for isempty: isempty :: c d r 1 r 3. List r 3 d 1 c 1 Bool r1 1 = Rad r 2 RadT c Rad r 3 RadT d, c 1 = x : List r 2 c, Shap c d Not that as pr w hav not gnralisd r 2 bcaus it appars in th outrmost closur of th function. At runtim, th application of (==) to [ ] will build a thunk containing a pointr to th function and th mpty list. This mpty list is shard btwn all uss of isempty Shap constraints and rigid typ variabls Considr th following Haskll typ class dclaration: class Foo a whr foo :: b. a [b] [b] An instanc of this class is: instanc Foo Bool whr foo x y = if x thn tail y ls rvrs y Th locally quantifid typ variabl b is calld a rigid typ variabl. This highlights th fact that vry instanc of foo must hav a similarly gnral typ. For xampl, th following instanc is invalid: instanc Foo Char whr foo x y = if x == a thn tail y ls [x] This noninstanc tris to assign foo th following typ: foo Char :: Char [Char] [Char] This is strictly lss gnral than th on in th typ class dclaration, bcaus w cannot apply it to lists whos lmnts do not hav typ Char. Th Copy typ class dclaration also contains a rigid typ variabl. Hr it is again: class Copy a whr copy :: b. a 1 b 1 = RadT a, Shap a b Not th local b quantifir. W hav said that copyint is a valid instanc of copy bcaus it producs a frshly allocatd objct. Rcall that copyint has th following typ: copyint :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1
111 2.6. TYPE CLASSING 111 On th othr hand, th following instanc is not valid: instanc Copy Char whr copy x = x This is so bcaus it dos not actually copy its argumnt. W can s this fact in its typ: copy Char :: r 1. Char r 1 Char r 1 This situation is vry similar to th on with foo Char, bcaus th signatur of copy Char is not sufficintly polymorphic to b usd as an instanc for copy. W now discuss how to dtrmin th rquird typ of an instanc function from th typ class dclaration. Th subtl point is in daling with Shap constraints on rigid typ variabls. Hr is th Copy class dclaration again. For th sak of xampl w hav addd th outr quantifir for a. a. class Copy a whr copy :: b. a 1 b 1 = RadT a, Shap a b Say that w wish to dtrmin th rquird typ of copy Int. To do this w instantiat th typ class dclaration with Int r 1, whr r 1 is frsh. W can thn rgnralis th dclaration for r 1, to gt a r 1 quantifir at top lvl: r 1. class Copy (Int r 1 ) whr copy :: b. Int r 1 1 b 1 = RadT (Int r 1 ), Shap (Int r 1 ) b Rducing th RadT ffct and th Shap constraint givs: r 1. class Copy (Int r 1 ) whr copy :: r 2. Int r 1 1 b 1 = Rad r 1, b = Int r 2 Rduction of th shap constraint has introducd th nw typ constraint b = Int r 2 whr r 2 is frsh. This maks b hav th sam shap as th function s first argumnt. W hav also rplacd b with r 2. Evry tim th rduction of a Shap constraint on a quantifid typ variabl introducs a nw rgion variabl, w quantify th nw variabl instad of th old on. Substituting for b complts th procss: r 1. class Copy (Int r 1 ) whr copy :: r 2. Int r 1 1 Int r2 1 = Rad r 1 W can now xtract th rquird typ for copy Int by appnding th outr quantifir, and th toplvl Copy (Int r 1 ) constraint: copy Int :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1, Copy (Int r 1 )
112 112 CHAPTER 2. TYPE SYSTEM If w ar prforming this procss to chck whthr a givn instanc function is valid, thn w hav alrady satisfid th Copy (Int r 1 ) constraint. Discharging it givs: copy Int :: r 1 r 2. Int r 1 1 Int r2 1 = Rad r 1 This is th xpctd typ for an Int instanc of copy. If th typ of a providd instanc function cannot b instantiatd to this typ, thn it is invalid Shap constraints and immatrial rgions Considr th IntFun typ from 2.5.4: data IntFun r c 1 = SInt (Int r 2 ) SFun (Int r 1 c 1 3 Int r4 ) Using th class instantiation procss from th prvious sction, th typ of a copy instanc function for IntFun must b at last as polymorphic, and no mor ffctful, closurful 10 or othrwis constraind than: copy IntFun :: r c 1. IntFun r c 2 1 IntFun r c 1 2 = Rad r 1 Rad r 2 Rad r 3 Rad r 4 Unfortunatly, w don t hav any way of writing a copy function for IntFun that has this typ. W could try somthing lik: copy IntFun xx = cas xx of SInt i SInt (copyint i) SFun f SFun f For th SInt altrnativ w hav just usd copyint to copy th containd intgr. Howvr, w hav no way of copying a function valu, nor ar w sur what it would man to do so. Instad, w hav simply rusd th variabl f on th right of th scond altrnativ. Unfortunatly, this givs copy IntFun th following typ: copy IntFun :: r c 1. IntFun r c 2 1 IntFun r5..6 r c 1 2 = Rad r 1 Rad r 2 Not that in th rturn typ of this function, r 5 and r 6 ar frsh but r 3 and r 4 ar not. Th first two paramtrs of IntFun ar matrial rgion variabls that corrspond to actual objcts in th stor. W could rasonably xpct an instanc function to copy ths. On th othr hand, th scond two paramtrs ar immatrial. For th SFun altrnativ, th bst w can do is to pass f through to th rturn valu, but doing this dos not frshn th rgion variabls in its typ. 10 Th author bags nw word crdit for closurful.
113 2.7. TYPE DIRECTED PROJECTIONS 113 Our solution is to modify th rduction rul for Shap so that all valu typ and rgion variabls that ar not strongly matrial ar idntifid. That is, if a particular variabl in a data typ dfinition dos not always corrspond to actual data in th stor, thn w will not frshn that variabl whn rducing Shap. W also dfin th rul for rducing RadT so that rad ffcts on immatrial rgion variabls ar discardd. Immatrial rgions do not corrspond with ral data in th stor, so rading thm dos nothing. Using ths nw ruls, and th instantiation procss from th prvious sction, th rquird typ for copy IntFun bcoms: copy IntFun :: r c 1. IntFun r c 2 1 IntFun r5..6 r c 1 2 = Rad r 1 Rad r 2 This is th sam typ as our instanc function, so w can accpt it as valid. 2.7 Typ dirctd projctions In w discussd how rfrncs (and pointrs) ar usd to updat valus within containr structurs, without knowldg of th surrounding containr. W also discussd how thy ar usd to updat valus that ar shard by svral diffrnt parts of th program, without nding information about how thy ar shard. On th othr hand, in 1.7 w saw how th us of ML styl rfrncs can lad to a larg amount of rfactoring ffort whn writing programs. This is bcaus th rfrnc appars in th valu typs of trms that us thm, and w must us an xplicit function call to rad a rfrnc whn w want th containd valu. Th Discipl projction systm provids a mchanism to crat rfrncs on th fly, so w can us thm for shard updat without th nd to chang th structur of valu typs. W also provid a sparat nam spac associatd with ach typ constructor, and projction functions ar placd in th nam spac corrsponding to th typ of valu thy projct. This avoids th problm with Haskll styl rcords, also discussd in 1.3.2, whr th nams of projction functions pollut th toplvl scop of th program. In this thsis w rstrict ourslvs to associating namspacs with constructors instad of gnral typs. This is to avoid issus with ovrlapping typs such as List a and List Int. Projctions ar complmntary to typ classs. For xampl, whn prforming typ infrnc for an xprssion lik show x, th variabl x may hav a polymorphic typ. As th instanc function to us for show may b rsolvd at run tim via a dictionary passing mchanism 11, th compilr itslf will not know which instanc function will b usd. Du to this, th typ of show in th class dfinition must b an uppr bound of th typs of all possibl instancs. On th othr hand, whn prforming typ infrnc for th projction x fild1, w rquir th typ of x to rsolv to somthing that includs an outr constructor. W us this constructor to dtrmin how to implmnt th projction of 11 At last it can in a matur compilr lik GHC. Our prototyp implmntation dos not yt support dictionary passing, though w ar not awar of any barrir to adding it.
114 114 CHAPTER 2. TYPE SYSTEM fild1. This in turn allows ach of th projctions namd fild1 to rturn valus of diffrnt typs Dfault projctions Considr th following data typ dfinition. data Vc2 r a = Vc2 { x :: a; y :: a } x and y ar th fild nams of th constructor. In Haskll, this dfinition would introduc x and y as rcord slctors in th top lvl scop. In Discipl, w instad gt two projctions x and y that can b applid to valus of typ Vc2 r a, for any r or a. As our typ xprssions may contain commas, w us a smicolon as a fild sparator instad of a comma. Also, is an infix oprator, and x is writtn.x in th concrt syntax. Hr is an xprssion which uss th two projctions: do vc = Vc angl = sqrt (squar vc x + squar vc y) Th projction oprator binds mor tightly than function application, so squar vc x should b rad as squar (vc x). If w do not hav a handy objct of th rquird typ thn w can rfr to th projction functions in a particular namspac dirctly with th & oprator. For xampl, w could rwrit th abov xprssion as: do vc = Vc angl = sqrt (squar (Vc2 &x vc) + (squar (Vc2 &y vc)) Th projctions associatd with fild nams ar calld dfault projctions. Ths ar introducd automatically by th languag dfinition. For Vc2 th two projction functions ar: Vc2 & x :: r 1 a. Vc2 r 1 a 1 a 1 = Rad r 1 Vc2 & x (Vc2 x y) = x Vc2 & y :: r 1 a. Vc2 r 1 a 1 a 1 = Rad r 1 Vc2 & y (Vc2 x y) = y This syntax is similar to th us of :: in C++ to dfin class mthods. For xampl, th nam of a mthod in a class namd Vc2 would b Vc2 :: x Ambiguous projctions and typ signaturs Ambiguous projctions aris whn w projct a valu whos typ is not constraind to includ an outr constructor. For xampl, th projctions in th following cod ar ambiguous: tuplofvc = λvc. (vc x, vc y)
115 2.7. TYPE DIRECTED PROJECTIONS 115 Without furthr information, th typ of vc in this cod is just a variabl. If our program includd mor than on data typ that had an x or y fild, thn thr would b no way of knowing which projction function to us. Th programmr can rsolv this problm by providing a typ signatur that constrains th typ of vc. For xampl: tuplofvc :: Vc2 a (a, a) tuplofvc = λvc. (vc x, vc y) Not that w do not nd to provid rgion, ffct or closur information in typ signaturs. Th fact that this information is missing from th abov signatur can b dtrmind from th kind of Vc2, and it can b filld in by th typ infrnc procss Pull back projctions Pull back projctions allow th programmr to crat rfrncs to th filds of a rcord. For xampl, a rfrnc to th x fild of our Vc2 typ can b cratd with vc # x, pronouncd vc pull x. If th typ of vc is Vc2 r 1 a thn th typ of vc # x is Rf r 1 a. If w imagin Rf typs bing quivalnt to pointrs in C, thn vc # x has th sam maning as th C xprssion &(vc.x). Th := # function (pronouncd updat rf ) is thn usd to updat th valu of th fild. Not that vc # x and := # ar writtn as vc#x and #= in th concrt syntax. Hr is th typ of := # (:= # ) :: r 1 a. Rf r 1 a a 1 c 1 () 1 = Writ r 1, c 1 = x : Rf r 1, Mutabl r 1 Hr is an xampl that crats a vctor thn updats on of its componnts: do vc = Vc rf = vc # x... rf := # Aftr th updat statmnt has bn xcutd, th projction vc x will rturn th valu 5.0 instad of 2.0. Pull back projction functions can also b accssd dirctly. Hr ar th nams and typs of th pull back projctions for th x and y filds: Vc2 & x pull Vc2 & y pull :: r 1 a. Vc2 r 1 a Rf r 1 a :: r 1 a. Vc2 r 1 a Rf r 1 a Not that th cratd rfrnc shars th sam rgion variabl as th projctd valu. Also not that as Vc2 only has a singl data constructor, th functions x pull and y pull ar pur. This is bcaus whn w valuat an xprssion lik vc # x, w do not nd to accss th vc objct at all. W simply allocat a nw rfrnc that contains a pointr into it. This can b don basd on th
116 116 CHAPTER 2. TYPE SYSTEM addrss of th vc objct, th objct itslf is not ndd. For xampl, if w say: vc :: Vc2 r 1 (Float r 2 ) (Float r 3 ) vc = Vc thn w would hav: rf :: Rf r 1 (Float r 2 ) rf = vc # x which producs th following objcts in th stor: rf: RfP vc: Vc2 r 1 F 2.0 F 3.0 r r 2 3 W us th tag RfP to rcord th fact that th rf objct is a pull back rfrnc that points into anothr objct, as opposd to a rgular ML styl rfrnc. Whn w xcut th statmnt rf := # 5.0, it is th pointr insid th vc objct that is updatd, not th Float objct itslf: rf: RfP vc: Vc2 r 1 F 5.0 F 2.0 r 2 F 3.0 r 3 This lavs th old 2.0 objct to b rclaimd by th garbag collctor. Th bnfit of this systm ovr ML styl rfrncs is that w ar abl to updat data structurs without nding Rf in thir typ dfinitions, which addrsss th rfactoring problm discussd in 1.7. Not that in th abov diagram, both th Vc2 and RfP objcts ar in th sam rgion, r 1. This mans that whn w us a function lik (:= # ) to updat th vctor via th rfrnc, th vctor objct will also b markd as mutabl. Although w don t nd ML styl rfrncs, Discipl dos support thm, and w can qually dfin: data Vc2 r 1 a = Vc2 { x :: Rf r 1 a; y :: Rf r 1 a }
117 2.7. TYPE DIRECTED PROJECTIONS 117 In this cas w would construct a vctor with: vc :: Vc2 r 1 (Float r 2 ) (Float r 3 ) vc = Vc2 (Rf 2.0) (Rf 3.0) This producs th following objcts in th stor: vc: Vc2 r 1 Rf Rf F 2.0 r 2 F 3.0 r 3 Hr, th rfrnc objcts includ th constructor tag Rf, instad of RfP as bfor. This indicats that to updat ths rfrncs, th pointr in th objct itslf should b modifid, not th word that is pointd to Custom projctions Along with th dfault fild projctions introducd by data typ dclarations, th programmr can also dfin thir own custom projction functions. In fact, any variabls thy dsir can b addd to th nam spac associatd with a typ constructor, whthr thy ar bound to functions that prform tru projctions, or not. For xampl, w can add a magnitud function to th Vc2 nam spac with: projct Vc2 whr magnitud (Vc2 x y) = sqrt (squar x + squar y) W us magnitud to invok this nw projction. For xampl: do vc = Vc putstr ( Th magnitud is: ++ (show vc magnitud)) Unlik dfault projctions, custom projctions can b dfind to tak xtra argumnts. For xampl, hr is a projction to dtrmin th dot product of two vctors: projct Vc2 whr dot (Vc2 x1 y1) (Vc2 x2 y2) = x1 x2 +y1 y2 W can thn us it as: do vc = Vc vc2 = Vc putstr ( Th product is: ++ (show vc dot vc2)) This allows a styl of programming similar to using local mthods in objct orintd languags. For xampl, in Java w would writ vc.dot(vc2). With Discipl cod, w find it hlpful to viw th projction dot as a singl oprator.
118 118 CHAPTER 2. TYPE SYSTEM This highlights th similaritis with th quivalnt xprssion in vctor calculus, v 1 v 2. Discipl also provids a punning syntax for adding variabls to projction namspacs. This allows th programmr to add variabls dfind lswhr in th modul, and hlps rduc th lvl of indnting in th cod. For xampl, w could dfin our magnitud and dot projctions with: projct Vc2 with {magnitud, dot} magnitud (Vc2 x y) = sqrt (squar x + squar y) dot (Vc2 x1 y1) (Vc2 x2 y2) = x1 x2 +y1 y2 W find this syntax usful whn writing library cod. Our usual approach is to dfin all th hlpr functions for a particular data typ in th sam modul that dclars it. Ths hlpr functions ar prsnt in th top lvl scop of th modul, but ar not xportd from it dirctly. W us th punning syntax to add th hlpr functions to th projction namspac for th data typ. W thn xport th data typ nam, and th projction namspac along with it. This allows us to writ th majority of our program in th familiar Haskll styl, whil rducing th opportunity for nam clashs btwn moduls. 2.8 Comparisons with othr work FX Gifford, Lucassn, Jouvlot and Talpin. Although Rynolds [Ry78] and Popk t al [PHL + 77] had discussd th bnfits of knowing which parts of a program may intrfr with othrs, Gifford and Lucassn [GL86] wr th first to annotat a subroutin s typ with a dscription of th ffcts it may prform. This allowd rasoning about ffcts in languags with first class functions, whras prvious work basd on flow analysis [Ban79] was limitd to first ordr languags. A rfind vrsion of thir systm is mbodid in th languag FX [GJSO91], which has a Schmlik syntax. W considr FX to b a spiritual prdcssor of Discipl. In Gifford and Lucassn s original systm [GL86], th typs of subroutins ar writtn τ C τ whr C is an ffct class and can b on of Procdur, Obsrvr, Function or Pur. Subroutins markd Procdur ar prmittd to rad, writ and allocat mmory. Obsrvr allows a subroutin to rad and allocat mmory only. Function allows a subroutin to allocat mmory only. A subroutin markd Pur may not rad, writ or allocat mmory. Corrctnss dictats that subroutins markd Pur cannot call subroutins markd Function, thos cannot call subroutins markd Obsrvr, and thy cannot call subroutins markd Procdur. In this systm, th concpt of purity includs idmpotnc, and a subroutin that allocats its rturn valu is not idmpotnt. Although such a subroutin cannot intrfr with othr parts of th program, th fact that it might allocat mmory must b accountd for whn transforming it. W will rturn to this
119 2.8. COMPARISONS WITH OTHER WORK 119 point in Not that in Discipl w us quantification of rgion variabls to track whthr a function allocats its rturn valu, and our dfinition of purity includs functions that do so. In [LG88] Gifford and Lucassn introduc th polymorphic ffct systm. This systm includs rgion variabls, quantification ovr rgion and ffct variabls, and ffct masking. Th primitiv ffcts ar Rad r, Writ r and Alloc r, and 1 2 is writtn maxff 1 2. Thir languag uss xplicit SystmF styl typ, rgion and ffct abstraction and applications, which maks thir xampl programs quit vrbos. Thir systm also includs rgion unions, whr th rgion typ union r 1 r 2 rprsnts th fact that a particular objct may b in ithr rgion r 1 or rgion r 2. Discipl dos not yt includ rgion unions as thy complicat typ infrnc. This point is discussd in In [JG91] Jouvlot and Gifford dscrib an algbraic rconstruction algorithm for typs and ffcts. Thy sparat typ schms into two parts, th valu typ and a st of ffct constraints, which givs us th familiar a. τ Ω for typ schms. Hr, a is a collction of typ variabls, τ is th body of th typ and Ω ar th constraints. On th othr hand, th lft of th constraints in thir work can b full ffct trms, not just variabls. Thy prsnt a proof of soundnss, but only a singl xampl xprssion. Thy also rmark that thy wr still working on th implmntation of thir systm in FX, so its practicality could b assssd. In [TJ92a] Talpin and Jouvlot abandon th xplicit polymorphism prsnt in prvious work, rquir th lft of ffct constraints to b a variabl, and introduc subffcting. This allows thir nw systm to hav principl typs. Subffcting is also usd to typ ifxprssions, as th typs of both altrnativs can b corcd into a singl uppr bound. Finally, in [TJ92b] thy prsnt th Typ and Effct Disciplin and addrss th problm of polymorphic updat 2.4. Thy us ffct information to dtrmin whn to gnralis th typ of a ltbound variabl, instad of rlying on th syntactic form of th xprssion as thy did in [JG91]. W hav basd Discipl on this work C Bjarn Stroustrup. Th C++ languag [Str86, Cpp08] includs som control ovr th mutability of data. In C++ a pointr typ can b writtn *const, which indicats that th data it points to cannot b updatd via that pointr. Pointrs can also b xplicitly dfind as mutabl. Filds in structurs and classs can b dfind as ithr mutabl or constant, though thy dfault to mutabl du to th nd to rtain backwards compatibility with C. C++ also provids som limitd control ovr sid ffcts whrby a const qualifir can b attachd to th prototyp of a class mthod. This indicats that it dos not (or at last should not) updat th attributs of that class. Howvr, this can b circumvntd by an xplicit typ cast, or by accssing th attribut via a nonconst pointr. const annotations ar also supportd in C99 [C05]. Som C compilrs including GCC [GCC09] also provid spcific, nonstandard ways to annotat function typs with mutability and ffct information. For xampl in GCC th programmr can attach a purity attribut to a function that allows th optimisr to trat it as bing rfrntially transparnt. Attributs can also b addd to variabls to indicat whthr or not thy alias othrs. Of cours, ths attributs ar
120 120 CHAPTER 2. TYPE SYSTEM compilr pragmas and not chckd typ information. Nithr C++ or C99 has typ infrnc. Mor rcnt work basd on Java [BE04] can nsur that const qualifid objcts rmain constant, and [FFA99] prsnts a gnral systm of typ qualifirs that includs infrnc Haskll and unsafprformio Simon Pyton Jons t al. GHC provids a function unsafprformio that is usd to brak th monadic ncapsulation of IO actions. It has th following typ: unsafprformio :: IO a a Us of this function discards th guarants providd by a pur languag, in favour of putting th programmr in dirct control of th fat of th program. Using unsafprformio is akin to casting a typ to void* in C. Whn a programmr is forcd to us unsafprformio to achiv thir goals, it is a sign that th undrlying systm cannot xprss th fact that th program is still saf. Of cours, this assums th programmr knows what thy r doing and th rsulting program actually is saf. As Discipl includs an ffct systm which incorporats masking, th nd for a function lik unsafprformio is rducd. As discussd in 2.3.7, if a particular rgion is only usd in th body of a function, and is not visibl aftr it rturns, thn ffcts on that rgion can b maskd. In this cas th systm has provd that rsulting program is actually saf. On th othr hand functions lik unsafprformio allow th programmr to mask top lvl ffcts, such as FilSystm. For xampl, w might know that a particular fil will not b updatd whil th program runs, so th ffct of loading th fil can b safly maskd. In ths situations th typ systm must always trust th programmr, as it cannot hop to rason about th full complxity of th outsid world Bhaviors and Trac Effcts Nilson and Nilson t al In [NN93] Nilson and Nilson introduc bhaviours, which ar a richr vrsion of th FX styl ffct typs. As wll as containing information about th actions a function may prform, bhaviours includ th ordr in which ths actions tak plac. Thy also rprsnt whthr thr is a nondtrministic choic btwn actions, and whthr th bhaviour is rcursiv. Having tmporal information in typs can b usd to, say, nforc that fils must b opnd bfor thy ar writtn to. Skalka t al s rcnt work [SSh08] givs a unification basd infrnc algorithm for a similar systm. For Discipl, w hav bn primarily concrnd with optimisation and hav so far avoidd adding tmporal information to our ffct typs. Howvr, w xpct that Discipl s main faturs such as mutability infrnc and purity constraints ar rasonably indpndnt of tmporal information, and adding it rprsnts an intrsting opportunity for futur work.
121 2.8. COMPARISONS WITH OTHER WORK λ var Odrsky, Rabin, Hudak, Chn In [ORH93] Odrsky, Rabin and Hudak prsnt an untypd monadic lambda calculus that includs assignabl variabls. Intrstingly, thir languag includs a kyword pur that provids ffct masking. pur is sn as th opposit of th monadic rturn function. This work is continud in Rabin s thsis [Rab96]. Th Imprativ Lambda Calculus [SRI91, YR97] is a rlatd systm. In [CO94] Chn an Odrsky prsnt a typ systm for λ var to vrify that uss of pur ar saf. This is don by stratifying th typ systm into two layrs, that of pur xprssions and that of commands. Thir infrnc algorithm uss a simpl ffct systm that dos not distinguish btwn pur and impur lambda bound functions. Thy not that using th rgion variabls of Talpin and Jouvlot s systm [TJ92a] would giv bttr rsults MLKit Toft, Talpin, Birkdal MLKit [TBE + 06], uss rgions for storag managmnt, whras DDC uss thm to hlp rason about th mutability and sharing proprtis of data. In MLKit, rgion annotations ar only prsnt in th cor languag. As in DDC, MLKit supports rgion polymorphism, so functions can b writtn that accpt thir argumnts from any rgion, and output thir rsult into any rgion. Unlik DDC, MLKit adds rgion annotations to function typs, as th runtim objcts that rprsnt functions ar also allocatd into rgions. MLKit prforms typ infrnc with a two stag procss [TB98]. Th SML typing of th program is dtrmind first, and rgion annotations ar addd in a sparat analysis. This hlps whn prforming typ infrnc in th prsnc of polymorphic rcursion, which is important for storag fficincy. Although polymorphic rcursion of valu typs is known to mak th gnral typ infrnc problm undcidabl [Myc84], in MLKit it is supportd on th rgion information only, via a fixd point analysis. As DDC dos not us rgions for storag managmnt, polymorphic rcursion is not as important, and w do not support it Functional Encapsulation Gupta In [Gup95] Gupta prsnts a systm to convrt mutabl objcts to constant ons for th paralll languag Id. As discussd in this is ndd for objcts that ar constructd imprativly, but ar usd functionally thraftr. Lik our own systm, Gupta s is basd on Lroy s closur typing 2.5. H prsnts a trm clos t 1 whos rsult has th sam valu as t 1, xcpt that th typ systm statically nforcs that it will no longr b updatd. Th typ of clos t 1 can also b gnralisd, bcaus th rturn valu is guarantd not to suffr th problm of polymorphic updat 2.4. clos is intrsting bcaus it srvs as th dual of th ffct masking oprator, pur, which appars in λ var [ORH93]. As in our own systm, Gupta uss rgion variabls to track th mutability of objcts. Instad of using rgion constraints, rgion variabls ar only attachd to th typs of mutabl objcts. All constant objcts ar annotatd with th null rgion ǫ.
122 122 CHAPTER 2. TYPE SYSTEM In his conclusion, Gupta lamnts that clos had not yt bn implmntd in th Id compilr, and it still rlid on hacks. Th Id languag was rincarnatd as a part of ph [NAH + 95], but clos did not mak it into th languag spcification. Bing basd on Haskll, it ndd up using stat monads to provid its impur faturs. Although w hav not yt implmntd mutability masking in DDC, it is a highly dsirabl fatur and is first in lin for futur work Objctiv Caml Lroy, Doligz, Garrigu, Rémy and Jérôuillon. As wll as Rf typs, O Caml [LDG + 08] supports mutabl rcord filds. In fact, th Rf constructor is xprssd as a rcord with a singl mutabl fild. Mutabl filds ar dclard with th mutabl kyword. Filds that ar not dclard as mutabl dfault to constant. Mutabl filds ar updatd with th oprator. Th following xampl is from th O Caml 3.11 manual: typ mutabl point = {mutabl x : float; mutabl y : float}; ; lt translat p dx dy = p.x p.x + dx; p.y p.y + dy; ; On of th bnfits of mutabl rcord filds ovr Rf typs is that w do not nd to sprinkl calls to radrf throughout our cod. This rducs th rfactoring ffort rquird whn th mutability of an objct is changd. Howvr, O Caml dos not support mutability polymorphism, so two rcords that hav th sam ovrall structur but diffr in th mutabilitis of thir filds hav incompatibl typs. A constant list has a diffrnt typ to a mutabl list, and th standard O Caml libraris only provid th constant vrsion. This point was also discussd in Calculus of Capabilitis and Cyclon Crary, Walkr, Grossman, Hicks, Jim, and Morristt Cyclon [JMG + 02] is a typsaf dialct of C which uss rgions for storag managmnt. Its typ systm drivs from Crary, Walkr and Morristt s work on th Calculus of Capabilitis [CWM99]. Th Vault [DF01] and RC [GA01] languags ar rlatd. Cyclon s typ safty is achivd in part by using rgion typing to track th liftims of objcts, and to nsur that programs do not drfrnc dangling pointrs [GMJ + 02]. Cyclon has rgion polymorphism and paramtric valu polymorphism [Gro06], but not mutability polymorphism. Bing an imprativ styl languag, programs tnd to b xprssd using updat and pointr manipulation. Allocation is xplicit, though dallocation can b prformd via th rgion systm, or implicitly via garbag collction. As in C, highr ordr functions can b introducd using function pointrs. Cyclon supports xistntial typs, and ths can b usd to xprss typ saf function closurs. Cyclon dos not support full HindlyMilnr styl typ rconstruction, but instad rlis on usr providd typ annotations. Rgion annotations ar attachd to pointr typs in th sourc languag, though many annotations can b lidd and subsquntly rconstructd by using intrafunction typ infrnc and dfaulting ruls.
123 2.8. COMPARISONS WITH OTHER WORK 123 Th main tchnical fatur that th Calculus of Capabilitis (CC) has ovr th DDC cor languag is that th capability to prform an action can b rvokd. Th CC can thn statically nsur that that a rvokd capability is no longr usd by th program. This mchanism is usd in Cyclon s rgion systm, whr th capability to accss a particular rgion is rvokd whn th rgion is dallocatd. In contrast, in DDC a capability such as th ability to updat a rgion cannot b rvokd by th programmr. W hav discussd mutability masking in 2.3.7, but hav not implmntd it. On th othr hand, DDC supports full typ infrnc (apart from ambiguous projctions, which ar an orthogonal issu). Although Cyclon is an imprativ languag, its us of rgions in th sourc languag mans that it shars som common ground with Discipl. For xampl, hr is th typ of sts from [GMJ + 02]: struct St<α, ρ> { list t <α, ρ> lts; int (*cmp)(α, α; rgions of(α)); } Th ρ annotation is th primary rgion variabl and α is a typ variabl. Th trm rgions of(α) is an ffct that rprsnts th fact that th comparison function cmp on two valus of typ α could accss any rgion containd in that typ. In this rspct rgions of(α) has th sam maning as RadT a WritT a from 2.6. Not that as Cyclon is basd on C, most data is mutabl. In such a languag thr is lss to b gaind by sparating ffcts on rgions into rads and writs. A gnral rgion accss ffct suffics BitC Shapiro, Sridhar, Smith, Dorri BitC [SSD08a] is a Schmlik languag targtd at systms programming. On of its statd aims is to offr complt mutability, maning that any location whthr on th stack, hap or within unboxd structurs can b mutatd [SSS08]. BitC supports th imprativ variabls that w dcidd not to in 2.1. Th oprational smantics of BitC includs an xplicit stack as wll as a hap, and th argumnts of functions ar implicitly copid onto th stack during application. This allows th local copis to b updatd in a way that is not visibl to th callr, a bhaviour dmonstratd by th following C program: int fun(int x) { x = x + 1; rturn x; }
124 124 CHAPTER 2. TYPE SYSTEM BitC includs mutability infrnc, and infrrd typ for th BitC vrsion of fun will b: (mutabl int) > (mutabl int) Not that th fact that x is updatd locally to fun has lakd into its typ. W do not actually nd to pass a mutabl intgr to fun, bcaus only th frsh copy, locatd in th stack fram for th call, will b updatd. For this rason, BitC introducs th notion of copy compatibility, which is similar to th proprty xprssd by our Shap constraint from W can pass a const int to a function xpcting a mutabl int, bcaus th first will b implicitly copid during th call. Although [SSD08b] discusss adding ffct typing to BitC, it dos not mntion rgion variabls, so th possibl ffcts ar limitd to th coarsgraind pur, impur and unfixd. Exploiting ffct information during program optimisation is not discussd, and th mor rcnt formal spcification of th typ systm in [SSS09] dos not includ it Monadic Rgions Flut, Morristt, Kislyov, Shan In [FM06] Flut and Morristt draw on th MLKit and Cyclon work to xprss a vrsion of th rgion calculus in a monadic framwork. Onc again, thy focus on using rgions for storag managmnt. Thy trad complxity of th original rgion typ systm for complxity of ncoding, though th rsult could srv as a usful intrmdiat languag.
125 Chaptr 3 Typ Infrnc Sourc Program Slurp Solv Export Dsugar Annot ToCor Simpl Sourc Typ Constraints Annotatd Simpl Sourc Solvd Typ Graph Flat Typs Cor Program Th abov diagram givs an ovrviw of our compilation procss. Th sourc program is first dsugard into a simplr languag, and thn annotatd with typ variabls that srv as hooks for typ constraints. Typ constraints rlating ths hook variabls ar xtractd (slurpd) from th annotatd program. Th constraints ar solvd, which producs a solution in th form of a typ graph. Th solution is a graph bcaus it can contain cycls through ffct and closur information du to th dfinitions of rcursiv functions. This was discussd in W thn xtract flat, nongraphical typs for ach of th hook variabls, and us this information to translat th annotatd sourc program into th cor languag. This chaptr concrns th annotation, constraint slurping, solving and xport stags. W giv th motivation for our ovrall approach in 3.1, and discuss th us of typ graphs. W dfin th simplifid sourc languag in 3.2, and go on to discuss th annotation procss and constraint slurping. Constraint solving is outlind in 3.3 and 3.4, whr 3.3 dals with th rduction of monomorphic constraints, and 3.4 discusss typ gnralisation and th xtraction of flat typs. In practic w also kp track of how typ schms ar instantiatd. This information is usd whn translating th sourc program to cor, but w do not discuss this or othr dtails of th translation in this thsis. Sction 3.5 xtnds th sourc languag and infrnc algorithm with support for typ dirctd projctions, and 3.6 discusss how to handl mutual rcursion in th prsnc of such projctions. Sction 3.7 discusss th builtin typ class constraints such as Pur and Shap, and 3.8 considrs how to produc rasonabl rror mssags. 125
126 126 CHAPTER 3. TYPE INFERENCE 3.1 Binding ordr and constraint basd infrnc Whn prforming typ infrnc for Haskll, a binding dpndncy graph is usd to dtrmin which groups of bindings ar mutually rcursiv. This graph is also usd to sort th binding groups so that thir typs ar gnralisd bfor thy nd to b instantiatd [Jon99]. Unfortunatly, du to th inclusion of typ dirctd projctions, a similar dpndncy graph cannot b xtractd from Discipl programs bfor typ infrnc propr. Considr th following program: fun1 x = 1 + fun2 x 5 fun2 x y = x + y As th body of fun1 rfrncs fun2, w should gnralis th typ of fun2 bfor infrring th typ of fun1. It is asy to xtract such dpndncis from Haskll programs bcaus at ach lvl of scop, all bindings must hav uniqu nams. Howvr, in Discipl programs, projctions associatd with diffrnt typ constructors can shar th sam nam. For xampl: projct T1 whr fild1 x = (x, 5) projct T2 whr fild1 x = (x, hllo ) W hav dfind two projctions namd fild1, on for constructor T1 and on for constructor T2. Now considr what happns whn w prform a fild1 projction in th program: fun x =... x fild1... This x fild1 projction will b implmntd by on of th instanc functions abov, but w cannot dtrmin which until w know th typ of x. For Discipl programs, thr is no asy way to dtrmin th binding dpndncy graph, or to arrang th bindings into an appropriat ordr bfor infrring thir typs. Instad, w must dtrmin how th bindings dpnd on ach othr on th fly, during infrnc. This implis that our infrnc algorithm cannot b ntirly syntax dirctd. Whn infrring th typ of fun, onc w dtrmin which instanc function to us for th fild1 projction, w may discovr that this typ hasn t bn infrrd yt ithr. W must thn stop what w r doing and work out th typ of th instanc function, bfor rturning to complt th typ of fun. In gnral, this procss is rcursiv. Work on th typs of svral bindings may nd to b dfrrd so that w can first dtrmin th typ of anothr. W manag this problm with a constraint basd approach, similar to that usd by Hrn in th Hlium compilr [HHS02, HHS03, H05]. W xtract typ constraints from th dsugard sourc program, solv thm, and thn us th solution to translat th dsugard cod into th cor languag, whil adding typ annotations. By approaching typ infrnc as th solution of a st of constraints instad of a bottomup travrsal of th program s abstract syntax tr, w mak it asir to dynamically rordr work as th nd ariss. This
127 3.1. BINDING ORDER AND CONSTRAINT BASED INFERENCE 127 framwork also hlps to manag our xtra rgion, ffct and closur information. Onc w hav a systm for xprssing and solving gnral typ constraints, th fact that w hav constraints of diffrnt kinds dos not add much complxity to th systm. Constraint basd systms also naturally support th graphical ffct and closur trms discussd in 2.3.8, as wll as providing a convnint way to manag th information usd to gnrat typ rror mssags. Our systm has som similarity to th on us by ML F [RY08], though w do not considr highr rank typs. W bliv our systm could b xtndd to support thm, but w hav bn mainly intrstd in th rgion, ffct and closur information, and hav not invstigatd it furthr. W also driv inspiration from Erwig s visual typ infrnc [Erw06], and th graphs usd by Duggan [DB96] to track th sourc of typ rrors. Howvr, unlik thir work w do not draw our typ graphs pictorially. W hav found that th addition of rgion, ffct and closur information, along with th associatd typ class constraints, tnds to mak ths two dimnsional diagrams into birds nsts with many crossing dgs, which hindrs th prsntation. Instad, w simply writ down th constraints as quations, and try to imagin th graph bing sparatd into svral two dimnsional layrs, on for ach kind. Such graphs might mak an intrsting targt for work on computr aidd visualisation as w know of no tool to gnrat a suitably plasing diagram.
128 128 CHAPTER 3. TYPE INFERENCE 3.2 Sourc languag and constraint slurping This sction prsnts th formal dscription of our dsugard sourc languag and discusss how to gnrat typ constraints. Th typing ruls givn in this chaptr srv as inspiration whn gnrating constraints, but corrctnss for our ovrall systm rlis on th proof of soundnss for th cor languag givn in th appndix. Any rrors in constraint gnration or typ infrnc will b dtctd whn chcking th program onc it has bn translatd to cor. W bliv this is a fair approach, bcaus nw typ systms ar usually prsntd for a cut down, dsugard languag anyway. W viw th cor typ systm as th ral typ systm for Discipl, with th systm prsntd in this chaptr bing part of th compilr implmntation. Dclarations pgm dcl; t (program) dcl data T :: % κ whr K : ϕ (data typ dclaration) Programs consist of a list of dclarations followd by a trm to b valuatd. Data typ dclarations introduc a nw typ constructor T, and giv its kind. All typ constructors T, and data constructors K dfind in a program must b distinct. W dfin th mtafunction ctortyps(t) to gt th list of data constructors K : ϕ corrsponding to a particular typ constructor T. Th st of allowabl typs for data constructors is mor rstrictiv than indicatd hr. Ths rstrictions ar introducd by th typing ruls prsntd in Kinds κ (κ 1 κ 2 ) (kind function) %! $ (atomic kind constructors) Kinds consist of kind functions and th atomic kinds, %,! and $ which ar th kinds of valu typs, rgions, ffcts and closurs rspctivly.
129 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 129 Typs ϕ, τ, σ, ς a κ (typ variabls) ϕ Ω (constraind typ) (a : κ). ϕ (unboundd quantification) ϕ 1 ϕ 2 (last uppr bound) κ κ (top and bottom) σ ς τ 1 τ 2 (function typ constructor) T κ r ϕ (data typ constructor) Rad r RadH τ Writ r (ffct typ constructors) x : ϕ (closur constructor) W do not mak a rigid syntactic distinction btwn polytyps and monotyps, or constraind and unconstraind typs. For this w ar inspird by th pur typ systm approach of th lambda cub and th Hnk intrmdiat languag [PJM97]. W also do not mak a syntactic distinction btwn valu typs, rgions, closurs and ffcts. W hav found maintaining ths distinctions to b cumbrsom in both th prsntation and implmntation. Howvr, w will hint at th intndd kind of a particular typ by using th variabls ϕ, τ, σ and ς. W intnd τ to b an unquantifid valu typ, σ and ς to b unquantifid ffct and closur typs rspctivly, and allow ϕ to b any typ. a k ar typ variabls taggd with thir kind, though w tnd to lid thir kinds in this prsntation. As typ variabls contain thir kinds, w can dtrmin th kind of an arbitrary typ xprssion without nding an auxiliary nvironmnt. Whn a spcific kind is intndd w us s, r, and c as valu typ, rgion, ffct and closur variabls rspctivly. Ω is a st of constraints. Th trm ϕ Ω is a constraind typ whos gnral maning is similar to Ω ϕ in Haskll styl systms driving from typ classs [WB89] and Jons s work on gnral qualifid typs [Jon92]. Th xprssion ϕ Ω is pronouncd ϕ with Ω. W us th ϕ Ω form bcaus w find it asir to rad whn thr ar a larg numbr of constraints, and th ordr of constraints in th sourc languag is irrlvant. Although Ω is a st, w usually writ ϕ χ 1, χ 2 instad of ϕ {χ 1, χ 2 }. W tak ϕ as bing quivalnt to ϕ. W us only unboundd quantification in th sourc languag. In th typ (a : κ).ϕ w usually lid th kind trm whn it is obvious from th nam of th variabl. For xampl, r 1.ϕ quantifis a rgion variabl and 1.ϕ quantifis an ffct variabl. W trat a : κ. ϕ as short for a : κ. ϕ. W also trat xprssions lik r ϕ as short for r 1 r 2 r 3. ϕ. Th oprator binds mor tightly than, so th typ (a : κ). ϕ Ω should b rad as (a : κ). (ϕ Ω). W do not considr highr rankd typs, and assum that all quantifid typs ar in prnx form. Th last uppr bound ϕ 1 ϕ 2 is dfind on ffct and closur typs only. κ and κ includ thir kinds and may only b an ffct. In th typs prsntd to th usr, κ may b an ffct or closur only, but during typ infrnc w abus th notation and us it as a valu typ and rgion typ as wll. Th σ ς function typ τ 1 τ 1 contains ffct and closur annotations, but if ths ar not prsnt w will assum thy ar. Du to th form of th data typ dfinitions, data typ constructors T κ r ϕ always hav thir primary rgion
130 130 CHAPTER 3. TYPE INFERENCE variabl as as thir first paramtr. Th κ in th subscript is th constructor s kind. Rad r, RadH τ and Writ r ar our initial ffct typs, though w will add mor latr. RadH τ xprsss a rad on a data constructor s primary rgion, and w us it whn gnrating typ constraints for cas xprssions. x : ϕ is a closur trm taggd with a usfully namd valu variabl. S 2.5 for a discussion of this. Constraints χ τ 1 = τ 2 (typ quality) ϕ 1 ϕ 2 (ffct or closur constraint) Our initial typ constraints ar τ 1 = τ 2 and ϕ 1 ϕ 2, though w will add typ class constraints latr. Equality constraints lik τ 1 = τ 2 ar usd to constrain valu typs and typ variabls of all kinds. Inquality constraints lik ϕ 1 ϕ 2 ar usd to constrain ffcts and closurs. Whn prforming typ chcking w must allow th lft of ths constraints to b a full typ, though in annotations and typ schms it is always a variabl. Whn prforming typ infrnc and chcking, all ffct and closur constraints must b in th wak form discussd in Typs ar strngthnd only whn prsnting thm to th usr or convrting thm to th cor languag. Trms t x (trm variabl) K (data constructor) λx. t (trm abstraction) t 1 t 2 (trm application) lt x = t in t (lt bindings) cas t of p t (cas xprssion) Pattrns p (wild card) K x (constructor pattrn) Drivd Forms if t 1 thn t 2 ls t 3 do bindstmt ; t whr bindstmt mkbind(x = t) mkbind(t) df = cas t 1 of {Tru t 2 ; Fals t 3 } df = lt mkbind(bindstmt) in t x = t t df = x = t df = x = t, x frsh Our trm languag is standard, with lt bindings bing mutually rcursiv. This is only a simpl dsugard languag. Full Discipl is swtr and includs pattrn guards, kind infrnc, monadic do notation, and othr faturs but w do not discuss thm hr.
131 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING Normal typs Although th languag dfinition provids a high dgr of frdom whn writing typ xprssions, th typs prsntd to th programmr ar all normal. Considr th following typ: succ :: 1 r 1 r 2. Int r 1 1 Int r2 1 Rad r 1 W could also writ this as: succ :: 1 r 1 r 2. s 1 1 s2 s 1 = Int r 1, s 2 = Int r 2, 1 Rad r 1 or: succ :: 1 r 1 r 2. (s 1 s 1 = Int r 1 ) 1 s 2 s 2 = Int r 2, 1 Rad r 1 All thr of ths typs ar quivalnt, and prfctly valid in our systm, though only th first is normal. Th last two can appar as intrmdiat forms during typ infrnc. Normal typs oby th following ruls: 1. Normal typs ar of th form a : κ. ϕ Ω whr ϕ is not anothr constraind typ lik ϕ 1 Ω. Whn this rstriction is in plac w rfr to ϕ as th body of th typ. 2. Thr ar no τ 1 = τ 2 constraints, and th lft positions of all ϕ 1 ϕ 2 constraints ar variabls. 3. For vry constraint st Ω in th typ, thr is only on constraint pr variabl. For xampl, w writ ϕ σ 1 σ 2 instad of ϕ σ 1, σ Normal typs do not contain nstd closur trms of th form x 1 : x 2 : ϕ. Th valu variabls ar usd for documntation only, so w kp just th first on and writ x 1 : ϕ instad.
132 132 CHAPTER 3. TYPE INFERENCE Fr variabls of typs Th function for computing th fr variabls of a typ is unsurprising: fv(a) = {a} fv(ϕ Ω) = fv(ϕ) \ {a (a = ϕ ) Ω} fv( (a : κ). ϕ) = fv(ϕ) \ {a} fv(ϕ ϕ ) = fv(ϕ) fv(ϕ ) fv( ) fv( ) fv(τ σ ς τ ) fv(t κ r ϕ) fv(rad r) fv(radh τ) fv(writ r) fv(x : ϕ) = = = fv(τ) fv(τ ) fv(σ) fv(ς) = {r} fv(ϕ) = {r} = fv(τ) = {r} = fv(ϕ) Dangrous variabls Th dangrous variabls of a typ ar computd with th following dv function, using for th initial constraint st Ω. Dangrous variabls wr discussd in Not that as w only comput th dangrous variabls of a typ bfor gnralising it, thr is nd to match on th (a : κ).ϕ form. dv(ω, a) dv(ω, ϕ Ω ) dv(ω Ω, ϕ) dv(ω, ϕ ϕ ) dv(ω, ϕ) dv(ω, ϕ ) dv(ω, ) dv(ω, ) dv(ω, τ σ c 1 τ ) dv(ω, ϕ) whr (c 1 ϕ) Ω dv(ω, T κ r ϕ) Mutabl r Ω fv(ϕ) othrwis { dv(ω, τ[r ϕ/a]) a. τ args(ctortyps(t)) } dv(ω, Rad r) dv(ω, RadH τ) dv(ω, Writ r) dv(ω, x : ϕ) dv(ω, ϕ) Th ctortyps function rturns th st of constructor typs associatd with a particular data typ constructor T. Th args function rturns th argumnts of ths constructors, rtaining th outr quantifirs.
133 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 133 For xampl, suppos th typ TwoThings was dfind as: data TwoThings r 1..3 a b = T1 (Mayb r 2 a) T2 (Mayb r 3 b) In th dsugard languag this bcoms: data TwoThings r 1..3 a b whr T1 :: r 1..3 a b. Mayb r 2 a TwoThings r 1..3 a b T2 :: r 1..3 a b. Mayb r 3 b TwoThings r 1..3 a b Now, if r 1 was mutabl, thn w could updat both altrnativs, so both a and b would b dangrous. Howvr, if r 2 was mutabl thn a would b dangrous (but not ncssarily b), and if r 3 was mutabl thn b would b dangrous (but not ncssarily a). With this dfinition, th valu of args(ctortyps(twothings)) is: { r 1..3 a b.mayb r 2 a, r 1..3 a b.mayb r 3 b } Th following is a rduction of dv for a particular xampl typ: dv(, TwoThings r 4 r 5 r 6 (Int r 7 ) (c d) Mutabl r 5 ) dv(mutabl r 5, TwoThings r 4 r 5 r 6 (Int r 7 ) (c d)) dv(mutabl r 5, Mayb r 5 (Int r 7 )) dv(mutabl r 5, Mayb r 6 (c d)) { r 7 } { r 7 } Not that c and d ar lft as nondangrous. Ths variabls would only b dangrous if r 6 or r 4 was mutabl. Th dv function is dfind with as a suprst rlationship, instad of an quality rlationship for two rasons. Firstly, it is always saf to trat mor variabls as bing dangrous than w strictly nd to, as this will simply rsult in a lss gnral schm for th typ bing tstd. Scondly, using allow us to dal with rcursivly dfind typs. For xampl, th list typ has th following dsugard dfinition: data List r 1 a whr Nil :: r 1 a.list r 1 a Cons :: r 1 a c 1. a List r 1 a c 1 List r 1 a c 1 x : a Whn dtrmining th dangrous variabls in an xampl such as List r 1 (Mayb r 2 c) Mutabl r 2 w gt: dv(, List r 1 (Mayb r 2 c) Mutabl r 2 ) dv(mutabl r 2, List r 1 (Mayb r 2 c)) dv(mutabl r 2, Mayb r 2 c) dv(mutabl r 2, List r 1 (Mayb r 2 c)) Not that th xprssion in this last stp contains two componnts. Th first is du to th a paramtr of th Cons constructor, and th scond is du to th
134 134 CHAPTER 3. TYPE INFERENCE List r 1 a paramtr. This dv(mutabl r 1, List r 1 (Mayb r 2 c)) is trivially satisfid with rspct to th scond stp, so w can simplify th drivation to: dv(, List r 1 (Mayb r 2 c) Mutabl r 2 ) dv(mutabl r 2, List r 1 (Mayb r 2 c)) dv(mutabl r 2, Mayb r 2 c) As r 2 is mutabl, c is dangrous, so th final lin rducs to { c }. Not that th dv function ncods a simpl rachability analysis, and that prforming th abov simplification is quivalnt to dciding that w hav alrady visitd th typ List r 1 (Mayb r 2 c) Matrial and immatrial variabls Th diffrnc btwn matrial and immatrial rgion variabls was discussd in Rcall that matrial rgion variabls corrspond to physical objcts in th stor, whras immatrial rgion variabls ar usd to dscrib th locations of th paramtr and rturn valus of functions. In w discussd how closur trms that do not contain matrial rgion variabls can b trimmd out. In w dfind strongly matrial rgion variabls to b th ons that appar in matrial positions, but not in immatrial ons. In w discussd how th immatrial portions of objcts cannot b copid. Th following functions, mv, iv and smv comput th matrial, immatrial and strongly matrial variabls of a typ rspctivly. Th typ is rquird to b in normal form, which is dscribd in Th thr functions ar dfind similarly to th dv function from 3.2.3, using th arg and ctortyps functions to inspct th constructors of data typ dfinitions. Not that w classify isolatd valu typ variabls as matrial bcaus thy hav th potntial to b constraintd to a typ that contains matrial rgion variabls, such as Int r 1. mv(ω, a κ ) κ {%, } {a κ } othrwis mv(ω, ϕ Ω ) mv(ω Ω, ϕ) mv(ω, ϕ ϕ ) mv(ω, ϕ) mv(ω, ϕ ) mv(ω, κ ) mv(ω, κ ) mv(ω, τ σ c τ ) mv(ω, ϕ) whr (c ϕ) Ω mv(ω, T κ r ϕ) { r } {mv(ω, τ[r ϕ/a]) a.τ args(ctortyps(t)) } mv(ω, Rad r) mv(ω, RadH r) mv(ω, Writ r) mv(ω, x : ϕ) mv(ω, ϕ)
135 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 135 iv(ω, a κ ) κ {%, } othrwis {a κ } iv(ω, ϕ Ω ) iv(ω Ω, ϕ) iv(ω, ϕ ϕ ) iv(ω, ϕ) iv(ω, ϕ ) iv(ω, κ ) iv(ω, κ ) iv(ω, τ c τ ) fv(τ) fv(τ ) fv(ϕ) iv(ω, ϕ ) {, c} whr ( ϕ) Ω, (c ϕ ) Ω iv(ω, T κ r ϕ) {iv(ω, τ[r ϕ/a]) a.τ args(ctortyps(t)) } iv(ω, Rad r) iv(ω, RadH τ) iv(ω, Writ r) {r} fv(τ) {r} iv(ω, x : ϕ) iv(ω, ϕ) smv(ω, ϕ) mv(ω, ϕ) \ iv(ω, ϕ) Exampls: τ mv(, τ) iv(, τ) smv(, τ) Int r 1 r 1 r 1 List r 1 a r 1 a r 1 a a Int r 1 a r 1 () 1 c 1 () 1 Writ r 3 r 3 r 4 1 c 1 r 3 r 4, c 1 x 1 : Int r 3 x 2 : Int r 4 Int r 1 c 1 1 Int r2 1 Rad r 1 r 2 r 1 r 2 1 c 1, c 1 x : Int r 2 Mayb r 1 (a c 1 Int r 3 ) r 1 r 3 a c 1 r 3 r 1 c 1 x : Int r 3 List r 1 (Tupl2 r 2 (Int r 3 ) (a 1 c 1 b)) 1 Rad r 3 r 1 r 2 r 3 a b 1 c 1 r 3 r 1 r 2, c 1 x : Int r 3
136 136 CHAPTER 3. TYPE INFERENCE Th map xampl W will us th following program as a running xampl: data List :: % whr Nil :: (r : %). (a : ). List r a Cons :: (r : %). (a : ). (c : $). a List r a c List r a c x : a lt map = λf. λxx. cas xx of Nil Nil Cons x xs Cons (f x) (map f xs) in map succ foo This program dfins th familiar List data typ and map function, thn applis succ to all lmnts of th list foo. W will assum that succ and foo ar dfind lswhr and hav th following typs: succ :: r Int r 1 1 Int r2 1 Rad r 1 foo :: List r 5 (Int r 6 ) Annotatd sourc languag Th first stp in typ infrnc is to annotat th sourc program with frsh typ variabls to srv as hooks for th typ constraints. Formally, w considr th annotatd languag to b an xtnsion of th sourc languag from th prvious sction, with th following additional productions: Trms t... λ(x : s x ). t (annotatd trm abstraction) lt (x : s x ) = t in t (annotatd lt bindings) Pattrns p... K (x : s x ) (annotatd constructor pattrn) Annotations ar placd on lt and lambda bound variabls, as wll as variabls that ar bound by a pattrn match. Although th annotatd languag is concptually sparat from th sourc languag, in our practical implmntation w rprsnt thm with th sam data typ.
137 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 137 Whn w add frsh variabls, th body of our xampl program bcoms: lt (map : s map ) = λ(f : s f ). λ(xx : s xx ). cas xx of Nil Nil Cons (x : s x ) (xs : s xs ) Cons (f x) (map f xs) in map succ foo Not that w hav namd th frsh typ variabls aftr th valu variabls thy rprsnt. W can imagin that thr is a mapping btwn corrsponding valu and typ variabls, and any typ variabl namd aftr a valu variabl in th sam xampl is assumd to map to it. W avoid introducing this mapping xplicitly to rduc cluttr in th prsntation. W will also assum that all variabls hav uniqu nams, so w can asily convrt btwn th two Exampl: annotatd syntax tr Whn prforming infrnc by hand, w draw th abstract syntax tr for th annotatd program. Each of th dgs in th tr is givn a uniqu numbr, and w will us ths numbrs to nam th typ variabls in th gnratd constraints. For xampl, w will nam th typ of th whol casxprssion s 3, and its ffct 3. (map:s ) xx map 4 Nil = 1 λ(f:s ) f Nil 2 λ(xx:s ) cas xx 3 lt Cons 0 map (x:s x) (xs:s xs) 23 foo f x map f 18 xs
138 138 CHAPTER 3. TYPE INFERENCE Slurping and constraint trs In DDC w call th procss of xtracting typ constraints from th annotatd syntax tr slurping th tr. Th function SLURP taks this syntax tr and producs th corrsponding constraint tr: SLURP : SyntaxTr ConstraintTr If th syntax tr has alrady bn annotatd with typ variabls and dg numbrs, thn th constraints for ach nod can b producd indpndntly. Howvr, in our implmntation w prfr to annotat th tr and gnrat constraints in a singl, bottomup pass. Th typ constraints xtractd from th program s syntax tr ar rprsntd by anothr tr that mirrors its ovrall shap. W us φ to rprsnt a branch in this tr, and th branchs hav th following structur: φ INST x (instantiat this var) LAMBDA x φ (lambda or cas bound var) LET x φ (lt bound var) GROUP x φ (group of lt bindings) a = ϕ (typ quality) a ϕ (ffct or closur inquality) INST x corrsponds to an occurrnc of a bound variabl in th program sourc. Whn xtracting constraints w gnrat an INST x for vry occurrnc, irrspctiv of whthr th variabl was bound by a lt binding, lambda abstraction or pattrn match. LAMBDA x φ contains constraints arising from a lambda abstraction or pattrn match. x is th list of bound variabls and φ is a list of constraint branchs from th body of th abstraction. LET x φ contains constraints arising from a lt binding. GROUP x φ contains all th constraint branchs from a particular mutually rcursiv lt xprssion. a = ϕ and a ϕ ar individual constraints on typ variabls.
139 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING Typs of programs and dclarations Γ pgm :: ϕ Γ dcl :: Γ d Γ t :: ϕ Γ = Γ o, Γ d Γ o dcl ; t :: ϕ (Pgm) Γ dcl :: Γ ValidCtor(T, % κ, ϕ) Γ data T : % κ whr K : ϕ :: (T : % κ, K : ϕ) (DclData) ValidCtor(T, % κ, ϕ) whr ϕ = (r : %) a : κ. T r a ValidCtor(T, % κ, ϕ) whr ϕ = (r : %) a : κ. τ T r a fv(τ) \ {r, a} ValidCtor(T, % κ, ϕ) c whr ϕ = (r : %) a : κ (c : $). τ 1 τ 2 T r a c x 1 : τ 1 (fv(τ 1 ) fv(τ 2 )) \ {r, a} In (Pgm), w st th ovrall typ of th program to b th typ of its final xprssion. As data typ dclarations can b mutually rcursiv, w add th typs and kinds gnratd by ach on to th typ nvironmnt usd whn chcking thm. In (DclData) th prdicat ValidCtor chcks that ach constructor has a typ appropriat to th data typ bing dclard. W hav givn th first fw cass of ValidCtor, and lav th inductiv gnralisation to th radr. In our implmntation w gnrat th typs of data constructors from Haskll styl algbraic typ dfinitions, instad of rquiring th programmr to giv thm xplicitly, but th chcking ruls ar asir to prsnt. Th dfinition of ValidCtor has svral points of not: th typ of a constructor cannot hav fr variabls; th typ of th rturn valu must hav a primary rgion variabl; th typs of paramtrs cannot contain variabls that ar not prsnt in th rturn typ, and constructors do not hav sid ffcts. Also not that th function arrows of constructor typs must hav appropriat closur annotations, th last cas of ValidCtor is an xampl. This is ndd to support th partial application of data constructors.
140 140 CHAPTER 3. TYPE INFERENCE Kinds of typs and constraints ϕ :: κ a κ :: κ (KiVar) ϕ :: κ χ :: κ χ Ω ϕ Ω :: κ (KiConstr) ϕ :: κ (a κ : κ). ϕ :: κ (KiAll) ϕ 1 :: κ ϕ 2 :: κ κ {!, $ } ϕ 1 ϕ 2 :: κ (KiJoin) κ {!, $ } κ :: κ (KiBot)! ::! (KiTop) τ 1 :: τ 2 :: σ ::! ς :: $ σ ς τ 1 τ 2 :: (KiFun) r :: % T % κ ϕ :: κ r ϕ :: (KiData) r :: % Rad r ::! (KiRad) ϕ :: RadH ϕ ::! (KiRadH) r :: % Writ r ::! (KiWrit) ϕ :: κ κ {, $ } (x : ϕ) :: $ (KiClo) χ :: κ τ 1 :: κ τ 2 :: κ (τ 1 = τ 2 ) :: κ (KiCEq) ϕ 1 :: κ ϕ 2 :: κ κ {!, $ } (ϕ 1 ϕ 2 ) :: κ (KiCGq)
141 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 141 Our kinding ruls ar mostly standard. In (KiConstr) w us th trm χ :: κ to rquir ach of th constraints to hav a valid kind. Th χ :: κ judgmnt nsurs that th typs on both sids of a constraint hav th sam kind Typs of trms Γ t :: ϕ Ω ; σ Th judgmnt form Γ t :: ϕ Ω ; σ rads: with nvironmnt Γ th trm t has typ ϕ, constraints Ω and ffct σ. W will assum that ϕ contains no furthr constraint sts, and that th typing ruls maintain this proprty. This is a slight abus of, but w find it mor convnint than introducing anothr oprator. Our handling of constraints is basd on Lroy s closur typing systm [LW91], so th constraint st Ω is global. Whn building a typ schm w will includ only th constraints rachabl from th body of th typ. Lroy s approach can b contrastd with Jons s systm of qualifid typs [Jon92] which ncods constraints as bounds on quantifirs, and uss sparat ruls to mov thm btwn local typs and th global st. Our cor languag uss this scond systm instad, and w convrt btwn th two rprsntations whn translating th sourc program to cor. In our typing ruls w mak no attmpt to kp th constraint st consistnt or satisfiabl. Inconsistncis such as Int r Mutabl r, Const r or Consol will b discovrd whn th program is convrtd to cor. Th cor typing ruls nsur that witnsss to th mutability and constancy of a particular rgion cannot xist in th sam program, and ffct constraints ar chckd during typ application. Attmpting to translat a program that includs inconsistnt typ constraints to th cor languag will rsult in a cor typ rror. Howvr, if ths problms ar instad dtctd during typ infrnc, thn th compilr would b in a bttr position to mit a hlpful rror mssag. Error handling is discussd in 3.8. Th typing ruls ar prsntd in thr parts, with th static rul in th cntr, th associatd nod of th abstract syntax tr on th lft, and th gnratd typ constraints on th right. Th combination of nod and typ constraints inductivly dfins th SLURP function mntiond in
142 142 CHAPTER 3. TYPE INFERENCE Var / Ctor x : a : κ. ϕ Ω Γ Γ x :: ϕ[ϕ /a] Ω[ϕ /a] Ω ; x 1 s 1 = INST s x W assum that th sourc program s syntax has alrady bn chckd, so x is bound somwhr abov its us. Th rul for data constructors is idntical to th on abov, with x rplacd by K. Th typ for x is rquird to b in th nvironmnt, and this typ may includ quantifirs a : κ and mor constraints Ω. W instantiat this typ schm by substituting nw typs b for th quantifid variabls in th body of th typ as wll as its constraints. Th xtra constraint trm Ω is ndd to match th constraints introducd by othr parts of th program, and allows th instantiatd typ to b waknd and tratd as having a largr ffct or closur trm than it dos in th nvironmnt. This is rquird whn typing th highr ordr xampls discussd in Whn gnrating constraints w dfr th qustion of whthr th variabl was introducd by a lt binding, lambda binding, pattrn match, or whthr it is part of a (mutually) rcursiv group. If a variabl turns out to hav bn bound by a lambda or pattrn match thr will b no corrsponding gnralisation of its typ, but w will us INST to instantiat it anyway. This maks th rsulting constraints asir to rad, and simplifis discussion of how to work out th binding dpndncy graph in 3.6. During typ infrnc w can think of INST as a function that blocks on th variabl s x, waiting for th typ schm of x to b bcom availabl. Abs Γ, x : τ 1 Ω 1 t 2 :: τ 2 Ω 2 ; σ 2 Γ λx. t 2 :: τ 2 c 1 1 τ2 Ω 1 Ω 2 ; whr for all y fv(λx. t 2 ) w hav (c 1 y : Γ(y)) Ω 2 and 2 σ 2 Ω 2 1 λ( x: s x ) 2 t 2 LAMBDA {x} s 1 = s 2 c 1 x s2 c 1 y 0 : s y0 y 1 : s y1... whr y n fv(λx. t 2 ) SLURP(t 2 ) An abstraction taks a trm of typ τ 1 and producs a trm of typ τ 2. Whn th abstraction is applid it will hav th ffct σ 2 of its body. In th typing rul w giv this ffct th nam 2 and bind it to σ 2 in Ω 2. Whn gnrating constraints w can simply annotat th function constructor with 2, and th rquird ffct constraints will b gnratd whn slurping th body. As valuating th abstraction itslf causs no ffct, w hav in th conclusion of th rul.
143 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 143 Th closur of an abstraction contains th typs of its fr variabls. In th typing rul w can rad ths typs dirctly from th nvironmnt using Γ(y). Whn w r gnrating constraints w won t know what ths typs ar yt, so w us th th plac holdr variabls s y0, s y1... instad. Ths variabls will b bound to thir ral typs during infrnc. App σ Γ t 2 :: τ 4 ς 4 3 τ1 Ω; σ 2 Γ t 3 :: τ 3 Ω ; σ 3 Γ t 2 t 3 :: τ 1 Ω ; σ 2 σ 3 σ t 2 t 3 s 2 = s 4 c 4 3 s , c 4 frsh SLURP(t 2 ) SLURP(t 3 ) σ An application nod applis a function of typ τ 4 ς 4 3 τ1 to its argumnt of typ τ 3, yilding a rsult of typ τ 1. Th act of applying th function has an ffct σ 4. Th ffct of valuating th ntir xprssion consists of th ffct of valuating th function valu, of valuating th argumnt, and of applying th function. In th trminology of [LG88], σ 4 is th intrinsic ffct of th application and σ 2 σ 3 is th inhritd ffct. Th closur of th function is of no consqunc whn typing an application, so ς 4 is only mntiond onc in th rul. Whn gnrating typ constraints w will not yt know what th ffct of th function will b. In our constraints w us 4 and c 4 as local nams for th function s ffct and closur. Ths will b bound to th actual ffct and closur of th function during typ infrnc.
144 144 CHAPTER 3. TYPE INFERENCE LtPoly Γ, x n : ϕ n t :: τ Ω ; σ Γ, x n : τ n Ω t 0 :: τ 0 Ω ; σ 0 ϕ 0 = Gn(Γ, τ 0 Ω) Γ, x n : τ n Ω t 1 :: τ 1 Ω ; σ 1 ϕ 1 = Gn(Γ, τ 1 Ω).. Γ lt x n = t n in t :: τ Ω ; σ σ 0 σ 1... = (x 0:s x0) a0 1 lt = a1 (x 1:s x1) t 0 t 1 2 t GROUP {x 0, x 1,... } s 1 = s 2 1 a0 a1 2 LET x 0 s x0 = s a0 SLURP(t 0 ) LET x 1 s x1 = s a1 SLURP(t 1 ). SLURP(t) Th function Gn gnraliss th typs of ach binding. This procss is discussd in 3.4. Not that in th xprssion: ϕ = Gn(Γ, τ Ω) Th rsulting typ ϕ contains only th constraints from Ω that ar rachabl from τ. Th conclusion of (LtPoly) includs th constraint st Ω, and th sam st is usd in ach of th prmiss. This mans that constraints that ar concptually local to a particular binding will lak into th global st. For xampl: Γ, succl : r 1 r 2. Int r 1 Int r 2 Const r 1 succl 3 :: Int r 3 Const r 3, Const r 4 ; Γ, succl : Int r 4 Int r 5 Const r 3, Const r 4 λx. suspnd1 succ x :: Int r 4 Int r 5 Const r 3, Const r 4 ; Γ lt succl = λx. suspnd1 succ x in succl 3 :: Int r 3 Const r 3,Const r 4 ; Th function succl is a lazy vrsion of succ that rads its argumnt only whn th rsult is dmandd. Th gnral typ of succl is: succl :: r 1 r 2. Int r 1 Int r 2 Const r 1 Th constraint Const r 1 ariss from th us of suspnd1 in th dfinition of succl. Whn chcking this dfinition w giv succl th monotyp:
145 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 145 Int r 4 Int r 5 Const r 4 Du to th formulation of th (LtPoly) rul, th constraint Const r 4 is actually prsnt in both prmiss, as wll as th conclusion. Also, in th body of th ltxprssion, th application of succl to th constant 3 rquirs that constant to b (rally) constant, hnc th constraint Const r 3. Although this constraint only concrns th body of th ltxprssion, it is also prsnt in th st usd whn typing th bindings. This bhavior is unlik that of th (Lt) rul prsntd by Lroy in [LW91]. Lroy s rul uss Gn to split th constraint st arising from a ltbinding into two substs: thos that ar rachabl from th body of th typ bing gnralisd, and thos that arn t. If w wr to us Lroy s approach, th first prmis and conclusion of our xampl would not contain Const r 4, and th scond prmis would not contain Const r 3. Lroy s rul is nicr whn drawing proof trs, but w stick to th laky vrsion bcaus it mirrors what happns during typ infrnc. Our infrnc algorithm adds all th typ constraints xtractd from th program into a global graph, solvs thm, thn rturns th whol graph. It dos not sction th graph into portions rlating to individual bindings, and it only rmovs constraints from th graph whn daling with th typ classs discussd in 3.7. Rtaining information from all bindings also maks it asy for th implmntation to add typ annotations to th dsugard program whn convrting it to cor. As w hav not implmntd polymorphic rcursion [Myc84], w chck th right of ach binding using th ungnralisd typs for ach ltbound variabl. Du to this, many usful programs ar not dirctly typabl with this (LtPoly) rul. Considr this xampl from [Myc84]: lt map = λf. λxx. cas xx of Nil Nil Cons x xs Cons (f x) (map f xs) squarlist = λl. map (λx. x x) l complmnt = λl.map (λx.not x) l in... This program will not b accptd as it stands. W nd to us th gnralisd, polymorphic typ of map whn applying it to (λx. x x) and (λx.not x) bcaus ths xprssions hav diffrnt typs. If w us th ungnralisd, monomorphic typ thn w will gt an rror. This highlights th fact that our sourc typing ruls ar only a guid for gnrating typ constraints, and that w cannot us thm to chck th sourc program dirctly. W must first prform typ infrnc by xtracting typ constraints and thn solving thm. As discussd in 3.6, our algorithm for solving typ constraints also builds a graph that rcords what bindings ar mutually rcursiv. Onc w hav this graph w can us it to split out th dfinition of map from th abov xampl, and convrt th program to:
146 146 CHAPTER 3. TYPE INFERENCE lt map = λf. λxx. cas xx of Nil Nil Cons x xs Cons (f x) (map f xs) in lt squarlist in... = λl. map (λx. x x) l complmnt = λl.map (λx.not x) l For this vrsion, (LtPoly) allows us to us th gnralisd typ of map whn chcking th body of th scond ltxprssion. This nw program will b accptd without rror. Cas 2 t cas Γ t :: T r ϕ Ω ; σ Γ p p 0 t 0 :: T r ϕ τ Ω ; σ 0 Γ p p 1 t 1 :: T r ϕ τ Ω ; σ 1 Γ cas t of p t :: τ Ω ; Rad r σ σ 0 σ p0 a0 p1 a1 p t 0 p t s 2 s 2 s 1 s 1. = s p0 = s p1. = s a0 = s a1. 1 = RadH s 2 2 a0 a1... SLURP(t) SLURP(p 0 ) SLURP(p 1 ). SLURP(t 0 ) SLURP(t 1 ) A cas xprssion rquirs th discriminant t to hav th sam typ as th pattrns bing matchd against. For all altrnativs, th typs of th pattrns must b idntical, and so must th typs of th xprssions. Th typ of th ntir cas xprssion is th typ of th right of th altrnativs. Th ffct of a cas xprssion includs th ffct of valuating th discriminant and xamining it, as wll as valuating th altrnativs. Whn typ chcking a program in a bottomup mannr, whn it s tim to apply th (Cas) rul w will alrady know th typ of th discriminant. In this situation w can us Rad r as th ffct of xamining it. On th othr hand, whn gnrating constraints w will not yt know th typ of th discriminant. W instad us RadH s 2, which rprsnts a rad ffct on th primary rgion of th (currntly unknown) typ s 2. During infrnc, th typ of s 2 will rsolv to th ral typ of th discriminant. Aftr this is don, RadH s 2 can b rducd to a Rad ffct on th primary rgion of this nw typ..
147 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 147 Γ p p t :: τ 1 τ 2 Ω Γ p Γ t :: τ 2 Ω ; σ t :: τ 1 τ 2 Ω ; σ (PatWildcard) T : % κ Γ K : (r : %) a : κ c : $. τ c T r a Ω Γ θ = [ r /r ϕ/a ] Γ, x n : θ(τ n ) θ(ω) n t :: τ Ω ; σ Γ p K x t :: T r ϕ τ Ω ; σ (PatConstructor) 2 (x:s ) x 1 K s 1 = T r a s x = τ. whr τ T r a = Inst( (r : %) a : κ c : $. τ c T r a) Th judgmnt form Γ p p t :: τ 1 τ 2 Ω rads: with nvironmnt Γ an altrnativ matching a pattrn p and producing a trm t has typ τ 1 to τ 2 with constraints Ω. Matching against a wildcard producs no constraints. In (PatConstructor) w lookup th typ of th constructor K from th nvironmnt. Th (DclData) rul from introducs ths typs into th nvironmnt and nsurs that thy hav th particular form shown hr. Th variabls bound by th pattrn ar namd x, and th typs of ths variabls must hav th sam form as th typs of th argumnts of th constructor. If th constructor producs a typ containing variabls a thn all occurrncs of x must agr on th particular typs usd for a. For xampl with th constructor: Cons :: r a c. a List r a c List r a c x : a Considr th altrnativ in: cas... of Cons x xs... W cannot, say, us x at typ Int r 1, but xs at typ Cons r 2 (Bool r 1 ) bcaus Int r 1 Bool r 1. This rstriction is achivd by rquiring th typs of ach of th pattrn bound variabls to b rlatd by th substitution θ. Th constraint gnration ruls givn hr only concrn th pattrn in a particular altrnativ. Th job of matching up th typs of all altrnativs in a casxprssion is handld by th constraints for th (Cas) rul on th prvious pag. Whn gnrating constraints for a pattrn, w first tak a frsh instanc of th constructor s typ schm. Th rsult typ is th typ of th ovrall pattrn, and th argumnt typs ar assignd to th variabls bound by th pattrn.
148 148 CHAPTER 3. TYPE INFERENCE Exampl: typ constraints Th following contraint tr is for our map xampl: GROUP {map} s 0 = s LET map s map = s 1 LAMBDA {f} s 1 = s 2 c 1 f c 1 s2 map : s map LAMBDA {xx} s 2 = s xx 3 c 2 s3 c 2 map : s map f : s f s 3 = s 6 3 RadH s s 3 = s 8 s 4 = s 5 s 4 = s 7 s 5 = List r 5 a 5 s 7 = List r 7 a 7 s x = a 7 s xs = List r 7 a 7 s 4 = INST s xx LAMBDA s 6 = INST s Nil LAMBDA {x, xs} s 9 = s 8a c 8 14 s a s 10 = s 9a c 9 11 s a s 10 = INST s Cons s 12 = s 11a c s a s 12 s 13 = INST s f = INST s x s 15 = s 14a c s a s 16 = s 15a c s a s 16 s 17 s 18 = INST s map = INST s f = INST s xs s 20 = s 19a c s19 19 = a s 21 = s 20a c s20 20 = a s 21 s 22 s 23 = INST s map = INST s doubl = INST s foo
149 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 149 Th constraint tr chos th abstract syntax tr. W hav rtaind th ovrall structur of th program, whil dispnsing with dtails such as distinction btwn cas altrnativs and lambda abstractions, and th ordr of function applications. Onc constraints hav bn xtractd, th infrnc algorithm can ignor th sourc program ntirly. In our ral implmntation w us a sourc languag that has mor sugar than th on prsntd hr, but th constraint languag is th sam. Bfor discussing how to actually solv th constraints, not that thr ar svral dgrs of frdom in thir ordring. Within a particular LAMBDA, LET or GROUP block it is always saf to mov = or constraints arlir in th block. It is also saf to mov ths constraints up and arlir in th tr, such as moving s map = s 1 so it appars dirctly aftr Moving ths constraints highr up in th tr mans thy will b considrd arlir, and such modifications will not dgrad th final constraint solution. It is also saf to chang th ordr of LAMBDA or LET blocks at th sam lvl. This simply corrsponds to changing th ordr of ltbindings or casaltrnativs in th original program. On th othr hand, in gnral it is not saf to mov INST constraints as thy control th ordr in which typs ar instantiatd. Although w will discuss rcursion mor fully in 3.6, th structur of th constraints rvals that map is rcursivly dfind. This is vidnt from th fact that s 16 = INST s map, prsnt in th lowr quartr of th list, appars insid th LET map block. This constraint corrsponds to a rcursiv us of map. This is in contrast to s 21 = INST s map which appars outsid th block and corrsponds to a nonrcursiv us. Without polymorphic rcursion, all rcursiv uss of ltbound variabls should b at idntical typs, so w will chang s 16 = INST s map to s 16 = s map. From th structur of tr w s that th INST constraints for s 4, s 12, s 13, s 17 and s 18 all corrspond to uss of lambda or pattrn bound variabls. This is clar bcaus thy appar insid a LAMBDA block corrsponding to th variabl thy instantiat. For this xampl w will also simplify ths constraints by idntifying th variabls on th lft and right, giving: s 4 = s xx, s 12 = s f, s 13 = s x and so on. W will assum that th typs of Nil and Cons ar known. This allows us to rplac th constraints for s 6 and s 10 with frsh instantiations of thir typ schms. Although th typ of Cons includs a closur trm, w stor th closur constraint in th graph instad of dirctly in its typ. Th form of our rduction ruls rquir that all constraints involv a singl constructor only. s 6 = List r 6 a 6 s 10 = a 10 s 10a s 10a c = s 10 10b s10c s 10b = List r 10 a 10 s 10c = List r 10 a 10 c 10 = x : a Constraint sts and quivalnc classs Now w can start building th typ graph. In th graph our constraints ar organisd into a st of quivalnc classs. Each quivalnc class contains a st of typs that must b qual, or constraind by an inquality. Equivalnc classs
150 150 CHAPTER 3. TYPE INFERENCE can b in on of thr forms, dpnding on th kind of th typs containd. Valu quivalnc classs hav th form κn s = τ, whr κ is th kind of th class, n is a uniqu intgr idntifying it, s is a list of typ variabls, and τ is a st of nonvariabl typs. Th intntion is for th variabls on th lft of th = to b idntifid with th typs on th right. Effct and closur classs us instad of =, so w writ thm as κn a τ. As thr ar no constructors of rgion kind, w writ rgion quivalnc classs as κn s. For xampl, whn w construct an quivalnc class from th following constraint st: w gt: { s 1 = s 2 c 1 f s2, s 16 = s 15a c s15, s 16 = s map, s 1 = s map } *0 s map, s 1, s 16 = s 2 c 1 f s2, s 15a c s15 This class has th kind of valu typs and is idntifid as class 0. Th variabl that coms first in th list is th canonical nam for th class. Th canonical nam is th variabl that w choos to rprsnt th class, and whn doing infrnc by hand w choos th nam that is most intrsting. In this cas w hav chosn s map as mor intrsting than s 1 or s 16, but this choic will not affct th substanc of our constraint solution. Whn a nw typ variabl is addd to an quivalnc class w substitut th canonical nam for occurrncs of this variabl in th graph. Th two typs on th right of th = com from th s 1 = s 2 c 1 f s2 and s 16 = s 15a c s15 constraints. W rfr to th st of quivalnc classs as th typ graph to distinguish it from th st of constraints which it is built from. Constraint sts and quivalnc classs xprss similar information, but ar not compltly intrconvrtibl. An quivalnc class contains variabls and typ constructors from th constraint st, but no information about how to match thm up. For xampl, from th quivalnc class abov w cannot tll if th original constraint st containd s 1 = s map, s 1 = s 16, or both. An quivalnc class rcords a st of typs that ar all qual, but not xactly why. Th fact that this information is is lost will not mattr until w discuss rror rporting in 3.8. Until thn w will us quivalnc classs, as this notation is mor compact Exampl: typ graph Continuing on with our map xampl, w will add all constraints up to th nd of th LET map block to th typ graph. Th rsult is shown on th nxt pag. Not that w hav lidd classs that contain only a singl variabl, such as for r 4 and 1. Th form of th typ graph alrady suggsts how w should procd from hr. Not that th class for s map (*1) contains two typ constructors s 15a c 15 f s15 and s 2 c 1 f s2. Ths rprsnt th us and dfinition of map rspctivly. Unifying ths two typs implis that th classs for s 15 (*13) and s 2 (*5) should b mrgd. This inducs th unification of s xx and s xs, which implis that th input list must hav th sam typ as its tail, as xpctd.
151 3.2. SOURCE LANGUAGE AND CONSTRAINT SLURPING 151 (map:s ) xx map 4 Nil = 1 λ(f:s ) f Nil 2 λ(xx:s ) cas xx 3 lt Cons 0 map (x:s x) (xs:s xs) 23 foo f x map f 18 xs *0 s 0, s 19 = *1 s map, s 1, s 16 = s 15a c 15 f s15, s 2 c 1 f s2 *2 s f, s 17, s 12 = s 11a c 11 x *3 s x, s 13, a 7 = *4 s xs, s 18 = List r 7 a 7 *5 s 2 = s 3 c 2 xx s3 *6 s 3, s 6, s 8 = List r 6 a 6 *7 s xx, s 4, s 5, s 7 = List r 5 a 5, List r 7 a 7 *8 s 9 = s 8a c 3 14 s3 *9 s 10 = s 9a c 9 11 s9, s11 c *10 s 10a = s 10 10b s10c *11 s 10b = List r 10 a 10 *12 s 10c = List r 10 a 10 *13 s 15 = s 14a c 14 xs! !1 3 RadH s xx 6 8! a s14! a! a! a! a $1 c 1 map : s map $2 c 2 map : s map f : s f $3 c 10 x : a 10 a 10 s 10a
152 152 CHAPTER 3. TYPE INFERENCE 3.3 Constraint rduction Our immdiat goal is to dtrmin a typ for map. Howvr, th quivalnc class corrsponding to s map currntly contains two diffrnt typ xprssions. Although union typing systms [DP03] provid a join oprator on valu typs, w do not considr ths systms hr and will instad tak th standard approach of unifying all th typs in a particular quivalnc class. Unifying all typs corrsponds to a ML styl systm, which is usually xprssiv nough for our nds. W will considr union typing again in Th unification of typs may gnrat mor constraints. Ths nw constraints must b addd back to th graph, possibly rsulting in mor unifications, which may gnrat mor constraints, and so on. In DDC w call this procss grinding th graph, and w tak this to includ prforming unifications as wll as rducing typ class constraints and compound ffcts Constraint ntailmnt W us ntailmnt ruls to dscrib oprations on constraint sts. Entailmnt ruls hav th form P Q, whr P and Q ar both sts. P Q can b rad: P ntails Q, or prhaps P producs Q. If w hav a constraint st R and a rul P Q whr P R, thn w can rplac th constraints P in R by th nw constraints Q. Any variabls prsnt in P match th corrsponding typs in R. For xampl, w could apply transitivity rul: (trans) {s 1 = s 2, s 2 = s 3 } {s 1 = s 2, s 2 = s 3, s 1 = s 3 } To th following constraint st: to gt: {s a = s b, s b = Int r 1 } {s a = s b, s b = Int r 1, s a = Int r 1 } Whn w apply an ntailmnt rul P Q, w tak any variabls prsnt in Q but not P or R to b frsh. Not that our ntailmnt ruls ar xprssd as oprations on constraint sts, not on typ graphs. To apply a rul to th typ graph w must imagin it bing convrtd to a constraint st and back again. As discussd in th two forms ar not totally quivalnt, but th fact that w los information whn convrting a constraint st to a typ graph will only mattr whn w com com to discuss typ rror mssags in 3.8. W us th graph rprsntation until thn as it is mor compact and simplifis th prsntation.
153 3.3. CONSTRAINT REDUCTION Unification Th ntailmnt ruls for unification ar: (unify fun) { s = a 1 c 1 1 b1, s = a 2 c 2 2 b2 } { s = a 1 c 1 1 b1, a 1 = a 2, b 1 = b 2, 1 = 2, c 1 = c 2 } (unify data) { s = T 1 a, s = T 1 b } { s = T 1 a, a = b } Th first rul is applicabl whn thr ar two function typ constraints on a particular variabl s. Applying th rul causs th scond constraint to b discardd, whil gnrating four nw ons. Ths nw constraints quat th typ variabls for th argumnt, rturn valu, ffct and closur of ach function. Th scond rul is similar. Whn w com to add a constraint lik a 1 = a 2 to our typ graph, if th two variabls ar alrady in th sam quivalnc class thn w just ignor th constraint. If thy ar in sparat classs thn w add all th variabls and typs in th first on to th scond, and dlt th first (or vicvrsa). For xampl, our graph for map includs th following: *1 s map, s 1, s 16 = s 15a c 15 f s15, s 2 c 1 f s2 *2 s f, s 17, s 12 = s 11a c 11 x *5 s 2 = s 3 c 2 xx s3 *13 s 15 = s 14a c 14 xs!7 15a!8 2 $1 c 1 map : s map $4 c 15 s11 s14 Applying th unification rul to *1 allows us to dlt th first function typ, whil gnrating th nw constraints s f = s f, s 15 = s 2, 15a = 2 and c 15 = c 1. W can safly discard th trivial idntity s f = s f. To add s 15 = s 2 back to th graph w add th lmnts of *5 to *13 and discard *5. Likwis, to add 15a = 2 w will add th lmnts of!7 to!8 and dlt!7. This yilds: *1 s map, s 1, s 16 = s 2 c 1 f s2 *2 s f, s 17, s 12 = s 11a c 11 x s11 *13 s 15, s 2 = s 14a c 14 xs s14, s 3 c 2 xx!8 2, 15a $1 c 1, c 15 map : s map s3 Not that whn thr ar multipl typs in a valu typ quivalnc class w sparat thm by a comma. On th othr hand, multipl typs in an ffct or closur quivalnc class ar sparatd by. This follows naturally from th fact that constraints on valu typs ar always xprssd with =, but constraints
154 154 CHAPTER 3. TYPE INFERENCE on ffcts and closurs ar always xprssd with. Using th dfinition of w can thn go on to simplify to just. Not that in th constraint st rprsntation this simplification isn t ndd. If w hav both 1 and 1, thn putting ths constraints in a st automatically mrgs thm. Th application of (unify fun) to *1 has causd a nw typ to b addd to *1. W kp applying our unification ruls until no furthr progrss can b mad, and whn this is don w hav: *0 s 0, s 19 = *1 s map, s 1, s 16 = s 2 c 1 f s15 *2 s f, s 17, s 12 = s 11a c 11 x *3 s x, s 13, a 7, a 5 = *6 s 3, s 6, s 8, s 14, s 10b, s 10c = List r 6 s 11 *7 s xx, s 4, s 5, s 7, s xs, s 18 = List r 5 s x *9 s 10 = s 9a c 9 11 s10a *10 s 10a s 9 = s 8a c 3 3 s3 *13 s 15, s 2 = s 3 c 2 xx s3 *14 s 11, a 10, a 6 %0 r 5, r 7 %1 r 6, r 10! !1 3, 14a RadH s xx 6 8! a! a! a! ! !7 2, 15a $1 c 1 map : s map $2 c 2 map : s map f : s f $3 c 10 x : a 10 s Had rad Whn unification is complt w hav a constraint s xx = List r 5 s x in *7. This allows us to rduc th RadH s xx ffct in!1 that was gnratd by th casxprssion in th original program. In DDC w call th procss of rducing ffct typs or typ class constraints crushing. Th ntailmnt rul for RadH is : (rad had) { RadH s, s = T r s } { Rad r, s = T r s } This says that th ffct of rading th primary rgion of a data typ can b rducd to a simpl rad of that rgion onc th rgion is known. This lts us rduc:
155 3.3. CONSTRAINT REDUCTION 155 to: *7 s xx, s 4, s 5, s 7, s xs, s 18 = List r 5 s x!1 3, 14a RadH s xx 6 8 *7 s xx, s 4, s 5, s 7, s xs, s 18 = List r 5 s x!1 3, 14a Rad r Rcall that whn applying an ntailmnt rul, w must imagin th typ graph bing convrtd to a constraint st and back. Th two quivalnc classs *7 and!1 corrspond to th st: { s xx = s 4, s xx = s 5, s xx = s 7, s xx = s xs, s xx = s 18, s xx = List r 5 s x, 3 = 14a, 3 RadH s xx, 3 6, 3 8 } Exprssing th graph in this form sparats out th constraints 3 RadH s xx and s xx = List r 5 s x, which match th prmis of th (rad had) rul.
156 156 CHAPTER 3. TYPE INFERENCE 3.4 Gnralisation Whn no mor typs can b unifid, and no mor ffcts or typ class constraints can b rducd, th graph is said to b in normal form. W can now xtract th typ for map from our graph and gnralis it into a typ schm. In DDC w rfr to th complt procss of building a typ schm from th information in th typ graph as gnralisation. This procss is brokn down into svral stags, summarisd blow. Not that in a concrt implmntation, svral of ths stags can prformd at th sam tim. For xampl, chcking for loops through th constraints can b don whil tracing thm, as tracing corrsponds to a simpl rachability analysis. 1. Tracing: isolat th typ information of intrst. 2. Loop chcking: chck for infinit valu typ rrors. 3. Packing: pack th graphical constraints into flat form. 4. Loop braking: brak loops through ffct and closur constraints. 5. Claning: discard nonintrsting ffct and closur variabls. 6. Quantification: introduc typ quantifirs Tracing Th first stp is to trac out th sction of graph that is rachabl from th typ variabl w r intrstd in. For this xampl w r intrstd in map and all quivalnc classs xcpt *0 ar rachabl from s map. This procss maks a copy of th information prsnt in th global graph, and th oprations dscribd in th rst of this sction ar prformd on th copy Loop chcking W now chck for loops through th valu typ portion of th copid subgraph. A classic xampl of a program with a looping typ is: x = Cons xnil whr Cons and Nil hav th following typs: Nil Cons :: r a.list r a :: r a c. a List r a c List r a c x : a Aftr slurping and grinding constraints, this program has th following graph: *1 s x, s 1, s 4, a 3, a 5 = List r 3 s x *2 s 2, = s 1 c 1 5 sx *3 s 3, s Cons = s 2 c 2 4 s2 *4 s 5, = List r 3 s x $1 c 3, c 1 x : s x %1 r 3, r 5 Th loop is through quivalnc class *1. W cannot produc a flat, nongraphical typ for s x bcaus if w trid to solv its constraint our algorithm would divrg:
157 3.4. GENERALISATION 157 s x = List r 3 s x s x = List r 3 (List r 3 s x ) s x = List r 3 (List r 3 (List r 3 s x ))... Unlik [CC91] w do not attmpt to handl rcursiv valu typs, so w flag thm as rrors instad. This is common to othr compilrs such as GHC, which would mit a mssag cannot construct infinit typ. Not that loops through th ffct or closur portions of a typ graph ar not countd as rrors. W dal with ths in Packing Packing is th procss of convrting a st of individual typ constraints into th normalisd form of Whn w pack th constraints from our map xampl into this form w hav: s map = (s 11a c 11 x s11 ) 2 c 1 List r5 s 3 c 2 x List r6 s 11 3 Rad r 5 6 8, a, a, a, , , c 1 map : (s 11a c 11 x s11 ) 2 c 1 List r5 s 3 c 2 x List r6 s 11, c 2 map : (s 11a c 11 x s11 ) 2 c 1 List r5 s 3 c 2 x List r6 s 11 f : s 11a c 11 x s11 Although th body of this typ is now in th familiar form, thr is still a hash of ffct and closur constraints. Howvr, notic that thr is only on us ach of th variabls 8, 9, 11, 14 and 15, and thy ar not mntiond in th body of this typ. From a compilr optimisation point of viw, th only ffct information that w nd to prsrv is th manifst ffct of ach function arrow. Th fact that, say, 3 includs 8 and 8 includs 9 dos not mattr, as long as all of th appropriat variabls ar rachabl from 3. This mans that w can inlin th constraints on 8, 9 and so on into th constraint for 3. W can also us th closur trimming procss discussd in to simplify th constraints for c 1 and c 2. This producs: s map = (s 11a c 11 x s11 ) 2 c 1 List r5 s 3 c 2 x List r6 s 11 3 Rad r a a a , c 1 map : c 1, c 2 map : c 1 f : c 11
158 158 CHAPTER 3. TYPE INFERENCE Loop braking As discussd in 2.3.8, w can us th lattic structur of ffcts and closurs to brak loops through ffct and closur constraints. If th typ of a particular valu variabl contains looping constraints, thn braking ths loops maks th typ simplr, and allows it to b xportd to th cor languag. Th following diagram shows a loop through th ffct portion of th typ for map, as it was aftr th first stag of packing: 3 Rad r 5 8a a a Notic how th structur of this ffct graph chos th original abstract syntax tr for map. In th ffct graph w can s two branchs, hadd by 9 and 14, corrsponding to th two altrnativs of th original cas xprssion. W can also s th rcursiv call via 3. map applis itslf, so th ffct of map includs th ffct of map. Similarly, map rfrncs itslf, so th closur of map includs th closur of map. Howvr, although rcursion in th function s dfinition srvs a usful purpos, th fact that its ffct and closur is also rcursiv is not xploitd by our analysis. W nd to rtain th st of ffcts causd by an application of map, that is, th ffcts rachabl from 3, but this information would not b lost if w substitutd for its rcursiv occurrnc. Finally, th constraints 3 3 and c 1 map : c 1 ar trivially satisfid, so can b discardd. This lavs us with: s map = (s 11a c 11 x s11 ) 2 c 1 List r5 s 3 c 2 x List r6 s 11 3 Rad r a a a , c 2 map : c 1 f : c Clan boring ffct and closur variabls Thr ar still a larg numbr of ffct and closur variabls in our typ that don t provid any usful information. For xampl, 6 is th ffct of valuating th variabl Nil, but valuating a variabl dosn t hav a visibl ffct. Also considr 9, th ffct of valuating Cons (f x). Th valuation of (f x) itslf has th ffct 11, which is intrsting bcaus it dpnds on th function argumnt passd to map, but th partial application of Cons to th rsult dos not hav an ffct, so is boring. In any vnt, th constraint on 3 alrady contains 11, so it dosn t nd to includ 9 as wll. W dfin boring ffct and closur variabls to b th ons that cannot tak on any typ othr than. This will b th cas whn th variabl is nithr in th
159 3.4. GENERALISATION 159 typ nvironmnt, has a constraint, nor is mntiond in a paramtr of th typ bing gnralisd. If a variabl is in th typ nvironmnt thn it dpnds on a dfinition in an highr scop of th program. In this cas, a mor intrsting typ may b unifid into th variabl latr in th infrnc procss. If it has a constraint thn it dpnds on othr typs. If it is mntiond in a paramtr typ thn it may b diffrnt for ach application of th function. For our xampl, 11a, c 11, 3 and c 2 ar intrsting, and th rst ar boring. W substitut for boring variabls, thn us th dfinition of : s map = (s 11a c 11 x s11 ) List r 5 s 3 c 2 x List r6 s 11 3 Rad r 5 11a, c 2 f : c Quantification W can now add quantifirs to our typ and crat a typ schm. Thr ar svral rstrictions as to which variabls can b quantifid, which w will rcall in a momnt, but for this xampl non apply. Aftr quantification w hav: s map = s x s 11 r 5 r 6 11a c 11 3 c 2. (s 11a c 11 x s11 ) List r 5 s 3 c 2 x List r6 s 11 3 Rad r 5 11a, c 2 f : c 11 W will also rwrit th quantifid variabls to us mor familiar nams: s map = a b r 1 r c 1 c 2. (a 1 c 1 b) List r1 a 2 c 2 List r2 b 2 Rad r 1 1, c 2 f : c 1 At this stag w could also apply th th ffct masking ruls from and 2.5.2, though non apply in this xampl. Onc gnralisation is complt w updat th s map quivalnc class in th global graph so it contains this nw typ schm. Th nongnralisabl variabls Thr ar svral rasons why a particular typ variabl may not b prmittd to b gnralisd. All but th first wr discussd in th prvious chaptr. Don t gnralis: 1. Variabls fr in th typ nvironmnt. This is th standard rstriction for HindlyMilnr typ systms [Mil78, DM82]. Howvr, as w r prforming typ infrnc instad of typ chcking, th ral typ nvironmnt is not clos at hand. W instad us th mthod discussd in 3.6 to dtrmin th valu variabls that ar fr in th binding whos typ is bing gnralisd. Th typs of ths variabls can b dtrmind from th graph, and w hold thir fr typ variabls monomorphic. This achivs th sam rsult.
160 160 CHAPTER 3. TYPE INFERENCE 2. Dangrous typ variabls, which wr discussd in and Ths ar variabls that appar fr undr typ constructors whos rgions ar constraind to b mutabl. Dangrous typ variabls must b hld monomorphic to avoid th problm with polymorphic updat that was discussd in Matrial rgion variabls, which wr discussd in Matrial rgions corrspond with objcts that ar shard btwn all uss of th variabl whos typ is bing gnralisd. Ths must also b hld monomorphic Lat constraints and postinfrnc chcking Th fact that mutability constraints influnc what typ variabls ar quantifid introducs a slight complication into th infrnc procss. Th typ infrncr might quantify a typ variabl whil assuming that a particular rgion is constant, but latr discovr a mutability constraint that indicats it shouldn t hav quantifid. W rfr to such mutability constraints as lat constraints. Th following xampl dmonstrats th problm: latfun () = do rf = nwrf id f = λ().radrf rf writrf rf succ f () oh nos with id :: a. a a succ :: r 1 r 2 1. Int r 1 1 Int r2 1 Rad r 1 nwrf :: a r 1. a Rf r 1 a radrf :: a r 1 1.Rf r 1 a 1 a 1 Rad r 1 writrf :: a r 1 1 c 1.Rf r 1 a a 1 c 1 () 1 Writ r 1, c 1 x : Rf r 1 a, Mutabl r 1 From th typs of nwrf, radrf and writrf, w s that an objct of typ Rf r 1 a is only tratd as mutabl if w actually apply th writrf function to it. If w only vr rad a rfrnc, thn thr is no nd to mark it as mutabl or rstrict th typ of th containd valu. Howvr, with our latfun xampl, th typ infrncr will only discovr that rf is mutabl whn it procsss th third lin of th doxprssion. If it considrs th bindings inordr, and gnraliss th typ of rf whil assuming constancy, it will gt: rf :: a.rf r 1 (a a)
161 3.4. GENERALISATION 161 with this schm, th typ of f bcoms: f :: b 1 c 1. () 1 c 1 b b 1 Rad r 1, c 1 rf : Rf r 1 (b b) Latr, th infrncr will discovr th call to writrf, which placs a mutability constraint on r 1 and invalidats th prvious typ schm for rf. Not that it is not saf to simply chang th schm for rf to a lss gnral on on th fly, bcaus th old schm was instantiatd whn infrring th typ of f, and now that typ is wrong as wll. A simpl solution is to wait until typ infrnc is complt, rgnralis th typs of all ltbound variabls, and compar th rsulting typ schms against th prviously infrrd ons. Waiting until infrnc is complt nsurs that all th availabl mutability constraints hav mad thir way into th typ graph. If a nwly gnralisd schm is diffrnt to its original vrsion, thn a mutability constraint must hav bn addd to th graph aftr th original was cratd. This is rportd as an rror. This solution has th disadvantag of rquiring th typs of polymorphic mutabl objcts to b givn xplicitly as signaturs. For xampl, although th following program will not caus a problm at runtim, it will b markd as rronous: falslat = do rf = nwrf id writrf rf succ (radrf rf ) 5 Adding a typ signatur nsurs that th infrncr will trat rf as bing mutabl whn its typ is gnralisd: fixdlat = do rf :: Rf r 1 (a a) Mutabl r 1 rf = nwrf id writrf rf succ (radrf rf ) 5 An altrnat solution would b to rgnralis th typ of rf at ach instantiation point. If th nwly gnralisd schm was diffrnt to th prvious on, thn w could backtrack to original dfinition and rtyp th subsqunt program using th nw schm. W could also prform backtracking in a coars graind mannr, by doing th postinfrnc chck as bfor, but rtyping th whol program if any schms wr diffrnt. Howvr, backtracking adds xtra complxity, and w xpct programs lik th abov to b rar, so w us th simplr nonbacktracking solution in our implmntation. Th BitC compilr also chcks for th lat constraint problm [SSS08]. It dos not backtrack, but prforms th chck during typ infrnc propr. It also uss local huristics to guss whthr a particular variabl is mutabl, without prforming complt infrnc. Bfor gnralising th typ of a variabl it inspcts how it is usd latr in th function. If th variabl is updatd locally, its typ is gnralisd using this information. This is possibl in BitC bcaus th assignmnt oprator := is bakd into th languag, instad of bing dfind in th standard libraris.
162 162 CHAPTER 3. TYPE INFERENCE 3.5 Projctions This sction givs th formal dfinition of typ dirctd projctions, which wr introducd in 2.7. Syntactically, projctions ar a clan xtnsion of th languag dscribd in 3.2. Typ infrnc for projctions is a mostlyorthogonal xtnsion to th systm discussd thus far, though th handling of mutually rcursiv dfinitions rquirs carful ordring of th constraints considrd by th infrncr. This sction introducs typ infrnc for projctions, though w dfr furthr discussion of mutual rcursion and constraint ordring to 3.6. Dclarations Trms dcl... projct T with l x (projction dclaration) t... t 1 l (projction) t 1 (l : c) (annotatd projction) DclProj Proj Γ dcl projct T with l x :: l T x Γ t :: T r τ Ω ; 2 Γ x :: T r τ 3 c 4 τ Ω ; Γ t l :: τ Ω ; 2 3 l T x Γ 1 t 2 3 (l : c 4 ) s 3 = PROJ l s 2 s 3 = s 3 c 4 2 s (projction) { s 1 = PROJ l s 2, s 2 = T s } { s 1 = INST s v, s 2 = T s } whr l T v A projction dictionary projct T with l x is associatd with a particular typ constructor T. Th dictionary lists th nams of th instanc functions x that should b usd to implmnt ach of th projctions labld l. Rcall that th projction oprator binds mor tightly than function application, so t 1 t 2 fild should b rad as t 1 (t 2 fild) Th annotatd projction t 1 (l : c) contains a closur variabl c, and w will discuss how this is usd in a momnt. Th (DclProj) rul introducs th bindings l T x from th projction dictionary into th typ nvironmnt.
163 3.5. PROJECTIONS 163 Th (Proj) rul says that to assign a typ to th projction t l, th xprssion t must hav a data typ that includs an outr constructor T. Thr must b a binding l T x in th typ nvironmnt showing which instanc function x to us to implmnt th projction. This instanc function must tak a valu of th objct typ T r ϕ and rturn a valu of th rsult typ τ. W nam th ffct and closur of th instanc function 3 and c 4 rspctivly. Evaluation of th xprssion t l causs th instanc function to b applid, so w hav 3 in th rul s conclusion. In th list of constraints, s 3 = PROJ l s 2 says that w nd to wait until th typ of s 2 is known bfor w look up th instanc function for l from th corrsponding projction dictionary. Whn this is don w can bind th typ of th instanc function to s 3. Th constraint s 3 = s 3 c 4 2 s1 rquirs th instanc function to hav an appropriat typ. Th last constraint givs th ffct of th whol nod. W now discuss th maning of th closur variabl on an annotatd projction. Firstly, rcall that whn w gnrat constraints for λ abstractions, w nd to know what fr variabls li in thir bodis. For xampl, if w hav an annotatd xprssion: λ(x : s x ). f x With labld syntax tr: 0 λ( x : s x ) 2 3 f x This would lad to th following constraints: LAMBDA {x} s 0 = s 1 c 0 x c 0 s 2 s 3 f : s f = s f = s x s1 Th closur trm f : s f is prsnt bcaus f is fr in th body of th abstraction. At runtim f might b rprsntd as a thunk which contains pointrs to shard objcts, and w us th closur trm to account for this. Now, suppos that th body of th abstraction containd a projction instad: λ(x : s x ). x l Until w hav infrrd th typ of x w won t know what instanc function will b calld, or what th closur of th body should b. If, during constraint rduction, w discovr that th projction x l rsolvs to g x, thn this tlls us that it is g that will b calld at runtim. Howvr, whn gnrating constraints w can t us c 0 g : s g as th closur constraint for th surrounding lambda
164 164 CHAPTER 3. TYPE INFERENCE abstraction, bcaus w won t know about g until th appropriat constraints ar solvd. Instad, w annotat th projction labl with a frsh variabl c 1, and us this as a plac holdr until th typ of x bcoms known. Onc th typ of x is known w can dtrmin what instanc function will b calld, and thn bind its closur to c 1. λ(x : s x ). x (l : c 1 ) Th final task is to modify th constraint gnration ruls for lambda abstraction to tak account of ths nw closur variabls: AbsProj 1 λ( x: s x ) 2 t 2 LAMBDA {x} s 1 = s 2 c 1 x s2 c 1 y 0 : s y0 y 1 : s y1... l 0 : c 0 l 1 : c 1... whr y n fv(t 2 ) \ x l n : c n closannot(t 2 ) SLURP(t 2 ) Th function closannot(t 2 ) simply collcts th (l : c) pairs from all xprssions of th form t (l : c) prsnt in trm t Exampl: vctors Th following program dfins data typs for vctors of two and thr dimnsions, along with projctions that calculat thir magnituds. W hav takn th librty of using floating point numbrs and infix oprators without formally introducing thm first, and hav lidd som insignificant dtails. data Vc2 :: % whr c MkVc2 :: r 1 c 1.Float r 1 Float r 1 1 Vc2 r1 c 1 x : r 1 data Vc3 :: % whr MkVc3 ::... projct Vc2 with magnitud vc2 magnitud projct Vc3 with magnitud vc3 magnitud lt vc2 magnitud = λv. cas v of MkVc2 x y sqrt (x x + y y) vc3 magnitud =... vc = MkVc in vc magnitud Not that our full sourc languag contains sugar that allows us to combin th projction dictionaris with th first two ltbindings. S 2.7 for a dscription of this. Th point of this xampl is that th typ infrncr will not b abl to dcid whthr to us vc2 magnitud or vc3 magnitud to implmnt vc magnitud until it dtrmins whthr vc is a Vc2 or a Vc3.
165 3.5. PROJECTIONS 165 Hr ar th constraints for vc magnitud, with s 1 bing th typ of th whol xprssion: s 3 = PROJ magnitud s 2 s 3 = s 1a c 1a 2 s1 1 = 2 1a s 2 = INST s vc Adding ths to th typ graph yilds th following quivalnc classs: *1 s 3 = PROJ magnitud s 2, s 1a c 1a 2 s1 *2 s 2 = INST s vc! a Not th dpndncy btwn th constraint on s 3 and on s 2. Bfor w can crush PROJ magnitud s 2, w must wait until s 2 has bn rsolvd to a concrt typ. This rquirs that w first infr th typ schm for vc. Suppos this works out as: vc :: Vc2 r 0 Instantiating this schm (which is a noop in this cas) and adding it to th typ graph givs: *1 s 3 = PROJ magnitud s 2, s 1a c 1a 2 s1 *2 s 2 = Vc2 r 0! a Now that w hav a constructor for s 2, w can lookup what projction instanc function to us for magnitud from th corrsponding dictionary: projct Vc2 with magnitud vc2 magnitud This tlls us that magnitud for Vc2 typs is implmntd by vc2 magnitud, so w can crush th PROJ constraint into an appropriat INST: *1 s 3 = INSTvc2 magnitud, s 1a c 1a 2 s1 *2 s 2 = Vc2 r 0! a Now w must wait until w hav a typ schm for vc2 magnitud. Suppos this schm works out to b: vc2 magnitud :: r 1 r 2 1. Vc2 r 1 1 Float r2 1 Rad r 1
166 166 CHAPTER 3. TYPE INFERENCE Instantiating this schm and adding it to th graph givs: *1 s 3 = s 4 5 s6, *2 s 2 = Vc2 r 0 *3 s 5 = Vc2 r 4 *4 s 6 = Float r 5! a!2 4 Rad r 4 s 1a c 1a 2 s1 Prforming th unification in *1 givs: *1 s 3 = s 4 c 1a 2 s1 *2 s 2, s 5 = Vc2 r 0 *4 s 1, s 6 = Float r 5 %1 r 0, r 4! a!2 4, 1a Rad r 4 Inspcting th constraint on s 1 shows that th ovrall typ of our program is Float r 5. Thr ar a fw things w should not bfor moving on. Firstly, th typ of a projction instanc function is not rquird to b th sam as anothr bound to th sam labl. For xampl, w could hav dfind vc3 magnitud to rturn an Int or a List, instad of a Float lik with vc2 magnitud. Scondly, in gnral th infrncr must altrnat btwn instantiating typ schms, prforming unifications, and crushing projction constraints. Each PROJ that is crushd rsults in an INST constraint bing addd to th graph. This INST constraint may nd to b rsolvd, and som unifications prformd, bfor w hav th typ that anothr PROJ constraint is waiting for. This bhaviour is common whn th program includs chains of projctions such as: xp fild1 fild2 fild3 Th projctions in this xprssion must b handld from lft to right. W first dtrmin th typ of xp, us that to dtrmin what instanc function to us for fild1, add its typ to th graph, and unify th rsulting constraints. W can thn us th solution to dtrmin which instanc function to us for fild2, add its typ to th graph, unify constraints, and so on. In DDC w implmnt this bhavior by maintaining svral work sts of quivalnc class idntifirs. W hav a st for classs that contain typs nding to b unifid; a st for projction constraints nding to b rsolvd, and a st for typ class constraints nding to b crushd. Th infrncr altrnats btwn th various sts, working on on until nothing mor can b don, thn switching to anothr. If this procss gts stuck, with on of th sts nonmpty and no furthr progrss possibl, thn this is a symptom of having an ambiguous projction constraint in th graph.
167 3.5. PROJECTIONS Ambiguous projctions and typ signaturs Ambiguous projctions ar thos that oprat on valus whos typs ar not constraind to includ an outr constructor. For xampl, th projction in th following cod is ambiguous: lt f = λx. x magnitud in... Th abstract syntax tr and constraints for th f binding ar: f = lt 1 λ( x : s x ) x magnitud LET x s f = s 1 s 1 = s 2 c 1 x s2 s 4 = PROJ magnitud s 3 s 4 = s 4 c 5 3 s s 3 = s x Adding ths constraints to th typ graph givs: *1 s f, s 1 = s 2 c 1 x s2 *2 s 4 = PROJ magnitud s x, s 4 c 5 x *3 s x, s 3 =! s2 Not that *2 contains two sparat typ constraints, PROJ magnitud s x and s 5 c 5 x s2. As w hav no typ constructor for s x w cannot crush th PROJ constraint, and as w cannot rprsnt both th PROJ and function constraints as a normal form typ w cannot mak a typ schm for f. W can procd no furthr, and in this situation our implmntation rports an ambiguous projction rror. In futur work w plan to invstigat th possibility of assigning f a typ such as th following: f :: a b 1 c 1. a 1 c 1 b HasProj magnitud a (a 1 c 1 b) In this typ, th constraint HasProj magnitud a (a 1 c 1 b) says that a can b any typ that supports a projction magnitud whos instanc function has typ (a 1 c 1 b). This would support som aspcts of a tru rcord systm, such as dscribd by Rémy in [Rm94]. For now, th programmr can fix ambiguous projctions by supplying a typ signatur that constrains th typ bing projctd. Importantly, thy only nd to supply nough information to allow th projction to b rsolvd. For xampl, th programmr could writ: lt f :: Vc2 Float f = λx. x magnitud in...
168 168 CHAPTER 3. TYPE INFERENCE This signatur dos not contain quantifirs, rgion variabls, or ffct and closur information. Th sourc dsugarr uss th kinds of Vc2, Float, and th function constructor to dtrmin that this information is missing. It thn insrts frsh typ variabls in th appropriat positions: f :: Vc2 r 7 c 8 6 Float r9 This typ is tratd as a nw constraint, and is addd dirctly to th typ graph: *1 s f, s 1 = s 2 c 1 x s2, s 7 c 8 5 s6 *2 s 4 = PROJ magnitud s x, s 5 c 5 x *3 s x, s 3 = *4 s 5 = Vc2 r 6 *5 s 6 = Float r 9! s2 Th nw constraint givs us nough information to rsolv th projction in *2, though w nd to prform th unification in *1 to xpos it: *1 s f, s 1 = s 2 c 1 x s2 *2 s 4 = PROJ magnitud s x, s 5 c 5 x *3 s x, s 3, s 5 = Vc2 r 6 *5 s 2, s 6 = Float r 9! !2 2, 7 %1 c 1, c 8 s2 Unifing th two function typs in *1 has causd s x and s 5 to b idntifid. This in turn inducs unification of classs *3 and *4. Class *3 now contains Vc2 r 6, which includs th constructor that th PROJ constraint in *2 was waiting for. W can now lookup th typ of th appropriat magnitud instanc function from th Vc2 projction dictionary, crush th PROJ constraint to an INST of this typ, and complt th infrnc procss as pr th xampl in 3.5.1
169 3.6. CONSTRAINT ORDERING AND MUTUAL RECURSION Constraint ordring and mutual rcursion Considr th following program: projct Int whr vn i = if i == 0 thntru ls (i 1) odd odd i = if i == 0 thnfals ls (i 1) vn main () = print 5 odd This program dfins two projctions, thn uss th scond to dtrmin whthr 5 is odd. Now, although w can plainly s that ths projction functions ar mutually rcursiv, th infrnc algorithm dos not know this a priori. This point should b clarr whn w dsugar th program into th simplifid languag dscribd in 3.2 projct Int :: % with vn int vn odd int odd lt main int vn int odd in... = λx. cas x of Unit print 5 odd = λi 1. if i 1 == 0 thn Tru ls (i 1 1) odd = λi 2. if i 2 == 0 thn Fals ls (i 2 1) vn In this program w hav introducd nw bindings for ach of th projction functions, xprssd function bindings with λabstractions, addd th kind signatur for Int, and rnamd th i variabls so thy hav uniqu nams. W hav also takn th librty of moving th binding for main to th front of th list, as it will mak for a bttr xampl. Not that th projction labls vn and odd ar not spcific to th int vn and int odd instanc functions. W could hav asily rusd ths labls in projction dictionaris for othr typs, so th infrncr rally dos nd to infr that (i 1 1) is an Int bfor it can dcid that (i 1 1) vn is implmntd by int vn. This sction givs an ovrviw of how our typ infrnc algorithm handls programs such as this on, that dfin rcursiv projctions. Th main point is that w must comput th binding dpndncy graph on th fly whil w ar infrring th typs of xprssions. W must also rordr bindings on th fly, so that th typ of int odd will b known whn w com to rsolv th 5 odd projction in th main function. Th constraint tr for this program is shown on th following pag, laving out th constraints that arn t important to th discussion.
170 170 CHAPTER 3. TYPE INFERENCE GROUP {main, int vn, int odd} LET main LAMBDA x s 1 = PROJ odd s 2 s 2 = Int r 1... LET int vn LAMBDA i 1 s 3 = INST i 1... s 4 = PROJ odd s 5 s 5 =... LET int odd LAMBDA i 2 s 6 = INST i 2... s 7 = PROJ vn s 8 s 8 =... For th rmaindr of this sction w will draw our constraint trs graphically, as it maks th prsntation clarr. Th abov tr bcoms: GROUP { main, int_odd, int_vn} LET main LET int_vn LET int_odd LAM x LAM i LAM i 1 = = = = = = = = s1 PROJ s2 Int s3 INST s4 PROJ s5... s 6 INST s 7 PROJ s 8... odd r1 i1 odd i2 vn s s 2 5 During typ infrnc w prform a lft to right, dpth first travrsal ovr th constraint tr. As w do this w dlt constraints from th tr and add thm to th typ graph. W start with a full tr and an mpty typ graph, and finish with a mpty tr and a full graph. Intrnal nods such as GROUP, LET and LAM organis th typ constraints and rprsnt th structur of th original program. W rfr to th subtr hadd by a GROUP, LET or LAM nod as a GROUP, LET or LAM branch. Onc w hav addd all th constraints in a particular branch to th typ graph w can dlt th hadnod as wll. Dlting a LET nod also triggrs typ gnralisation, which w will discuss in a momnt. Firstly, not that w whn w arriv at an INST nod, w can dtrmin how th containd variabl was bound by xamining its parnts. In th abov xampl, w s that i 1 is lambda bound. In our practical implmntation w maintain a stack of intrnal nods for this purpos, pushing thm onto th stack as w ntr a branch, and popping as w lav. As mntiond arlir, dltion of a LET nod invoks gnralisation of th typ of th containd variabl. Howvr, rcall from 3.4 that bfor w gnralis a typ from th graph w must pack it into flat form, and this is only possibl whn th graph is in normal form. Th graph is in normal form whn no s 8 2
171 3.6. CONSTRAINT ORDERING AND MUTUAL RECURSION 171 furthr rduction ruls apply, and whn it contains no unrsolvd PROJ or INST constraints. Ths two rquirmnts nsur that w hav solvd all th constraints from a particular binding bfor w gnralis its typ. Whn prforming typ infrnc on a program whos bindings ar not in dpndncy ordr, or whos bindings ar mutually rcursiv, thr will b situations whn w wish to lav a LET branch but th graph is not in normal form. This will b bcaus w hav no typ schm to satisfy an INST nod, or no typ constructor to guid th rduction of a PROJ nod. In ths situations w rmov th offnding nod from th graph and plac it back in th tr, thn rstructur th tr so that furthr progrss can b mad bfor w nd to prform th gnralisation. This givs us tim to infr th rquird typ schm, or dtrmin th rquird typ constructor, bfor w hav to gnralis th original typ. Both of ths situations aris whn typing th vn/odd xampl on th prvious pag, so w will work through it now. W us to indicat whr w ar in th travrsal, and ε to rprsnt an mpty branch. Aftr dscnding into th right most branch and adding th s 1 and s 2 constraints w arriv at: GROUP { main, int_odd, int_vn} LET main LET int_vn LET int_odd ε LAM i 1 LAM i = = = = = = s3 INST s4 PROJ s5... s 6 INST s 7 PROJ s 8... i1 odd i2 vn s5 s 8 Th typ graph is: 2 *1 s 1 = PROJ odd s 2 *2 s 2 = Int r 1 Now, w would lik to lav th currnt branch and gnralis th typ of main, but bfor w do that w must rduc th graph to normal form. This rquirs that w rsolv th projction constraint in *1. Th projction constraint rfrs to s 2, which is constraind to b Int r 1. This mans that w can look up th instanc function to us from th corrsponding dictionary. Hr is th Int dictionary again: projct Int :: % with vn int vn odd int odd Th odd instanc for intgrs is int odd, so w can crush th PROJ nod in th graph into an INST of this function s typ. This yilds: *1 s 1 = INST int odd *2 s 2 = Int r 1 Now, w cannot actually instantiat th typ for int odd yt bcaus w havn t infrrd it. Instad, w will dfr furthr work on th typ of main and focus
172 172 CHAPTER 3. TYPE INFERENCE on int odd instad. W do this by rmoving th s 1 = INST int odd constraint from th graph and placing it back in th tr. W thn mov th LET int odd branch undr LET main, so w can work on that bfor rturning to gnralis th typ of main: GROUP { main, int_odd, int_vn} LET main ε s 1 = INST int_odd s LAM i LAM i = = = = = = INST i LET int_vn LET int_odd 1 s PROJ s... INST s PROJ s... odd i2 vn s s s 8 2 Not that th s 1 = INST int odd constraint is placd aftr th LET branch, so that th typ for int odd will hav bn gnralisd bfor w nd to instantiat it. Complting th mov yilds: GROUP { main, int_odd, int_vn} s 6 INST i 2 LET main LET int_odd LAM i 2 = = = s 1 s7 PROJ s 8... vn s 8 = INST int_odd i 1 LET int_vn LAM i 1 = = = s 3 INST s 4 PROJ s 5... odd s 5 W can now continu our dpth first travrsal into th int odd branch, adding th constraints for s 6, s 7 and s 8 to th typ graph. Assuming s 8 rsolvs to th typ Int r 2, w nd up with th following graph: *1 s 1 = *2 s 2 = Int r 1 *3 s 6 = s i2 *4 s 7 = PROJ vn s 8 *5 s 8 = Int r 2 Not that in our constraint tr, th constraint s 6 = INST i 2 appars undr th LAM i 2 nod, which tlls us that i 2 is lambda bound. As w do not support highr rank typs, lambda bound variabls do not hav polytyps. This mans that w do not hav to instantiat thm, and w can simplify th s 6 constraint to s 6 = s i2.
173 3.6. CONSTRAINT ORDERING AND MUTUAL RECURSION 173 Aftr th constraints from th int odd branch ar addd, our constraint tr is: GROUP { main, int_odd, int_vn} LET main LET int_odd ε And th graph is still: s 1 = INST int_odd s 3 i 1 LET int_vn LAM i 1 = = = INST s 4 PROJ s 5... odd s 5 *1 s 1 = *2 s 2 = Int r 1 *3 s 6 = s i2 *4 s 7 = PROJ vn s 8 *5 s 8 = Int r 2 Now, th shows that w ar still insid th LETint odd branch. Howvr, w cannot lav it yt and gnralis th typ of int odd bcaus th graph contains an unrsolvd PROJ constraint, so is not in normal form. As bfor, this constraint rfrs to s 8 which an Int, so w can lookup th projction instanc function from th corrsponding dictionary and crush PROJ vn s 8 to INST int vn. Not that crushing a PROJ constraint in this way corrsponds to discovring part of th program s call tr, bcaus w now know that int odd calls int vn. Th nw graph is: *1 s 1 = *2 s 2 = Int r 1 *3 s 6 = s i2 *4 s 7 = INST int vn *5 s 8 = Int r 2 W still cannot gnralis th typ of int odd sinc it is not in normal form. As bfor, w will rmov th offnding s 7 = INST int vn constraint from th graph and plac it back in th tr, thn rorganis th tr so w can mak furthr progrss. This givs: GROUP { main, int_odd, int_vn} i 1 LET main LET int_odd LET int_vn LAM i 1 = = s 3 INST s 4 PROJ odd s 5 s 5 =... s 2 s 1 = INST = int_odd INST int_vn
174 174 CHAPTER 3. TYPE INFERENCE GROUP { main, int_odd, int_vn} i 1 LET main LET int_odd LET int_vn LAM i 1 = = s 3 INST s 4 PROJ odd s 5 s 5 =... s 2 s 1 = INST = int_odd INST int_vn As bfor, w can continu our travrsal by dscnding into th lft of th tr, and adding th constraints for s 3, s 4 and s 5 to th graph. Onc this is don w hav: GROUP { main, int_odd, int_vn} LET main LET int_odd LET int_vn ε s 2 s 1 = INST = int_odd INST int_vn Aftr crushing th s 4 = PROJ odd s 5 constraint to s 4 = INST int odd th typ graph bcoms: *1 s 1 = *2 s 2 = Int r 1 *3 s 6 = s i2 *4 s 7 = *5 s 8 = Int r 8 *6 s 3 = s i1 *7 s 4 = INST int odd *8 s 5 = Int r 5 Not that at this point, w hav discovrd that int odd and int vn ar mutually rcursiv. This bcoms clar whn w plac s 4 = INST int odd back in th tr: GROUP { main, int_odd, int_vn} LET main LET int_odd LET int_vn = s 4 INST int_odd s 2 s 1 = INST = int_odd INST int_vn
175 3.6. CONSTRAINT ORDERING AND MUTUAL RECURSION 175 In this tr, th fact that th INST int odd constraint appars undr LET int vn tlls us that th binding for int vn rfrncs int odd, likwis, int odd rfrncs int vn. As with Haskll [Jon99], in th absnc of polymorphic rcursion w typ mutually rcursiv bindings using monotyps for th bound variabls. This allows us to rwrit th s 4 = INST int odd and s 2 = INST int vn constraints to s 4 = s int odd and s 2 = s int vn. Ths can b addd dirctly to th graph without nding to instantiat typ schms for int odd or int vn. Not that in this xampl w hav lidd th majority of th constraints from th program. In practic, aftr adding th two constraints s 4 = s int odd and s 2 = s int vn w will nd to prform unifications and othr rductions to rturn it to normal form. Finally, whn laving th LET int vn and LET int odd branchs, w must wait until w ar outsid all th branchs of a binding group bfor w gnralis thir typs. This nsurs that all constraints from all bindings in th group hav bn procssd, and that w trat th group as a singl unit Comparison with Hlium Hrn, Hag, Swirstra. Thr ar many dgrs of frdom to th ordr in which constraints ar procssd. If a program contains multipl typ rrors, thn solving constraints in a diffrnt ordr affcts which rrors ar ncountrd first. For all othr programs, changing th ordr should not affct th substanc of th solution. Howvr, thr is on ovrriding rstriction. Bfor th typ of a ltbound variabl can b gnralisd into a typ schm, all th constraints from th right of th binding must hav bn addd to th graph. If w fail to do this thn th rsulting schm may b instantiatd at svral diffrnt typs bfor w ncountr a constraint that would hav prvntd part of it from bing gnralisd. W handl this rstriction by xprssing th typ constraints as a tr. Each ltbinding corrsponds to a branch in th tr, and during our travrsal w us th structur of th tr to nsur that constraints from subbranchs ar addd to th graph bfor th typ of th binding is gnralisd. In contrast, in th Hlium [HHS03, HHS02] compilr, th typ constraints fd to th solvr hav a flat structur, and th rquirmnt to procss constraints from th right of a ltbinding bfor gnralising th typ of th bound variabl is handld in a diffrnt way.
176 176 CHAPTER 3. TYPE INFERENCE Hlium uss a constraint of th following form: τ 1 M τ 2 This constraint says that τ 1 is obtaind by first gnralising τ 2 with rspct to th st of monomorphic variabls M, and thn instantiating th rsulting typ schm. Th rstriction is nforcd by rquiring that all constraints involving typ variabls that ar prsnt in τ 2, but cannot appar in M, ar procssd first. This rquirmnt nsurs that th form of τ 2 cannot chang onc w mak th typ schm. W fl that this is a mor lgant solution than our own mthod of dynamically rordring constraint trs. On th othr hand w ar unsur whthr it is possibl to adapt Hlium s algorithm to dal with th mutually rcursiv projction dfinitions considrd in this sction. In [HHS03], th ruls givn to xtract typ constraints from th sourc program rquir th calculation of th binding dpndncy graph, and w hav sn that this is not possibl with rcursiv projctions. It would sm that to calculat th binding dpndncy graph on th fly, w must rtain information about which projctions appar in which bindings. It may wll b possibl to construct a hybrid of Hlium s systm and our own, but w hav not lookd into it in dtail. W also wondr about th run tim cost of dtrmining which of th τ 1 M τ 2 constraints in th graph ar rady to b procssd. Using a flat constraint tr provids mor frdom to choos th ordr in which constraints ar considrd, but using a hirarchical on provids mor dirction. Chaptr 4 of [H05] contains furthr discussion of th pros and cons of svral rlatd approachs. Bsids th rstriction outlind abov, it is also important that nough typ information maks it into th graph bfor w ar forcd to rsolv projction constraints. In our currnt implmntation, a particular typ is only gnralisd th first tim w nd to instantiat it. If thr ar no bound occurrncs of a variabl in th modul bing compild, which is common for library cod, thn its typ is gnralisd aftr all othr information is addd to th graph. W ar unsur whthr our chosn approach admits dg cass whr a particular projction constraint should hav bn rsolvd, but wasn t. This would crat spurious ambiguous projction rrors, but w hav not noticd any so far.
177 3.7. TYPE CLASSES Typ Classs It is straightforward to add basic support for typ class constraints to a graph basd infrnc algorithm. This includs support for bakd in constraints such as Mutabl and Pur, as wll as programmr dfind constraints such as Show and Eq. Th additions to th languag ar: Dclarations dcl... class C a whr x :: ϕ (typ class dclaration) Typs instanc C τ whr x = t (typ class instanc) ϕ, τ, σ, ς... RadT τ WritT τ (ffct constructors) Constraints χ... C τ (valu typ classs) Shap τ τ LazyH τ ConstT τ MutablT τ Const r Mutabl r (rgion classs) Lazy r Dirct r Pur σ (ffct class) Empty ς (closur class) Th nw dclarations bhav th sam way as thir Haskll countrparts. W us C to rprsnt th programmr dfind typ class constructors such as Show and Eq. Th manings of Shap, ConstT and MutablT ar discussd in 2.6. Th manings of Lazy, LazyH and Dirct wr discussd in Pur is discussd in and Empty is discussd in Whn prforming infrnc w rprsnt typ class constraints as xtra nods in th graph. For xampl, th typ: s updatint = Int r 1 Int r 1 c 1 2 () 1 Rad r 2 Writ r 1, c 1 x : r 1, Mutabl r 1 Would b rprsntd as: *1 s updatint = Int r 1 Int r 1 c 1 2 ()!1 1 Rad r 2 Writ r 1 $1 c 1 x : r 1 1 Mutabl r 1
178 178 CHAPTER 3. TYPE INFERENCE In th typ graph w us as an idntifir for typ class quivalnc classs. 1 Not that in 1 w hav not usd an = or oprator. Both of ths oprators ar binary and infix, but Mutabl is unary and prfix. W stor multiparamtr typ class constraints such as Shap in th sam way. Following on from th sction on gnralisation 3.4, whn w trac a typ from th graph w must also includ any typ class constraints that rfrnc variabls in th body of th typ. For xampl, if w wr to rtrac th typ of updatint from th graph, w would nd to includ Mutabl r 1. In a ral implmntation it would b a disastr if w had to inspct vry quivalnc class in th graph to find all th appropriat constraints. In DDC w mitigat this problm associating ach valu, rgion, ffct and closur quivalnc class, with a st of typ class quivalnc classs that contain rfrncs to it. Although th programmr dfind typ classs do not hav supr class constraints, thr ar implicit supr class constraints on som of th built in ons. W nd to rduc ths constraints whn prforming typ infrnc, and th rst of this sction discusss how this is don Dp Rad/Writ (dp rad data) { s = T κ a, RadT s } { s = T κ a, RadT b Rad r} whr b { b b a, b ::, b mv(, T κ a) } r { r r a, r :: %, r mv(, T κ a) } A dp rad ffct such as RadT a rprsnts a rad on any rgion variabl containd within th asyt unknown typ a. Th RadT constructor has kind!, and th T in RadT stands for valu typ. This distinguishs it from th standard Rad constructor that works on singl rgions. Whn rducing a dp rad on a data typ T ϕ, w first sparat th argumnt variabls a according to thir kinds. Rads on rgion variabls ar xprssd with th Rad constructor, and rads on valu typ variabls ar b xprssd with RadT. Rads on ffct and closur argumnts can b safly discardd, as thr is no associatd action at runtim. It is only maningful to rad (or writ) matrial variabls, hnc th clauss b mv(, T κ a) and r mv(, T κ a). In ths clauss, it is saf to us for th constraint st. As mntiond in 3.2.4, th mv function xprsss a simpl rachability analysis, but so dos th (dp rad data) rduction rul. Th appropriat rad ffcts will b gnratd whn w prform furthr rductions on th rsulting graph. Dp writs ar handld similarly to dp rads. Not that an implmntation must b carful about applying ths rduction ruls whn thr ar loops through th valu portion of th typ graph. For xampl, if w had th following constraints: { s = List r s, RadT s } This graph cannot b rducd to normal form bcaus ach application of (dp rad data) to RadT s gnrats Rad r as wll as anothr RadT s ffct. 1 Prhaps th typ thorist union should start a ptition to introduc mor synonyms for constraint, and class.
179 3.7. TYPE CLASSES 179 (dp rad fun) σ ς { s = τ 1 τ 2, RadT s } σ ς { s = τ 1 τ 2, } Th rul (dp rad fun) shows that dp rads (and writs) on function typs can b rmovd from th graph. Function valus do not contain matrial objcts that ar capabl of bing updatd Dp Mutabl/Const Dp mutability and constancy constraints ar rducd in a similar way to dp rad and writ ffcts. (dp mutabl) { s = T a, MutablT s } { s = T a, MutablT b, Mutabl r } whr b { b b a, b ::, b mv(, T κ a) } r { r r a, r :: %, r mv(, T κ a) } Purification (purify) { Rad r, Pur } { Rad r, Pur, Const r} (dp purify) { RadT s, Pur } { RadT s, Pur, ConstT s} (purify trans) { 1 2, Pur 1 } { 1 2, Pur 1, Pur 2 } To purify a Rad ffct on a rgion r, w constrain that rgion to b constant by adding Const r to th graph. Purification of dp rads is similar. As discussd in , w choos to lav th original Rad ffct in th graph, though w could qually rmov it. W must lav th Pur constraint in th graph. If th quivalnc class containing is unifid with anothr, thn ths nw ffcts nd to b purifid as wll. For xampl, suppos w had th following constraint st: (1) { s = a 1 b, 1 Rad r 1, Pur 1, s = a 2 b, 2 Rad r 2, Mutabl r 2 } If w wr to st r 1 constant whil rmoving th Pur 1 constraint w would gt: (2) { s = a 1 b, 1 Rad r 1, s = a 2 b, 2 Rad r 2, Mutabl r 2, Const r 1 } (bad purify, 1)
180 180 CHAPTER 3. TYPE INFERENCE Prforming unification on s givs: (3) { s = a 1 b, 1 Rad r 1, 1 Rad r 2, Mutabl r 2, Const r 1, 1 = 2 } (unify fun, 2) Now, although w usd to hav a purity constraint on 1, this ffct now includs a rad of th mutabl rgion r 2. In addition, thr is nothing lft in th constraint st to indicat that such an ffct is in any way invalid. On th othr hand, if w wr to tak our original constraint st and prform th unification first, thn w would gt: (4) { s = a 1 b, 1 Rad r 1, Pur 1, 1 Rad r 2, Mutabl r 2, 1 = 2 } (unify fun, 1) Applying th bad purify rul to this nw st yilds: (5) { s = a 1 b, 1 Rad r 1, 1 Rad r 2, Mutabl r 2, 1 = 2, Const r 1, Const r 2 } (bad purify, 4) In this cas w hav both Mutabl r 2 and Const r 2 in th final constraint st, which indicats a typ rror. Rmoving th purity constraint from th graph has causd our rduction to b nonconflunt Shap (shap lft) { s 1 = T κ a, Shap s 1 s 2 } { s 1 = T κ a, s 2 = ϕ } addshap(, T κ a, ϕ ) whr ϕ = frshn(, T κ a) (shap right) { s 2 = T κ a, Shap s 1 s 2 } { s 2 = T κ a, s 1 = ϕ } addshap(, T κ a, ϕ ) whr ϕ = frshn(, T κ a) frshn(sm, a κ ) a κ SM and κ {, %} = a κ frsh frshn(sm, T κ ϕ) = T κ frshn(sm smv(, T κ ϕ), ϕ) frshn(sm, ϕ) = ϕ addshap(sm, a, a ) a SM and a a = { Shap2 a a } addshap(sm, T κ ϕ, T κ ϕ ) = addshap(sm smv(, T κ ϕ), ϕ, ϕ ) addshap(sm, ϕ, ϕ ) =
181 3.7. TYPE CLASSES 181 Whn rducing a constraint lik Shap s 1 s 2, th choic of what rul to us dpnds on whthr w hav a typ constructor for s 1 or s 2. If w hav a constructor for s 1, w can us this as a tmplat to constrain th typ of s 2, and vic vrsa. If w hav a constructor for both s 1 and s 2, thn it dos not mattr which of th ruls w us. Exampl W will us th FunThing typ as an xampl. A FunThing can contain an intgr, a charactr, a function that taks an intgr, or a thing of arbitrary typ. data FunThing r 1 r 2 a 1 a 2 1 c 1 = FInt (Int r 1 ) FChar (Char r 2 ) FFun (Int r 1 c 1 2 a1 ) FThing a 2 Suppos w hav constraints: { s 1 = FunThing r 1 r 2 s 2 s 3 1 c 1 s 2 = Int r 3 s 3 = Int r 4 1 Rad r 2 Rad r 5 c 1 Int r 5 Shap s 1 s 1 } As w hav a constructor for s 1 w can us th (shap lft) rul. Th matrial variabls of FunThing r 1 r 2 s 2 s 3 1 c 1 ar: mv(,funthing r 1 r 2 s 2 s 3 1 c 1 ) = {r 1, r 2, a 2 } Whras th immatrial variabls ar: iv(,funthing r 1 r 2 s 2 s 3 1 c 1 ) = {r 2, 1, c 1, a 1 } This mans th strongly matrial variabls ar: smv(,funthing r 1 r 2 s 2 s 3 1 c 1 ) = {r 1, a 2 } Not that whn rducing th Shap constraint, rgion variabls that ar only rachabl from th closur of a typ, such as r 5, ar not countd as matrial. Similarly to th xampl givn in 2.6.5, th programmr cannot copy objcts in such rgions, so w do not frshn th associatd rgion variabls. This is achivd in part by passing as th first argumnt of frshn and addshap, instad of th full st of constraints bing rducd. This nsurs that ths functions do not hav information about th c 1 constraint. Th altrnativ would b to frshn c 1 as wll, and crat a nw constraint c 1 Int r 5. W would also nd to crat a nw vrsion of th constraint on 1, and nsur that this rfrrd to th copid closur. Of cours, actually copying th objcts in th closurs of functions would rquir additional support from th runtim systm, so w hav not considrd it furthr. Applying th frshn function to th typ of s 1 givs us th nw typ: s 1 = FunThing r 1 r 2 s 2 s 3 1 c 1 with r 1, s 3 frsh
182 182 CHAPTER 3. TYPE INFERENCE Applying th addshap function provids Shap constraints on th componnts of this typ: addshap(, FunThing r 1 r 2 s 2 s 3 1 c 1, FunThing r 1 r 2 s 2 s 3 1 c 1 ) So our final rsult is: addshap(sm, r 1, r 1 ) addshap(sm, r 2, r 2 ) addshap(sm, s 2, s 2 ) addshap(sm, s 3, s 3 ) addshap(sm, 1, 1 ) addshap(sm, c 1, c 1 ) whr SM = {r 1, s 3 } Shap s 3 s 3 { s 1 = FunThing r 1 r 2 s 2 s 3 1 c 1 s 2 = Int r 3 s 3 = Int r 4 1 Rad r 2 Rad r 5 c 1 Int r 5 s 1 = FunThing r 1 r 2 s 2 s 3 1 c 1 Shap s 3 s 3 } Not that in th nw typ FunThing r 1 r 2 s 2 s 3 1 c 1, th frsh variabls r 1 and s 3, corrspond to just th componnts of th undrlying FunThing valus that can potntially b coppid. r 2 and s 2 ar not frshnd bcaus ths variabls ar usd in th paramtr and rturn typs of an mbddd function valu. Likwis 1 and c 1 ar not frshnd bcaus thy do not rprsnt data objcts. 3.8 Error Rporting In a constraint basd infrnc algorithm, th natural way to includ rror rporting is to add justifications to ach of th constraints xtractd from th sourc program. Ths justifications can b maintaind as th graph is rducd, and if w ncountr an rror w can us th justification to dtrmin why th conflicting constraints wr addd to th graph. This approach is outlind by Wand [Wan86], and laboratd by Duggan [DB96] and Hrn [H05]. W will giv an ovrviw of th gnral idas, and focus on how w manag th constraints that ar spcific to Discipl. Considr th succdlay program from succdlay () = do x = 5 y = x... x := This program has a purity conflict. Th binding for y crats a suspnsion that will rad th valu of x, but latr in th program this valu is updatd. This implis that th valu of y will dpnd on whn it is forcd, which is a program bhaviour w tak as bing invalid. Hr ar th syntax trs for th thr statmnts in th doblock, aftr dsugaring:
183 3.8. ERROR REPORTING 183 = 1 = 2 7 x suspnd1 succ updatint x Aftr xtracting typ constraints and solving thm, w ar lft with a typ graph containing th following quivalnc classs: *1 s x, a, s 1 s 6, s 10 = Int r 1 *2 s y, b, s 2 = Int r 6 *3 s 3 = s 2 c 2 x sy *4 s 4 = s 3 c 3 5 s3 *5 s 5 = s 5 c 5 x sy...!1 5, 6 Rad r 1!2 7, 9 Rad r 10 Rad r Pur 5 2 Const r 1 3 Mutabl r 1 This graph contains an obvious typ rror. 2 contains a constraint that rquirs r 1 to b constant, whil 3 contains a constraint that rquirs it to b mutabl. As discussd in 4.1, w cannot convrt this xampl to a valid cor program bcaus thr is no way to construct witnsss for both of ths constraints at onc. Unfortunatly, th rason for this rror is not so obvious. It would b unhlpful for a compilr to simply rport that it cannot crat cor witnsss, or that Const r 1 conflicts with Mutabl r 1. Nithr of ths mssags hlp us dtrmin what part of th program causd th rror, or suggst how w might rsolv it Constraint justifications As mntiond prviously, w track th sourc of typ rrors by attaching justifications to ach of th constraints from th program. For xampl: s 4u = s 3 c 3 5 s3 i 1 s 4d = INST s suspnd i 2 s 4u = s 4d i 3 s 5 = INST s succ i 4 s 9 = INST s updatint i 5 i 1 = IApp 3 suspnd succ i 2 = IVar 3 suspnd i 3 = IUsDf 3 i 4 = IVar 3 succ i 5 = IVar 5 updatint...
184 184 CHAPTER 3. TYPE INFERENCE W now writ valu typ constraints as s = τ i, whr s is a typ variabl, τ is a typ, and i is a sourc information variabl. In this prsntation w will rfr to sourc information as just information. W xtnd rgion, ffct, closur and typ class constraints in a similar way. Information variabls ar bound to information xprssions in sparat constraints. Information xprssions ar built with information constructors such as IApp and IVar. W giv information constructors informal, dscriptiv kinds: IApp IVar IUsDf :: num xp xp info :: num var info :: num St info info IApp taks a lin numbr and two xprssions. It producs information that says a particular constraint is du to th application of ths two xprssions, on that lin of th sourc program. IVar producs information that says a constraint is du to th us of a particular variabl. IUsDf producs information that says a constraint is du to th fact that th dfinition of a variabl must match its us. Th first argumnt of IUsDf is a lin numbr as bfor, but th scond argumnt is a st of othr information xprssions. W will s how this works in a momnt. W now discuss how to rcord sourc information in th typ graph rprsntation. For constraints involving a constructor, w can tak th information variabl from th constraint, and us it to annotat th constructor as it is placd into an quivalnc class. Whn prforming an instantiation du to an INST constraint, th information variabl on th INST constructor is propagatd to all th nw constructors cratd during th instantiation. For xampl, aftr adding th abov constraints to th typ graph and prforming th instantiations w gt: *1 s 4u = (s 3 c 3 5 s3 ) i 1 *2 s 4d = (s 4d c 4d 41 s42 ) i 2 *3 s 41 = (a 41 c 41 b) i 2 *4 s 42 = (a 42 c 42 b) i 2!1 5 (Rad r 1 ) i 2 1 (Pur 41 ) i 2 3 (Mutabl r 2 ) i 4 1 i 1 = IApp 3 suspnd succ... Not that w hav usd to idntify th quivalnc classs that hold sourc information xprssions. For a constraint of th form s 4u = s 4d i 3, assuming that s 4u and s 4d ar not alrady in th sam class, adding this constraint to th graph may rsult in typs bing unifid. As w wish to track th rason for this unification, w modify th rduction rul for unification so that it combins th information about th typs bing unifid:
185 3.8. ERROR REPORTING 185 (unify fun info) { s 1 = s 2 i 1, s 1 = a 1 1 c 1 b1 i 2, s 2 = a 2 2 c 2 b2 i 3 i 1 = IUsDf n } { s 1 = s 2 i 1, s 1 = a 1 c 1 1 b1 i 4 a 1 = a 2 i 4, b 1 = b 2 i 4 1 = 2 i 4, c 1 = c 2 i 4 i 1 = IUsDf n i 4 = IUsDf n {i 2, i 3 } } Th rul for unification of data typs is similar. Th nw information constraint i 4 = IUsDf n {i 2, i 3 } rcords why th valu, ffct and closur constraints in th conclusion of th rul wr addd to th graph. It also contains th information variabls from both typs that wr unifid. Rturning to our xampl, w us this nw unification rul to add th constraint s 4u = s 4d i 3 to th typ graph: *1 s 4d, s 4u = (s 3 c 3 5 s3 ) i 6 *3 s 41, s 5 = (a 41 c 41 b) i 2 *4 s 42 = (a 42 c 42 b) i 2 1 i 1 = IApp 3 suspnd succ 2 i 2 = IVar 3 suspnd 6 i 6 = IUsDf 3 {i 1, i 2 }... Unfortunatly, although th st rprsntation contains full information about why a particular constraint is prsnt, in our typ graph rprsntation som of this information is lost. Sinc w attach sourc information to constructors only, w hav no way of adding a constraint lik s 1 = s 2 i 1 to an mpty graph without losing th information variabl i 1. For xampl, doing so yilds: *1 s 1, s 2 = On th lft of th = w hav th list of variabls in this quivalnc class, with th canconical nam s 1 apparing first. This list rprsnts a substitution, whr all occurrncs of s 2 in th graph should b rplacd by s 1. W hav rcordd this bar fact, but hav lost th rason why such a substitution should tak plac. For this rason w will stick with th constraint st rprsntation for th rst of this sction.
186 186 CHAPTER 3. TYPE INFERENCE Tracking purity rrors Rturning to th succdlay xampl from 3.8, w can track th sourc of th purity rror by modifying th rduction ruls for purity constraints: (purify info) { 1 Rad r 1 i 1, Pur 1 i 2 } { 1 Rad r 1 i 1, Pur 1 i 2, i 3 = IPurify r 1 i 1 i 2, Const r 1 i 3 } (purify trans info) { 1 2 i 1, Pur 1 i 2 } { 1 2 i 1, Pur 1 i 2, i 3 = IPurifyTrans 1 i 2, Pur 2 i 3 } Th (purify info) rul is an xtnsion of (purify) from 3.7. Th rsulting Const r 1 constraint is now taggd with an information variabl i 3. Th constraint i 3 = IPurify r 1 i 1 i 2 says that Const r 1 aros from th purification of a rad ffct on rgion r 1. It also includs th information variabls from th associatd ffct and purity constraints. W modify th (dp purify) rul in a similar mannr. Th (purify trans info) rul xtnds (purify trans) from 3.7. Th rsulting Pur 2 constraint is taggd with a variabl i 3, and th information constraint i 3 = IPurifyTrans 1 i 2 rcords th variabls in th prmis of th rul. IPurifyTrans constraints can b usd by th compilr to find th original sourc of a purity constraint. For xampl, considr th following st: { 1 2 i 1, 2 3 i 2, 3 Rad r 1 i 3, i 3 = IVar 3 succ, Pur 1 i 4, i 4 = IVar 3 suspnd, Mutabl r 1 i 5, i 5 = IVar 5 updatint } This constraint st contains a latnt purity conflict, as th Pur constraint on 1 will lad to a Const constraint on r 1 whn it is rducd. Aftr rduction w hav: { 1 2 i 1, 2 3 i 2, 3 Rad r 1 i 3, i 3 = IVar 3 succ, Pur 1 i 4, i 4 = IVar 3 suspnd, Pur 2 i 6, i 6 = IPurifyTrans 1 i 4 Pur 3 i 7, i 7 = IPurifyTrans 2 i 6 Const r 1 i 8, i 8 = IPurify r 1 i 3 i 7 Mutabl r 1 i 5, i 5 = IVar 5 updatint } This st contains an obvious typ rror. In fact, w hav two sparat symptoms. Th first symptom is that r 1 is constraind to b both mutabl and constant. Th sourc of th mutability constraint can b obtaind dirctly from th information constraint on i 5. Th sourc of th constancy constraint can b obtaind by tracing up th chain of IPurifyTrans constraints to rach i 4,
187 3.8. ERROR REPORTING 187 which tlls us that it aros du to th us of suspnd at lin 3 in th program. Th scond symptom is that 3 is constraind to b pur, but 3 includs a rad ffct on a mutabl rgion, which is not pur. This sort of rror ariss from a thr way intraction btwn th function rading th rgion, th function writing to it, and th us of suspnd. DDC rports th sourc location of all thr function calls. Th following pag shows th rror mssag obtaind whn compiling succdlay. This mssag givs th xact rason for th rror, though dos not suggst how to fix it. In futur work w plan to adapt th tchniqus dscribd in [HJSA02] to stimat which xprssion in th program is most at fault, and suggst a solution. For xampl, suppos th program contains svral xprssions that updat a particular objct, but only on occurrnc of a function that rads it bing suspndd. In this cas it is likly that th program is basd around dstructiv updat, and that th suspnsion is mor wrong than th mutability of th objct. Th compilr could thn suggst that th offnding function application is valuatd strictly, instad of bing suspndd, or that th objct is copid bforhand../tst/error/purity/purifyradwrit1/main.ds:9:23 Cannot purify Rad ffct on Mutabl rgion. A purity constraint on a Rad ffct rquirs th rgion it acts on to b Const, and it cannot b Mutabl at th sam tim. th us of: succ with ffct:!rad %r1 at:./main.ds:9:18 is bing purifid by th us of: suspnd1 at:./main.ds:9:23 which conflicts with constraint: Mutabl % r1 from th us of: (:=) at:./main.ds:10:16
188 188 CHAPTER 3. TYPE INFERENCE
189 Chaptr 4 Cor Languag Our cor languag is basd on SystmF, and includs a witnss passing mchanism similar to on in SystmFc [SCPJD07] which is usd in GHC. Our languag is typd, and ths typs ar usd as both an intrnal sanity chck, and to guid cod optimisations. This thsis discusss a fw optimisations, though w do not offr any nw ons. What w prsnt is a framwork whrby optimisations prviously rsrvd for pur languags can b applid to ons that includ sid ffcts. With rgard to optimisation, transforms that do not chang th ordr of function applications, and do not modify th sharing proprtis of data, ar qually applicabl to both pur and impur languags. For xampl, th caslimination transform from [dms95] is ffct agnostic. Inlining function dfinitions into thir call sits also dos not prsnt a problm, providd th function argumnts ar in normal form. This rstriction prvnts th duplication of computations at runtim, and is also usd in pur languags such as GHC [PJS98]. On th othr hand, w nd ffct information to prform th ltfloating transform, as it changs th ordr of bindings. W also nd information about th mutability of data to guid optimisations that hav th potntial to incras data sharing, such as th full lazinss transform. In this chaptr w prsnt th main faturs of our cor languag, discuss how to us th typ information to prform optimisation, thn compar our systm with othr work. W also giv highlights of th proof of soundnss, though th bulk of th proof is dfrrd to th appndix. 189
190 190 CHAPTER 4. CORE LANGUAGE 4.1 Constraints and vidnc Witnss passing Considr th Haskll function paireq which tsts if th two lmnts of a pair ar qual: paireq :: a. Eq a (a, a) Bool paireq (x, y) = x == y In th typ signatur, th constraint Eq a rstricts th typs that a can b instantiatd with to just thos which support quality. This rquirmnt ariss bcaus w hav usd (==) to compar two valus of typ a. As wll as bing a typ constraint, a Haskll compilr such as GHC would trat Eq a as th typ of an xtra paramtr to paireq. In this cas, th paramtr will includ an appropriat function to compar th two lmnts of th pair. During compilation, th compilr will dtct applications of paireq and add an xtra argumnt appropriat to th typ it is calld at. For xampl, a GHC styl translation of paireq to its cor languag [HHPJW96] would yild somthing similar to: paireq = Λ a :. λ comp : (a a Bool). λ pair : (a, a). cas pair of (x, y) comp x y whil an application of this function in th sourc languag: paireq (2, 3) would b translatd to: paireq Int priminteq (Pair Int 2 3) whr priminteq is th primitiv quality function on intgrs. Rturning to th translation of paireq, th xtra paramtr comp binds vidnc [Jon92] that typ a rally dos support th quality opration and thr is no bttr vidnc than th function which prforms it. With this in mind, suppos that w wr only intrstd in th fact that paireq rquirs a to support quality, rathr than how to actually valuat this function at runtim. In th abov translation, w manag our vidnc at th valu lvl, by xplicitly passing around a comparison function. Altrnativly, w could manag it at th typ lvl: paireq = Λ a :. Λ w : Eq a. λ pair : (a, a). cas pair of (x, y) (==) w x y
191 4.1. CONSTRAINTS AND EVIDENCE 191 In this nw translation th xtra paramtr, w, binds a proof trm. On stp rmovd from valulvl vidnc, this typlvl proof trm srvs as witnss that typ a rally dos support quality, and this is rcordd in its kind Eq a. Th application of (==) to th lmnts of our pair rquirs a to support quality, and w satisfy this rquirmnt by passing it our witnss to th fact. How a particular calling function happns to manufactur its witnsss is of no concrn to paireq, though thy do nd to ntr th systm somhow. In th gnral cas, a callr has thr options: rquir th witnss to b passd in by an outr function, combin two witnsss into a third, or construct on xplicitly. For this xampl, th third option suffics, and w can translat th call as: paireq Int (MkEq Int) (Pair Int 2 3) Th typ lvl function MkEq is a witnss constructor which taks a typ, and constructs a witnss of kind Eq a. Th xprssion (MkEq Int) is as an axiom in our proof systm, and it is valid to rpat it in th program whn rquird. On th othr hand, whn w discuss witnsss of mutability in 4.1.3, thir construction will b rstrictd to crtain placs in th program, to nsur soundnss. With this plumbing in plac w can nsur our cod is consistnt with rspct to which typs support quality (or mutability), simply by typ chcking it in th usual way and thn inspcting th way witnsss ar constructd Dpndnt kinds Dpndnt kinds ar kinds that contain typs, and in DDC w us thm to dscrib witnss constructors. Dpndnt kinds wr introducd by th Edinburgh Logical Framwork (LF) [AHM89] which uss thm to ncod logical ruls, and aspcts of this framwork ar prsnt in our cor languag. Typs ar viwd as assrtions about valus, and kinds ar viwd as assrtions about typs. Functions that tak typs to kinds ar xprssd with th Π bindr, and w apply such a function by substituting its argumnt for th bound variabl, as usual. For xampl: MkEq :: Π(a : ). Eq a Int :: MkEq Int :: Eq Int Not that MkEq Int is a typ trm, and Eq Int is a kind trm. In this chaptr w us th convntion that typ constructors starting with Mk produc witnsss Witnsss of mutability Whn optimising programs involving dstructiv updat, it is of crucial importanc that w do not los track of which rgions ar mutabl and which ar supposd to b constant. As mntiond arlir, DDC uss th witnss passing mchanism to kp track of this information, both to guid optimisations and as a sanity chck on th intrmdiat cod.
192 192 CHAPTER 4. CORE LANGUAGE Of primary concrn ar functions which dstructivly updat objcts in th stor. For xampl, ignoring ffct and closur information, th updatint function from has typ: updatint :: r 1 r 2. Mutabl r 1 Int r 1 Int r 2 () Using idas from 4.1.1, w trat th rgion constraint Mutabl r 1 as th kind of an xtra typ paramtr to this function. Not that as w ar now considring ths constraints to also b typ paramtrs, w writ thm in prfix form with instad of in postfix form with as w did in th sourc languag. Whn w us updatint w nd to pass a witnss to th fact that r 1 is indd mutabl, and w now considr how ths witnsss should b constructd. W could prhaps construct thm dirctly at callsits as pr our paireq xampl. Howvr, unlik th typ class situation, th various rgion class witnsss ar not ncssarily compatibl. For xampl, thr is nothing wrong with MkEq a and MkShow a xisting in th sam program, but if w hav both MkMutabl r 1 and MkConst r 1 thn somthing has gon badly wrong. If w wr to allow rgion witnsss to b constructd anywhr in th intrmdiat cod, thn th compilr would nd accss to th whol program to nsur that multipl incompatibl witnsss ar not constructd for th sam rgion. This would b impossibl to implmnt with rspct to sparat compilation. Instad, w rquir that all witnsss involving a particular rgion variabl ar constructd at th sam plac in th cod, namly th point whr th variabl itslf is introducd. As in [TBE + 06], w us ltrgion to bring rgion variabls into scop. Hr is an xampl program which crats and intgr, updats it, and thn prints it to th consol: printm :: () () printm = λ(). ltrgion r 1 with { w 1 = MkMutabl r 1 } ltrgion r 2 with { w 2 = MkConst r 2 } do x = 5 r 1 updatint r 1 r 2 w 1 x (23 r 2 ) printint r 1 x in in Not that in th cor languag, litral valus such as 5 act as constructors that tak a rgion variabl and allocat a nw objct. This givs x th typ Int r 1. Th only plac th constructors MkMutabl and MkConst may b usd is in th st of witnss bindings associatd with a ltrgion. In addition, w may only crat witnsss for th rgion variabl bing introducd, and w cannot crat witnsss for mutability and constancy in th sam st. This nsurs that conflicting rgion witnsss cannot b cratd. To call th updatint function w must hav a witnss that r 1 is mutabl. Trying to pass anothr witnss, lik th on bound to w 2, would rsult in a typ rror. With this ncoding, it is asy to writ cod transformations that dpnd on whthr a particular rgion is mutabl or constant. Such a transformation can simply collct th st of rgion witnsss that ar in scop whil dscnding into th abstract syntax tr. W will s an xampl of this in
193 4.1. CONSTRAINTS AND EVIDENCE Witnsss of purity Whn translating a program which uss lazy valuation to th cor languag, w must also construct witnsss of purity. Rcall from that th typ of suspnd is: suspnd :: a b 1. Pur 1 (a 1 b) a b suspnd taks a function of typ a 1 b, its argumnt of typ a and builds a thunk that rprsnts th suspndd function application. Whn th thunk is forcd, th function will b applid to its argumnt yilding a rsult of typ b. Th Pur 1 constraint nsurs that th function application bing suspndd has no visibl sid ffcts, so th valu of its rsult will not dpnd on whn it is forcd. W now considr how witnsss of purity ar cratd in th cor languag. Considr th following sourc program: fun :: a r 1 r 2 1. (Int r 1 1 a) Bool r2 a Pur 1, Const r 2 fun f b = do g x = if x thn f 5 ls f 23 suspnd g b fun causs its first paramtr to b applid to ithr 5 or 23, dpnding on whthr its scond is tru or fals. This is don by an auxiliary function, g, and th application of this function is suspndd. Bcaus th application of g is suspndd it must b pur. Not that th purity of g rlis on two sparat facts: that f is pur, and that x is constant. Hr is fun convrtd to th cor languag: fun = Λ a r 1 r 2 1. Λ (w 1 : Pur 1 ). Λ (w 2 : Const r 2 ). λ (f : Int r 1 1 a). λ (b : Bool r 1 ). do g = λ(x : Bool r 1 ). if x thn f (5 r 1 ) ls f (23 r 1 ) suspnd (MkPurJoin 1 (Rad r 1 ) w 1 (MkPurify r 1 w 2 )) g b Whn w call suspnd, th trm (MkPurJoin 1 (Rad r 1 ) w 1 (MkPurify r 1 w 2 )) builds a witnss to th fact that g is pur. Not that in this chaptr w trat suspnd as a primitiv, so w do not nd applications for th argumnt and rturn typs, or th ffct of th function. Th typing rul for suspnd taks car of this paramtrisation. Th witnss to th purity of g is constructd from two simplr witnsss, on showing that 1 is pur, and anothr showing that th rad from r 1 is pur. Th first is givn to us by th calling function, and is bound to w 1.
194 194 CHAPTER 4. CORE LANGUAGE Th scond is constructd with th MkPurify witnss constructor which has kind: MkPurify :: Π(r : %).Const r Pur (Rad r) This kind ncods th rul that if a rgion is constant, thn any rads from it can b considrd to b pur. Whn w apply MkPurify to r 1, this variabl is substitutd for both occurrncs of r yilding: (MkPurify r 1 ) :: Const r 1 Pur (Rad r 1 ) From th Λbinding at th bginning of th function w hav w 2 :: Const r 1, so applying w 2 as th final argumnt givs: (MkPurify r 1 w 2 ) :: Pur (Rad r 1 ) Which shows that a rad from r 1 is indd pur. What rmains is to join th two simpl witnsss togthr. This is don with th MkPurJoin witnss constructor which has kind: MkPurJoin :: Π( 1 ::!). Π( 2 ::!). Pur 1 Pur 2 Pur ( 1 2 ) Applying th first two argumnts givs: (MkPurJoin 1 (Rad r 1 )) :: Pur 1 Pur (Rad r 1 ) Pur ( 1 Rad r 1 ) This says that if w hav a witnss that th ffct 1 is pur and a witnss that th ffct Rad r 1 is pur, th combination of ths two ffcts is also pur. Our final witnss thn bcoms: (MkPurJoin 1 (Rad r 1 ) w 1 (MkPurify r 1 w 2 )) :: Pur ( 1 Rad r 1 ) Th ffct 1 Rad r 1 is xactly th ffct of g, so th abov witnss is sufficint proof that w can safly suspnd a call to it. Not that w do not nd witnsss of impurity. Th fact that an xprssion is pur givs us th capability to suspnd its valuation, and by constructing a witnss of purity w prov that this capability xists. In constrast, th fact that an xprssion is impur is not a capability, bcaus it dos not allow us to do anything xtra with that xprssion.
195 4.2. SIMPLIFIED CORE LANGUAGE Simplifid cor languag Symbol Classs a, r,, w (typ variabl) x (valu variabl) ρ (rgion handls) l (stor locations) Kinds κ Π(a : κ 1 ). κ 2 (dpndnt kind abstraction) κ ϕ (dpndnt kind application) %! (atomic kinds) Const Mutabl Pur (witnss kind constructors) Typs ϕ, τ, σ, δ, a (typ variabls) (a : κ). τ (unboundd quantification) ϕ 1 ϕ 2 (typ application) σ 1 σ 2 (last uppr bound, top and bottom) () ( ) Bool (valu typ constructors) Rad Writ (ffct typ constructors) MkConst MkMutabl (rgion witnss constructors) MkPur MkPurify MkPurJoin (ffct witnss constructors) mutabl ϕ const ϕ pur σ (witnsss) ρ (rgion witnss) Trms t x (trm variabl) Λ(a : κ). t (typ abstraction) t ϕ (typ application) λ(x : τ). t (trm abstraction) t 1 t 2 (trm application) lt x = t 1 in t 2 (lt binding) ltrgion r with {w i = δ i } in t (rgion introduction) if t 1 thn t 2 ls t 3 (slction) Tru ϕ Fals ϕ (boolan constructors) updat δ t 1 t 2 (boolan updat) suspnd δ t 1 t 2 (suspnsion of function application) () (unit valu) l (stor location) Drivd Forms κ 1 κ 2 κ τ do bindstmt ; t whr bindstmt mkbind(x = t) mkbind(t) df = Π( :: κ 1 ). κ 2 df = ( :: κ). τ df = lt mkbind(bindstmt) in t x = t t df = x = t df = x = t, x frsh
196 196 CHAPTER 4. CORE LANGUAGE Th languag dscribd in this sction is a cutdown vrsion of th languag usd in our ral implmntation. To simplify th prsntation w hav omittd witnsss for dirct and lazy rgions, along with shap constraints. W hav also omittd boundd quantification, ffct masking, algbraic data typs and cas xprssions. Witnsss for dirct and lazy rgions ar handld similarly to th ons for mutabl and constant rgions. Shap constraints ar handld similarly to purity constraints. W will discuss boundd quantification in 4.3 and ffct masking in W hav includd ifxprssions as a simplr vrsion of casxprssions, and limit ourslvs to boolans as th only updatabl typ. Not also that closur information is not usd in th cor languag, though w discuss on of th bnfits that would b gaind from adding it in Symbol Classs W us a to man a typ variabl of arbitrary kind, r to man a typ variabl of rgion kind, of ffct kind, and w of witnss kind. Th distinction btwn ths symbols is for convninc only. W will us r whn only a variabl of rgion kind maks sns, but an implmntation must still chck that r dos indd hav rgion kind with rspct to th typing ruls. W us x to man a valu variabl. Rgion handls ρ ar trminal symbols that corrspond to a st of locations l, in th stor. Not that in a practical implmntation it is dsirabl to attach typ and kind information to valu and typ variabls. This allows us to rconstruct th typ or kind of an xprssion locally, without nding accss to th information attachd to surrounding bindrs. In [JPJ08] this is known as th uniqunss of typs proprty Kinds Starting from th top of th strata, our systm uss dpndnt kinds (typs in kinds) hnc th inclusion of th application and abstraction forms Π(a :: κ 1 ). κ 2 and κ ϕ. Th function kind κ 1 κ 2 is ncodd as a sugard form of Π( :: κ 1 ). κ 2, whr th undrscor indicats that th typ variabl is not prsnt in κ 2 and can b safly ignord. Th symbols, % and! giv th kinds of typs, rgions and ffcts rspctivly. Th symbol is th kind of witnss kinds. W could hav addd a suprkind strata containing as in [SCPJD07], but inspird by [PJM97] w do it this way to rduc th volum of typing ruls. Th witnss kind constructors Const, Mutabl and Pur ar usd to rcord th particular program proprty that a typ lvl witnss provs Typs W us ϕ to rang ovr all typlvl information including valu typs, rgion variabls, ffcts and witnsss. Whn w wish to b mor spcific w will us τ, σ and δ to rfr to valu typs, ffct typs and witnss typs rspctivly. Not that and ar ffct typs, and is only applid to ffct typs.
197 4.2. SIMPLIFIED CORE LANGUAGE 197 Th typs that ar undrlind, mutabl ϕ, const ϕ, pur σ and ρ ar runtim witnsss and do not appar in th sourc program. Thy ar constructd by th valuation of a witnss constructor, and w arrang th typing ruls so that thir construction rquirs th hap to possss th associatd proprty. Th first thr w hav sn alrady, and w will discuss rgion handls ρ in W us to rfr to witnsss. Not that although our oprational smantics manipulats witnss trms, w do not nd thm at runtim. Th compilr uss witnsss to rason about th program during compilation, but thy can b rasd bfor cod gnration, along with all othr typ information Trms Th majority of th trm languag is standard. Our lt x = t 1 in t 2 trm is not rcursiv, but w includ it to mak th xampls asir to writ. Th addition of a ltrc form can b don via fix in th usual way [Pi02, 11.11] but w do not discuss it hr. As pr w writ our (nonmonadic) do xprssions as a sugard vrsion of lt. Th trm ltrgion r with {w i = δ i } in t introducs a nw rgion variabl r which is in scop in both th witnss bindings w i = δ i and th body t. Th witnss bindings ar usd to st th proprtis of th rgion bing cratd, and introduc witnsss to thos proprtis at th sam tim. If th rgion has no spcific proprtis thn w includ no bindings and writ ltrgion r in t. Th us of ltrgion imposs som syntactic constraints on th program. Ths nsur that conflicting rgion witnsss cannot b cratd: Wllformdnss of rgion witnsss: In th list of witnss bindings w i = δ i, ach δ i must b ithr MkConst r or MkMutabl r, and th list may not mntion both. In our full cor languag w also us th witnsss MkDirct r and MkLazy r from , and ths ar also mutually xclusiv. Rquiring such witnsss to b mutually xclusiv rjcts obviously brokn trms such as: ltrgion r with {w 1 = MkConst r, w 2 = MkMutabl r} in... Uniqunss of rgion variabls: In all trms ltrgion r with {w i = δ i } in t in th initial program, ach bound rgion variabl r must b distinct. This constraint nsurs that conflicting witnsss cannot b cratd in sparat ltrgion trms. For xampl: ltrgion r with {w 1 = MkConst r} in ltrgion r with {w 2 = MkMutabl r} in... In an implmntation this is asily satisfid by giving variabls uniqu idntifirs.
198 198 CHAPTER 4. CORE LANGUAGE No fabricatd rgion witnsss: Rgion witnsss constructors may not b usd in a typ applid dirctly to a trm. This constraint nsurs that conflicting witnsss cannot b cratd in othr parts of th program. For xampl: ltrgion r with {w 1 = MkConst r} in... updat (MkMutabl r) t 1 t 2... Rturning to th list of trms, Tru ϕ and Fals ϕ allocat a nw boolan valu into rgion ϕ in th hap. W us th gnral symbol ϕ to rprsnt th rgion as it may b ithr a rgion variabl r or a rgion witnss ρ during valuation. Th updat function ovrwrits its first boolan argumnt with th valu from th scond, and rquirs a witnss that its first argumnt is in a mutabl rgion. Th suspnd function suspnds th application of a function to an argumnt, and rquirs a witnss that th function is pur. Stor locations, l, ar cratd during th valuation of a Tru ϕ or Fals ϕ trm. Thy can b thought of as th abstract addrsss whr a particular boolan objct lis. Whn w manipulat stor locations in th program w writ thm as l, and trat thm as (valu lvl) witnsss that a particular stor location xists. Akin to rgion witnsss, stor locations ar not prsnt in th initial program Wak valus and lazy valuation Valus ar trms of th form x, Λ(a : κ).t, λ(x : τ).t or l. W us v to rfr to trms that ar valus. Additionally, wak valus ar all valus, plus trms of th form suspnd δ t 1 t 2. Th lattr trm is a thunk, which dlays th valuation of th mbddd function application. As such, t 1 is th function, t 2 is its argumnt, and δ is a witnss that th application is pur. Whn w prform function application th function argumnt is rducd to a wak valu only. Whn rducing a ltxprssion, th right of th binding is also rducd to a wak valu only. W us v to rfr to wak valus, and imagin th circl in th suprscript as a bubbl that can carry an unapplid function application through th rduction, sans valuation. A wak valu is only forcd whn th surrounding xprssion dmands its (strong) valu. This happns whn th valu is inspctd by an ifxprssion, or is ndd by a primitiv oprator such as updat. Th nxt pag givs an xampl valuation, whr th trm bing rducd at ach stp is undrlind.
199 4.2. SIMPLIFIED CORE LANGUAGE 199 lt z = (λx. x) cat in lt f = suspnd (λx.λy. x) (suspnd (λx. x) dog) in f z (1) lt z = cat in lt f = suspnd (λx.λy. x) (suspnd (λx. x) dog) in f z (2) lt f = suspnd (λx.λy. x) (suspnd (λx. x) dog) in f cat (3) (suspnd (λx.λy. x) (suspnd (λx. x) dog)) cat (4) (λy. suspnd (λx. x) dog) cat (5) (suspnd (λx. x) dog) (6) dog (7) Not that in th stp from (3) to (4), th right of th f binding is a thunk, so it is substitutd dirctly into th body of th ltxprssion. In th stp from (4) to (5), th function application dmands th valu of th function, so th thunk that rprsnts it is forcd Stors, machin stats and rgion handls ρ W modl th stor as a st of bindings of th form l V, whr l is a location, V is an atomic valu, and ρ is th handl of th rgion th valu is in. As w hav limitd ourslvs to boolans as th only updatabl typ, only boolans valus ar prsnt in th stor. This mans V can b ithr T or F for tru or fals valus rspctivly. Stors may also contain lmnts of th form (mutabl ρ) and (const ρ) which spcify th associatd proprty of th rgion with that handl. Not th distinction btwn proprtis and witnsss. Proprtis xist in th stor and ar not undrlind, whras witnsss xist in th xprssion bing rducd, and ar undrlind. To convrt a witnss to its quivalnt proprty w us th propof function. For xampl: propof(mutabl ρ) mutabl ρ A machin stat is a combination of a stor and th trm bing valuatd. W writ machin stats as H ; t, whr H is th stor (also known as th hap) and t is th trm. Whn th program starts valuating th stor is mpty, so w us ; t as th initial stat. Rgion witnsss ar witnsss to th fact that a particular rgion is prsnt in th stor, and is availabl to hav things allocatd into it. Not that th rgion witnsss in th stor ar writtn ρ, but whn usd as a typlvl witnss thy ar writtn with an undrlin, ρ. W us ltrgion to crat a nw rgion, and th Tru and Fals constructors to allocat valus into it. W must pass a rgion handl to ths constructors to prov that th rquird rgion xists for thm to allocat thir valu into.
200 200 CHAPTER 4. CORE LANGUAGE For xampl, to crat a nw rgion and allocat a Tru valu into it w could start with th following machin stat: ; ltrgion r with {w = MkConst r} in Tru r To rduc th ltrgion, w crat frsh rgion handl ρ, along with its witnss ρ and substitut th witnss for all occurrncs of th bound rgion variabl r. If thr ar witnsss to mutability or constancy attachd, thn w also construct thos and add thm to th hap. For xampl: ; ltrgion r with {w = MkConst r} in Tru r ρ, const ρ ; Tru ρ Not that th trm Tru ρ is closd. If w had not substitutd th witnss ρ for r thn r would b fr, which would violat th progrss thorm w discuss in To rduc th application of a data constructor, w crat a frsh location in th stor and bind th associatd valu to it: ρ, const ρ ; Tru ρ ρ ρ, const ρ, l T ; l Not again that th location in th stor is writtn l, but in th trm it is writtn l. W can think of l as a valu lvl witnss, or vidnc, that thr is an associatd location in th stor. This must b tru, bcaus th only way can acquir an l is by prforming an allocation. Importantly, in a concrt implmntation thr is no nd to actually rcord proprtis lik ρ and (const ρ) in th stor. A trm such as (const ρ) xprsss a proprty which th running program will honor, but w do not nd privilg bits, tabls, locks, or othr low lvl machinry to achiv this it s takn car of statically by th typ systm. Th fact a wll typd program will not updat data in a constant rgion is part of th guarant that it will not go wrong. ρ On th othr hand, w do nd to rcord bindings such as l T, bcaus thy corrspond to physical data in th stor Rgion allocation vrsus lazy valuation Not that ltrgion xampl from th last sction would b invalid in systms such as [TB98] which us rgions for mmory managmnt. Hr it is again: ; ltrgion r with {w = MkConst r} in Tru r This xprssion has typ Bool r, which indicats that it rturns a boolan valu in a rgion namd r. Th troubl is that th valu will xist in th stor aftr th trm has finishd valuating. Systms such as [TB98] us th syntactic scop of th variabl bound by a ltrgion to dnot th liftim of th associatd rgion. In ths systms, onc th body of a ltrgion trm has finishd valuating, th rgion namd r, along with all th objcts in it, is rclaimd by th storag managr. Th typ chckr nsurs that th surrounding program cannot hold rfrncs to objcts in rclaimd rgions, by rquiring that th rgion variabl r is not fr in th typ nvironmnt, or th typ of th rturn valu. This is an obsrvation critria similar to th on discussd in
201 4.2. SIMPLIFIED CORE LANGUAGE 201 Unfortunatly, this simpl critria only works for strict languags. In Discipl, vn though a valu may hav typ Bool r, if it is a lazy valu thn it may b rprsntd by a thunk. This thunk can hold rfrncs to rgions that ar not visibl in its typ, and if w wr to dallocat thos rgions bfor forcing th thunk, thn th rsult would b undfind. This is discussd furthr in As w do not us rgions for allocation, w do not nforc th obsrvation critria mntiond abov. Howvr, this rquirs us to rlax our notion of typ quality to account for th fact that rgion handls ar substitutd for rgion variabls during valuation. W us th notion of rgion similarity, writtn r ρ to rprsnt this, and th mchanism is discussd in th coming sctions Stor typings A stor typing Σ is a st of lmnts of th form: ρ, mutabl ρ, const ρ, l : τ, r ρ. Th stor typing is an abstract modl of th currnt stat of th stor, and th proprtis w rquir it to hav. A stor H is said to b wll typd with rspct to a stor typing Σ, writtn Σ H, if vry binding in th stor has th typ prdictd by th stor typing. That is: ρ for all l V H w hav l : τ Σ and ρ Σ for som τ, ρ. for all mutabl ρ H w hav mutabl ρ Σ for all const ρ H w hav const ρ Σ Th dual of wll typd is modls, that is a stor typing Σ is said to modl a stor H, writtn Σ = H, if all mmbrs in th stor typing corrspond to mmbrs in th stor: for all l : τ Σ w hav l for all ρ Σ w hav ρ H ρ V H for all mutabl ρ Σ w hav mutabl ρ H for all const ρ Σ w hav const ρ H Rgion similarity Th trm r ρ, pronouncd r is similar to ρ, is usd to associat a rgion handl with a rgion variabl. This notation is usd in our proof of soundnss to account for th fact that th typs of trms chang during valuation.
202 202 CHAPTER 4. CORE LANGUAGE Our typing ruls us th following judgmnt form: Γ Σ t :: τ ; σ This is rad: with typ nvironmnt Γ and stor typing Σ th trm t has typ τ and its valuation causs an ffct σ. Th typ nvironmnt maps valu variabls to typs, and typ variabls to kinds. Whn a ltrgion is rducd, th act of substituting th frsh rgion handl for th rgion variabl changs th typ of th trm. W can s this in th following rduction from ; ltrgion r with {w = MkConst r} in Tru r ρ, const ρ ; Tru ρ Writing ach position out on a sparat lin, th typ judgmnt for th initial trm is: ltrgion r with {w = MkConst r} in Tru r :: Bool r ; Not that th Tru r trm givs ris to Bool r. Howvr, whn w rduc th outr ltrgion, w nd up with: ρ, const ρ, r ρ Tru ρ :: Bool ρ ; As th valu trm is now Tru ρ instad of Tru r, its typ is Bool ρ instad of Bool r. This is why w introduc th r ρ trm into th stor typing: it rcords th mapping btwn rgion handls and th variabls thy wr substitutd for. In our proof of soundnss w rquir that whn w rduc an xprssion, th rsult has a typ that is similar to th initial xprssion. That is, it is idntical up to th rnaming of rgion handls to thir associatd rgion variabls. Not that th ffct trm can also chang during rduction, with rgion variabls in ffcts lik Rad r bing rplacd by rgion handls Duplication of rgion variabls during valuation Bfor moving on to discuss th formal typing ruls, w point out a final proprty of th stor typing. Thr can b multipl rgion handls bound to a particular rgion variabl, that is, w can hav both r ρ 1 and r ρ 2 in th stor typing, whr ρ 1 and ρ 2 ar distinct. This is causd whn a trm containing a ltrgion is duplicatd during function application (or via a ltbinding).
203 4.2. SIMPLIFIED CORE LANGUAGE 203 For xampl, starting with th statmnt: f :... (λx : () ::... ; Bool r. f (x ()) (x ())) (λy : (). ltrgion r in Tru r) W substitut th argumnt for x, giving: f :... f ((λ(y : ()). ltrgion r in Tru r) ()) ((λ(y : ()). ltrgion r in Tru r) ()) ::... ; Not th duplication of r in th ltrgion trm. Whn th first copy is rducd it crats its own rgion handl: f :... ρ 1 ρ 1, r ρ 1, l 1 Bool ρ1 f l 1 ((λ(y : ()). ltrgion r in Tru r) ()) ::... ; Rducing th scond copy producs a diffrnt on, ρ 2 : f :... ρ 1 ρ 1, r ρ 1, l 1 Bool ρ1 ρ 2 ρ 2, r ρ 2, l 2 Bool ρ2 f l 1 l 2 ::... ; This illustrats that th mapping btwn rgion variabls and rgion handls is not simply ontoon, a point w must b mindful of in our proof of soundnss.
204 204 CHAPTER 4. CORE LANGUAGE Witnss production H ; δ δ H, const ρ ; MkConst ρ const ρ (EwConst) H, mutabl ρ ; MkMutabl ρ mutabl ρ (EwMutabl) H ; MkPur pur H ; MkPurify ρ (const ρ) pur (Rad ρ) (EwPur) (EwPurify) H ; δ 1 δ 1 H ; MkPurJoin σ 1 σ 2 δ 1 δ 2 MkPurJoin σ 1 σ 2 δ 1 δ 2 (EwPurJoin1) H ; δ 2 δ 2 H ; MkPurJoin σ 1 σ 2 δ 1 δ 2 MkPurJoin σ 1 σ 2 δ 1 δ 2 H ; MkPurJoin σ 1 σ 2 pur σ 1 pur σ 2 pur (σ 1 σ 2 ) (EwPurJoin2) (EwPurJoin3) Th judgmnt form H ; δ δ rads: with stor H, typ δ producs typ δ. Th first two ruls, EwConst and EwMutabl ar usd to sampl a particular proprty of th stor. Th ida is that a trm lik MkMutabl ρ cannot b rducd to a witnss to th fact, unlss th stor rally dos support th rquird proprty. Whn proving soundnss, w show that such a trm can only b valuatd in a contxt that nsurs th rquird proprty is tru, so th valuation can always progrss. EwPur is a simpl axiom allows us to construct a witnss that th ffct is pur. EwPurify is usd to produc a witnss that a rad from a rgion is pur from a witnss that th rgion is constant. Th final thr ruls, EwPurJoin1, EwPurJoin2 and EwPurJoin ar usd to join two witnsss, showing th purity of sprat ffcts, into on that shows th purity of both.
205 4.2. SIMPLIFIED CORE LANGUAGE Transitions H ; t H ; t H ; t H ; t H ; t ϕ H ; t ϕ H ; (Λ(a :: κ). t) ϕ H ; t[ϕ/a] (EvTApp1) (EvTAppAbs) H ; t 1 H ; t 1 H ; t 1 t 2 H ; t 1 t 2 H ; t H ; t H ; v t H ; v t H ; (λ(x :: τ). t) v H ; t[v /x] (EvApp1) (EvApp2) (EvAppAbs) H ; t 1 H ; t 1 H ; lt x = t 1 in t 2 H ; lt x = t 1 in t 2 H ; lt x = v in t H ; t[v /x] H, propof( i ) ; δ i i ρ frsh H ; ltrgion r {w i = δ i } in t H, ρ, propof( i ) ; t[ i /w i ][ρ/r] (EvLt1) (EvLt) (EvLtRgion) H ; t 1 H ; t 1 H ; if t 1 thn t 2 thn t 3 H ; if t 1 thn t 2 thn t 3 H, l H, l ρ ρ T ; if l thn t 2 thn t 3 H, l T ; t 2 ρ ρ F ; if l thn t 2 thn t 3 H, l F ; t 3 l frsh H, ρ ; Tru ρ H, ρ, l l frsh H, ρ ; Fals ρ H, ρ, l ρ T ; l ρ F ; l (EvIf) (EvIfThn) (EvIfEls) (EvTru) (EvFals) H ; t 1 H ; t 1 H ; updat t 1 t 2 H ; updat t 1 t 2 H ; t H ; t H ; updat v t H ; updat v t (EvUpdat1) (EvUpdat2)
206 206 CHAPTER 4. CORE LANGUAGE ρ 1 ρ 2 H, mutabl ρ 1, l 1 V1, l 2 V2 ; updat mutabl ρ 1 l 1 l 2 ρ 1 ρ 2 H, mutabl ρ 1, l 1 V2, l 2 V2 ; () H ; δ δ H ; suspnd δ t 1 t 2 H ; suspnd δ t 1 t 2 (EvUpdat3) (EvSuspnd1) H ; t 1 H ; t 1 H ; suspnd t 1 t 2 H ; suspnd t 1 t 2 H ; t H ; t H ; suspnd v t H ; suspnd v t H ; suspnd pur σ 1 (λ(x : τ). t) v H ; t[v /x] (EvSuspnd2) (EvSuspnd3) (EvSuspnd4) Ruls EvTApp1  EvLt ar standard. EvLtRgion crats a nw rgion in th stor, and substituts its rgion handl into th valu trm. By inspction of th witnss production ruls, th statmnt H, propof( i ) ; δ i i is always tru. It says that if w plac th rquird proprtis in th hap, w can thn construct witnsss that sampl ths proprtis. EvIf  EvIfEls ar standard. EvTru  EvFals show how to allocat nw boolan valus into th stor. Not that to allocat a nw valu, th rgion it is to b allocatd in must alrady xist in th stor. In th proof of progrss w show that if a trm contains a rgion witnss ρ thn th corrsponding rgion will always b prsnt. EvUpdat1  EvUpdat3 show how to updat a boolan valu in th stor. EvSuspnd1  EvSuspnd4 handl th suspnsion of function applications. In EvSuspnd1 w includ th statmnt H ; δ δ to allow for th valuation of witnss production ruls, such as EwPurJoin. Not that in EvSuspnd, th ffct trm σ 1 is only mntiond in th witnss trm. Our typing ruls nsur that σ 1 actually rprsnts th ffct of valuating th trm t.
207 4.2. SIMPLIFIED CORE LANGUAGE Kinds of kinds Γ K κ :: κ κ {, %,!, } Γ K κ :: κ (KsRfl) Γ K κ 1 :: κ 11 κ 12 Γ K ϕ :: κ 11 Γ K κ 1 ϕ :: κ 12 (KsApp) Γ K Const :: % Γ K Mutabl :: % Γ K Pur ::! Th judgmnt form Γ K κ :: κ rads: in nvironmnt Γ, kind κ has kind κ. KsRfl stats that th kind of a simpl kind is itslf, which caps th valutypkind strata. For xampl, th kind of % is simply % and not som highr lvl objct. KsRfl must b rstrictd to simpl kinds othrwis a kind application such as Const a would hav two possibl kinds, itslf and. KsApp is th rul for th application of kind functions. Th last thr ruls giv kinds for th witnss kind constructors and allow us to chck for malformd kind xprssions such as Pur (Bool a) and Const Rad. Th gnral dpndnt kind abstraction Π(a :: κ 1 ). κ 2 is lft without a kind assignmnt as it is only introducd by th witnss constructor ruls in th nxt sction. It should not appar isolatd in th program.
208 208 CHAPTER 4. CORE LANGUAGE Kinds of typs Γ Σ T ϕ :: κ a : κ Γ Γ Σ T a :: κ (KiVar) Γ K κ 1 :: κ 1 Γ, a : κ 1 Σ T τ :: κ 2 a / fv(γ) Γ Σ T (a : κ 1 ). τ :: κ 2 (KiAll) Γ Σ T ϕ 1 :: Π(a : κ 1 ). κ 2 Γ Σ T ϕ 2 :: κ 1 Γ Σ T ϕ 1 ϕ 2 :: κ 2 [ϕ 2 /a] (KiApp) Γ Σ T σ 1 ::! Γ Σ T σ 2 ::! Γ Σ T σ 1 σ 2 ::! (KiJoin) Γ Σ T ::! (KiTop) Γ Σ T ::! (KiBot) ρ Σ Γ Σ T ρ :: % (KiHandl) mutabl ρ Σ Γ Σ T mutabl ρ :: Mutabl ρ (KiMutabl) const ρ Σ Γ Σ T const ρ :: Const ρ (KiConst) Γ Σ T pur :: Pur (KiPur) const ρ Σ Γ Σ T pur (Rad ρ) :: Pur (Rad ρ) (KiPurify) Γ Σ T pur σ 1 :: Pur σ 1 Γ Σ T pur σ 2 :: Pur σ 2 Γ Σ T pur (σ 1 σ 2 ) :: Pur (σ 1 σ 2 ) (KiPurJoin)
209 4.2. SIMPLIFIED CORE LANGUAGE 209 Γ Σ T () :: Γ Σ T ( ) ::! Γ Σ T Bool :: % Γ Σ T Rad :: %! Γ Σ T Writ :: %! Γ Σ T MkConst :: Π(r : %). Const r Γ Σ T MkMutabl :: Π(r : %). Mutabl r Γ Σ T MkPur :: Pur Γ Σ T MkPurify :: Π(r : %). Const r Pur (Rad r) Γ Σ T MkPurJoin :: Π( 1 :!). Π( 2 :!). Pur 1 Pur 2 Pur ( 1 2 ) Th judgmnt form Γ Σ T ϕ :: κ rads: with nvironmnt Γ, and stor typing Σ, th typ ϕ has kind κ. KiVar is standard. In KiAll th a / fv(γ) prmis guards against nam collisions btwn th typ trm and th nvironmnt. In practic this is satisfid by giving th binding occurrncs of variabls uniqu nams. Although κ 1 is only mntiond onc in this rul, inclusion of th Γ T κ 1 :: κ 1 prmis nsurs that kind xprssions in th trm languag ar wll formd. KiApp is th rul for typtyp application, and th substitution in th conclusion handls our dpndnt kinds. KiJoin nsurs that both argumnts ar ffcts, as th join oprator is only dfind for typs of that kind. KiTop and KiBot ar straightforward. KiHandl rquirs all rgion witnsss prsnt in th trm to b prsnt in th stor typing. Providd th stor typing modls th stor 4.2.8, this nsurs that if a rgion witnss is prsnt in th trm, th corrsponding rgion is also prsnt in th stor. Likwis, KiMutabl and KiConst nsur that th appropriat witnsss ar prsnt in th stor typing, so th stor has th rquird proprty. KiPur and KiPurify rlat typlvl witnsss of purity with th corrsponding kindlvl dscription of that proprty. KiPurJoin joins two sparat witnsss, ach showing th purity of an ffct, into a witnss of purity of th sum of ths ffcts. KiPurJoin was introducd in Th rmaining ruls giv th kinds of our typ constructors. W could hav arrangd for ths kinds to b prsnt in th initial typ nvironmnt, but prsnt thm as sparat ruls du to thir builtin natur.
210 210 CHAPTER 4. CORE LANGUAGE Similarity Σ T κ κ Σ T κ κ (SkmRfl) Σ ϕ 1 ϕ 2 Σ T κ ϕ 1 κ ϕ 2 (SkmApp) Σ ϕ ϕ r ρ Σ Σ r ρ (SimHandl) Σ ϕ 1 ϕ 2 (SimRfl) Σ ϕ 1 ϕ 2 Σ ϕ 2 ϕ 3 Σ ϕ 1 ϕ 3 (SimTrans) Σ ϕ 1 ϕ 2 Σ ϕ 2 ϕ 1 (SimCommut) Σ T κ 1 κ 2 Σ τ 1 τ 2 Σ (a : κ 1 ). τ 1 (a : κ 2 ). τ 2 (SimAll) Σ ϕ 11 ϕ 21 Σ ϕ 21 ϕ 22 Σ ϕ 11 ϕ 12 ϕ 21 ϕ 22 (SimApp) Σ σ 11 σ 21 Σ σ 12 σ 22 Σ σ 11 σ 12 σ 21 σ 22 (SimJoin) Σ ϕ 1 ϕ 2 Σ mutabl ϕ 1 mutabl ϕ 2 (SimMutabl) Σ ϕ 1 ϕ 2 Σ const ϕ 1 const ϕ 2 (SimConst) Σ ϕ 1 ϕ 2 Σ pur ϕ 1 pur ϕ 2 (SimPur) Th judgmnt form Σ T κ κ rads: with stor typing Σ, kind κ is similar to kind κ. W also writ this as κ Σ κ. Th judgmnt form Σ ϕ ϕ is similar. Th ruls for similarity should b slf xplanatory. Th only intrsting on is SimHandl. This rul says that rgion variabls ar similar to thir associatd rgion handl, providd th mapping is prsnt in th stor typing.
211 4.2. SIMPLIFIED CORE LANGUAGE Subsumption Γ Σ σ σ Σ σ 1 σ 2 Γ Σ σ 1 σ 2 (SubRfl) Γ Σ σ 1 σ 2 Γ Σ σ 2 σ 3 Γ Σ σ 1 σ 3 (SubTrans) Γ Σ T σ ::! Γ Σ σ (SubTop) Γ Σ T σ ::! Γ Σ σ (SubBot) Γ Σ σ 1 σ 3 Γ Σ σ 2 σ 3 Γ Σ σ 1 σ 2 σ 3 (SubJoin1) Γ Σ σ 1 σ 2 Γ Σ T σ 2 σ 3 ::! Γ Σ σ 1 σ 2 σ 3 (SubJoin2) Γ Σ T δ :: Pur σ Γ Σ σ (SubPurify) Th judgmnt form Γ σ σ rads: with nvironmnt Γ and stor typing Σ, ffct σ is subsumd by ffct σ. All but th last of ths ruls ar standard. Not that th typ nvironmnt Γ is not usd in th prmiss of ths ruls. W will mak us of it whn w discuss boundd quantification in SubPurify says that if w hav a Pur σ witnss, thn w can trat σ as bing pur. This rul is th kyston of our systm. It allow us to us th information mbodid in a witnss to rason that th valuation of an xprssion with a rad ffct cannot intrfr with othrs. Th rul is usd in th TySuspnd cas whn proving prsrvation of ffcts undr valuation in Appndix A.
212 212 CHAPTER 4. CORE LANGUAGE Typs of trms Γ Σ t :: τ ; σ x : τ Γ Γ Σ x :: τ ; (TyVar) Γ, a : κ Σ t 2 :: τ 2 ; σ 2 Γ Σ Λ(a : κ). t 2 :: (a : κ). τ 2 ; σ 2 (TyAbsT) Γ Σ t 1 :: (a : κ 11 ). ϕ 12 ; σ 1 Γ Σ T ϕ 2 :: κ 2 κ 11 Σ κ 2 Γ Σ t 1 ϕ 2 :: ϕ 12 [ϕ 2 /a] ; σ 1 [ϕ 2 /a] (TyAppT) Γ, x : τ 1 Σ t :: τ 2 ; σ Γ Σ λ(x : τ 1 ). t :: τ 1 σ τ2 ; (TyAbs) Γ Σ t 2 :: τ 2 ; σ 2 Γ Σ t 1 :: τ 11 σ τ12 ; σ 1 τ 11 Σ τ 2 Γ Σ t 1 t 2 :: τ 12 ; σ 1 σ 2 σ (TyApp) Γ Σ t 1 :: τ 1 ; σ 1 Γ, x : τ 3 Σ t 2 :: τ 2 ; σ 2 τ 1 Σ τ 3 Γ Σ lt x = t 1 in t 2 :: τ 2 ; σ 1 σ 2 (TyLt) δ i wll formd Γ K κ i :: Γ, r : %, w i : κ i Σ t :: τ ; σ Γ Σ T δ i :: κ i Γ Σ ltrgion r with {w i = δ i } in t :: τ ; σ (TyLtRgion) Γ Σ t 1 :: Bool ϕ ; σ 1 Γ Σ t 2 :: τ 2 ; σ 2 Γ Σ t 3 :: τ 3 ; σ 3 τ 2 Σ τ 3 Γ Σ if t 1 thn t 2 ls t 3 :: τ 2 ; σ 1 σ 2 σ 3 Rad ϕ (TyIf) Γ Σ T ϕ :: % Γ Σ Tru ϕ :: Bool ϕ ; (TyTru) Γ Σ T ϕ :: % Γ Σ Fals ϕ :: Bool ϕ ; (TyFals) Γ Σ t 1 :: Bool ϕ 1 ; σ 1 Γ Σ T δ :: Mutabl ϕ 1 Γ Σ t 2 :: Bool ϕ 2 ; σ 2 Γ Σ updat δ t 1 t 2 :: () ; σ 1 σ 2 Rad ϕ 2 Writ ϕ 1 (TyUpdat)
213 4.2. SIMPLIFIED CORE LANGUAGE 213 τ 11 Σ τ 2 Γ Σ t 1 :: τ 11 σ τ12 ; σ 1 Γ Σ T δ :: Pur σ Γ Σ t 2 :: τ 2 ; σ 2 Γ Σ suspnd δ t 1 t 2 :: τ 12 ; σ 1 σ 2 Γ Σ () :: () ; l : τ Σ Γ Σ l :: τ ; (TySuspnd) (TyUnit) (TyLoc) Th judgmnt form Γ Σ t :: τ ; σ rads: with nvironmnt Γ and stor typing Σ th trm t has typ τ and ffct σ. Many of ths ruls ar standard, apart from th fact that w must us th similarity judgmnts κ Σ κ and ϕ Σ ϕ whn prforming comparisons. TyAppT handls typ application. Not that th typ paramtr is substitutd into th rsulting ffct σ 1 [ϕ 2 /a] as wll as th rsulting typ ϕ 12 [ϕ 2 /a]. This nsurs th ffct trm rmains stabl during valuation. For xampl, if w wr to omit this substitution thn w could construct th valuation: ltrgion r 1 in (Λ(r 2 : %). if Tru r 2 thn... ls...) r 1 ::... ; Rad r 2 ρ 1, r 1 ρ 1 (Λ(r 2 : %). if Tru r 2 thn... ls...) ρ 1 ::... ; Rad r 2 ρ 1, r 1 ρ 1 if Tru ρ 1 thn... ls... ::... ; Rad ρ 1 Whn th trm in th scond stp is valuatd, its ffct changs from Rad r 2 to Rad ρ 1. As thr is no lmnt in th stor typing spcifying that r 2 and ρ 1 ar similar, our prsrvation thorm would b violatd.
214 214 CHAPTER 4. CORE LANGUAGE Soundnss of typing ruls Our proof of soundnss is split into progrss and prsrvation (subjct rduction) thorms, in th usual way. Th proof s main utility is to srv as a chck on th typing ruls, and to mak sur w hav not inadvrtntly lft any out. Th proof itslf is not particularly intrsting, so it is rlgatd to th appndix. W rpat th main thorms hr: Thorm: (Progrss) Suppos w hav a stat H ; t with stor H and trm t. Lt Σ b a stor typing which modls H. If H is wll typd with rspct to Σ, and t is closd and wll typd, and t contains no fabricatd rgion witnsss (discussd in 4.2.4), thn ithr t is a valu or H ; t can transition to th nxt stat. If and and and thn or Σ t :: τ ; σ Σ = H Σ H nofab(t) t Valu for som H, t w hav (H ; t H ; t and nofab(t )) Thorm: (Prsrvation) Suppos w hav a stat H ; t with stor H and trm t. Lt Σ b a stor typing which modls H. If H and t ar wll typd, and H ; t can transition to a nw stat H ; t thn for som Σ which modls H, H is wll typd, t has a similar typ to t, and th ffct σ of t is no gratr than th ffct σ of t. If Γ Σ t :: τ ; σ and H ; t H ; t and Σ H and Σ = H thn for som Σ, τ, σ w hav Γ Σ t :: τ ; σ and Σ Σ and Σ = H and Σ H and τ Σ τ and σ Σ σ Not that whn a trm is valuatd, its ffct tnds to bcom smallr, which is xprssd as th σ Σ σ claus in th prsrvation thorm. For xampl, although updat δ x y has th ffct of rading y and writing x, it is rducd to (), which has no intrinsic ffct. Also not that th stor typing grows during valuation, which is xprssd as th Σ Σ claus of th prsrvation thorm. This mans that onc a rgion s constancy is st, it cannot b rvokd, or changd during valuation.
215 4.3. EXTENSIONS TO THE SIMPLIFIED LANGUAGE Extnsions to th simplifid languag Th simplifid cor languag of 4.2 is not syntactically complt with rspct to th sourc languag. This mans that it cannot dirctly xprss all th possibl wll typd sourc programs. It dos not includ algbraic data typs, cas xprssions, ffct masking or boundd quantification. In addition, th typing rul for ifxprssions dos not allow us to choos btwn two functions that hav th sam valu typ, but diffring ffcts. Th additions ndd for algbraic data typs and cas xprssions ar unsurprising, so w will not discuss thm furthr. W discuss th othrs in turn Masking nonobsrvabl ffcts W mask thr sorts of ffcts: ffcts of computations that ar unobsrvabl, ffcts on frshly allocatd valus, and ffcts that ar known to b pur. Th following rul handls th first sort: Γ Σ t :: τ ; σ r / fv T (Γ) r / fv(τ) Γ Σ t :: τ ; σ \ (Rad r Writ r) (TyMaskObsrv) This rul ncods th obsrvation critria discussd in 2.4. It says that if a rgion variabl is not prsnt in th typ nvironmnt or typ of a trm, thn w can ignor th fact that its valuation will prform rad or writ actions on th associatd rgion. As w trat as akin to st union th ffct minus oprator \ is dfind in th obvious way. Not that it is saf to allow kind bindings of th form r : % to b prsnt in th nvironmnt, as long as th rgion variabl is not mntiond in th τ part of any x : τ. This is handld by th fv T (Γ) function which is dfind as: fv T (Γ) = { fv(τ) x : τ Γ } For a concrt implmntation, th troubl with TyMaskObsrv is that it is not syntax dirctd. It is valid to apply this rul to any trm, but applying it to vry trm could b too slow at compil tim. Usfully, whn rconstructing th typ of a trm w only nd to prform this sort of masking on subtrms that ar th bodis of λabstractions. This is bcaus th typing rul for abstractions is rsponsibl for moving ffct information from th σ in Γ Σ t :: τ ; σ into th valu typ xprssion. Instad of using a sparat TyMaskObsrv rul, w find it convnint to incorporat ffct masking dirctly into th rul for λabstractions. This givs: Γ, x : τ 1 Σ t :: τ 2 ; σ r / fv T (Γ) r / fv(τ 1 ) fv(τ 2 ) σ = σ \ (Rad r Writ r) Γ Σ λ(x : τ 1 ). t :: τ 1 σ τ 2 ; (TyAbsObsrv) An altrnativ would b to combin th ffct masking TyLtRgion, but this would rquir th typ chckr to inspct th ffct trm mor frquntly.
216 216 CHAPTER 4. CORE LANGUAGE Masking ffcts on frsh rgions As discussd in 2.3.7, w can mask ffcts that ar only usd to comput th rsult of a function, and ar not othrwis visibl. Hr is th rul to do so: Γ Σ λ(x : τ). t :: τ σ Bool r ; σ r / fv T (Γ) r / fv(τ) σ = σ \ (Rad r Writ r) Γ Σ λ(x : τ). t :: τ σ Bool r ; σ (TyMaskFrsh) As hav not includd closur typing information in our simplifid languag, w hav to ti TyMaskFrsh to th lambda abstraction λ(x : τ). t. This prvnts us from inadvrtntly masking ffcts on rgions prsnt in th closur of th function. Whn TyMaskFrsh is applid, all th fr variabls in t (th closur) must b prsnt in th nvironmnt Γ, and thus th trm fv T (Γ) accounts for thm. Not that in TyMaskFrsh w hav st th rsult typ of th function to Bool as that is th only nonfunction valu typ constructor in our simplifid languag. For th full languag, w can rplac Bool by any typ constructor, so long as w only mask ffcts on rgion variabls that ar in strongly matrial positions. Matriality was discussd in Rturning to th issu of closur typing, not that th following mor gnral variant of TyMaskFrsh is bad. 1 Γ Σ t :: τ σ Bool r ; σ r / fv T (Γ) r / fv(τ) σ = σ \ (Rad r Writ r) Γ Σ t :: τ σ Bool r ; σ (BadTyMaskFrsh) W can s why BadTyMaskFrsh is bad by considring its (non) applicability in th following program. Not that for a clarr xampl, w hav takn th librty of using Int instad of Bool. makinc = λ(). lt x = 0 r 1 f = λ(). do { x := x + 1 r 1 ; x } in f This program is similar in spirit to th xampls from It allocats a mutabl intgr x, thn rturns a function that updats it and rturns its valu. Without masking, th typ of th innr ltxprssion is: (lt x = 0... in f) :: () Rad r 1 Writ r 1 Int r1 At this point, th typ nvironmnt only nds to contain th trm r 1 : % and typ for (+), which has no fr variabls. If w wr to apply BadTyMaskFrsh hr, thn w would nd up with: (lt x = 0... in f) :: () Int r 1 1 W avoid th word unsound bcaus its us will not prvnt a trm from bing rducd to normal form. Howvr, if w apply it during typ rconstruction and thn optimis th program basd on this information, thn w run th risk of producing a program that givs an unintndd answr, hnc badnss.
217 4.3. EXTENSIONS TO THE SIMPLIFIED LANGUAGE 217 This is invalid bcaus th xprssion will rturn a diffrnt valu ach tim w apply it to (), hnc w cannot rordr calls to it. In futur work w plan to xtnd our cor languag with closur typing information. This would allow us to us a rul similar to th following: Γ Σ t :: τ σ ς Bool r ; σ r / fv T (Γ) r / fv(τ) r / fv(ς) σ = σ \ (Rad r Writ r) Γ Σ t :: τ σ ς Bool r ; σ (CloTyMaskFrsh) Whn w includ closur typing information in th prvious xampl, th typ of th ltxprssion bcoms: (lt x = 0... in f) :: () (Rad r 1 Writ r 1 ) (x:int r) Int r 1 This closur trm x : Int r rvals th fact that succssiv applications of this function will shar a valu of typ Int r. Bcaus of this w cannot guarant that th rturnd valu is frsh, so w cannot mask ffcts on it Masking pur ffcts Rcall th mapl function from which prforms a spinlazy map across th lmnts of a list. W will convrt its dfinition to th cor languag. Firstly, th sourc typ of mapl is: mapl :: a b r 1 r 2 1. (a 1 b) List r 1 a 2 List r 2 b, 2 = Rad r 1 1 Pur 1, Const r 1 To convrt this typ to cor, w writ th purity and constancy constraints in prfix form, and plac th manifst ffct trm dirctly on th corrsponding function constructor: mapl :: a b r 1 r 2 1. Pur 1 Const r 1 (a 1 b) List r 1 a Rad r 1 1 List r2 b Th dsugard vrsion of th function dfinition follows. W hav xpandd th pattrn matching syntax, th infix us and hav introducd a binding for ach function argumnt: mapl = λf. λxx. cas xx of Nil Nil Cons x xs do x = f x mapl = mapl f xs = suspnd1 mapl xs Cons x xs
218 218 CHAPTER 4. CORE LANGUAGE From th typ of mapl w s that th cor vrsion of th function should hav svn typ paramtrs: fiv du to th univrsal quantifir, and two to bind th witnsss for Pur 1 and Const r 1. W will add ths typ argumnts, along with typ applications whr rquird: mapl = Λ a b r 1 r 2 1. Λ w 1 :: Pur 1. Λ w 2 :: Const r 1. λ f :: a 1 b. λ xx :: List r 1 a. cas xx of Nil Nil a r 2 Cons x xs do x = f x mapl = mapl a b r 1 r 2 1 w 1 w 2 f xs = suspnd1 (List r 1 a) (List r 2 b) (Rad r 1 1 ) (MkPurJoin (Rad r 1 ) 1 (MkPurify r 1 w 2 ) w 1 ) Cons b r 2 x xs W hav lidd th kind annotations on th first fiv typ paramtrs to aid radability. Th variabls w 1 and w 2 bind witnsss to th facts that 1 is pur and r 1 is constant. Not that in th rcursiv call to mapl all of its typ paramtrs must b passd back to itslf. W also add typ applications to satisfy th quantifirs and constraints on suspnd1, and to satisfy Nil and Cons. For rfrnc, Nil and Cons hav th following typs: Nil Cons :: a r 1.List r 1 a :: a r 1. a List r 1 a List r 1 a Not that bcaus th typ w usd for mapl contains th ffct trm Rad r 1 1, whn w call suspnd1 w must provid a witnss that this ffct is pur. This is th rason for th (MkPurJoin (Rad r 1 ) 1 (MkPurify r 1 w 2 ) w 1 ) trm. Such witnsss wr discussd in This is a valid translation, but as mntiond in it would b nicr if w could mask th Rad r 1 and 1 ffcts and not hav to writ thm in th typ. Aftr all, th point of proving that a particular ffct is pur is so w can ignor it from thn on. Masking ths ffcts in th typ is straightforward, and th cor vrsion is: mapl :: a b r 1 r 2 1. Pur 1 Const r 1 (a 1 b) List r 1 a List r 2 b Howvr, using this typ rquirs that w add a mchanism to mask th quivalnt ffcts in th cor program. On option is to add a rul similar to Ty MaskObsrv from 4.3.1: Γ Σ t :: τ ; σ Γ Σ T δ :: Pur σ Γ Σ t :: τ ; σ \ σ (TyMaskPur)
219 4.3. EXTENSIONS TO THE SIMPLIFIED LANGUAGE 219 Howvr, as with TyMaskObsrv, this rul is not syntax dirctd. Anothr option is to introduc an xplicit masking kyword, which stats th witnss bing usd to mask th ffct of a particular xprssion. For xampl: Γ Σ t :: τ ; σ Γ Σ T δ :: Pur σ Γ Σ mask δ in t :: τ ; σ \ σ (TyMaskPurEx) Th following cod is a cor vrsion of th mapl function that uss th mask kyword, and has th nic typ mntiond abov. Not that bcaus th ffct of mapl is now w us this as th ffct argumnt to suspnd1. mapl = Λ a b r 1 r 2 1. Λ w 1 :: Pur 1. Λ w 2 :: Const r 1. λ f :: a 1 b. λ xx :: List r 1 a. mask MkPurJoin (Rad r 1 ) 1 (MkPurify r 1 w 2 ) w 1 in cas xx of Nil Nil a r 2 Cons x xs do x = f x mapl = mapl a b r 1 r 2 1 w 1 w 2 f xs = suspnd1 (List r 1 a) (List r 2 b) (MkPur ) Cons b r 2 x xs Boundd quantification W add boundd quantification to th cor languag so w can support th highr ordr programs discussd in For xampl, whn convrtd to cor, th third ordr function foo has th following typ and dfinition: foo :: r 1 r 2 r 3 r 4 ( 1 Rad r 1 ) 2. ((Int r 1 1 Int r2 ) 2 Int r 3 ) 2 Rad r 3 Int r4 foo = Λ r 1 r 2 r 3 r 4 ( 1 Rad r 1 ) 2. λ f : (Int r 1 1 Int r2 ) 2 Int r 3. do x 1 = succ r 1 r 2 x 2 = f x 1 succ r 3 r 4 x 2 Not that in th application f x 1 th xpctd typ of th argumnt is: but x 1 has typ: f :: Int r 1 1 Int r2 Rad r x 1 :: Int r 1 1 Int r2 To support this w modify th rul for application so that th argumnt may hav any typ that is subsumd by th typ of th function paramtr. W
220 220 CHAPTER 4. CORE LANGUAGE arrang th typing rul for boundd typ abstraction to add its constraint to th typ nvironmnt, and us this to show that applications such as f x 1 ar valid. Th additions to th cor languag ar as follows: ϕ... ( σ). τ (boundd quantification) t... Λ( σ). t (boundd typ abstraction) Oprationally, boundd typ application bhavs th sam way as th unboundd cas: H ; (Λ( σ). t) ϕ H ; t[ϕ/] (EvTAppAbsB) Th nw typing ruls ar: Γ Σ T σ ::! Γ, :! Σ T τ :: κ / fv(γ) Γ Σ T ( σ). τ :: κ 2 (KiAllB) Γ Σ T σ 1 ::! Γ, :!, σ 1 Σ t 2 :: τ 2 ; σ 2 Γ Σ Λ( σ 1 ). t 2 :: ( σ 1 ). τ 2 ; σ 2 (TyAbsTB) Γ Σ t 1 :: ( σ 11 ). τ 12 ; σ 1 Γ Σ T σ 2 ::! σ 11 Σ σ 2 Γ Σ t 1 σ 2 :: τ 12 [σ 2 /] ; σ 1 [σ 2 /] (TyAppTB) Γ Σ t 2 :: τ 2 ; σ 2 Γ Σ t 1 :: τ 11 σ τ12 ; σ 1 τ 2 Σ τ 11 Γ Σ t 1 t 2 :: τ 12 ; σ 1 σ 2 σ (TyAppB) a σ Γ Γ Σ σ a (SubVar) Γ Σ τ 21 τ 11 Γ Σ τ 12 τ 22 Γ Σ σ 1 σ 2 σ Γ τ 1 σ 11 τ12 τ 2 21 τ22 (SubFun) Σ T κ 1 κ 2 Σ σ 1 σ 2 Σ τ 1 τ 2 Σ (a σ 1 ). τ 1 (a σ 2 ). τ 2 (SimAllB)
221 4.3. EXTENSIONS TO THE SIMPLIFIED LANGUAGE 221 KiAllB and TyAbsTB ar similar to thir unboundd countrparts. Not that boundd quantification is only dfind for ffcts, so th bounding typ has this kind. In TyAbsTB, th ffct bound σ 1 is addd to th typ nvironmnt, and SubVar is usd to rtriv it highr up in th proof tr. In TyAppTB w us subsumption on ffcts, σ 11 Σ σ 2, to satisfy th bound on th quantifir. In TyAppB w us a subsumption judgmnt on valu typs, τ 2 Σ τ 11, to support applications such as th on dscribd in th foo xampl. Not that although subsumption only has maning on th ffct portion of a typ, w still nd to dfin it to work on valu typs. This is bcaus th ffct typ information is attachd to th valu typ information. W don t rally nd contravarianc In SubFun, although w us contravariant subsumption, τ 21 τ 11, for th function paramtr, in practic this contravarianc isn t usd. W could hav qually writtn τ 11 τ 21. This ariss du to th way w strngthn infrrd typs, discussd in As w do not strngthn constraints on ffct variabls that appar in th typs of function paramtrs, th ffct annotations on such typs will always b variabls. In TyAppB, whn w apply a function to its argumnt, w us th subsumption judgmnt to invok th SubVar rul, which accpts xampls lik foo. Howvr, in that xampl w only applid a scond ordr function to a first ordr on. Annotations on function arrows of highr ordr will always b variabls, so applications involving thm ar accptd via SubRfl. Th co/contravarianc of function typs dos not com into play. For contrast, th procss algbra of [NN93] includs an ffct systm in which co/contravarianc dos mattr. Howvr, that work is prsntd as a standalon languag, not as a cor languag mbddd in a largr compilr. For DDC, w cannot writ a program in th sourc languag that maps onto a corlvl program in which co/contravarianc mattrs, so w hav not invstd furthr ffort into supporting it. This situation is similar to whn SystmF is usd as a basis for th cor languag of a Haskll 98 compilr. SystmF supports highr rankd typs [PJVWS07], but Haskll 98 dosn t. Typs of rank2 can b introducd whn prforming lambda lifting [PJ87], but no trms ar producd that hav typs of rank highr than this. Th compilr dos not nd to support full SystmF bcaus only a fragmnt of that languag is rachabl from sourc.
222 222 CHAPTER 4. CORE LANGUAGE Effct joining in valu typs Considr th following sourc program: fiv = 5 f = if... thn (λ(). succ fiv) ls (λ(). do { putstr hllo ; succ fiv}) with putstr :: r 1.String r 1 1 () 1 = Rad r 1 Consol Not that in th dfinition of f, th two functions in th right of th ifxprssion hav diffrnt ffcts. Th first rads th intgr bound to fiv, but th scond also prints to th consol. If w st fiv to hav typ Int r 5, thn ths two xprssions hav th following typs: (λx. succ fiv) :: () 1 Int r 1 1 = Rad r 5 (λ(). do { putstr hllo ; succ fiv}) :: () 2 Int r 1 2 = Rad r 5 Consol As it stands, w cannot translat this program dirctly to our cor languag, bcaus th typing rul TyIf of rquirs both altrnativs to hav similar typs, inclusiv of ffct information. W support such programs by xtnding th dfinition of to join th ffcts containd within valu typs, and us this oprator to comput th rsulting typ of ifxprssions. This mirrors what happns during typ infrnc. (τ 1 1 τ2 ) (τ 2 1 τ3 ) τ (τ2 τ 3 ) Γ Σ t 1 :: Bool ϕ ; σ 1 Γ Σ t 2 :: τ 2 ; σ 2 Γ Σ t 3 :: τ 3 ; σ 3 τ = τ 2 τ 3 Γ Σ if t 1 thn t 2 ls t 3 :: τ ; σ 1 σ 2 σ 3 Rad ϕ (TyIfJoin) Not that as our typ infrnc algorithm only prforms gnralisation at ltbindings, th typs of altrnativs will nvr contain quantifirs. For this rason w don t nd to dfin ovr quantifid typs. Also, as w only strngthn th manifst ffcts of a function typ, th ffct annotations on paramtrs will always b variabls. Similarly to 4.3.4, this guarants that th ffct annotations in function paramtrs ar variabls, so w don t hav to join thm. An altrnat mthod would b to provid an xplicit typ annotation for th rsult of th ifxprssion, and us th subsumption judgmnt to chck that th typs of both altrnativs ar lss than th annotation. This approach was takn in [NN93], but w avoid it bcaus it incrass th volum of annotation.
223 4.4. OPTIMISATIONS Optimisations For DDC, th primary purpos of tracking ffct information is to support compilr optimisations. With that said, w don t prsnt any nw ons, nor do w mak substantial improvmnts ovr xisting ons. What w do provid, is th ability to prform th sam sort of optimisations prviously rsrvd for purly functional languags such as Haskll, but now in th prsnc of sid ffcts. Th grat nablrs ar th ltfloating transforms discussd in [PJPS96]. Ths allow bindings to b movd from thir dfinition sits to thir us sits. This in turn xposs opportunitis for othr simpl, corrctnss prsrving transforms, many of which ar dscribd in Santos s thsis [dms95]. W will discuss how our ffct and mutability information can b usd to prform ths transforms. Th radr is advisd to consult [PJPS96] or [dms95] for mattrs not rlating to ffcts. W distinguish four kinds of ltfloating transforms, and will considr ach in turn: Local transforms that ar part of th languag normalisation procss. Floating bindings to othr positions at th sam scop lvl. Floating into if/cas altrnativs. Floating outsid lambda abstractions. Although w prsnt our xampls in th cor languag discussd in 4.2, w lid typ annotations whn thy do not contribut to th discussion. W also mak us of standard faturs such as intgrs, cas xprssions and unboxd valus. As DDC is still a rsarch prototyp, w do not prsnt any concrt spdup figurs for ths optimisations. Such figurs would b skwd by th naiv implmntation of our runtim systm. S [dms95] for data rlating to a matur compilr. As th saying gos, what s amazing is not how wll th bar dancs what s amazing is that th bar dancs at all! Local transforms Hr is an xampl local transform, givn in [PJPS96]: (lt v = in b) a lt v = in b a Although this is a valid transform, its applicability in a concrt implmntation dpnds on whthr th cor program can vr contain a trm of th initial form. Thr is also th qustion of whthr a trm in th rsulting form can b dirctly translatd to th backnd intrmdiat languag (or machin cod). In DDC, w kp th cor program normalisd so that th first trm of an application is always a variabl. W do this bcaus w compil via C, and this procss dos not support mor gnral forms of application. In this sns, th abov transform is not an optimisation pr s, bcaus it is part of th normalisation procss, and must always b prformd.
224 224 CHAPTER 4. CORE LANGUAGE Floating at th sam lvl Floating bindings at th sam scop lvl srvs to xpos opportunitis for othr transforms. Local unboxing is on such transform, and is a simpl, wll known tchniqu for liminating th majority of boxing and unboxing oprations in numric cod. W discuss how to prform it in th prsnc of sid ffcts by using th typ information prsnt in th cor languag. Local unboxing can also b xprssd as a backwards dataflow analysis, but w us (forwards) ltfloating as th prsntation is simplr. Hr is a simpl program which taks th succssor of an intgr, as wll as updating it: 2 succupdat x = do y = succ x x := 5 succ y Convrting this program to th cor languag yilds th following: succupdat = Λ r 1 r 2 (w 1 : Mutabl r 1 ). λ x : Int r 1. ltrgion r 3 with {w 3 = MkConst r 3 } in ltrgion r 4 with {w 4 = MkConst r 4 } in do y = box r 3 (succ # (unbox r 1 (forc x))) updatint # r 1 w 1 (forc x) (unbox r 4 (box r 4 5 # )) box r 1 (succ # (unbox r 3 (forc y))) In this translation w hav xpandd th boxd numric functions succ and updatint into a combination of boxing, unboxing, and thunk forcing oprators. Hr ar th typs of ths nw oprators: Rad r unbox :: r 1. Int r 1 1 box :: r 1. Int # Int r 1 succ # :: Int # Int # Int# Writ r updatint # :: r 1.Mutabl r 1 Int r 1 1 Int# () W us Int # as th unboxd vrsion of Int, and writ unboxd litrals as 5 #. A valu of typ Int # can b hld in a machin rgistr. For th rasons discussd in 2.1, plain unboxd intgrs ar nonupdatabl and thus do not nd a rgion variabl. As an asid, whn w wish to stor updatabl arrays of unboxd intgrs in th hap, w giv th array th typ Ptr # r 1 Int #, and attach th mutability constraint to th pointr typ instad. Not that updatint # uss th valu of an unboxd intgr to updat a boxd on. Th boxd intgr rsids in th hap, not in a rgistr. In this thsis w trat forc as a primitiv of th cor languag. forc tsts its argumnt to s if it is rprsntd by an objct with an outrmost thunk, and forcs that thunk if nd b. W trat it as a primitiv oprator bcaus our 2 This xampl has bn kpt simpl to so that th typst intrmdiat cod is a managabl siz. Hopfully th radr can apprciat that th tchniqus also scal to mor intrsting programs.
225 4.4. OPTIMISATIONS 225 typ systm is not xprssiv nough to writ a snsibl typ of forc othr than a. a a. W could us this typ, but doing so would introduc a larg numbr of suprfluous typ applications in our xampl. S for a discussion of how w might giv a bttr typ to forc. From th abov cod, w can alrady s an obvious optimisation. In th scond argumnt of updatint # w can collaps th trm (unbox r 4 (box r 4 5 # )) into just 5 #. Aftr w hav xposd th primitiv boxing, unboxing and forcing oprators, th nxt stp is to flattn th program so that ach binding consists of a singl application. This incrass th mobility of ach binding, that is, th probability that it will b saf to mov it. Not that ordr of valuation in th program runs lftto right, dpth first, so th bindings com out in th following ordr: succupdat x = Λ r 1 r 2 (w 1 : Mutabl r 1 ). λ x : Int r 1. ltrgion r 3 with {w 3 = MkConst r 3 } in ltrgion r 4 with {w 4 = MkConst r 4 } in do x 1 = forc x x 2 = unbox r 1 x 1 Rad r 1 y 1 = succ # x 2 y = box r 3 y 1 u 1 = 5 # u 2 = forc x updatint # r 1 w 1 u 2 u 1 Writ r 1 z 1 = forc y z 2 = unbox r 3 z 1 Rad r 3 z 3 = succ # z 2 box r 2 z 3 W hav rcordd th ffct of ach binding on th right. Th majority of ths bindings ar pur, so thir position is constraind only by th data dpndncis in th program. A spcial cas is th binding for x 2. From its ffct w s that it rads th x valu from th rgion namd r 1. This intrfrs with th updat opration, which writs to r 1. Not that th binding for x 1 is a duplicat of u 2, so w can rmov th scond and substitut u 2 = x 1 into succssiv bindings. W can thn float all bindings xcpt x 1 and x 2 into thir us sits. W do not float x 1 as it now has two bound occurrncs, and w do not float x 2 as this would rquir moving it across th intrfring updat xprssion: succupdat x = Λ r 1 r 2 (w 1 : Mutabl r 1 ). λ x : Int r 1. ltrgion r 3 with {w 3 = MkConst r 3 } in ltrgion r 4 with {w 4 = MkConst r 4 } in do x 1 = forc x x 2 = unbox r 1 x 1 updatint # r 1 w 1 x 1 5 # box r 2 (succ # (unbox r 3 (forc (box r 3 (succ # x 2 )))))
226 226 CHAPTER 4. CORE LANGUAGE Now, in th last statmnt w can liminat th us of forc, bcaus a frshly boxd intgr is guarantd not to b a thunk. W can thn liminat th unbox box pair as wll. This givs: succupdat x = Λ r 1 r 2 (w 1 : Mutabl r 1 ). λ x : Int r 1. ltrgion r 3 with {w 3 = MkConst r 3 } in ltrgion r 4 with {w 4 = MkConst r 4 } in do x 1 = forc x x 2 = unbox r 1 x 1 Rad r 1 updatint # r 1 w 1 x 1 5 # Writ r 1 box r 2 (succ # (succ # x 2 )) Compard to th original vrsion, w hav liminatd two uss ach of box, unbox and forc. If w wr to constrain th original typ of succupdat so that its paramtr was Dirct, thn w could liminat th rmaining us of forc as wll. Not that although th position of th x 2 binding is not constraind by data dpndncis, it is constraind by th intrfring ffct of th updat statmnt Effcts and rgion aliasing In th succupdat xampl of th prvious sction, w could tll that th unboxing and updat oprations intrfrd bcaus thir ffcts mntiond th sam rgion variabl. If two atomic ffcts mntion diffrnt rgion variabls, thn w must considr whthr th corrsponding objcts may alias whn dciding whthr th ffcts intrfr. For xampl, say w had a function of th following typ: fun :: r 1 r 2. Int r 1 Int r =..., Mutabl r 1 Th first part of its dfinition in th cor languag could wll b: fun = Λ r 1 r 2 (w 1 : Mutabl r 1 ). λ x : Int r 1. λ y : Int r 2. ltrgion r 3 with... in. ltrgion r 4 with... in. xp Assum that xp is som intrsting xprssion that rads th valus of x and y, and updats x in th procss. Now, thr is nothing prvnting th programmr from calling fun with th sam objct for both argumnts: lt x = 5 in fun x x Bcaus of this, whn transforming xp, w cannot assum that two ffcts Rad r 2 and Writ r 1 do not intrfr. On th othr hand, ffcts on r 3 and r 4 cannot intrfr bcaus thy hav bn introducd by th function itslf, and
227 4.4. OPTIMISATIONS 227 ar known to b distinct. Th typ systm nsurs that objcts in th rgion namd r 3 ar distinct from thos that ar in th rgion namd r 4. Likwis, ffcts on r 1 and r 3, or r 1 and r 4 cannot intrfr bcaus an objct with typ Int r 1 must hav bn allocatd by th callr, and thus cannot alias with locally allocatd objcts. Howvr, suppos r 1 and r 2 wr constraind to hav diffring mutabilitis: fun :: r 1 r 2. Int r 1 Int r =..., Mutabl r 1, Const r 2 In this cas th first part of th function dfinition could b: fun = Λ r 1 r 2 (w 1 : Mutabl r 1 ) (w 2 : Const r 2 ). λ x : Int r 1. λ y : Int r 2. ltrgion r 3 with... in. ltrgion r 4 with... in. xp With this nw dfinition th two ffcts Rad r 2 and Writ r 1 ar guarantd not to intrfr. Th callr cannot pass th sam objct for both paramtrs bcaus it cannot produc witnsss of mutability and constancy for th sam rgion variabl. In futur work w intnd to us this lin of rasoning to xtnd th languag with NoAlias witnsss. This is discussd in Floating into altrnativs Considr th following program: do y = f x if xp thn y ls... As Discipl uss callbyvalu valuation by dfault, th application f x will always b valuatd. Not that in DDC, bfor w try to float bindings into altrnativs w transform th program to administrativ normal form. In this form th trms involvd in an application ar ithr variabls or constants. In th abov xampl, if f x and xp ar pur, or thy only rad mutabl data, thn it is saf to mov th y binding into th altrnativ to giv: if xp thn f x ls... This liminats th nd to valuat f x in th vnt th scond branch of th ifxprssion is takn. Not that if th first altrnativ contains othr function applications, thn w nd to considr whthr f x can intrfr with thm.
228 228 CHAPTER 4. CORE LANGUAGE For xampl: do (x 1 : Int r 1 ) = 5 r 1 (x 2 : Int r 2 ) = succ x 1 Rad r 1 if... thn do x 1 := 23 r 3 Writ r 1 Rad r 3 succ x 2 Rad r 2 ls 42 r 2 Rcall that in th cor languag w us litral intgrs such as 5 as constructors, so (5 r 1 ) is quivalnt to box r 1 5 #. W hav also addd typ annotations to th binding occurrncs of variabls to mak th xampl clarr. Not that w cannot mov th x 2 binding into its us sit bcaus it intrfrs with th xprssion x 1 := 23 r 1. Howvr, w can mov th x 2 binding into th first altrnativ of th ifxprssion, so long as w plac it bfor th updat: do (x 1 : Int r 1 ) = 5 r 1 if... thn do (x 2 : Int r 2 ) = succ x 1 Rad r 1 x 1 := 23 r 3 Writ r 1 Rad r 3 succ x 2 Rad r 2 ls 42 r 2 If a binding causs a top lvl ffct thn w cannot mov it across anothr. Likwis, w cannot mov such a binding inwards, as that would tnd to rduc th numbr of tims it was valuatd. For xampl: do x 1 = do { putstr hllo ; 5 r 1 } Consol if... thn succ x 1 Rad r 1 ls 42 r Floating outsid lambda abstractions Floating bindings outsid of lambda abstractions, also known as th full lazinss transform, allows us to shar th rsult of a computation btwn calls to a function. This is similar to th lifting xprssions out of loops optimisation don in compilrs for imprativ languags. For xampl, considr th following program: Λ r 2 r 3. ltrgion r 1 with {w = Const r 1 } in do (xs : List r 1 (Int r 3 )) =... f = λ(y : Int r 2 ). do (n : Int r 3 ) = lngth xs n + y Rad r 2 Rad r 3 z 1 = f (5 r 2 ) Rad r 2 Rad r 3... z 2 = f (23 r 2 ) Rad r 2 Rad r 3
229 4.4. OPTIMISATIONS 229 As th valu of n dos not dpnd on th bound variabl y, w can lift it out of th nclosing λabstraction. This liminats th nd to rcomput it for ach application of f: Λ r 2 r 3. ltrgion r 1 with {w = Const r 1 } in do (xs : List r 1 (Int r 3 )) =... (n : Int r 3 ) = lngth xs f = λ(y : Int r 2 ). n + y Rad r 2 Rad r 3 z 1 = f (5 r 2 ) Rad r 2 Rad r 3... z 2 = f (23 r 2 ) Rad r 2 Rad r 3 Of cours, in gnral this is only valid if th liftd xprssion is pur. Hr, w must guarant that th lngth of th list is not dstructivly changd btwn ach application of f. For this xampl, th purity of th n binding is guarantd by th constancy of r 1, which is witnssd by w. Only lift bindings that produc constant rsults As it is only saf to incras th sharing of constant data, w must insur that th rsults of liftd bindings ar constant. Hr is an xampl whr a binding is pur, and indpndnt of th λbound variabl, but it is not saf to float it outwards: Λ r 4 r 6. ltrgion r 5 with {w = Mutabl r 5 } in do (xs : List...) =... (ys : List r 4 (Int r 5 )) = map (λ. do { (m : Int r 5 ) = succ 0; m }) xs updatint r 5 r 6 w (ys!! 2) (5 r 6 ) (ys!! 3) Whr updatint has typ: Rad r updatint :: r 1 r 2. Mutabl r 1 Int r 1 Int r 2 Writ r 1 2 () Th oprator!! is usd to rtriv a numbrd lmnt of th list. This xampl crats a nw list of intgrs, ys, which is th sam lngth as th original list xs. It thn updats th scond lmnt of ys, and rturns th third. Not that th m binding is pur, but as succ allocats its rsult, ach lmnt of th list ys will b rprsntd by a diffrnt runtim objct. Evn though w updat th scond lmnt, th third lmnt will still hav th valu succ 0 = 1. If w wr to rronously lift th m binding out of th lambda abstraction, this would caus th sam objct to b usd for vry lmnt of th list:
230 230 CHAPTER 4. CORE LANGUAGE Λ r 4 r 6. ltrgion r 5 with { w = Mutabl r 5 } in do (xs : List...) =... (m : Int r 5 ) = succ 0 (ys : List r 4 (Int r 5 )) = map (λ. m) xs updatint r 5 r 6 w (ys!! 2) (5 r 6 ) (ys!! 3) In this cas, whn w updat th scond lmnt of th list, this is th sam as updating th third lmnt as wll, so w hav changd th maning of th program. Suspnd liftd bindings to rduc wastd computation If w cannot guarant that a particular λabstraction is applid at last onc, thn w should suspnd th valuation of any bindings that ar liftd from it. This guards against th cas whr th abstraction is nvr applid, or th valuation of th binding dos not trminat. For xampl: Λ r 3. ltrgion r 4 with { w = Const r 4 } in do (xs : List r 4 (Int r 3 )) =... f = λy. do { n = lngth xs; n + y } g =... if... thn f 5 + f 23 ls g 42 As lngth xs is pur, w can lift th n binding out of th abstraction. This will sav it bing rvaluatd for ach occurrnc of f. Howvr, if th ls branch of th ifxprssion is takn, thn th valu of n won t b ndd. Du to this w should suspnd th function application that producs it: Λ r 3. ltrgion r 4 with { w = Const r 4 } in do (xs : List r 4 (Int r 3 )) =... n = suspnd1 (MkPurify r 4 w) lngth xs f = λy. n + y g =... if... thn f 5 + f 23 ls g 42
231 4.5. COMPARISONS 231 In practic, w only want to introduc on thunk pr binding. If th right of th binding is somthing othr than a singl function application, thn w can wrap it in a dummy lambda abstraction and suspnd that instad. For xampl, if th right of th n binding was actually succ (lngth xs) thn w could translat our original xampl to: Λ r 3. ltrgion r 4 with { w = Const r 4 } in do (xs : List r 4 (Int r 3 )) =... n = suspnd1 (MkPurJoin (MkPurify r 4 w)...) (λ.succ (lngth xs)) () f = λy. n + y g =... if... thn f 5 + f 23 ls g 42 Not that as w only lift pur bindings, w should always b abl to crat witnsss of purity for thos bindings. This is an xampl of typ information srving as an intrnal sanity chck, rathr than bing usd to guid optimisations. If w cannot crat a witnss of purity for a liftd binding, thn thr is a bug in our compilr implmntation. 4.5 Comparisons Monadic intrmdiat languags Tolmach, Bnton, Knndy, Russll. On of th main inspirations for our work has bn to build on th monadic intrmdiat languags of [Tol98], [BK99] and [PJSLT98]. Th systm of [Tol98] uss a coars graind ffct analysis to guid th translation of th sourc program into a cor languag incorporating a hirarchy of monadic typs. Th monads ar ID, LIFT, EXN, and ST. Starting from th bottom of th hirarchy: ID dscribs pur, trminating computations; LIFT ncapsulats pur but potntially nontrminating computations; EXN ncapsulats potntially nontrminating computations that may rais uncaught xcptions, and ST ncapsulats computations that may do vrything including talk to th outsid world. Th optimisations in [Tol98] ar givn as transform ruls on monadic trms, and lss transforms apply to xprssions writtn with th mor ffctual monads. Limitations of this systm includ th fact that it lacks ffct polymorphism, and th coarsnss of th hirarchy. In th last part of [Tol98], Tolmach suggsts that it would b natural to xtnd his systm with HindlyMilnr styl polymorphism for both typs and monads in th TalpinJouvlot styl. H also suggsts that it would xtnd naturally to a collction of fingraind monads ncapsulating primitiv ffcts, but lamnts th lack of a gnric mchanism for combining such monads.
232 232 CHAPTER 4. CORE LANGUAGE Monads and ffcts xprss quivalnt information In [WT03], Wadlr and Thimann compar th ffct typing and monadic systms, and giv a translation from th first to th scond. For thir monadic systm, thy writ th typs of computations as T σ a, whr a is th typ of th rsulting valu and σ is a st of stor ffcts. Thy considr stor ffcts such as Rad r 1 and Writ r 2, us to collct atomic ffct trms, and includ typ schms that quantify ovr typ, rgion and ffct variabls. Clarly, thir monadic systm shars a lot of common ground with an ffct systm. Th main tchnical diffrnc btwn th two is that th monadic vrsion of th typing rul for applications is brokn into two parts: Whras in th ffct systm w hav: σ Γ t 1 :: τ 3 11 τ12 ; σ 1 Γ t 2 :: τ 11 ; σ 2 Γ t 1 t 2 :: τ 12 ; σ 1 σ 2 σ 3 (EffApp) In th monadic systm w hav: Γ t 1 :: τ 11 τ 12 Γ t 2 :: τ 11 Γ t 1 t 2 :: τ 12 (MonApp) Γ t 1 : T σ 1 τ 1 Γ, x : τ 1 t 2 : T σ 2 τ 2 Γ lt x t 1 in t 2 :: T σ 1 σ 2 τ 2 (MonBind) In th ffct typing systm, ffcts ar causd by th application of functions, as wll as by th valuation of primitiv oprators such as radrf and writrf. In th monadic systm, all ffcts ar invokd xplicitly with th lt x t 1 in t 2 form, which valuats th computation t 1, and thn substituts th rsulting valu into t 2. Function application of th form t 1 t 2 is always pur. Exprssing Tmonads in Discipl Not that T σ a styl computation typs ar straightforward to xprss in Discipl, bcaus w can dfin data typs that hav ffct paramtrs. For xampl, liding rgion and closur information w can writ: data T 1 a = MkT (() 1 a) Our T 1 a data typ simply ncapsulats a function that producs a valu of typ a whn applid to th unit valu (), whil having an ffct 1. Th monadic rturn and bind oprators ar dfind as follows: rturnt :: a. a T a rturnt x = MkT (λ(). x) bindt :: a b 1 2. T 1 a (a T 2 b) T 3 b 3 = 1 2 bindt (MkT f 1 ) mf 2 = MkT (λ(). cas mf 2 (f 1 ()) of MkT f 2 f 2 ())
233 4.5. COMPARISONS 233 Although w can dirctly xprss T monads in a languag with an ffct systm, th rvrs is not tru. A monadic systm rquirs all ffcts to b ncapsulatd within a computation typ such as T, and th function arrow,, must b pur. Howvr, an ffct systm allows arbitrary function applications to hav ffcts, σ and w can add ths ffcts as annotations to th arrows,. What s mor natural? In [BK99] Bnton and Knndy suggst that th monadic styl taks th distinction btwn computations and valus mor sriously, and that it has a mor wllbhavd quational thory. Howvr, thir work has diffrnt goals to ours. On on hand, [BK99] includs rigorous proofs that thir optimising transforms ar corrct. For this purpos, w can apprciat how rducing ffct invocation to a singl plac in th languag would mak it asir to rason about. Thir systm was implmntd in th MLj [BKR98] compilr, so it is dmonstrably practical. In [BKBH07] Bnton t al considr th smantics of a similar systm xtndd with rgion variabls and ffct masking, and in [BB07] Bnton and Buchlovsky prsnt th smantics of an ffct basd analysis for xcptions. On th othr hand, [BKR98] dos not includ ffct polymorphism, and th mor rcnt work of [BKBH07] and [BB07] dos not discuss typ infrnc and has not yt bn implmntd in a compilr. For our purposs, w find it mor natural to think of function application and primitiv oprators as causing ffcts, as this is closr to th oprational rality. Aftr spnding tim writing a compilr for a languag that includs lazinss, w don t fl too strongly about th distinction btwn computations and valus. Whn w slp w dram about thunks, and th fact that th inspction of a lazy valu of typ Int may divrg is prcisly bcaus that valu rprsnts a possibly suspndd computation. If w wr going to follow Bnton and Knndy s approach thn w would writ T LIFT Int for th lazy cas and Int for th dirct on. Using (MonBind) abov, this would hav th bnfit that th potntial nontrmination of lazy computations would b propagatd into th typs of trms that us thm. Howvr, for th rasons discussd in 1.4 w don t actually trat nontrmination as a computational ffct. W also rmain unconvincd of th utility of introducing a sparat monadic binding form into th cor languag, at last in th concrt implmntation. Horss for courss SystmFc Sulzmann, Chakravarty, Pyton Jons, Donnlly. Th cor languag of GHC is basd on SystmFc [SCPJD07], which uss typ quality witnsss to support gnralisd algbraic data typs (GADTs) [XCC03] and associatd typs [CKJM05]. Th kinds of such witnsss ar writtn a b, which xprss th fact that typ a can b takn as bing quivalnt to typ b. Th witnsss xprss nonsyntactic typ qualitis, which ar a major fatur of th work on GADTs and associatd typs. Th witnss passing mchanism in DDC was inspird by an arlir draft of [SCPJD07] that includd th dpndnt kind abstraction Πa : κ 1. κ 2. In this draft, abstraction was usd to writ th kinds of polymorphic witnss constructors such as:
234 234 CHAPTER 4. CORE LANGUAGE lmlist :: Πa :.Elm [a] a Hr, Elm is th constructor of an associatd typ. Th kind of lmlist says that lmnts of a list of typ a hav typ a. In th publishd vrsion of th papr, xtra typing ruls wr introducd to compos and dcompos typs that includ quality constraints, and ths nw ruls subsumd th nd for an xplicit dpndnt kind abstraction. In th publishd vrsion, th typ of lmlist is writtn: lmlist :: ( a :.Elm [a]) ( a :. a) Not that whn this typ is instantiatd, th typ argumnt is substitutd for both bound variabls. For xampl: lmlist Int :: Elm Int Int Th dpndnt kind abstraction is still thr in spirit, but th syntax has changd. SystmFc includs witnss constructors such as sym, trans, lft and right whos kinds xprss logical proprtis such as th symmtry and transitivity of th typ quality rlation, as wll as providing dcomposition ruls. Although [SCPJD07] givs typing ruls for ths constructors, if w wr prpard to limit thir applicability to first ordr kinds thn w could also xprss thm with th dpndnt kind abstraction. For xampl: would bcom: Γ ϕ : τ 1 τ 2 Γ sym ϕ : τ 2 τ 1 (Sym) sym :: Π(a : ). Π(b : ). a b b a Adding kind abstraction to th systm would allow us to rmov th rstriction to first ordr kinds, and rgain th full xprssivnss of th original ruls: sym :: λ(k : ). Π(a : k). Π(b : k). a b b a Hr, th suprkind rstricts k to b somthing lik or, and not anothr witnss kind. Not that th SystmFc witnss constructors such as sym, and th DDC witnss constructors such as MkPurJoin ar of th sam brd. Thy both xprss logical proprtis of th spcific systm, which ar sparat from th undrlying LF [AHM89] styl framwork. It would b intrsting to s how wll both systms could b xprssd in a mor gnral on, such as Ωmga [Sh05], which has xtnsibl kinds.
235 Chaptr 5 Conclusion Th work prsntd in this thsis is mbodid in th Disciplind Discipl Compilr (DDC) which can b obtaind from th haskll.org wbsit. W hav found it invaluabl to dvlop th compilr alongsid th sourc languag and typ systm. Having a ral compilr allows us to xprimnt with xampl programs that would b impractical to manipulat by hand, and w hav bn working on DDC sinc th vry start of this projct. DDC is not yt industrial strngth, but it dos hav nough functionality to compil nontrivial programs. Scrnshots from two of our tst programs ar blow. Th on on th lft is a raltim, 2dimnsional particl collision simulation that uss a quadtr to dtrmin whn two particls ar clos nough to possibly collid. Th scond is a simpl ray tracr which uss a vctor library basd on our projction systm. Dvloping ths programs has givn us insight into som of th strngths and waknsss of our currnt systm. In this chaptr w brifly discuss our backnd implmntation, idntify opportunitis for furthr work, summaris our contributions, and conclud. Gratuitous Scrnshots 235
Quantum Graphs I. Some Basic Structures
Quantum Graphs I. Som Basic Structurs Ptr Kuchmnt Dpartmnt of Mathmatics Txas A& M Univrsity Collg Station, TX, USA 1 Introduction W us th nam quantum graph for a graph considrd as a ondimnsional singular
More informationThe author(s) shown below used Federal funds provided by the U.S. Department of Justice and prepared the following final report:
Th author(s) shown blow usd Fdral funds providd by th U.S. Dpartmnt of Justic and prpard th following final rport: Documnt Titl: Author(s): Impact Munitions Data Bas of Us and Effcts Kn Hubbs ; David Klingr
More informationSuggestion of Promising Result Types for XML Keyword Search
Suggstion o Promising Rsult Typs or XML Kyword Sarch Jianxin Li, Chngi Liu and Rui Zhou Swinurn Univrsity o Tchnology Mlourn, Australia {jianxinli, cliu, rzhou}@swin.du.au Wi Wang Univrsity o Nw South
More informationPedro Linares, Francisco Javier Santos, Mariano Ventosa, Luis Lapiedra
Masuring th impact of th uropan carbon trading dirctiv and th prmit assignmnt mthods on th Spanish lctricity sctor Pdro Linars, Francisco Javir Santos, Mariano Vntosa, Luis Lapidra Instituto d Invstigación
More informationIMPROVE CUSTOMERS LOYALTY IN ONLINE GAMING: AN EMPIRICAL STUDY Fan Zhao
Fan Zhao ABSTRACT In th past dcad, onlin gams hav bcom an important lctronic commrc application A good undrstanding of customr onlin gam bhaviors is critical for both rsarchrs and practitionrs, such as
More informationBlock. It puts some writers down for DRAFT NO.4. Replacing the words in boxes. THE WNTING UFE
Block. It puts som writrs down for months. It puts som writrs down for lif. A not always brif or minor form of it muts all writrs from th outst of vry day. "Dar Jol..." This is just a random sampl from
More informationOptimization design of structures subjected to transient loads using first and second derivatives of dynamic displacement and stress
Shock and Vibration 9 (202) 445 46 445 DOI 0.3233/SAV2020685 IOS Prss Optimization dsign of structurs subjctd to transint loads using first and scond drivativs of dynamic displacmnt and strss Qimao Liu
More informationCategory 11: Use of Sold Products
11 Catgory 11: Us of Sold Products Catgory dscription T his catgory includs missions from th us of goods and srvics sold by th rporting company in th rporting yar. A rporting company s scop 3 missions
More informationQuadrature Signals: Complex, But Not Complicated
Quadraur Signals: Complx, Bu No Complicad by Richard Lyons Inroducion Quadraur signals ar basd on h noion of complx numbrs and prhaps no ohr opic causs mor harach for nwcomrs o DSP han hs numbrs and hir
More informationWhat are the most abundant proteins in a cell?
What ar th most abundant s in a cll? Evn aftr rading svral txtbooks on s, on may still b lft wondring which of ths critical molcular playrs in th lif of a cll ar th most quantitativly abundant. Though
More informationMonads for functional programming
Monads for functional programming Philip Wadler, University of Glasgow Department of Computing Science, University of Glasgow, G12 8QQ, Scotland (wadler@dcs.glasgow.ac.uk) Abstract. The use of monads to
More informationOut of the Tar Pit. February 6, 2006
Out of the Tar Pit Ben Moseley ben@moseley.name Peter Marks public@indigomail.net February 6, 2006 Abstract Complexity is the single major difficulty in the successful development of largescale software
More informationHow to Think Like a Computer Scientist
How to Think Like a Computer Scientist C Version Allen B. Downey CVersion by Thomas Scheffler Version 1.08 November 25th, 2012 2 Copyright (C) 1999 Allen B. Downey This book is an Open Source Textbook
More informationThe Conception, Evolution, and Application of Functional Programming Languages
The Conception, Evolution, and Application of Functional Programming Languages Paul Hudak Yale University Department of Computer Science March 1989 Final Draft Abstract The foundations of functional programming
More informationProgramming with Arrows
Programming with Arrows John Hughes Department of Computer Science and Engineering, Chalmers University of Technology, S41296 Sweden. 1 Introduction 1.1 Pointfree programming Consider this simple Haskell
More informationMaintain Your F5 Solution with Fast, Reliable Support
F5 SERVICES TECHNICAL SUPPORT SERVICES DATASHEET Maintain Your F5 Solution with Fast, Rliabl Support In a world whr chang is th only constant, you rly on your F5 tchnology to dlivr no mattr what turns
More informationPart 1: Jumping into C++... 2 Chapter 1: Introduction and Developer Environment Setup... 4
Part 1: Jumping into C++... 2 Chapter 1: Introduction and Developer Environment Setup... 4 Chapter 2: The Basics of C++... 35 Chapter 3: User Interaction and Saving Information with Variables... 43 Chapter
More informationThere is no Fork: an Abstraction for Efficient, Concurrent, and Concise Data Access
There is no Fork: an Abstraction for Efficient, Concurrent, and Concise Data Access Simon Marlow Facebook smarlow@fb.com Louis Brandy Facebook ldbrandy@fb.com Jonathan Coens Facebook jon.coens@fb.com Jon
More informationHow to think like a computer scientist. Allen B. Downey
How to think like a computer scientist Allen B. Downey November 2012 2 How to think like a computer scientist C++ Version Copyright (C) 2012 Allen B. Downey Permission is granted to copy, distribute, and/or
More informationObjectOriented Programming in Oberon2
Hanspeter Mössenböck ObjectOriented Programming in Oberon2 Second Edition Springer Verlag Berlin Heidelberg 1993, 1994 This book is out of print and is made available as PDF with the friendly permission
More informationProgramming in Standard ML
Programming in Standard ML (DRAFT: VERSION 1.2 OF 11.02.11.) Robert Harper Carnegie Mellon University Spring Semester, 2011 Copyright c 2011 by Robert Harper. All Rights Reserved. This work is licensed
More informationProgramming from the Ground Up
Programming from the Ground Up Jonathan Bartlett Edited by Dominick Bruno, Jr. Programming from the Ground Up by Jonathan Bartlett Edited by Dominick Bruno, Jr. Copyright 2003 by Jonathan Bartlett Permission
More informationBasics of Compiler Design
Basics of Compiler Design Anniversary edition Torben Ægidius Mogensen DEPARTMENT OF COMPUTER SCIENCE UNIVERSITY OF COPENHAGEN Published through lulu.com. c Torben Ægidius Mogensen 2000 2010 torbenm@diku.dk
More informationDependent Types at Work
Dependent Types at Work Ana Bove and Peter Dybjer Chalmers University of Technology, Göteborg, Sweden {bove,peterd}@chalmers.se Abstract. In these lecture notes we give an introduction to functional programming
More informationAbstract. 1. Introduction. Butler W. Lampson Xerox Palo Alto Research Center David D. Redell Xerox Business Systems
Experience with Processes and Monitors in Mesa 1 Abstract Butler W. Lampson Xerox Palo Alto Research Center David D. Redell Xerox Business Systems The use of monitors for describing concurrency has been
More informationShould I Stay or Should I Go? Migration under Uncertainty: A New Approach
Should Stay o Should Go? Migation und Unctainty: A Nw Appoach by Yasmn Khwaja * ctob 000 * patmnt of Economics, School of intal and Afican Studis, Unisity of ondon, Thonhaugh Stt, Russll Squa, ondon WC
More informationIntellectual Need and ProblemFree Activity in the Mathematics Classroom
Intellectual Need 1 Intellectual Need and ProblemFree Activity in the Mathematics Classroom Evan Fuller, Jeffrey M. Rabin, Guershon Harel University of California, San Diego Correspondence concerning
More informationProgramming and Reasoning with Algebraic Effects and Dependent Types
Programming and Reasoning with Algebraic Effects and Dependent Types Edwin C. Brady School of Computer Science, University of St Andrews, St Andrews, Scotland. Email: ecb10@standrews.ac.uk Abstract One
More informationHandlers in Action. Ohad Kammar. Sam Lindley. Nicolas Oury. Abstract. 1. Introduction. University of Cambridge ohad.kammar@cl.cam.ac.
Handlers in Action Ohad Kammar University of Cambridge ohad.kammar@cl.cam.ac.uk Sam Lindley University of Strathclyde Sam.Lindley@ed.ac.uk Nicolas Oury nicolas.oury@gmail.com Abstract Plotkin and Pretnar
More informationHypercomputation: computing more than the Turing machine
Hypercomputation: computing more than the Turing machine Abstract: Toby Ord Department of Philosophy * The University of Melbourne t.ord@pgrad.unimelb.edu.au In this report I provide an introduction to
More information