BRICS

Basic Research in Computer Science

From Natural Semantics to Abstract Machines

Mads Sig Ager BRICS Report Series RS-04-20 ISSN 0909-0878 October 2004 BRICS RS-04-20 M. S. Ager: From Natural Semantics to Abstract Machines Copyright \begin{matrix}c \\ ◯ \end{matrix} 2004, Mads Sig Ager.

BRICS, Department of Computer Science University of Aarhus. All rights reserved.

Reproduction of all or part of this work is permitted for educational or research use on condition that this copyright notice is included in any copy.

See back inner page for a list of recent BRICS Report Series publications. Copies may be obtained by contacting:

BRICS Department of Computer Science University of Aarhus Ny Munkegade, building 540 DK–8000 Aarhus C Denmark

Telephone: +45 8942 3360
Telefax: +45 8942 3255
Internet: BRICS@brics.dk

BRICS publications are in general accessible through the World Wide Web and anonymous FTP through these URLs:

http://www.brics.dk
ftp://ftp.brics.dk

This document in subdirectory RS/04/20/

From Natural Semantics to Abstract Machines^{∗}

Mads Sig Ager BRICS^{†} Department of Computer Science University of Aarhus^{‡}

October 2004

Abstract

We describe how to construct correct abstract machines from the class of L-attributed natural semantics introduced by Ibraheem and Schmidt at HOOTS 1997. The construction produces stack-based abstract machines where the stack contains evaluation contexts. It is defined directly on the natural semantics rules. We formalize it as an extraction algorithm and we prove that the algorithm produces abstract machines that are equivalent to the original natural semantics. We illustrate the algorithm by extracting abstract machines from natural semantics for call-by-value, call-by-name, and call-by-need evaluation of lambda terms.

∗ Appears in Etalle, editor, Pre-proceedings of the International Symposium on Logicbased Program Synthesis and Transformation, LOPSTR 2004, pages 260-277.

† Basic Research in Computer Science (www.brics.dk), funded by the Danish National Research Foundation.

‡ IT-parken, Aabogade 34, DK-8200 Aarhus N, Denmark.

Email: mads@brics.dk

Contents

1 Introduction 3

2 From natural semantics to abstract machines 3 2.1 L-attributed natural semantics . . . . . . . . . . . . . . . . . . . 4 2.2 Abstract-machine extraction . . . . . . . . . . . . . . . . . . . . . 5 2.3 Correctness of the extraction . . . . . . . . . . . . . . . . . . . . 7

3 Applications 11 3.1 Call-by-value evaluation of λ-terms . . . . . . . . . . . . . . . . . 12 3.2 Call-by-name evaluation of λ-terms . . . . . . . . . . . . . . . . . 13 3.3 Call-by-need evaluation of λ-terms . . . . . . . . . . . . . . . . . 14 3.4 Other applications . . . . . . . . . . . . . . . . . . . . . . . . . . 16

4 Limitations 16

5 Related work 17

6 Conclusion 19

1 Introduction

Abstract machines have been widely used in the implementation of programming languages [7]. Most of them have been invented from scratch and subsequently been proved to correctly implement the specification of a programming language [11]. Some of them have been derived from the specification of a programming language using some formal system [10, 17]. Most of these derivations use ad hoc derivation steps and are fairly complicated.

In this work we present a simple approach to the construction of correct abstract machines from natural semantics descriptions. At HOOTS 1997 Ibraheem and Schmidt introduced a restricted class of natural semantics called Lattributed natural semantics [12]. The class of L-attributed natural semantics is restricted to have a left-to-right ordering on the premises of each rule ensuring that a proof search using the rules can be performed as left-to-right tree traversals. We observe that for the class of L-attributed natural semantics it is possible to directly extract abstract machines from the natural semantics rules. The extracted machines are stack based and the stack contains evaluation contexts. We formalize this observation as an extraction algorithm and we prove that the algorithm produces abstract machines that are equivalent to the natural semantics.

The class of L-attributed natural semantics is large, containing for instance semantics for pure functional languages, impure functional languages, and imperative languages. The extraction algorithm makes it possible to mechanically extract abstract machines that are correct by construction from these semantics. We illustrate the extraction algorithm by extracting abstract machines from Lattributed natural semantics for call-by-value, call-by-name, and call-by-need evaluation of λ-terms.

The rest of this article is organized as follows. We first define the class of L-attributed natural semantics (Section 2.1). We next define an algorithm for extracting abstract machines from L-attributed natural semantics (Section 2.2) and prove its correctness (Section 2.3). We then consider applications of the extraction (Section 3). Finally, we consider limitations of the approach (Section 4), review related work (Section 5), and conclude (Section 6).

2 From natural semantics to abstract machines

We consider operational semantics for languages consisting of terms. Terms are inductively constructed from atomic terms using term constructors. Other than that, the terms are left unspecified. Values and environments are left unspecified.

• t ∈ Terms,

• op ∈ Term constructors,

• v ∈ Values, • ρ ∈ Environments,

• σ ∈ Stacks.

We use the notation v : σ for the stack σ with the value v added as the top element. We use subscripting (t_{i}) and primes (t′) to distinguish different occurrences of the meta variables.

2.1 L-attributed natural semantics

In this section we present a restricted class of natural semantics called Lattributed natural semantics. The definition below is essentially identical to the definition of Ibraheem and Schmidt [12]. Similar restrictions on the format of natural semantics rules can be found in Hannan and Miller’s work on deriving abstract machines from operational semantics using proof-theoretic methods [10].

Definition 1 (L-attributed natural semantics) A natural semantics is Lattributed if it consists of rules of the form:

\frac{ρ_{1} ⊢ t′_{1} ⇓ v_{1}  ρ_{2} ⊢ t′_{2} ⇓ v_{2}  …  ρ_{m} ⊢ t′_{m} ⇓ v_{m}}{ρ_{0} ⊢ op(t_{1}, …, t_{n}) ⇓ v_{m+1}}  (r)

