Sheng Liang Paul Hudak Mark Jonest Yale University Department Of
Total Page:16
File Type:pdf, Size:1020Kb
Monad Transformers and Modular Interpreters* Sheng Liang Paul Hudak Mark Jonest Yale University Department of Computer Science New Haven, CT 06520-8285 {li-ang, hudak, j ones -mark}@cs. yale. edu Abstract a specific feature. The interpreter writer is able to specify the set of incorporated features at a very high level. We show howa set of building blocks can be used to construct The motivation for building modular interpreters is to programming language interpreters, and present implemen- isolate the semantics of individual programming language tations of such building blocks capable of supporting many features for the purpose of better understanding, simplifying, commonly known features, including simple expressions, and implementing the features and their interactions. The three different function call mechanisms (call-by-name, call- lack of separability of traditional denotational semantics [19] by-value and lazy evaluation), references and assignment, has long been recognized. Algebraic approaches such as nondeterminism, first-class continuations, and program trac- Mosses’ action semantics [16], and related efforts by Lee ing. [131, Wand [231, Appel & Jim [11, Kelsey & Hudak [111, and The underlying mechanism of our system is monad frans- others, attempt to solve parts of this problem, but fall short fonners, a simple form of abstraction for introducing a wide in several crucial ways} range of computational behaviors, such as state, 1/0, con- A ground-b~aking attempt to better solve the overall tinuations, and exceptions. problem began with Moggi’s [151 proposal to use monads to Our work is significant in the following respects. First, structtue denotational semantics. Wadler [211 popularized we have succeeded in designing a fully modular interpreter Moggi’s ideas in the functional programming community based on monad transformers that includes features miss- by showing that many type constructors (such as List) were ing from Steele’s, Espinosa’s, and Wadler’s earlier efforts. monads and how monads could be used in a variety of Second, we have found new ways to lift monad operations settings, many with an “imperative” feel (such as in Peyton through monad transformers, in particular difficult cases not Jones & Wadler [17]). Wadler’s interpreter design, however, achieved in Moggi’s original work. Third, we have demon- treats the interpreter monad as a monolithic structure which strated that interactions between features are reflected in has to be reconstructed every time a new feature is added. liftings and that semantics can be changed by reordering More recently Steele [181 proposed pseudomonadesas a way monad transformers. Finally, we have implemented our to compose monads and thus build up an interpreter from interpreter in Gofer, whose constructor classes provide just smaller parts, but he failed to properly incorporate important the added power over Haskell’s type classes to allow precise features such as an environment and store, and struggled and convenient expression of our ideas. This implementa- with restrictions in the Haskell [71 type system when trying tion includes a method for constructing extensible unions to implement his ideas. In fact, pseudomonades are really and a form of subtyping that is interesting in its own right. just a special kind of monad transformer, first suggested by Moggi [15] as a potential way to leave a “hole” in a monad 1 Introduction and Related Work for further extension. Returning to Moggi’s original ideas, Espinosa [4] nicely This paper discusses how to construct programming lan- formulated in Scheme a system called Semantic Lego — the guage interpreters out of modular components. We will first modular interpreter based on monad transformers — show how an interpreter for a language with many features and laid out the issues in lifting. Espinosa’s work reminded can be composed from building blocks, each implementing the programming language community (including us) — who had become distracted by the use of monads — that ●This work was supported by the Advanced ResearchProject Agency Moggi himself, responsible in many ways for the interest in and the Oi%ce of Naval Research under Arpa Order 8888, Contract monadic programming, had actually focussed more on the NOO014-92-C-0153. TCurrent addresa: Department of Computer science, uIIiVWSity Of importance of monad transformers. Nottingham, University Park, Nottingham NG7 2RD, England. Email: We begin by realizing the limitations of Moggi’s frame- mpj@cs. nott .ac. uk. work and Espinosa’s implementation, in particular the diffi- culty in dealing with complicated operations such as callcc, Permission to copy without fee all or part of this materfal is and investigate how common programming language fea- granted provided that the copies are not made or distributed for direct commercial advantage, the ACM copyrigM notice and the lVery recently, CartWright and Felleisen [31have independently proposed title of the publication and its date appear, and notice is given a modular semantics emphasizing a di?ectsemantics approach, which seems that oopying is by permission of the Association of CompW”ng somewhat more complex than ours; the pxecise dationship between the Machinery. To copy otherwise, or to republish, requires a fee appm=hes is, however, not yet clear. and/or specific permission. POPL ’951/95 San Francisco CA USA 0 1995 ACM 0-89791 -692-1/95/0001 ....$3.50 333 type Term = OR TermA -- arithmetic type lnterpM = StateT Store - - memory cells ( OR TermF -- functions ( EnvT Env - - environment ( OR TwmR -- assignment ( ConfT Answer -- continuations ( OR TermL -- lazy evaluation ( StateT String J - trace output ( OR TermT -- tracing ( ErrorT ( OR TermC -- callcc List ll~~i~~~~& TermN -- nondeterminism )))) ))))) type Value = OR Int (OR Fun ()) I Figure 1: A modular interpreter tures interact with each other. In so doing we are able to expressions, etc. T~e constructors such as SfateT and ConfT express more modularity and more language features than in are monad fransfor m$rs; they add features, and are used to previous work, solving several open problems that arose not transform the mona Listinto the monad InterpM used by only in Moggi’s work, but in Steele’s and Espinosa’s as well. the interpreter, 1 Our work also shares results with Jones and Duponcheel’s To see how Term, alue, and InterpM constitute to modular [101 work on composing monads. interpreters, in the rext section we will walk through some Independently Espinosa [51 has continued working on simple examples. monad transformers, and has also recognized the limitations of earlier approaches and proposed a solution quite different 2 An Example from ours. His new approach relies on a notion of “higher- order” monads (called situated monads) to relate different A conventional inte preter maps, say a term, environment, layers of monad transformers, and he has investigated the and store, to an ansI er. In contrast, a monadic interpreter semantic implications of the order of monad transformer such as ours maps t~rms to computations, where the details composition. It is not yet clear how his new approach relates of the environment, tore, etc. are “hidden”. Specifically: to ours. We use Gofer [81 syntax, which is very similar to Haskell’s, interp :; Term + nferpM Value throughout the paper. We choose Gofer over Haskellbecause where “hzterpM Vu /ue” is the interpreter monad of final of its extended type system, and we choose a functional answers. language over mathematical syntax for three reasons: (1) What makes ou interpreter modular is that all three it is just about as concise as mathematical syntax,2 (2) components above —1 the term type, the value type, and the it emphasizes the fact that our ideas are implementable monad — are config rable. To illustrate, if we initially wish (and thus have been debugged!), and (3) it shows how the to have an interpret r for a small arithmetic language, we I relatively new idea of constructor ckzsses [9] can be used can fill in the definitions as follows: to represent some rather complex typing relationships. Of /3RInt () course, monads can be expressed in a variety of other type Value = (higher-order) programming languages, in particular SML type T~m ermA rrorT Id [141, whose type system is equally capable of expressing type InterpM z some of our ideas. The system could also be expressed The first line declar i s the answer domain to be the union in Scheme, but of course we would then lose the benefits of integers and the ~nit type (used as the base type). The of strong static type-checking. Our Gofer source code is second line defines 4erms as TermA, the abstract syntax for available via anonymous ftp from nebuZa.cs.yaZe.eduin the arithmetic operation . The final line defines the interpreter directory pub/yak- fi/modular-inferpre fer. monad as a transfo ation of the identify monad Id. The To appreciate the extent of our results, Figure 1 gives the monad transformer ErrorT accounts for the possibility of high-level definition of an interpreter, which is constructed errors; in this case, a~ “thmetic exceptions. in a modular way, and supports arithmetic, three different At this point the interpreter behaves like a calculator: 3 kinds of functions (call-by-name, call-by-value, and lazy), references and assignment, nondeterminism, first-class con- > ((1+4)*8) tinuations, and tracing. The rest of the paper will provide 40 the details of how the type declarations expand into a full > (3/0) interpreter and how each component is built. For now just ERROR: divide by O note that OR is equivalent to the domain sum operator, and Now if we wish o add function calls, we can extend the Term, Value and InterpM denote the source-level terms, run- value domain with 1 nction types, add the abstract syntax time values, and supporting features (which can be regarded for function calls to the term type, and apply the monad as the run-time system), respectively.