Project Summary - CiteSeerX

3 downloads 0 Views 289KB Size Report
Sep 21, 1999 - was supported by the NSF in the project Type Safe Program Generators (IRI-9625462). This proposal ..... Instead of specifying Haskell in a logical framework, we propose to ..... 6] Charles Consel and Fran cois No el. A generalĀ ...
Project Summary Meta-Programming with Intensional Analysis Tim Sheard and Zine El-Abidine Benaissa Oregon Graduate Institute of Science & Technology The project Meta-Programming with Intensional Analysis explores the use of meta-programming systems with intensional analysis capabilities as a method for constructing meta-programs in a systematic manner. Such systems can be used to optimize, transform, and reason about complex software systems. Many meta-programs share some common components, and their implementations must solve common problems. Meta-programming systems with intensional analysis capabilities provide highlevel abstractions for expressing these analyses in an economical way to share and leverage these costs.

The objective of the project is to provide high-quality meta-programming systems for typed

languages that incorporate a high-level interface to intensional analysis. Such systems should signi cantly lower the cost of constructing many kinds of code analyses.

The goal of the project is to provide materials such as automated tools, well-de ned step-by-

step methods, libraries of reusable components, and case studies of the construction of optimizers transformers, and system analysers built with meta-programming technology.

The impact of meta-programming on software design is considerable. As systems become more

complex, it is no longer sucient to simply design and then code them. Complex analysis of the actual running code is often necessary to ensure elements of trust, reliability, and performance. The actual kind of analyses varies widely, and the cost of many analysis tools can be prohibitive.

By providing tools for the cheap construction of program optimizers, program tranformers, and program reasoning systems which deal with actual executable code users can safely and economically construct exactly the analyses they need to ensure the properties they require.

The methods employed will use new programming language mechanisms that have come out of