where \begin{aligned}ρ_{i} & = & fr^{ρ_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ t′_{i} & = & fr^{t_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ v_{m+1} & = & fr^{val}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{m}, v_{1}, …, v_{m}) \end{aligned}

for some partial functions fr^{ρ_{i}}, fr^{t_{i}}, and fr^{val}with 1 ≤ i ≤ m.

Rules with no premises (m = 0) are called axiom rules and rules with at least one premise (m > 0) are called non-axiom rules. The number of premises m of a rule is not related to the number of subterms n of the term in the conclusion of the rule as illustrated by the following examples:

• A semantics for a language of boolean-valued terms might contain a negation term constructor ¬t with one subterm. The natural semantics rule for the evaluation of ¬t would have one premise stating that the subterm t evaluates to a boolean b. The value in the conclusion of the rule would then be ¬b. In this case the number of premises equals the number of subterms.

• For a language with if -expressions the number of premises will be less than the number of subterms in rules for the if term constructor if t_{0} then t_{1} else t_{2}. There will be one premise for the evaluation of the first subterm t_{0} and one premise for the evaluation of either t_{1} or t_{2}.

• A natural semantics for call-by-value evaluation of λ-terms contains a rule for the application term constructor t_{0} t_{1} with two subterms. This rule has three premises: the evaluation of t_{0} to a function value, the evaluation of t_{1} to an argument value, and the evaluation of the application of the function value to the argument value. In this case the number of premises is greater than the number of subterms.

Compared to Kahn’s original definition of natural semantics [13], an Lattributed natural semantics is restricted to working on ternary relations relating a term and an environment to a value. The restriction to ternary relations is not a serious restriction: environments, terms, and values are left unspecified, so all three components can have structure. In Kahn’s format, each rule has an unordered collection of premises and the rule may have conditions. The L-attributed rules instead have a left-to-right ordering on the premises. This ordering is captured in the definition by ensuring that each of the environments ρ_{i}, terms t_{i}, and values v_{i} can be computed from the previous environments, terms, and values. Furthermore, the rules do not have explicit conditions. Conditions are encoded as part of the functional dependencies fr^{t_{i}}, fr^{ρ_{i}}, and fr^{val} between environments, terms, and values. Therefore, the functions giving the dependencies are partial functions and a rule only applies if the dependency functions are defined for the given arguments.

Enforcing a left-to-right ordering on the premises of the rules ensures that if the semantics is deterministic, a proof search using the rules can be performed as a single left-to-right depth-first traversal. Therefore, if the semantics is deterministic, the proof search can be implemented as a recursively defined evaluator in a functional language. For the rest of the development in this article we do not assume that the semantics is deterministic.

2.2 Abstract-machine extraction

We now show how to extract an abstract machine directly from L-attributed natural semantics rules. The abstract machines we consider are state-transition systems operating on three types of states:

1. Triples (t, ρ, σ)_{E} consisting of a term, an environment, and a stack. States of this form correspond to evaluating the term t in the environment ρ and stack σ.

2. Pairs (σ, v)_{A} consisting of a stack and a value. States of this form correspond to ‘applying’ the stack σ to the value v.

3. Values v representing the final state of a computation.

Before defining the extraction, we introduce a bit of notation. Given an L-attributed natural semantics rule of the form

\frac{ρ_{1} ⊢ t′_{1} ⇓ v_{1}  ρ_{2} ⊢ t′_{2} ⇓ v_{2}  …  ρ_{m} ⊢ t′_{m} ⇓ v_{m}}{ρ_{0} ⊢ op(t_{1}, …, t_{n}) ⇓ v_{m+1}}  (r)

where \begin{aligned}ρ_{i} & = & fr^{ρ_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ t′_{i} & = & fr^{t_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ v_{m+1} & = & fr^{val}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{m}, v_{1}, …, v_{m}) \end{aligned}

for 1 ≤ i ≤ m, we define the tuples r_{j}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j}}, \overline{v_{1}}, …, \overline{v_{j−1}}] for each 1 ≤ j ≤ m. The overlining of terms, environments, and values indicates that the terms, environments, and values are only present in the tuple if they are used by dependency functions fr^{ρ_{k}} or fr^{t_{k}} for k > j or by fr^{val}. A term, environment, or value is used by a later dependency function if the corresponding variable occurs free in the body of one of these functions. For such a tuple, we define the application f(\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j}}, \overline{v_{1}}, …, \overline{v_{j−1}}, v_{j}) to be the application of the function f to the elements that are actually present in the tuple and a value supplying dummy arguments for the elements not present in the tuple. Supplying dummy arguments makes sense since they will not be used—if they were used, there would be a value corresponding to the overlined variable in the tuple.

With these notational conventions in place, we are ready to define the extraction of an abstract machine from an L-attributed natural semantics.

Definition 2 (Extracted abstract machine) Given an L-attributed natural semantics where each rule has a distinct name, define the extracted abstract machine consisting of the following transition rules:

1. An unload rule to terminate the computation:

(σ_{0}, v)_{A} → v

where σ_{0} is the empty stack.

2. For each axiom in the L-attributed natural semantics

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v  (r)

the rule:

(op(t_{1}, …, t_{n}), ρ, σ)_{E} → (σ, v)_{A}

where v = fr^{val}(t_{1}, …, t_{n}, ρ).

3. For each non-axiom rule in the L-attributed natural semantics

\frac{ρ_{1} ⊢ t′_{1} ⇓ v_{1}  ρ_{2} ⊢ t′_{2} ⇓ v_{2}  …  ρ_{m} ⊢ t′_{m} ⇓ v_{m}}{ρ_{0} ⊢ op(t_{1}, …, t_{n}) ⇓ v_{m+1}}  (r)

where \begin{aligned}ρ_{i} & = & fr^{ρ_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ t′_{i} & = & fr^{t_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ v_{m+1} & = & fr^{val}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{m}, v_{1}, …, v_{m}) \end{aligned}

for 1 ≤ i ≤ m, the rules:

• Initial evaluation rule:

(op(t_{1}, …, t_{n}), ρ_{0}, σ)_{E} → (t′_{1}, ρ_{1}, r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ)_{E}

where t′_{1} = fr^{t_{1}}(t_{1}, …, t_{n}, ρ_{0}) and ρ_{1} = fr^{ρ_{1}}(t_{1}, …, t_{n}, ρ_{0}).

• Stack application rules for 1 ≤ i ≤ m − 1:

\begin{matrix}(r_{i}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{i}}, \overline{v_{1}}, …, \overline{v_{i−1}}] : σ, v_{i})_{A} → \\ (t′_{i+1}, ρ_{i+1}, r_{i+1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{i+1}}, \overline{v_{1}}, …, \overline{v_{i}}] : σ)_{E} \end{matrix}

