Mo dula - cs. · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga...

8

Click here to load reader

Transcript of Mo dula - cs. · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga...

Page 1: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

A Modular Interpreter In Scheme With Objects

Steven E. Ganz�

Indiana University

Daniel P. Friedmany

Indiana University

Abstract

The problem of writing modular interpreters forfunctional languages has largely been studied fromthe perspective of statically typed languages. Thispaper explores the use of an object-oriented exten-sion of Scheme for this purpose, and �nds it to belargely successful. Use of a dynamically typed lan-guage has the advantages of greater uniformity and exibility.

1 The Problem of Extensibility, the TestCase of Modular Interpreters and theSearch for a Solution in Object-OrientedProgramming

Extensibility is the ability of a program to beadapted to new tasks without accessing its sourcecode [7]. Interpreters make an interesting exten-sibility problem, because in the terminology ofDuponcheel [4], there are both syntactic and se-mantic aspects. By syntax, here, he means abstractsyntax, i.e., the logical structure of expressions. Bysemantics, he means the computations and valuesengendered by those expressions. This extensibilityproblem should be contrasted with another that hasalso been studied extensively, that of adding oper-ations to an object-oriented system [3, 5].

On the syntactic side of our problem, both inthe cases of program and of data, the extensionmust be made retroactively to recursions within theoriginal version. Extending a language with a newform does not merely add expressions of that typeto the language. It also adds expressions of all pre-existing types, with the new form substituted as asubexpression [12]. Similarly, when a new clauseis added to an interpreter to handle the new form,this updated interpreter must be used in recursivecalls in originally existing clauses.

On the semantic side, computations can be use-fully represented using a monad as the result type

�This work was supported in part by the National Sci-ence Foundation under grant CDA-9312614. Author's ad-dress: Department of Computer Science, Indiana Univer-sity, Bloomington, Indiana 47405. [email protected].

yThis work was supported in part by the National Sci-ence Foundation under grant CCR-9633109. Author's ad-dress: Department of Computer Science, Indiana Univer-sity, Bloomington, Indiana 47405. [email protected].

of the interpeter. When a monadic interpreteris extended, not only interpreter procedures butmonadic operators as well must be replaced in orig-inal interpreter clauses. Each new layer providesnew de�nitions of return and extend in terms ofthe old monad, and lifted versions of the other op-erators. Another semantic issue is the value type.The value type indicated in any module is not in-tended to fully de�ne the type, only to providea lower bound. The actual value type may beany supertype of that speci�ed. Finally, the ac-tual computation type may not be the one spec-i�ed in a module, but one generated from thatusing a monad transformer. These semantic is-sues have been described in detail by Liang, Hu-dak and Jones [9]. Duponcheel emphasizes thesyntactic issues. His Gofer implementation exclu-sively used constrained parametric polymorphismthrough type classes, and a higher-order versionthrough constructor classes [6]. The approachamounts to always extending non-recursive ver-sions, and then applying a recursion operator tothe result of the extension. These issues had ear-lier been studied by Cartwright and Felleissen [2],who provided a module-based solution, comment-ing that it is also possible to "use an object-orientedprogramming language in the spirit of CLOS".More will be said of their approach later.

Why go beyond the success of static type-basedsolutions to try a dynamic object-based solution?There are several reasons. First, the emphasis ona uniform hierarchical structure in object-orientedprograms makes them easier to understand. Thesolution based on constructor classes uses inheri-tance directly in the de�nition of the computationalmetalanguage, but not in the de�nition of expres-sions. The de�nition of basic expression types usedatatype variants; these are combined into a largerlanguage using a Sum datatype. The de�nition ofvalues are even more obscure, using a subtype type-class in place of the type-class mechanism itself.

More fundamentally, Lang and Pearlmutter, inpresenting their object system, Oaklisp, discuss thelanguage virtue of "uniformity of temporal seman-tics" [8]. By this, they mean that anything thatcan be done at compile-time ought to be doable atrun-time as well. A uniform temporal semanticsleads to a simpler language design, since dependen-

Page 2: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