our previous study of staged programming, insights from the study of higher-order abstract syntax and higher-order pattern matching, as well as new insights into the intensional analysis of code as rst-class objects. The project will build a meta-programming system for the lazy functional language Haskell. It will exploit the work on the integration of foreign systems into the Haskell programming language. This proposal leverages our previous work on the staged programming language MetaML, which was supported by the NSF in the project Type Safe Program Generators (IRI-9625462). This proposal extends this work with new mechanisms for the intensional analysis of code. This includes type-safe analysis of code, and hygienic analysis of code fragments with free variables using higher-order pattern matching. The type correctness of the meta-program, should guarantee type correctness of the object-programs it constructs or analyszes. We also study the semantic foundations of intensional analysis in meta-systems where the meta-language and object-language are the same. A{1

Meta-Programming with Intensional Analysis Tim Sheard and Zine El-Abidine Benaissa Oregon Graduate Institute of Science & Technology September 21, 1999

Contents Project Summary Table of Contents 1 Project Description 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 1.10

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . Meta-programming systems . . . . . . . . . . . . . . . . . Introduction to MetaML . . . . . . . . . . . . . . . . . . . Meta-programming and Lisp . . . . . . . . . . . . . . . . The Intentional Programming Project . . . . . . . . . . . Higher-order abstract syntax and Higher-order matching . A high-level interface to intensional analysis . . . . . . . . Example: Compiler Derivation . . . . . . . . . . . . . . . Example: An HOL-like theorem prover for ML . . . . . . MetaML and results from prior NSF support . . . . . . . 1.10.1 Summary of results from prior support . . . . . . . 1.10.2 Description of the research products produced. . . 1.10.3 Publications resulting from prior support. . . . . . 1.10.4 Students and Collaborators . . . . . . . . . . . . . 1.11 The research proposal . . . . . . . . . . . . . . . . . . . .

2 3 4 5

References Cited Biographical Sketches Summary Proposal Budget Current and Pending Support

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

A{1 B{1 C{1

C{1 C{2 C{3 C{4 C{5 C{6 C{7 C{8 C{9 C{11 C{11 C{12 C{12 C{13 C{13

D{1 E{1 F{1 G{1

6 Facilites and Equipment

H{1 B{1

1 Project Description 1.1 Introduction As systems become larger and more complex the current practice of design, coding, and testing is no longer sucient to ensure the elements of trust, reliability, and performance required. In addition to these practices, complex analysis of the actual running code such as enriched type systems, data- ow analysis, or deadlock detection is often necessary Unfortunately the use of analysis tools is not without cost. 





Current tools are often hard to use as they often require recasting the code in some new dialect understood by the tool. The actual kind of analyses varies widely, and the appropriate analysis tool is not always available. The cost constructing new analyses can be prohibitive.

Tools for the cheap construction of program optimizers, program transformers, and program reasoning systems which deal with actual executable code could lower the barriers to adoption of these enabling technologies. Meta-programming systems with intensional analysis capabilities are one way of constructing program analysis tools in a systematic manner. Many analyses share some common components, and their implementations must solve common problems. Meta-programming systems provide highlevel abstractions for expressing these analyses in an economical way to share and leverage these costs. Using meta-programming tools, users can safely and economically construct exactly the analyses they need to ensure the properties they require. We propose building a meta-programming system for the lazy, functional language Haskell which includes an intensional analysis component. We are perfectly positioned to do this work because of our experience on the MetaML (meta-programming) system and our proximity to the OGI Haskell community. A scenario. The Lisp hackers had it right. Code isn't only for executing; code is for manipulation as well. Programmers of the not too distant future will have to manipulate their code as well as write, test, and execute it. Consider the following scenario. The ABC company needs to build a new computer system. This system needs to meet some stringent requirements. The ABC company would like to validate these requirements directly on the source code. What language should they choose? The language needs to be formal enough so that it can be reasoned about. Otherwise, how could ABC know that the code written meets the required properties? Once the language is chosen, the ABC company ascertains what tools are available. Unfortunately, the requirements do not match up exactly with the available tools. The ABC company must write some of its own analyses. While the ABC company has expert programmers in their chosen language, none of them are familiar with the language internals. Could it be possible to exploit their programmer's expertise with the interface to the language that programmers use, and their expertise in the system domain? Could they express their analysis at the concrete syntax level that they understand. Are there o the shelf toolkits or other pieces of the problem they can reuse? This is exactly where a meta-programming system for their chosen language becomes useful. C{1

1.2 Meta-programming systems In a meta-programming system meta-programs manipulate object-programs. Meta-programs may construct object-programs, combine object-program fragments into larger object-programs, observe the structure and other properties of object-programs, and execute object-programs to obtain their values. There are two kinds of meta-programming systems: homogeneous systems where the meta-language and the object language are the same, and heterogeneous systems where the meta-language is different from the object-language. There are important advantages to homogeneous systems. Only homogeneous systems can be multi-level, where an object-program can itself be a meta-program which manipulates second-level object-programs. Only in a homogeneous meta-system one can extend the type system of the meta-language to type the object-language as well. Only homogeneous meta-systems can support re ection (where the meta-language is rich enough that every primitive on object-programs can be expressed as a meta-program). Only homogeneous meta-systems can support a run or eval operation in a uniform way. Homogeneous systems also have the important pedagogical and usability property that the user need only learn a single language. An important kind of meta-program is a program generator. Program generators come in two

avors: static generators, which generate code which is then written to disk and processed by normal compilers etc. and run-time code generators which are programs that write or construct other programs, and then immediately execute the programs they have generated. Examples of program generators are run-time code generation systems like the Synthesis Kernel[16], and static program generators such as Yacc. Another important kind of meta-program is a program analysis. A program analysis observes the structure and environment of an object-program and computes some value as a result. Results can be data- or control- ow graphs, or even another object-program with properties based on the properties of the source object-program. Examples of these kind of meta-systems are: program transformers, optimizers, and partial evaluation systems. A static type system keeps bad programs from executing by refusing to compile them. In a meta-system more expressive type systems are necessary because more things can go wrong. In brief, a sound typed meta-system refuses to compile meta-programs which could produce ill-typed object-programs. In addition to these operational properties, a meta-system should also have a good human-system interface. Our experience with meta-programming systems has led us to formulate the following high-level meta-programming human-system interface desiderata: 1. Construction. It should be easy to construct code using some sort of pattern-based objectcode templates. Templates should look like the object language they represent. 2. Splicing. Program fragments should be easy to combine into larger program fragments, this is best accomplished by a parameterizable splicing mechanism such as a \templatewith-holes". 3. Typing. In a homogeneous system, object-code has a parametric type, i.e., there is code with type Int, code with type Float, etc. Type correctness of the meta-program, should guarantee type correctness of the object-programs it constructs. C{2

4. Hygiene. Bound variables in templates should be handled in some sophisticated way which guarantees no name clashes, and which obeys the rules of static scoping. Free variables in program templates should refer to the value of the variable at the static location where the template is de ned, not where it is eventually executed. 5. Run. Object-programs can be run. Generated code can be tested inside the meta-system. 6. Printing. Object-programs can be printed. This is essential for debugging of metaprograms. The object-programs should be pretty-printed in the manner in which they are normally written by a programmer. They should not be represented by some abstract representation unfamiliar to the programmer. 7. Observation. Object-programs have structure. It should be possible to analyze objectprograms, take them apart, etc. We have spent the last three years building the meta-programming language MetaML [31, 30, 26], which was designed as a homogeneous run-time code generator tool kit. MetaML is a homogeneous meta-programming system for Standard ML and was designed to provide a high-level, user-friendly interface to object-code construction, splicing, typing, hygiene, running, and printing. See Section 1.10 for some examples which illustrate this interface. The systems we can build with MetaML are typical of many generator systems in that they do not observe or analyze the object-programs they build. The ability of a homogeneous meta-system to observe the structure of its object-programs is called intensional analysis. Intensional { because the meta-programs may observe the structure of the object-programs, not just the values that their object-programs represent. While the analysis of object-program structure is one of the desiderata of meta-programming systems, it has been (until now) left out of our research into meta-programming systems. It is the goal of this proposal to rectify this omission, to build meta-programming systems which directly support the intensional analysis of object-programs. This ability would greatly increase the range of meta-programs that can be written using the high-level style supported by MetaML.

1.3 Introduction to MetaML MetaML provides a meta-programming interface to the Standard ML language. In staging a program, the user can manipulate object-code by using staging annotations. In MetaML the staging annotations are Brackets , Escape ~, lift, and run. An expression builds the code representation of e; ~e splices the code obtained by evaluating e into the body of a surrounding Bracketed expression; and run e evaluates e to obtain a piece of code, and then evaluates this piece of code. It is important to note that ~e is only legal within lexically enclosing Brackets. Users access MetaML through a read-type-eval-print top-level. To illustrate, consider the scripts of a few small MetaML sessions below: -| val w = 3+4; val w = 7 : int

-| val x = ; val x = :

-| val y = lift(3+4); val y = :

-| val z = ; val z = :

The declaration for w is read, type-checked to see that it has a consistent type (int here), evaluated (to 7), and then both its value and type are pretty-printed. C{3

Placing brackets around an expression () defers the computation of 3+4 to the next stage, returning a piece of code. Brackets delimit the the begin and end of a code constructing template. Lifting an expression (lift (3+4)) evaluates that expression (to 7 here) and then lifts the value to a piece of code that when evaluated returns the same value. Brackets around a free variable () creates a new constant piece of code with the value of that variable. Such constants pretty-print with a % sign to indicate they are constants. We call this lexical-capture of free object-variables. Because in MetaML operators (such as + and *) are also identi ers, free occurrences of operators in constructed code often appear with % in front of them. -| fun inc x = ; val inc = fn : ->

-| val six = inc ; val six = :

-| run six; val it = 6 : int

The declaration of the function inc illustrates that larger pieces of code can be constructed from smaller ones by using the escape annotation. It is often convenient to construct a large piece of code by \splicing" in a previously constructed piece of code into a template hole. MetaML allows one to escape from a code constructing template by pre xing a sub-expression within it with the tilde (~) character. The escape marks the location of the template \hole". Because of this escape must only appear inside brackets. In the declaration for six, the function increment is applied to the piece of code constructing the new piece of code . Running a piece of code, strips away the enclosing brackets, and evaluates the expression inside. To give a brief feel for how MetaML is used to construct larger pieces of code at run-time consider: -| fun mult x n = if n=0 then else < ~x * ~(mult x (n-1)) >; val mult = fn : -> int -> -| val cube = ~(mult 3)>; val cube = a * (a * (a * 1))> : int>

-| fun exponent n = ~(mult n)>; val exponent = fn : int -> int>

The function mult, given an integer piece of code x and an integer n, produces a piece of code that is an n-way product of x. This can be used to construct the code of a function that performs the cube operation, or generalized to a generator for producing an exponentiation function from a given exponent n. Note how the looping overhead has been removed from the generated code cube. This is the purpose of program staging and it can be highly e ective as discussed elsewhere [6, 9, 13, 25, 31].

1.4 Meta-programming and Lisp Meta-programming can be done in Lisp, but compared to MetaML, only in a primitive fashion. MetaML 's three annotations, bracket, escape and run, are analogous to Lisp's back-quote, comma and eval (in the empty environment). However, the analogy is not perfect. Lisp di ers from MetaML in three important ways. C{4





Lisp does not ensure that variables (atoms) occurring in a back-quoted expression are bound according to the rules of static scoping. For example `(plus 3 5) does not bind plus in the scope where the back-quoted term appears. While in MetaML evaluates to . Here the constant %+ has the value that + did in the context where the template occurred. Lisp leaves the correct generation of new bound variables as a responsibility of the programmer. In MetaML we can write a function that creates a lambda expression whose body is the sum of the lambda's bound variable and the functions argument: -| fun fillBodyWith e = x + ~e>; val fillBodyWith = fn : -> int >

If the argument e is a piece of code with a free variable x, there is the disturbing possibility that this variable could be inadvertently captured by the bound variable, x appearing in the template. In MetaML this is not possible as template bound variables are automatically alpha-renamed. Note how the inner bound variable x is renamed below: -| val e = ~(fillBodyWith )>; val e = (fn y => y %+ x))> : int -> int >

Lisp does not provide any such mechanism for lambda bound variables inside of backquoted expressions. Instead one must write something akin to: (defun fillBodyWith (e) (let (x (gensym "y")) `(lambda (,x) ,x + ,e))) (setq e (let (x (gensym "x")) `(lambda (,x) ,(fillBodyWith x)))) 

Lisp employs a dynamic typing discipline, while MetaML employs a static typing discipline. A major advantage of static typing in MetaML is that it ensures, at the compile-time of the generator, that all generated programs are well typed. It is impossible to write a generator that generates ill-typed code. In a dynamically-typed language, a type error in generated code does not show up until the generated code is executed.

Intensional analysis is possible in Lisp, but it is extremely low-level. Since programs are represented as lists, the Lisp predicates consp, atom, and eq, can be used to observe the shape of program. We are interested in something at a much higher-level of abstraction. To nd it we must visit the world of logical frameworks.

1.5 The Intentional Programming Project Microsoft Research's Intentional Programming Project has created a software development environment which is independent of any particular programming language. The system seeks to capture the \intent" of the programmer. The system breaks the notion that a programming language is tied to a xed text-oriented syntax. It also allows the expressive power of a language to grow through the addition of new syntactic and semantic constructs as well as translators that transform these new constructs to ones already understood by the system. In contrast intensional programming in this proposal seeks not to capture the intent of the programmer, but instead to expose the programmer to his own code as an object that can be formally manipulated. C{5

1.6 Higher-order abstract syntax and Higher-order matching Higher-order abstract syntax (HOAS) is a generalization of the well-understood rst-order abstract syntax that is usually used to represent object-programs in meta-systems. This technique allows an elegant implementation of an object-language with binding operations. Using higher-order abstract syntax, one uses the function space of the meta-language to represent the binding constructs of the object-language. For example contrast the two implementations of the lambda calculus in ML below. One deals explicitly with variables and the lambda binding-construct, and the other uses the function space of the meta-language to represent lambdas in the object language. datatype Var of | Lambda | App of

Term = string of string * Term Term * Term;

datatype Term = Lambda of Term -> Term | App of Term * Term; val id = Lambda(fn x => x);

val id = Lambda("x",Var "x");

HOAS saves the implementor great deal of trouble with operations that deal with bound variables, such as alpha-renaming, name capture, scoping, and substitution. These tasks are tedious to implement and represent a major source of bugs in meta-programs. HOAS recognizes these common patterns and exploits the scoping mechanism of the meta-language (which already has all these tools) to implement them. Higher-order abstract syntax goes back to Church's [3] original de nition of the -calculus and Martin Lof's work on intuitionistic type theory [15]. Huet and Lang [12] noticed that higherorderness was a valuable technique for improving the abstraction level of syntax. Pfenning and Elliott [23] introduced the name \higher order abstract syntax" and generalized their work. Highorder abstract syntax is the central representation technique in the logical frameworks projects [10]. Logical frameworks are open metaprogramming systems. By open we mean that the objectlanguage, its type system, and transformation rules are speci ed in the logical framework. Many implementations of such systems are available [24, 22, 20, 14]. Specifying the full syntax of a complex language like Haskell, as well as its type system, and optimizing rules is not an easy task; even in high-level framework such as ELF. It requires a large amount of e ort and careful thought. Instead of specifying Haskell in a logical framework, we propose to integrate intentional analysis into Haskell. By making Haskell both the meta-language and the object-language we enrich Haskell by providing it with all the abilities that used to require the logical framework. While HOAS has many attractive advantages, it also has some serious drawbacks, including the loss of structural recursion over the object-language. This technique is very important in a programming language such as Haskell. Recently, there has been some interesting work towards a solution. We are particularly interested in the work of Gabbay and Pitts [8]. This work provides nice foundation for HOAS that allows a structural recursion and induction principles. Behind HOAS and intentional analysis of object-code with binding constructs, there is an essential algorithm that performs uni cation and pattern matching. Because of their higher-order nature, a higher-order uni cation algorithm is needed. This algorithm identi es terms that are convertible in the simply typed lambda calculus. Unfortunately, the algorithm is both undecidable, and unable to nd a most general uni er in some cases. C{6

Dale Miller [18] observed that the uni cation most commonly performed is on higher-order patterns. Higher-order patterns are terms of the form x: y: M y x where M is the uni cation variable. He showed that uni cation in this case is decidable and has a most general uni er which is an extension of rst-order uni cation that preserves scoping. This algorithm is behind our proposed intentional analysis techniques. We may need to add new axioms to identify two functions of type -> and B>. Theoretical study of this extension is needed. Miller warns that the extension of a language such as Haskell or ML is a serious business [17]. One has to give careful thought about adequate syntax extensions to implement the features, integration into the type system, proving its soundness, dynamic semantics, etc. In the next section we discuss our preliminary answers to this challenge. 





1.7 A high-level interface to intensional analysis Our experience with MetaML has shown us that intensional analysis of object code is required for some kinds of meta-programs. Since code is internally represented by a data structure inside a meta-system, analysis is always possible. We insist that this analysis be easy to use, not just possible, so we insist that intensional analysis have a high-level pattern matching interface. As discussed in Section 1.6 pattern matching against code fragments becomes complicated when the code patterns contain variable binding occurrences (such as lambda-abstractions or local declarations). In order to make sure that variables do not inadvertently escape their scope when doing intensional analysis we propose the use of higher-order pattern variables [18]. We propose to implement a high-level interface to such analysis similar to the following. Code patterns can be constructed by placing brackets around code. Bracketed arguments in function declarations or lamda expressions are patterns that match code. For example a pattern that matches the literal 5 can be constructed by: -| fun is5 = true | is5 _ = false; val is5 = fn : -> bool

-| is5 (lift (1+4)); val it = true : bool

-| is5 ; val it = false

: bool

The function is5 matches its argument to the constant pattern if it succeeds it returns true else false. Pattern variables in code patterns are indicated by escaping variables in the code pattern. -| fun parts < ~x + ~y > = SOME(x,y) | parts _ = NONE; val parts = fn : -> ( * ) option

-| parts ; val it = SOME (,) : ( * ) option

-| parts ; val it = NONE : ( * ) option

The function parts matches its argument against the pattern < ~ x + ~ y >. If its argument is a piece of code which is the sum of two sub terms, it binds the pattern variable x to the left subterm and the pattern variable y to the right subterm. We propose the use of higher-order pattern variables for code patterns that contain binding occurrences, such as lambda expressions, let expressions or functions. For example, a high-order pattern that matches the code of a function ...>, of type is written in eta-expanded form ~(g )>. When the pattern matches, the matching binds the higher-order pattern variable g to a function with type C{7

Every higher order pattern variable must be in fully saturated form. This is done by applying it to the bound variables of the code pattern. For example if g is a higher-order pattern variable with type -> int> -| f (x-4) + 0>; val it = a %- 4)> : int>

When the the function f is applied to the code (x-4) + 0>, the pattern variable g is bound to the function fn x => which has the type -> . The right-hand The right-hand side of f rebuilds a new code fragment, substituting formal parameter x of g by.

1.8 Example: Compiler Derivation Domain speci c language (DSL) implementation is one of the original motivating examples for our interest in meta-programming systems. One way to implement a DSL is to write an interpreter for it. A general-purpose staging tool, such as MetaML, allows DSL compilers to be written as staged interpreters [27]. We illustrate this in Figure 1. We specify a language's abstract syntax as an MetaML datatype. We give the language meaning by writing a staged, monadic interpreter. The result of running the interpreter is a monadic ML program1 While ML is probably not the target language desired, this approach has major advantages. The residual code is an MetaML code fragment. It can be either executed or analyzed. It is always type-correct, and the MetaML system handles the problems of generating new local names, pretty printing, and parsing the generated code implicitly. The nal step in exploiting these advantages is to translate this residual program into the target language. Fortunately, this is not as hard as providing a general purpose translation of ML to an arbitrary intermediate code. A well-designed staged interpreter will generate residual code with a high degree of structure. This is certainly the case for the residual program shown in Figure 1. Disregarding the higher-order functions implicit in the monad, it is rst order, and contains only Do expressions, Return expressions, if expressions, calls to the non-standard morphisms read and write, primitive arithmetic operators - and '>', and local looping functions. The code is so regular that it can be captured by a simple grammar. What we need is to analyze this code to make the nal translation to the target language, which is much simpler than translating an arbitrary ML program. We outline this process below. First recognize that the pretty printer prints Do m a; Do m c syntactic sugar for bind (fn x => f) e and Return (Mon(bind,unit)) e is syntactic sugar for unit e. 1

C{8

f

g

e; fg

is

datatype Com Assign of | Seq of | Cond of | While of | Declare of | Print of

= (string * Exp) (Com * Com) (Exp * Com * Com) (Exp * Com) (string * Exp * Com) Exp;

Abstract syntax as an MetaMLdatatype declare x = 10 in { x := x - 1; print x }

Sample program in concrete Syntax val S1 = Declare("x",Constant 10, Seq(Assign("x",Minus(Variable "x", Constant 1)), Print(Variable "y")));

Datatype encoding of sample program. -> where 'a is universally quanti ed. C{14

fun | |

g < (fn x => ~(h )) ~z > = h(g z) g = g e = e;

There are two problems here. First, a type inference algorithm infers the type -> for the second clause of the de nition, and infers the type < 'a > -> < 'a > for the other two clauses. The algorithm then uni es these two types, declaring the type of the whole function to be -> , which is too speci c. It will probably be necessary for users to declare the type of such analysis functions, and the typing system will need to check that each clause is an instance of the declared type. This checking requires that g must be polymorphically recursive. Note that each recursive call of g is at a di erent type. It is not known in general how to infer a polymorphically recursive type. This is another argument for requiring type declarations on recursive code analysis. The second research problem is how to type functions like get. Sheard and Popplestone gave get the type:
-> path -> . Clearly this is only an approximation. There is no guarantee that the sub-term pointed to by some path has type b. We will need some sophisticated dependent typing system, or to come up with some alternate interface to sub-expression selection.

How can we construct a pattern matching interface to intensional analysis when the object-code itself uses data-patterns to bind variables? Consider an analysis that searches

for all lambda abstractions. How do we recognize the similarity between (fn x => x), (fn (x,y) => x), and (fn (x,y,z) => x), yet also deal with the obvious di erences, all in a high-level pattern matching interface? This may also require such an analysis to have a dependent type.

How does intensional analysis a ect the semantics and observational behavior of metasystems? Our semantics have always been for systems without intensional analysis. In MetaML

we justi ed certain optimizations at code construction time by the observation that beta-reduction under brackets did not change the semantics of programs. For example, the meta-language compiler transformed the meta-program x + 1) 5> into the meta-program because the two meta-programs produced object-program results which were observationally equivalent. This is true if (and only if) the only observation of an object-program is the result that it produces when executed. If we allow other observations, such as intensional analysis, then these optimizations are no longer true. Thus a run, beta-reduction at higher levels, and intensional analysis are in some ways fundamentally incompatible in a system that has con uence. If we remove run from our meta-system, then we are reduced to constructing static generators and analysis tools. We are willing to live with this, but this invites an intriguing new possibility. Most of the complication in the type system in MetaML comes in separating code fragments with free variables from ones that are closed, because closed code fragments are safe to run, while open fragments are not. Without run the type system can be signi cantly simpli ed. We intend to investigate this possibility.

C{15

2 References Cited References [1] A. Aiken and M. Fahndrich. Making set-constraint based program analyses scale. Technical Report 96-917, University of California, Berkeley, California, September 1996. Also see http://www.cs.berkeley.edu/Research/Aiken/. [2] Z. Benaissa, E. Moggi, W. Taha, and T. Sheard. Logical modalities and multi-stage programming. In Intuitionistic Modal Logic (IML'99), Trento, Italy, July 1999. [3] A. Church. A formulation of the simple theory of types. Journal of Symbolic Logic, (5):56{68, 1940. [4] M. Clavel, F. Duran, P. Lincoln, N. Marti-Olliet, J. Meseguer, and J. Quesada. Maude: Speci cation and Programming in Rewriting Logic. SRI, San Fracisco, California, 1999. [5] Manuel Clavel, Steven Eker, Patrick Lincoln, and Jose Meseguer. Principles of Maude. In Jose Meseguer, editor, Proceedings of the First International Workshop on Rewriting Logic and its Applications, volume 4 of Electronic Notes in Theoretical Computer Science, pages 65{89, Asilomar, Paci c Grove, CA, September 1996. Elsevier. [6] Charles Consel and Francois Noel. A general approach for run-time specialization and its application to C. In Conference Record of POPL '96: The 23rd ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pages 145{156, St. Petersburg Beach, Florida, 21{24 January 1996. [7] Nancy A. Day, John Launchbury, and Je rey R. Lewis. Logical abstractions in Haskell. In Proceedings of the 1999 Haskell Workshop, 1999. [8] M. Gabbay and A. Pitts. A new approach to abstact syntax involving binding. In The Fourteenth Symposuim on Logic in Computer Science (LICS'99), Trento, Italy, July 1999. IEEE Computer Society Press. [9] Robert Gluck and Jesper Jrgensen. Ecient multi-level generating extensions for program specialization. In S. D. Swierstra and M. Hermenegildo, editors, Programming Languages: Implementations, Logics and Programs (PLILP'95), volume 982 of Lecture Notes in Computer Science, pages 259{278. Springer-Verlag, 1995. [10] R. Harper, F. Honsell, and G. Plotking. A framwork for de ning logics. Journal of the Association fro Computing and Machinery, 40(1):143{184, January 1993. [11] G. Huet, G. Kahn, and C. Paulin-Mohring. The Coq proof assistant: A tutorial. Version 6.3. Coq project, INRIA, Paris, France, 1999. Available at: http://coq.inria.fr/doc/tutorial.html. [12] G. Huet and B. Lang. Proving and applying program transformations expressed with secondorder patterns. Acta Informatica, (11):31{55, 1978. [13] Mark Leone and Peter Lee. A declarative approach to run-time code generation. In Workshop on Compiler Support for System Software (WCSSS), February 1996. D{1

[14] L. Magnusson. The implementation of ALF-a proof editor based on Martin-Lof's monomorphic type theory with explicit substitution. PhD thesis, Chalmers University of Technology and Gotborg University, Sweden, January 1995. [15] P. Martin-Lof. Intuitionistic theory of types: Predicative part. In sixth International Congress for Logic, Methodology, and Philosophy of Science, pages 73{118. North-Holland, 1975. [16] Henry Massalin. Synthesis: An Ecient Implementation of Fundamental Operating System Services. PhD thesis, Columbia University, 1992. [17] D. Miller. An extension to ml to handle bound variables in data structures (preliminary report). In the Proceedings of the Logical Frameworks BRA Workshop, May 1990. available on http://www.cis.upenn.edu/ dale/recentpapers.html. [18] D. Miller. A logic programming language with lambda-abstraction, function variables, and simple uni cation. Journal of Logic and Computation, (4):497{536, 1991. [19] E. Moggi, W. Taha, Z. Benaissa, and T. Sheard. An idealized MetaML: Simpler, and more expressive (includes proofs). In European Symposium on Programming (ESOP), volume 1576 of LNCS. Springer-Verlag, 1999. [20] G. Nadathur and D. Miller. An ovrview of prolog. In Fifth International Logic Programming Conference, pages 810{827, Seatle, Washington, August 1988. MIT press. [21] L. C. Paulson. Isabelle: A Generic Theorem Prover. Number 828 in LNCS. Springer-Verlag, 1994. [22] F. Pfenning. Elf: A meta-language for deduction systems. In A. Bundy, editor, Twelveth International Conference on Automated Deduction, number 813 in LNAI, pages 811{815, Nancy, France, June 1994. Springer-Verlag. [23] F. Pfenning and C. Elliott. Higher-order abstract synstax. In Proceedings of the 1988 ACM SIGPLAN'88 Symposium on Language Design and Implementation, pages 199{208, Atlanta, Georgia, June 1988. [24] P. Pfenning. Elf: A language for logic de nition and veri ed meta-programming. In Fourth Annual Symposium on Logic in Computer Science, pages 313{322, Paci c Grove, California, June 1989. IEEE Computer Society Press. [25] Calton Pu and Jonathan Walpole. A study of dynamic optimization techniques: Lessons and directions in kernel design. Technical Report OGI-CSE-93-007, Oregon Graduate Institute of Science and Technology, 1993. [26] T. Sheard. Advanced Functional Programming, chapter Using MetaML: A staged Programming Language, pages 207{240. Springer, 1999. [27] T. Sheard, Z. Benaissa, and E. Pasalic. Dsl implementation using staging and monads. In Second Conference on Domain-Speci c Languages (DSL'99), Austin, Texas, October 1999. USEUNIX. [28] Tim Sheard. A type-directed, on-line partial evaluator for a polymorphic language. In Proceedings of the ACM-SIGPLAN Symposium on Partial Evaluation and semantic based program manipulations PEPM'97, Amsterdam, page ?? ACM, 1997. D{2

[29] Mark Shields, Tim Sheard, and Simon Peyton Jones. Dynamic typing through staged type inference. In Proceedings of the 25th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, jan 1998. [30] Walid Taha, Zine-El-Abidine Benaissa, and Tim Sheard. Multi-stage programming: Axiomatization and type-safety. In 25th International Colloquium on Automata, Languages, and Programming, Aalborg, Denmark, 13{17July 1998. [31] Walid Taha and Tim Sheard. Multi-stage programming with explicit annotations. In Proceedings of the ACM-SIGPLAN Symposium on Partial Evaluation and semantic based program manipulations PEPM'97, Amsterdam, pages 203{217. ACM, 1997. [32] Andrew K. Wright and Matthias Felleisen. A syntactic approach to type soundness. Information and Computation, 115(1):38{94, 15 November 1994. [33] H. Xi and F. Pfenning. Eliminating array bound checking through dependent types. In Proceedings of ACM SIGPLAN Conference on Programming Language Design and Implementation(PLDI '98), pages 249{257, Montreal, CANADA, June 1998.

D{3