where \begin{aligned}t′_{i+1} & = & fr^{t_{i+1}}(\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{i}}, \overline{v_{1}}, …, \overline{v_{i−1}}, v_{i}) \\ ρ_{i+1} & = & fr^{ρ_{i+1}}(\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{i}}, \overline{v_{1}}, …, \overline{v_{i−1}}, v_{i}). \end{aligned} and

• Final stack application rule:

(r_{m}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{m}}, \overline{v_{1}}, …, \overline{v_{m−1}}] : σ, v_{m})_{A} → (σ, v_{m+1})_{A}

where v_{m+1} = fr^{val}(\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{m}}, \overline{v_{1}}, …, \overline{v_{m−1}}, v_{m}).

The stack introduced by the extraction algorithm is a stack of evaluation contexts. The extraction is therefore a new way of constructing evaluation contexts in the style of Felleisen [8]. (Our previous work on deriving abstract machines by continuation-passing style transforming and defunctionalizing evaluators provided another construction of evaluation contexts as defunctionalized continuations [1, 6].)

2.3 Correctness of the extraction

The extraction of Definition 2 is partially correct with respect to the original L-attributed natural semantics. The correctness is partial in the sense that we only consider finite derivations, i.e., convergent computations.

Theorem 1 (Equivalence) An L-attributed natural semantics and the extracted abstract machine are equivalent. For all term constructors op, terms t_{1}, …, t_{n}, environments ρ, and values v:

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v ⇒ (op(t_{1}, …, t_{n}), ρ, σ_{0})_{E} →^{∗} v

and

(op(t_{1}, …, t_{n}), ρ, σ_{0})_{E} →^{k} v ⇒ ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v

for some finite k > 0, where σ_{0} is the empty stack.

In order to prove Theorem 1 we prove two lemmas that each imply one part of the equivalence.

Lemma 1 For all term constructors op, terms t_{1}, …, t_{n}, environments ρ, stacks σ, and values v:

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v ⇒ (op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{∗} (σ, v)_{A}.

Proof: By induction on the height of the derivation of

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v

Assume that the last rule used in the derivation was an axiom of the form

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v  (r)

then by definition the extracted abstract machine contains the rule

(op(t_{1}, …, t_{n}), ρ, σ)_{E} → (σ, v)_{A}

where v = fr^{val}(t_{1}, …, t_{n}, ρ_{0}) which is what we needed to show.

Assume that the last rule used in the derivation was a non-axiom rule of the form

\frac{ρ_{1} ⊢ t′_{1} ⇓ v_{1}  ρ_{2} ⊢ t′_{2} ⇓ v_{2}  …  ρ_{m} ⊢ t′_{m} ⇓ v_{m}}{ρ_{0} ⊢ op(t_{1}, …, t_{n}) ⇓ v_{m+1}}  (r)

where \begin{aligned}ρ_{i} & = & fr^{ρ_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ t′_{i} & = & fr^{t_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ v_{m+1} & = & fr^{val}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{m}, v_{1}, …, v_{m}). \end{aligned}

By inversion we know that each of the premises holds and therefore by the induction hypothesis for all 1 ≤ i ≤ m

(t′_{i}, ρ_{i}, σ)_{E} →^{∗} (σ, v_{i})_{A}

for all stacks σ. For each 1 ≤ j ≤ m, we prove that

(op(t_{1}, …, t_{n}), ρ_{0}, σ)_{E} →^{∗} (r_{j}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j}}, \overline{v_{1}}, …, \overline{v_{j−1}}] : σ, v_{j})_{A}

by induction on j.

Base case: j = 1 and by definition of the extracted abstract machine there is an initial evaluation rule such that

(op(t_{1}, …, t_{n}), ρ_{0}, σ)_{E} → (t′_{1}, ρ_{1}, r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ)_{E}.

By the outer induction hypothesis on the premises of the L-attributed natural semantics rule, the following derivation exists:

\begin{aligned}(op(t_{1}, …, t_{n}), ρ_{0}, σ)_{E} & → & (t′_{1}, ρ_{1}, r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ)_{E} \\ & →^{∗} & (r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ, v_{1})_{A}. \end{aligned}

Induction case: j > 1. By the induction hypothesis on j − 1 we can derive

(op(t_{1}, …, t_{n}), ρ_{0}, σ)_{E} →^{∗} (r_{j−1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j−1}}, \overline{v_{1}}, …, \overline{v_{j−2}}] : σ, v_{j−1})_{A}.

By definition the extracted abstract machine contains the rule

\begin{matrix}(r_{j−1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j−1}}, \overline{v_{1}}, …, \overline{v_{j−2}}] : σ, v_{j−1})_{A} → \\ (t′_{j}, ρ_{j}, r_{j}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j}}, \overline{v_{1}}, …, \overline{v_{j−1}}] : σ)_{E}. \end{matrix}

By the outer induction hypothesis on the premises of the L-attributed natural semantics rule, the following holds:

\begin{matrix}(t′_{j}, ρ_{j}, r_{j}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j}}, \overline{v_{1}}, …, \overline{v_{j−1}}] : σ)_{E} →^{∗} \\ (r_{j}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{j}}, \overline{v_{1}}, …, \overline{v_{j−1}}] : σ, v_{j})_{A}. \end{matrix}

Putting these parts together finishes the subproof.

By what we have just proved with j = m combined with the final stack application rule of the extracted abstract machine we have the following derivation

\begin{aligned}(op(t_{1}, …, t_{n}), ρ, σ)_{E} & →^{∗} & (r_{m}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{m}}, \overline{v_{1}}, …, \overline{v_{m−1}}] : σ, v_{m})_{A} \\ & → & (σ, v_{m+1})_{A} \end{aligned}