cies of compile-time constructs on run-time dataneed not be speci�cally prohibited. For the samereason, it leads to a more exible and powerful pro-gramming environment. One might wish to give upthe assumption that the syntax and semantics of alanguage are known �a priori and consider situa-tions where elements are provided at run-time bythe user. When type information is statically avail-able, it can still be taken advantage of by a goodcompiler.

Section 2 presents the interface to the objectsystem. Section 3 demonstrates the use of the ob-ject system in writing modular interpreters. Sec-tion 4 concludes.

2 The Object System Interface

The object system we use is similar to Oaklisp [8],which prided itself on providing the full functional-ity of an object-oriented language while remainingtrue to Scheme's philosophy. We go even furtherin both areas. Oaklisp provided multiple inheri-tance, �rst-class types and single-dispatch genericfunctions, along with a metaclass facility. We alsoprovide multiple inheritance and �rst-class types,along with multiple-dispatch generic functions, dis-cussed in their future work section. We also allowfor the functional extension of generic functions,rather than the standard imperative extension.

Another di�erence is that our system is im-plemented directly on top of Scheme, rather thanthrough a compiler. Although we do provide meta-classes, we cut back somewhat in not providingMOP support. This can and probably will beadded.

The object system was designed with the em-phasis on functionality and not eÆciency. Multi-ple inheritance is implemented with explicit, sharedsubobjects, rather than the more standard implicitsubobjects [11, 10]. Slot access is dynamic. Thus,the time for slot access is proportional to the heightof the slot de�nition in the class hierarchy of the ac-tual class of the object.

We now present the object system interface.1

Like in Oaklisp, there are two fundamental pre-de�ned classes: we call them Object and Class.2

Classes and instances are both just clajects. Forconvenience, there are three forms for creating cla-jects, corresponding to their use as a class, both aclass and an instance, or just an instance.

hClaject Constructioni�; for classes of class Class(new-class %class-id (%super-exp ...)

([%slot-id %slot-class-exp%slot-deflt-exp ...]

; zero or one default exp...)(%initializer-exp ...))

; for classes of other classes(new-claject %class-id %class-exp

1The implementation is available on the internetat http://www.cs.indiana.edu/hyplan/sganz/publications/sfp00/code.tar.gz .

2Identi�ers referring to classes will be captialized.

(%super-exp ...)([%slot-id %slot-class-exp

%slot-deflt-exp ...] ...)(%initializer-exp ...)%rand ...)

; for instances which are not classes(new-inst %class-exp %rand ...)

Classes require an identi�er (used for casting)super-classes, slot declarations and instance initial-izers. Instances require a class and operands fortheir initialization. Slot declarations consist of anidenti�er, a class (used for run-time type-checks)and a default value. Both the class and defaultvalue expressions may refer to the fully allocatedactual claject as this. They may also access slotswhich are declared earlier in the list.

Primitive classes include Boolean, Integer,Procedure, Pair, List and EmptyList.

hClaject Relationshipsi�(eq? %class1 %class2)(class-of %inst)(subtype-of? %subtype %super-type)(isa? %inst %class)(cast %inst-exp %class-id)

The test for class identity is eq?. The cast oper-ator accesses the subobjects of an object. Castingis permanent, in the sense that the new object hasno recollection of its former class. Temporary castscan be de�ned as a form of method call.

hSlot Accessi�(meta-slot-ref %inst-exp %var %level)(meta-slot-set! %inst-exp %var %val %level)(slot-ref %inst-exp %var)(slot-set! %inst-exp %var %val)

The %level indicates one less than the number ofis-a? links up to where the slot is declared. Forslot-ref and slot-set!, it defaults to zero.

hGeneric Functionsi�(generic %multimethod ...)(memo-generic %multimethod ...)(extend-generic %generic %multimethod ...)(extend-generic! %generic %multimethod ...)

generic is the standard form for function cre-ation. memo-generic is a memo-ized version. Itensures that for each set of inputs, only one out-put is generated. It is required because eq?is the test of class equality, and we wish tohave equivalent applications return equal classes.extend-generic is a functional function extensionmechanism. extend-generic! is the standard im-perative add-multimethod operation. Function callis simply application.

