Monadic State: Axiomatization and Type Safety
Total Page:16
File Type:pdf, Size:1020Kb
Monadic State Axiomatization and Typ e Safety John Launchbury Amr Sabry Oregon Graduate Institute Department of Computer Science PO Box University of Oregon Portland OR Eugene OR jlcseogiedu sabrycsuoregonedu Our formal investigation reveals two subtle p oints that Abstract the previous informal reasoning failed to uncover First Typ e safety of imp erative programs is an area fraught with arbitrary b etareduction is unsound in a compiler which diculty and requiring great care The SML solution to the enco des statetransformers as statepassing functionsany problem originall y involving imp erative typ e variables has compiler that implemented the denotational semantics di b een recently simplied to the syntacticvalue restriction In rectly would have to take great care never to duplicate the Haskell the problem is addressed in a rather dierent way state parameter Second the recursive state op erator fixST using explicit monadic state We present an op erational cannot b e interpreted navely in callbyname but really semantics for state in Haskell and the rst full pro of of typ e needs callbyneed to make sense safety We demonstrate that the semantic notion of value provided by the explicit monadic typ es is able to avoid any Imp erative Typ es problems with generalization We b egin by reviewing the issue of typ e safety The need Intro duction for a sp ecial care arises in SML b ecause of examples like the following When Launchbury and Peyton Jones intro duced encapsu lated monadic state it came equipp ed with a de let val r ref fn x x notational semantics and a mo deltheoretic pro of that dif in fn r r not ferent state threads did not interact with each other The end encapsulation op erator runST had a typ e which statically guaranteed freedom of interaction and the guarantee relied The variable r is given the typ e ref which sub on a parametricity pro of What the pap er failed to provide sequently unies with both the integer and the b o olean uses was any formal reasoning principle at the syntactic level or Intuitively the problem is that the let has generalized over any pro of of typ e safety This pap er makes up for those typ e variables that actually o ccur free in the state shortcomings In particular we The solution adopted for many years is to have a class of imp erative typ e variables and only to generalize axiomatize the monadicstate operations this allows us to view the monad of state transformers as an ab over these if the expression b eing b ound by let is syntac tically a value Due to Wrights observations this has stract typ e and understand formally how it should b e have Previously the choice was b etween an informal since b een simplied to treat all typ e variables as if they were imp erative typ e variables and so collapsing the understanding or a rather heavyweight denotational description two tier structure Why do these problems not o ccur in Haskell when using prove type safety if I have a variable that claims to monadic state The precise answer comes from the pro of contain a list of integers say will it truly do so or later in the pap er of course but we can provide intuition might the typ e system have b ecome confused By us here When working within the state monad or any other ing the axiomatization as a reduction relation we are explicit monad for that matter the facilities provided by able to use standard techniques to show typ e safety of let are given by the use of monadic extension a bind op this system erator in Wadlers terminology thenST in the State in Haskell pap ers or in Haskell notation This prove syntactic noninterference our pro of shows that takes a computationa term of typ e M A where M is the if ever a stateread or write is ab out to b e attempted monadic typ e constructortogether with a function of typ e then the typ e system guarantees that the reference is A MB Intuitively the rst term is executed delivering lo cal a value of typ e A which is then passed as an argument to the function whose subsequent computation is also executed The value is passed according to regular function applica To app ear in ACM SIGPLAN International Confer tion so the typ e A in A M B is a regular typ e not a ence on Functional Programming typ e scheme The intermediate values within a computation are lambdabound therefore rather than b eing letb ound Thats the intuition The fact that it works relies on where we have used the Haskell notation for lamb da expres the correct interplay of a numb er of dierent asp ects of the sions xe instead of the mathematical notation xe system in what comes later for example if the typing judg could b e rewritten as follows ment for runST were relaxed then typ e safety would b e lost let omega omega One way of viewing all this is that the Haskell typ e system in runST do p newVar makes a distinction b etween computations with no eects v readVar p which we call semantic values and computations that may v readVar p have eects which we simply refer to as computations Se writeVar omega mantic values are b ound with the let construct and their returnST vv typ es can b e generalized results of computations are b ound with the construct and their typ es cannot b e general To get an informal feeling for the typ es and semantics of ized Hence like SML Haskells let only p erforms gener the expressions we intuitively explain the evaluation of the alization over values not over the results of computations ab ove fragment First we bind omega to some semantic However unlike SML the Haskell notion of value is seman value and then create a new state thread In this thread we tic and hence richer For example in Haskell the expression allo cate a reference cell p and initializ e it to The cell xx y y is classied as a semantic value whose typ e is then dereferenced twice and the results are added Once can b e generalized but not in SML the values of v and v are determined no more state op erations are p erformed as the nal result is now dened In other words we have a lazy store semantics in which state State in Haskell threads are executed on demand and values may b e re turned b efore the computation has b een completed Hence Our source language is an extension of the callbyname the assignment to the uncalculabl e lo cation omega do es not calculus with several constants and two language constructs aect the nal result which is let and runST later we will add a third Why b other with lazy stores The answer is that lazy stores have a clean interaction with the lazy semantics of the Denition Syntax of Terms Let x range over a set underlying language and provide elegant ways to express Vars of variables fx x x yzg The set of terms 1 2 imp erative functional programs as the following example is inductively dened as fol lows illustrates The example is drawn from streambased simulation in Simple Constants k j j j j j particular simulating a lo cal data cache within a micro pro cessor for our purp oses here we will assume no cache Primitive Store Operations misses The contents of the stream represent the values of 0 s newVar e j readVar e j writeVar e e the input and output wires over time The input streams to the cache will contain addresses data and a b o olean Syntactic Values readwrite ag The output stream will contain the mem 0 v k j xe j e e j returnST e j s ory contents for a read and if a write was p erformed As the cache will contain thousands of randomly acces Terms 0 0 sible lo cations a destructive array is the obvious choice for e x j v j e e j runST e j let fx e g in e i i i mo deling the contents We therefore use the store prim itives readArr and writeArr which are the the obvious We let k range over an unsp ecied set of simple constants generalization s to arrays of the op erations on single lo ca like numb ers and addition The constants newVar readVar tions Heres the co de in Haskell where the rst parameter and writeVar express the usual op erations on reference cells to cache is the size the second parameter contains the three The constants returnST and are the unit and bind op er input streams and the result is the output stream ations of the state monad resp ectively Expressions built up from these statetransformer op erations are treated as syn cache Int IntIntBool Int tactic values These syntactic values will b e used to sp ecify cache size ins the op erational semantics of the language but not to guide runST do arr newArray size generalization of typ e variables The expression runST e loop arr is an eliminator for statetransformer expressions e The op erational intuition b ehind runST is that it executes e in loop arr aasddsTruebs a newly created state thread returning the nal value pro do x readArr arr a duced by e while discarding the nal state The state in xs loop arr asdsbs the thread is neither accessible nor visible from outside the return xxs runST e expression In the examples we sometimes use the Haskell do loop arr aasddsFalsebs notation This construct acts like a nonrecursive let do x writeArr arr a d over computations and is denable in terms of For xs loop arr asdsbs example the following co de return xs let omega omega As the state is lazy the result of each op eration b ecomes in runST newVar p available immediately after it is p erformedthere is no need readVar p v to wait until al l the state op erations are p erformed In readVar p v deed if as we exp ect the list were innite there would b e writeVar omega no end to the state op erations Conceptually as the in returnST