which concludes the proof. □

Setting σ = σ_{0}, the empty stack, in Lemma 1 we obtain one direction of Theorem 1.

Lemma 2 For all term constructors op, terms t_{1}, …, t_{n}, environments ρ, stacks σ, and values v, if

(op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{k} v

for a finite k > 0 then

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v′

for some value v′ and there exists a prefix of the abstract machine derivation of length a < k such that

(op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{a} (σ, v′)_{A}.

Proof: By induction on the length k of the derivation.

Base case: k = 2. The minimum length of a derivation of the extracted abstract machine is two steps, and the derivation has the form:

(op(t_{1}, …, t_{n}), ρ, σ_{0})_{E} → (σ_{0}, v)_{A} → v

where σ_{0} is the empty stack. The first step of this derivation is only possible for a rule in the extracted abstract machine that corresponds to an axiom in the L-attributed natural semantics. Since such a rule exists in the extracted abstract machine, the following axiom must be a part of the natural semantics:

ρ ⊢ op(t_{1}, …, t_{n}) ⇓ v

Setting a = 1 finishes this case.

Induction case: k > 2. Since the number of steps in the abstract-machine derivation is larger than two, the first rule used in the derivation was extracted from a natural semantics rule with m ≥ 1 premises:

\frac{ρ_{1} ⊢ t′_{1} ⇓ v_{1}  ρ_{2} ⊢ t′_{2} ⇓ v_{2}  …  ρ_{m} ⊢ t′_{m} ⇓ v_{m}}{ρ_{0} ⊢ op(t_{1}, …, t_{n}) ⇓ v_{m+1}}  (r)

where \begin{aligned}ρ_{i} & = & fr^{ρ_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ t′_{i} & = & fr^{t_{i}}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{i−1}, v_{1}, …, v_{i−1}) \\ v_{m+1} & = & fr^{val}(t_{1}, …, t_{n}, ρ_{0}, …, ρ_{m}, v_{1}, …, v_{m}). \end{aligned}

We start by proving that for all 1 ≤ i ≤ m there exists a prefix of the abstract machine derivation of length a_{i} < k − 1 such that

(op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{a_{i}} (r_{i}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{i}}, \overline{v_{1}}, …, \overline{v_{i−1}}] : σ, v_{i})_{A}

and

ρ_{i} ⊢ t′_{i} ⇓ v_{i}

for some value v_{i}. The proof is by induction on i.

Base case: i = 1. The derivation of length k has the following form

(op(t_{1}, …, t_{n}), ρ, σ)_{E} → (t′_{1}, ρ_{1}, r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ)_{E} →^{k−1} v

By the outer induction hypothesis on k − 1

ρ_{1} ⊢ t′_{1} ⇓ v_{1}

and there exists a prefix of the abstract machine derivation of length p < k − 1 such that

(t′_{1}, ρ_{1}, r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ)_{E} →^{p} (r_{1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, \overline{ρ_{1}}] : σ, v_{1})_{A}.

Since the stack is non-empty, a final state cannot be reached in less than two steps, so we know that p < k−2. Letting a_{1} = p+1 finishes this case.

Inductive case: i = t + 1 for some t ≥ 1. By the induction hypothesis on t

(op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{a_{t}} (r_{t}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{t}}, \overline{v_{1}}, …, \overline{v_{t−1}}] : σ, v_{t})_{A}

for some a_{t} < k − 1. By definition, the extracted abstract machine contains the stack application rule

\begin{matrix}(r_{t}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{t}}, \overline{v_{1}}, …, \overline{v_{t−1}}] : σ, v_{t})_{A} → \\ (t′_{t+1}, ρ_{t+1}, r_{t+1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{t+1}}, \overline{v_{1}}, …, \overline{v_{t}}] : σ)_{E}. \end{matrix}

We have that

(t′_{t+1}, ρ_{t+1}, r_{t+1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{t+1}}, \overline{v_{1}}, …, \overline{v_{t}}] : σ)_{E} →^{k−(a_{t}+1)} v

and by the outer induction hypothesis

ρ_{t+1} ⊢ t′_{t+1} ⇓ v_{t+1}

for some v_{t+1} and there exists a prefix of the abstract machine derivation of length p < k − (a_{t} + 1) such that

\begin{matrix}(t′_{t+1}, ρ_{t+1}, r_{t+1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{t+1}}, \overline{v_{1}}, …, \overline{v_{t}}] : σ)_{E} →^{p} \\ (r_{t+1}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{t+1}}, \overline{v_{1}}, …, \overline{v_{t}}] : σ, v_{t+1})_{A} \end{matrix}

Set a_{t+1} = a_{t} + p + 1 < k. Since the stack is non-empty in the configuration after a_{t+1} steps, a final state cannot be reached in less than two steps. Therefore a_{t+1} < k − 1 which finishes the case.

We have just proved that for each 1 ≤ i ≤ m, ρ_{i} ⊢ t′_{i} ⇓ v_{i}. Therefore, we can build a derivation of ρ_{0} ⊢ op(t_{1}, …, t_{n}) ⇓ v using the natural semantics rule from which the first step in the abstract-machine derivation was extracted. We have also proved that there exists a prefix of the abstract machine derivation of the form