hMultimethods and Initializersi�(multimethod ([%var %type] ...)%body0 %body1 ...)

(initializer ([%var %type] ...)%body0 %body1 ...)

; within initializers(initialize %inst %rand ...)

Page 3: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

Both multimethods and initializers are de�ned asa sequence of parameter declarations followed bya sequence of body expressions. The body of aninitializer may refer to the actual claject as this.

When an instance is created, its class issearched for the most appropriate initializer (forthe operands provided). Within an initializer,initialize may be called on the subobjects of anobject to initialize them. In either situation, if noinitializer is found a default initialization is per-formed. The default initializer will yield to custominitializers for subobject initialization.

3 Building Modular Interpreters

We provide only the beginning functionality of amodular interpreter. Several comments regardingthe code are in order. For simplicity, primitives arehandled as any other language form. At the costof some extra complexity, logic for handling vari-ous primitive applications can be shared. Error-checking primitive applications based on the num-ber of operands could then also be easily added.The return and extend operators could be treatedas macros which take care to capture language, butwe choose to leave them in expanded form.

We use a three-level structure, making use ofmetaclasses. The class Language is the broadestlanguage speci�cation, de�ning the necessary com-ponents of any language, including its computa-tional metalanguage. Its subclasses are speci�ca-tions of more complex languages which may de-�ne additional computational operators. Instancesof these are languages, whose subobject structurematches the language speci�cation class hierarchy.Treated as classes, languages specify the form ofexpressions, and are subclassed by the various ex-pression types. Notice that if there were to be asubclass link between languages (none is needed),it would go in the opposite direction of the languagespeci�cation links, since any expression of a simplerlanguage can be used where an expression of a morecomplex language is required. The expression typesare de�ned as mixins so that they can be reused assubclasses of various languages. The usage of mix-ins for writing extensible programs has also beenstudied by Findler and Flatt [5].

Language represents the class of interpreted lan-guages, and so must specify the parsing and eval-uation required of any language. Recursions inparse will require the use of the parse proce-dure from the language actually being parsed, notthe language layer at which any given form andits corresponding parser clause were contributed.Similarly for eval-exp, recursions will require theuse of the eval-exp procedure and computationalmetalanguage operators from the language actu-ally being evaluated. Thus, the provided de�ni-tions of parse and eval-exp, called make-parseand make-eval-exp, are relative to the actual lan-guage. That language is available as this whenLanguage is instantiated. Because previously de-clared slots are available to default-value expres-sions of later ones, make-parse and make-eval-exp

can be fed the actual language to yield parse andeval-exp. Language also speci�es the requirementof return, extend and run procedures for any lan-guage. return and extend are assumed to satisfythe monadic laws [13]. Computations are repre-sented as monadic values. The return procedurecreates a monadic value representing a trivial com-putation from a term. The extend procedure com-poses a procedure expecting a value and returning amonadic value with an initial monadic value, yield-ing a composite monadic value. The run procedureundoes the encoding that is required to create amonadic value.

The go procedure is used to run the interpreter.For any language, it composes the run, eval-expand parse procedures.

hGeneral Interpreter Elementsi�(define Language(new-class Language (Object)

([make-parse Procedure][make-eval-exp Procedure][parse Procedure

((slot-ref this make-parse) this)][eval-exp Procedure

((slot-ref this make-eval-exp) this)][return Procedure][extend Procedure][run Procedure])

()))

(define go(generic

(multimethod ([language Language])(compose

(slot-ref language run)(slot-ref language eval-exp)(slot-ref language parse)))))

3.1 Basic Language

Computations in the most basic interpreter aremodeled on the identity monad. That monad isspeci�ed such that both return and extend are theidentitity function. Since no encoding is imposed,the run procedure is also the identity function.

hIdentity Monadi�(define return-id (lambda (t) t))(define extend-id (lambda (f) f))(define run-id (lambda (m) m))

The class Basic-language represents basicinterpreted languages. This is equivalent toLanguage, the class of interpreted languages, be-cause the * form which is added at this levelrequires no additonal operators in the computa-tional metalanguage. In practice, however, all in-stances of Basic-language will have parse andeval-exp functions able to handle the * form. Theclass includes basic interpreted languages such asBasic-expression de�ned below, and basic lan-guage subobjects of more specialized languagessuch as those belonging to Signal-language.

Our basic language contains two forms: integerliterals and binary multiplications, represented astwo subclasses of a basic language claject. Think-ing in terms of extensibility, such a basic language

Page 4: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

claject need not be an instance of Basic-languagedirectly, but may be an instance of any of its sub-classes. Thus, we de�ne integer literals and multi-plication expressions as mixins, i.e., functions fromsuper classes to derived classes [1]. In the caseof multiplication expressions, which have recursivesubparts, the language parameter serves anotherpurpose. It is used to declare the type of theoperand subexpressions.

hBasic Languagei�(define Basic-language

(new-class Basic-language (Language)() ()))

(define mixin-Int-lit(memo-generic(multimethod ([language Basic-language])

(new-class Int-lit (language)([int Integer]) ()))))

(define mixin-Mult-exp(memo-generic(multimethod ([language Basic-language])

(new-class Mult-exp (language)([rand1 language][rand2 language])

()))))

(define Basic-expression(new-claject Basic-expression Basic-language(Object) () ()hBasic make-parse ihBasic make-eval-exp ireturn-id extend-id run-id))

When we instantiate Basic-language asBasic-expression, we create a particular basiclanguage with procedures for parsing and eval-uating nested multiplication expressions, and acore computational metalanguage. That basiclanguage is itself a class which is given Object as asuperclass. It speci�es no slots itself, as these willbe provided by its subclasses through the mixinspresented above. The identity monad is all that isrequired for the core computational metalanguage.

As we have explained, make-parse andmake-eval-exp are relative to an actual lan-guage. In this case, the actual language is someBasic-language. For make-parse, the resultingprocedure is responsible for creating expressions ofthat language, using the mixins. Recursions are tothe parse procedure of that language.