\begin{matrix}(op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{a_{m}} \\ (r_{m}[\overline{t_{1}}, …, \overline{t_{n}}, \overline{ρ_{0}}, …, \overline{ρ_{m}}, \overline{v_{1}}, …, \overline{v_{m−1}}] : σ, v_{m})_{A} \end{matrix}

where a_{m} < k − 1. Combining this with the final stack application rule extracted from the natural semantics rule yields the prefix

(op(t_{1}, …, t_{n}), ρ, σ)_{E} →^{a_{m}+1} (σ, v)_{A}

of length a_{m} + 1 < k which finishes the proof.

□

Setting σ = σ_{0}, the empty stack, in Lemma 2 we obtain the second direction of Theorem 1. Therefore, the proof of Theorem 1 is a straightforward corollary of Lemmas 1 and 2.

3 Applications

In Section 2 we have shown that abstract machines can be extracted directly from L-attributed natural semantics. In this section we illustrate this extraction.

3.1 Call-by-value evaluation of λ-terms

We first consider the following standard natural semantics for call-by-value evaluation of λ-terms. Terms are λ-calculus terms: variables x, abstractions λx.t, and applications t_{0} t_{1}. Values are closures ⟨x, t, ρ⟩, which are triples containing a variable, a term, and an environment. An environment ρ is a partial function from variables to values.

ρ ⊢ x ⇓ ρ(x)  (Var)
ρ ⊢ λx.t ⇓ ⟨x, t, ρ⟩  (Lam)

\frac{ρ ⊢ t_{0} ⇓ ⟨x, t′, ρ′⟩  ρ ⊢ t_{1} ⇓ v′  ρ′[x ↦ v′] ⊢ t′ ⇓ v}{ρ ⊢ t_{0} t_{1} ⇓ v}  (App)

This natural semantics is obviously L-attributed: there is a left-to-right ordering of the premises of each rule, and the dependency of later terms, environments, and values on previous terms, environments and values can be easily specified as functions. Therefore, we can apply the extraction of Section 2.2 to obtain an abstract machine. The resulting abstract machine is as follows:

1. Unload rule:

(σ_{0}, v)_{A} → v

2. Axiom rules:

(x, ρ, σ)_{E} → (σ, ρ(x))_{A}
(λx.t, ρ, σ)_{E} → (σ, ⟨x, t, ρ⟩)_{A}

3. Non-axiom rules:

(t_{0} t_{1}, ρ, σ)_{E} → (t_{0}, ρ, App_{1}[t_{1}, ρ] : σ)_{E}
(App_{1}[t_{1}, ρ] : σ, v_{1})_{A} → (t_{1}, ρ, App_{2}[v_{1}] : σ)_{E}
(App_{2}[⟨x, t, ρ′⟩] : σ, v_{2})_{A} → (t, ρ′[x ↦ v_{2}], App_{3}[ ] : σ)_{E}
(App_{3}[ ] : σ, v)_{A} → (σ, v)_{A}

We identify this machine as a variant of the CEK machine [9]. The only difference is that the extracted machine pushes an empty evaluation context on the stack in the function application rule. This evaluation context is removed from the stack by the last rule and the value is passed unchanged to the next evaluation context. Our extracted machine is therefore not properly tail-recursive. We are currently extending our extraction to identify when the last evaluation context is empty and the fr^{val} is the ‘identity function’ that just returns the value of the last premise of a rule. In this case we could avoid adding an evaluation context to the stack and not define the final stack application rule, which would correspond to a tail-call optimization.

3.2 Call-by-name evaluation of λ-terms

The following natural semantics is the standard semantics for call-by-name evaluation of λ-terms. As in Section 3.1, terms are λ-calculus terms: variables x, abstractions λx.t, and applications t_{0} t_{1}. Values are closures ⟨x, t, ρ⟩ which are triples containing a variable, a term, and an environment. An environment ρ is a partial function from variables to pairs (t, ρ) consisting of a term and an environment.

\frac{ρ(x) = (t, ρ′)  ρ′ ⊢ t ⇓ v}{ρ ⊢ x ⇓ v}  (Var)

ρ ⊢ λx.t ⇓ ⟨x, t, ρ⟩  (Lam)

\frac{ρ ⊢ t_{0} ⇓ ⟨x, t, ρ′⟩  ρ′[x ↦ (t_{1}, ρ)] ⊢ t ⇓ v}{ρ ⊢ t_{0} t_{1} ⇓ v}  (App)

This natural semantics is L-attributed. It is easy to see that the Lam and App rules fit the format of L-attributed natural semantics, but the Var rule deserves a bit of explanation. The rule has one premise and a condition. Putting it into L-attributed form, we have a rule of the form:

\frac{ρ_{1} ⊢ t_{1} ⇓ v}{ρ_{0} ⊢ x ⇓ v}  (Var’)

The condition ρ(x) = (t, ρ′) of the Var rule needs to be captured in the functional dependencies fVar’^{t_{1}} and fVar’^{ρ_{1}}. The following functions capture the condition:

fVar’^{t_{1}}(x, ρ_{0}) = \{ \begin{matrix}t & if ρ_{0}(x) = (t, ρ′) \\ undefined & otherwise \end{matrix}

fVar’^{ρ_{1}}(x, ρ_{0}) = \{ \begin{matrix}ρ′ & if ρ_{0}(x) = (t, ρ′) \\ undefined & otherwise \end{matrix}

If the dependency functions are undefined for some arguments, the condition is not true, and the rule does not apply.

With this explanation, we see that the natural semantics is L-attributed, and we can apply the extraction of Section 2.2 to obtain an abstract machine. The resulting abstract machine is as follows:

1. Unload rule:

(σ_{0}, v)_{A} → v

2. Axiom rules:

(λx.t, ρ, σ)_{E} → (σ, ⟨x, t, ρ⟩)_{A}

3. Non-axiom rules:

(x, ρ, σ)_{E} → (t, ρ′, Var_{1}[ ] : σ)_{E} if ρ(x) = (t, ρ′)
(Var_{1}[ ] : σ, v)_{A} → (σ, v)_{A}
(t_{0} t_{1}, ρ, σ)_{E} → (t_{0}, ρ, App_{1}[t_{1}, ρ] : σ)_{E}
(App_{1}[t, ρ] : σ, ⟨x, t′, ρ′⟩)_{A} → (t′, ρ′[x ↦ (t, ρ)], App_{2}[ ] : σ)_{E}
(App_{2}[ ] : σ, v)_{A} → (σ, v)_{A}

As in the call-by-value case, the machine is not properly tail recursive. Both the Var_{1} and App_{2} evaluation contexts are empty, and when given a value they both pass it directly to the next evaluation context on the stack. We are currently extending the extraction algorithm to avoid generating these empty evaluation contexts. Such an extension would correspond to a tail-call optimization.

One might hope to obtain the Krivine machine [5] from the call-by-name semantics. However, the extraction always gives two transition relations: an eval transition relation where the left-hand side of the transitions are triples and an apply transition relation where the left-hand side of the transitions are pairs. The Krivine machine only has one transition relation, so we cannot directly obtain it by the extraction of Section 2.2. It is easy to transform the machine obtained into the Krivine machine, but in its current form the extraction does not give it directly.

3.3 Call-by-need evaluation of λ-terms

Launchbury gave a natural semantics for call-by-need evaluation of λ-terms [14] which Sestoft used as the starting point of his derivation of a lazy abstract machine [17]. Before deriving an abstract machine, Sestoft changed the renaming behaviour of Launchbury’s natural semantics. In this section we start from Sestoft’s revised version of Launchbury’s natural semantics and we apply the extraction algorithm to obtain a lazy abstract machine.

The terms of the natural semantics are so-called normalized λ-terms: variables x, abstractions λx.t, applications t x, and let-expressions of the form let x_{1} = t_{1}, …, x_{n} = t_{n} in t (we use the abbreviation let {x_{i} = t_{i}} in t for such let-expressions). In normalized λ-terms the argument in an application is restricted to being a variable and non-trivial arguments are bound in letexpressions. The bindings in a let-expression are mutually recursive.

The natural semantics is substitution based and we write t[t′/x] for the naive simultaneous substitution of t′ for all free occurrences of x in t. We let Γ, Δ, and Θ denote stores, which are partial functions from variables to terms, and A denote a set of variables. Following Sestoft, we distinguish between two types of variables: pointers p denoting an element in the store and let- or λ-bound variables x. Sestoft’s revised version of Launchbury’s natural semantics is as follows^{1}:

1We have slightly reformatted Sestoft’s rules by writing (Γ, A) ⊢ t ⇓ (Δ, w) instead of Γ : t ⇓_{A} Δ : w. This reformatting is inessential, but it makes it easier to realize that the semantics is L-attributed.

\frac{(Γ, A ∪ \{p\}) ⊢ t ⇓ (Δ, w)}{(Γ[p ↦ t], A) ⊢ p ⇓ (Δ[p ↦ w], w)}  (Var)

(Γ, A) ⊢ λx.t ⇓ (Γ, λx.t)  (Lam)

\frac{(Γ, A) ⊢ t ⇓ (Δ, λy.t′)  (Δ, A) ⊢ t′[p/y] ⇓ (Θ, w)}{(Γ, A) ⊢ t p ⇓ (Θ, w)}  (App)

\frac{(Γ[p_{i} ↦ t̂_{i}], A) ⊢ t̂⇓ (Δ, w)}{(Γ, A) ⊢ let \{x_{i} = t_{i}\} in t ⇓ (Δ, w)}  (Let)

In the Let rule, the p_{i} are fresh variables in the sense that they do not occur in Γ, A, or let {x_{i} = t_{i}} in t. The notation t̂ is shorthand for the substitution t[p_{1}/x_{1}, …, p_{n}/x_{n}].

The restriction to normalized λ-terms together with the above rules for letexpressions and variables ensures sharing of argument expressions, i.e., callby-need evaluation. In normalized terms, non-trivial argument expressions are let-bound. The Let rule allocates such arguments in the store and the Var rule updates the store with the value of the expression ensuring that the argument expression is only evaluated once.

When evaluating variables using the Var rule, the variable that is currently being evaluated is removed from the store to rule out recursions where the evaluation of a variable requires the value of the variable itself. The variable removed from the store is added again once its value is known. The set of variables A records the variables that are left out of the store at any point in the derivation. In the Let rule the freshness requirement on the variables can be checked locally by inspecting the store and the set of variables currently left out of the store.

The natural semantics is L-attributed. Environments are pairs consisting of a store and a set of variables, terms are normalized λ-terms, and values are pairs consisting of a store and a term. There is a clear left-to-right ordering on the premises as also identified by Sestoft [17, Page 5]:

“[the rules are] essentially sequential: to build a derivation tree, one must determine the final heap of any left-hand premise before proceeding to any right-hand premise.”

Applying the extraction algorithm to the natural semantics yields the following abstract machine:

1. Unload rule:

(σ_{0}, v)_{A} → v

2. Axiom rules:

(λx.t, (Γ, A), σ)_{E} → (σ, (Γ, λx.t))_{A}

3. Non-axiom rules:

(p, (Γ[p ↦ t], A), σ)_{E} → (t, (Γ, A ∪ {p}), Var_{1}[p] : σ)_{E}
(Var_{1}[p] : σ, (Δ, w))_{A} → (σ, (Δ[p ↦ w], w))_{A}
(t p, (Γ, A), σ)_{E} → (t, (Γ, A), App_{1}[p, (Γ, A)] : σ)_{E}

(App_{1}[p, (Γ, A)] : σ, (Δ, λy.t))_{A} → (t[p/y], (Δ, A), App_{2}[ ] : σ)_{E}

(App_{2}[ ] : σ, v)_{A} → (σ, v)_{A}

(let {x_{i} = t_{i}} in t, (Γ, A), σ)_{E} → (t̂, (Γ[p_{i} ↦ t̂_{i}], A), Let_{1}[ ] : σ)_{E}

(Let_{1}[ ] : σ, v)_{A} → (σ, v)_{A}

The transition rule for let-expressions has the same restrictions as the Let rule of the natural semantics: each p_{i} is a fresh variable in the sense that they do not occur in Γ, A, or let {x_{i} = t_{i}} in t and the notation t̂ is shorthand for the substitution t[p_{1}/x_{1}, …, p_{n}/x_{n}].

This abstract machine is essentially Sestoft’s mark 1 machine. Our machine contains two transition relations and is not properly tail-recursive whereas Sestoft’s is a variant of the Krivine machine with only one transition relation. Sestoft notices that when the machine adds a variable to the variable set A, the same variable is also added to the stack. Therefore, the variable set is not needed in the machine since the freshness restriction in the transition rule for let-expressions can be checked using the stack instead of the set of variables.

3.4 Other applications

In Sections 3.1, 3.2, and 3.3 we have constructed abstract machines from natural semantics for call-by-value, call-by-name, and call-by-need evaluation of λ-terms. Many natural semantics fit the format of L-attributed natural semantics. For instance, one can give an L-attributed natural semantics for λ-calculus extended with exceptions, state, and combinations of exceptions and state and therefore stack inspection can be specified with an L-attributed natural semantics [2]. Simple imperative languages can also be given L-attributed natural semantics. From each of these natural semantics, the extraction algorithm yields a correct abstract machine.

4 Limitations

The extraction presented in Section 2.2 has three main limitations:

1. The extraction algorithm is restricted to L-attributed natural semantics, which rules out some natural semantics. For instance, the mini-ML natural semantics of Kahn is not L-attributed because of cyclic dependencies used to model recursive bindings [13].

2. If an L-attributed natural semantics contains multiple rules for the same term, the abstract machine resulting from the extraction is non-deterministic.

3. As explained in Sections 3.1 and 3.2, the extraction algorithm does not give properly tail-recursive abstract machines.

We are currently working on extending both the class of L-attributed natural semantics and the extraction algorithm to address these limitations.

Another limitation of the approach is that we only consider partial correctness in the sense that we only consider convergent computations. In order to address the issue of divergent computations we would have to provide a means of reasoning about divergent computations in the framework of natural semantics. Ibraheem and Schmidt considered divergent computations by applying a coinductive interpretation of some of the natural semantics rules [12]. We leave such a generalization for future work.

5 Related work

Defining natural semantics and abstract machines separately and then proving that they coincide is standard. Most semantics textbooks describe both kinds of semantics and show how to relate them [16, 18]. The goal of our work is to mechanize the extraction of abstract machines from natural semantics so that the extracted abstract machines are correct by construction.

In previous work, we have observed that defunctionalized, continuation-pas-sing style evaluators are transition systems, i.e., abstract machines [1, 2, 3, 4, 6]. Starting from an evaluator written in a functional programming language such as ML [15], we (1) transform the evaluator into continuation-passing style to make its flow of control explicit, and (2) defunctionalize the continuations to make them first order, obtaining a stack of evaluation contexts. The result is the MLencoding of an abstract machine, and the correctness of the abstract machine is a corollary of the correctness of the original evaluator and of the program transformations. The evaluators are direct encodings of natural semantics:

[figure: Natural semantics; ML-encoding; Abstract machine; ML-encoding; Eval; _{Eval_{cps}}; _{Eval_{defun}}]

The work presented in this article is a different approach to constructing correct abstract machines from natural-semantics descriptions. We extract a correct abstract machine directly from the natural semantics rules:

\xymatrix{Natural semantics \ar@{-->}[r] & Abstract machine}

The idea of characterizing the left-to-right processing natural semantics in the form of L-attributed natural semantics is due to Ibraheem and Schmidt [12]. The motivation for their definition came from L-attributed grammars. Ibraheem and Schmidt are concerned with reasoning about divergent computations in the framework of natural semantics. To this end, they start from L-attributed natural semantics and generate sets of positive (or convergent) rules and negative (or divergent) rules. Using an inductive interpretation of the positive rules and a coinductive interpretation of the negative rules allows them to reason about divergent computations. In contrast, we only consider convergent computations, and we extract an abstract machine from an L-attributed natural semantics that is equivalent to the natural semantics.

Hannan and Miller derive abstract machines from natural semantics using proof theory [10]. Their derivation consists in encoding a natural semantics in a proof-theoretic meta-language and then carrying out transformations at the meta-language level. In that sense, the work of Hannan and Miller is closely related to our previous work on deriving abstract machine by using standard program transformations on an encoding of a natural semantics in a functional language. One of Hannan and Miller’s derivation steps relies on a left-to-right ordering of the premises of the natural semantics rules. This restriction seems to correspond to our present restriction to L-attributed natural semantics. Hannan and Miller derive abstract machines for call-by-name and call-by-value evaluation of λ-terms. Their starting points, called the N_{0} and V_{0} proof systems, are L-attributed natural semantics. Both natural semantics are very close to the standard ones presented in Sections 3.1 and 3.2. The difference is that λterms are de Bruijn encoded, environments are lists of values, and there are explicit rules for looking up an index in an environment. Applying our extraction to these L-attributes natural semantics yields abstract machines that are very similar to the machines extracted in Sections 3.1 and 3.2.

Kahn introduced natural semantics and presented natural semantics for various aspects of programming languages [13]. For instance, he presented a natural semantics for mini-ML which is almost L-attributed: removing the letrec construct from the language, the semantics is L-attributed and we can extract an abstract machine directly. The problem with the letrec construct is that there is a cyclic dependency between the value of a term and the environment in which the term is evaluated. The environment in which to evaluate the term can therefore not be defined solely as a function of previous terms, environments, and values and therefore the semantics is not L-attributed.

Sestoft derived a lazy abstract machine from Launchbury’s natural semantics for call-by-need evaluation of λ-terms [17]. His derivation consists of a number of intuitive steps and a proof of the correctness of each of the steps. As illustrated in Section 3.3 the extraction algorithm presented in this article applies to the natural semantics and the resulting machine is essentially Sestoft’s mark 1 machine. Sestoft obtained the mark 1 machine by introducing a stack of evaluation contexts and subsequently proving the correctness of the resulting machine. Our present work shows that such a stack introduction can be applied to a wide range of natural semantics and proves the correctness of the stack introduction algorithm once and for all instead of relying on a correctness proof for each machine. Sestoft only uses the mark 1 machine as a stepping stone, and goes on to introduce environments (besides the stores already present), closures, and variable indices. He proves the correctness of the resulting machines.

6 Conclusion

We have presented a simple and mechanical extraction of correct abstract machines from the class of L-attributed natural semantics introduced by Ibraheem and Schmidt. We have formalized this extraction as an extraction algorithm and proved its correctness. The class of L-attributed natural semantics is large, containing semantics for call-by-value, call-by-name, and call-by-need functional languages, as well as imperative languages. For each L-attributed natural semantics the extraction algorithm produces a correct abstract machine.

Acknowledgements. To Olivier Danvy for his encouragement, fruitful discussions, and useful comments. Thanks are also due to Neil Jones, Julia Lawall, Jan Midtgaard, and the anonymous reviewers for their useful comments.

References

[1] Mads Sig Ager, Dariusz Biernacki, Olivier Danvy, and Jan Midtgaard. A functional correspondence between evaluators and abstract machines. In Dale Miller, editor, Proceedings of the Fifth ACM-SIGPLAN International Conference on Principles and Practice of Declarative Programming, pages 8–19. ACM Press, 2003.

[2] Mads Sig Ager, Olivier Danvy, and Jan Midtgaard. A functional correspondence between monadic evaluators and abstract machines for languages with computational effects. Technical Report BRICS RS-03-35, DAIMI, Department of Computer Science, University of Aarhus, Aarhus, Denmark, November 2003. Presented at the 2nd APPSEM II workshop, Talinn, Estonia, April 2004.

[3] Mads Sig Ager, Olivier Danvy, and Jan Midtgaard. A functional correspondence between call-by-need evaluators and lazy abstract machines. Information Processing Letters, 90(5):223–232, 2004.

[4] Dariusz Biernacki and Olivier Danvy. From interpreter to logic engine by defunctionalization. Technical Report BRICS RS-04-5, DAIMI, Department of Computer Science, University of Aarhus, Aarhus, Denmark, March 2004. To appear in the proceedings of the 2003 International Symposium on Logic-based Program Synthesis and Transformation (LOPSTR 2003).

[5] Pierre Crégut. An abstract machine for the normalization of λ-terms. In Proceedings of the 1990 ACM conference on LISP and functional programming, pages 333–340. ACM Press, 1990.

[6] Olivier Danvy. A rational deconstruction of Landin’s SECD machine. Technical Report BRICS RS-03-33, DAIMI, Department of Computer Science, University of Aarhus, Aarhus, Denmark, October 2003.

[7] Stephan Diehl, Pieter Hartel, and Peter Sestoft. Abstract machines for programming language implementation. Future Generation Computer Systems, 16:739–751, 2000.

[8] Matthias Felleisen. The Calculi of λ-v-CS Conversion: A Syntactic Theory of Control and State in Imperative Higher-Order Programming Languages. PhD thesis, Department of Computer Science, Indiana University, Bloomington, Indiana, August 1987.

[9] Matthias Felleisen and Matthew Flatt. Programming languages and lambda calculi. Unpublished lecture notes. http://www.ccs.neu.edu/

home/matthias/3810-w02/readings.html, 1989-2001.

[10] John Hannan and Dale Miller. From operational semantics to abstract machines. Mathematical Structures in Computer Science, 2(4):415–459, 1992.

[11] Thérèse Hardin, Luc Maranget, and Bruno Pagano. Functional runtime systems within the lambda-sigma calculus. Journal of Functional Programming, 1(1):1–100, January 1993.

[12] Husain Ibraheem and David A. Schmidt. Adapting big-step semantics to small-step style: Coinductive interpretations and “higher-order” derivations. In Andrew Gordon, Andrew Pitts, and Carolyn Talcott, editors, Electronic Notes in Theoretical Computer Science, volume 10. Elsevier, 2000.

[13] Gilles Kahn. Natural semantics. In Franz-Josef Brandenburg, Guy Vidal-Naquet, and Martin Wirsing, editors, Proceedings of the 4th Annual Symposium on Theoretical Aspects of Computer Science, volume 247 of Lecture Notes in Computer Science, pages 22–39, Passau, Germany, February 1987. Springer-Verlag.

[14] John Launchbury. A natural semantics for lazy evaluation. In Proceedings of the 20th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, pages 144–154. ACM Press, 1993.

[15] Robin Milner, Mads Tofte, Robert Harper, and David MacQueen. The Definition of Standard ML (Revised). The MIT Press, 1997.

[16] Flemming Nielson and Hanne Riis Nielson. Semantics with Applications. John Wiley & Sons, 1992.

[17] Peter Sestoft. Deriving a lazy abstract machine. Journal of Functional Programming, 7(3):231–264, May 1997.

[18] Glynn Winskel. The Formal Semantics of Programming Languages. Foundation of Computing Series. The MIT Press, 1993.

Recent BRICS Report Series Publications

RS-04-20 Mads Sig Ager. From Natural Semantics to Abstract Machines. October 2004. 21 pp. Presented at the International Symposium on Logic-based Program Synthesis and Transformation, LOP-STR 2004, Verona, Italy, August 26–28, 2004.

RS-04-19 Bolette Ammitzbøll Madsen and Peter Rossmanith. Maximum Exact Satisfiability: NP-completeness Proofs and Exact Algorithms. October 2004. 20 pp.

RS-04-18 Bolette Ammitzbøll Madsen. An Algorithm for Exact Satisfiability Analysed with the Number of Clauses as Parameter. September 2004. 4 pp.

RS-04-17 Mayer Goldberg. Computing Logarithms Digit-by-Digit. September 2004. 6 pp.

RS-04-16 Karl Krukow and Andrew Twigg. Distributed Approximation of Fixed-Points in Trust Structures. September 2004. 25 pp.

RS-04-15 Jesús Fernando Almansa. Full Abstraction of the UC Framework in the Probabilistic Polynomial-time Calculus ppc. August 2004.

RS-04-14 Jesper Makholm Byskov. Maker-Maker and Maker-Breaker Games are PSPACE-Complete. August 2004. 5 pp.

RS-04-13 Jens Groth and Gorm Salomonsen. Strong Privacy Protection in Electronic Voting. July 2004. 12 pp. Preliminary abstract presented at Tjoa and Wagner, editors, 13th International Workshop on Database and Expert Systems Applications, DEXA ’02 Proceedings, 2002, page 436.

RS-04-12 Olivier Danvy and Ulrik P. Schultz. Lambda-Lifting in Quadratic Time. June 2004. 34 pp. To appear in Journal of Functional and Logic Programming. This report supersedes the earlier BRICS report RS-03-36 which was an extended version of a paper appearing in Hu and Rodríguez-Artalejo, editors, Sixth International Symposium on Functional and Logic Programming, FLOPS ’02 Proceedings, LNCS 2441, 2002, pages 134–151.

RS-04-11 Vladimiro Sassone and Pawe� Sobociński. Congruences for Contextual Graph-Rewriting. June 2004. 29 pp.