hBasic make-parse i�(generic

(multimethod ([language Basic-language])(lambda (x)

(cond[(integer? x)(new-inst (mixin-Int-lit language)x)]

[(and (pair? x) (eq? (car x) '*))(new-inst (mixin-Mult-exp language)

((slot-ref language parse)(cadr x))

((slot-ref language parse)(caddr x)))]

[else(error 'parse

"Couldn't parse ~s" x)]))))

For make-eval-exp, the resulting procedureuses the mixins to declare its parameters, and looksto the actual language for de�nitions of return andextend, as well as for the recursions.

hBasic make-eval-exp i�(memo-generic(multimethod ([language Basic-language])

(generic(multimethod

([int-lit (mixin-Int-lit language)])((slot-ref language return)(slot-ref int-lit int)))

(multimethod([mult-exp (mixin-Mult-exp language)])(((slot-ref language extend)

(lambda (arg1)(((slot-ref language extend)

(lambda (arg2)((slot-ref language return)(* arg1 arg2))))

((slot-ref language eval-exp)(slot-ref mult-exp rand2)))))

((slot-ref language eval-exp)(slot-ref mult-exp rand1)))))))

3.2 Signal Language

The type ErrorComp is introduced to represent com-putations under the error monad. It has two vari-ants, Ok, which holds a value, and Bad, which holdsan error code. We obtain the error monad by ap-plying the error monad transformer, which takesthe form of a sequence of transformer functions, toelements of the identity monad. The error monadtransformer is as presented by Liang, Hudak andJones [9].

A speci�cation of a new operator for the com-putational metalanguage is now provided. Thesignal-errt precedure does not require any argu-ments, but other operators may require any ele-ments of the previous computational metalanguage.The resulting operator takes an error code andbuilds a Bad record.

hError Monad Transformeri�(define ErrorComp(new-class ErrorComp (Object)

() ()))

(define Ok(new-class Ok (ErrorComp)

([val Object]) ()))

(define Bad(new-class Bad (ErrorComp)

([code Integer]) ()))

(define return-errt(lambda (return-prev)

(compose return-prev(lambda (x) (new-inst Ok x)))))

(define extend-errt(lambda (return-prev extend-prev)

(lambda (f)(lambda (in-m)

((extend-prev(generic

Page 5: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

(multimethod ([ok Ok])(f (slot-ref ok val)))

(multimethod ([bad Bad])(return-prev bad))))

in-m)))))

(define run-errt(lambda (run-prev)(generic

(multimethod ([ok Ok])(run-prev(slot-ref ok val)))

(multimethod ([bad Bad])(error 'eval "code: ~s~n"

(slot-ref bad code))))))

(define signal-errt(lambda () (lambda (x) (new-inst Bad x))))

Our language will be extended with two newforms: division expressions and error expressions.To support these, all succeeding languages mustprovide a signal-err operator in additon to thestandard monadic operators. The mixin for divi-sion expressions is similar to that for multiplica-tion expressions. The mixin for error expressions issimilar to that for integer literals.

Next, we wish to create a Signal-expressionclass as we did for Basic-expression. We willrequire a Basic-expression class in order to ac-complish this, since such a claject will have parseand eval-exp clauses for the rest of our language,as well as computational metalanguage operatorsthat we will need in order to obtain our own met-alanguage using the monad transformer. Thus,we �rst de�ne Signal-expression relative to aBasic-language which we call prev-language, andthen provide it with the only basic language wehave available, Basic-expression. In some cases,e.g., call-by-name vs. call-by-value semantics forthe �-calculus, there might be multiple reasonablechoices for prev-language.

We use the error monad transformer to modifythe monadic operators from the identity monad,and provide our new operator, signal-err. Hadthere been any other operators in the previous lan-guage, we would lift them to the new language [9].

hSignal languagei�(define Signal-language

(new-class Signal-language(Basic-language)([signal-err Procedure])()))

(define mixin-Div-exp(memo-generic(multimethod ([language Signal-language])(new-class Div-exp (language)

([rand1 language][rand2 language])()))))

(define mixin-Error-exp(memo-generic(multimethod ([language Signal-language])(new-class <error> (language)

([code Integer])()))))

(define new-Signal-language(memo-generic

(multimethod([prev-language Basic-language])(new-claject Signal-expression

Signal-language (Object) () ()hSignal make-parse ihSignal make-eval-exp i(return-errt

(slot-ref prev-language return))(extend-errt

(slot-ref prev-language return)(slot-ref prev-language extend))

(run-errt(slot-ref prev-language run))

(signal-errt)))))

(define Signal-expression(new-Signal-language Basic-expression))

The parse procedure makes use ofprev-language when it discovers that noneof its own clauses apply to the input expression. Ituses the clauses from the parser of the old language,but views them as directing the construction oflanguage forms in the current language. Thus, weuse make-parse and apply it to language.

hSignal make-parse i�(generic(multimethod ([language Signal-language])

(lambda (x)(cond

[(and (pair? x) (eq? (car x) '/))(new-inst (mixin-Div-exp language)

((slot-ref language parse)(cadr x))

((slot-ref language parse)(caddr x)))]

[(and (pair? x) (eq? (car x) 'error))(new-inst (mixin-Error-exp language)

((slot-ref language parse)(cadr x)))]

[else(((slot-ref prev-language

make-parse)language)

x)]))))

The interpreter procedure obtains the previousinterpreter from prev-language, and extends itwith additional multimethods for the language ex-tension. Just as with the parser above, we mustrebuild the interpreter using language. Thus, wemake use of the new computational metalanguage,and the new interpreter in recursions. By func-tionally extending the old interpreter, we leave theoriginal intact so that we can use it alongside thenew one without additional overhead.

hSignal make-eval-exp i�(generic(multimethod ([language Signal-language])

(extend-generic((slot-ref prev-language make-eval-exp)language)

(multimethod([div-exp (mixin-Div-exp language)])(((slot-ref language extend)

(lambda (arg1)(((slot-ref language extend)

(lambda (arg2)

Page 6: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

(if (zero? arg2)((slot-ref language

signal-err)9002)((slot-ref language return)(/ arg1 arg2)))))

((slot-ref language eval-exp)(slot-ref div-exp rand2)))))

((slot-ref language eval-exp)(slot-ref div-exp rand1))))

(multimethod([error-exp

(mixin-Error-exp language)])(((slot-ref language extend)

(lambda (code-arg)((slot-ref language signal-err)code-arg)))

((slot-ref language eval-exp)(slot-ref error-exp code)))))))

In summary, each interpreter module containsthe following components:

� Reference to previous interpreter module.

� Reference to monad transformer being addedto semantics.

� Language speci�cation (derived from previouslanguage speci�cation), and including anynew semantic operators as slots.

� Mixins de�ning syntax of new language forms.

� Expression speci�cation (in terms of previousexpression speci�cation), and including exten-sion of previous generic functions for parsingand evaluation, as well as transformed/liftedmonadic operators from the previous lan-guage, and any new operators.

3.3 Full Interpreter

Although we have presented only the �rst two inter-preter modules, we have found that this approachscales up well. The system has been extendedto provide extensive functionality described below.3

The following monad transformers were used:with custom operators

error monadsignal-err

environment monadcurrent-envmodify-env

store monadcurrent-stomodify-sto!

3Again, see http://www.cs.indiana.edu/hyplan/sganz/publications/sfp00/code.tar.gz for the full implementation.

continuation monadcallcc

The following interpeter modules were used:with monad transformer appliedand language features added

basicapplies identity monad as baselit formif formprimitive application form* primitive

signalapplies error monad transformererror primitive/ primitiveerrors are signalled on div by zero, etc.

read-only stackapplies environment monad transformer(environment holds values)let formvariable reference form

read-write stack(environment now holds locations)applies store monad transformerset! form

read-write stack, heapreapplies store monad transformerbox primitiveunbox primitiveset-box! primitive

read-write stack, heap, continuationsapplies continuation monad transformerletcc formthrow form

4 Conclusion

We have explored the use of an object-oriented ex-tension of Scheme for writing modular interpretersfor mostly functional languages. We �rst presentedour object system, which features generic functionswith multimethods, multiple inheritance and meta-classes. We then constructed the �rst several mod-ules of an interpreter, using techniques that couldeasily be extended for any number of modules.

Our e�ort has largely been successful. How-ever, there is room for improvement. Notice thatalthough we used mixins to represent the syntax offorms in a language, the interpreter modules them-selves are each hard-wired to the previous module.We were able to parameterize over the actual pre-

Page 7: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

vious language, but the previous language speci-�cation must be �xed. This is primarily becausesuch modularity would require automated tech-niques for lifting monadic operators. Even then,the initialization of abstract superclasses would becomplex. Monadic operators (other than returnand extend) would be defaulted to their non-liftedvalues through the language speci�cation. An ad-ditional argument (the list of monad transformersto be applied) would have to be added to languageconstructors. It would be forwarded up the hier-archy and would, upon reaching a superclass withsuch a monadic operator, be used to generate liftprocedures and apply them to the operator last-in,�rst-out, updating it in the language instance.

Our interpreter thus falls short of the claimsof complete independence and interchangeabilitymade by Cartwright and Felleisen [2], althoughthere are some interesting similarities between ourmethods. There are several reasons for the discrep-ancy. First, they use a largely untyped language,while ours is typed, albeit dynamically. The typingof expression components is an element of the in-terpreter that we need to update during any exten-sion. Second, they forgo the monadic approach tosemantics (although their programs are written in amonadic style) in favor of the more straightforwardone of sending a message, including an evaluationcontext, along with a list of resources to an ad-ministrative routine. They thus seem to avoid thecomplex issue of lifting operators which was a focusof Liang, Hudak and Jones. A possible indicationof a shortcoming of Cartwright and Felleisen's ap-proach is that they do not treat environments as amodular extension, but as an inherent part of anyinterpreter. A third reason is their use of mutationof global variables, which has the e�ect that theextensions to their interpreter cannot coexist withthe original.

Another disappointing aspect of this interpeteris the isolation of the mixins from the rest of thelanguage. One would prefer to see those mixinscombined and stored as part of the language, asthe object portion of a syntax functor. This wouldin turn pave the way for the introduction of cata-morphisms for the de�nition of the interpreter andanamorphisms for the de�nition of the parser, mak-ing the recursions implicit. It will be the subject offuture research.

References

[1] Gilad Bracha and William Cook. Mixin-basedinheritance. In ECOOP/OOPSLA '90, pages303{311, 1990.

[2] Robert Cartwright and Matthias Felleisen. Ex-tensible denotational language speci�cations.In Masami Hagiya and John C. Mitchell, ed-itors, Theoretical Aspects of Computer Soft-ware, volume 789 of Lecture Notes in Com-puter Science, pages 244{272. Springer-Verlag,April 1994.

[3] William R. Cook. Object-oriented program-ming versus abstract data types. In J. W.de Bakker, W. P. de Roever, and G. Rozen-berg, editors, Foundations of Object-OrientedLanguages, REX School/Workshop, Noordwi-jkerhout, The Netherlands, May/June 1990,volume 489 of Lecture Notes in ComputerScience, pages 151{178. Springer-Verlag, NewYork, NY, 1991.

[4] Luc Duponcheel. Using catamorphisms, sub-types and monad transformers for writingmodular functional interpreters. Research Re-port (draft), November 1995.

[5] Robert Bruce Findler and Matthew Flatt.Modular object-oriented programming withunits and mixins. In Proceedings of the ACMSIGPLAN International Conference on Func-tional Programming (ICFP '98), volume 34(1)of ACM SIGPLAN Notices, pages 94{104.ACM, June 1999.

[6] Mark P. Jones. A system of constructorclasses: overloading and implicit higher-orderpolymorphism. In FPCA '93: Conference onFunctional Programming and Computer Archi-tecture, Copenhagen, Denmark, pages 52{61,New York, N.Y., June 1993. ACM Press.

[7] Shriram Krishnamurthi and MatthiasFelleisen. Toward a formal theory of ex-tensible software. In Proceedings of the ACMSIGSOFT 6th International Symposium onthe Foundations of Software Engineering(FSE-98), volume 23, 6 of Software En-gineering Notes, pages 88{98, New York,November 3{5 1998. ACM Press.

[8] Kevin J. Lang and Barak A. Pearlmutter.Oaklisp: an object-oriented dialect of scheme.Lisp and Symbolic Computation: An Interna-tional Journal, 1(1):39{51, May 1988.

[9] Sheng Liang, Paul Hudak, and Mark Jones.Monad transformers and modular interpreters.In Conference Record of POPL '94: 21st ACMSIGPLAN-SIGACT Symposium on Principlesof Programming Languages, San Francisco,California, pages 333{343. ACM, January1995.

[10] Jonathan G. Rossie Jr., Daniel P. Friedman,and Mitchell Wand. Modeling subobject-basedinheritance. In Pierre Cointe, editor, ECOOP'96 | object-oriented programming: 10th Eu-ropean Conference, Linz, Austria, July 8{12,1996: proceedings, volume 1098 of LectureNotes in Computer Science, pages 248{274.Springer, 1996.

[11] A. Snyder. Common objects: an overview,1986.

[12] Guy L. Steele, Jr. Building interpreters bycomposing monads. In Conference Record ofPOPL '94: 21st ACM SIGPLAN-SIGACT

Page 8: Mo dula - cs.  · PDF fileA Mo dula r In t erpr eter Sc hem e Wi th Ob jects S te v e n E. Ga n z y I nd iana Uni v ersi t y Da n i el P.F ri edman iana U n i Abstr act The pro b

Symposium on Principles of ProgrammingLanguages, Portland, Oregon, pages 472{492.ACM, January 1994.

[13] P. Wadler. Monads for functional program-ming. Lecture Notes in Computer Science,925:24{??, 1995.