Defunctionalization, Refunctionalization, and Abstract Machines
Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.
Krivine’s abstract machine is usually presented as a finished object: a set of states and four transitions. With de Bruijn terms
They are recoverable from a program. The claim of this chapter is that the machine above is what a particular evaluator becomes after three mechanical transformations, that each transformation has a correctness statement, and that the transformations can be run backwards. The evaluator exhibits the reduction strategy; the machine exhibits the steps. The development follows Ager, Biernacki, Danvy and Midtgaard (2003), and the two transformations it composes are Reynolds’s defunctionalization (1972) and its left inverse, studied by Danvy and Millikin (2009).
The evaluator
Definition 135.1 — The higher-order call-by-name evaluator¶
Denotable and expressible values are
Referenced from 10 locations
Two properties of definition 135.1 determine everything below. It is compositional: the meaning of a term is built from the meanings of its immediate subterms and nothing else. And it is higher order: both value sets contain functions of the metalanguage. Call by name is visible in one place — the argument of an application is wrapped in a thunk rather than evaluated — and that is the only place a reader must look to see the strategy.
Because a program may diverge, the equations of definition 135.1 define a partial function. Write
Closure conversion
The function spaces of
Proposition 135.3 — Closure conversion is correct¶
Define relations
Referenced from 5 locations
Proof of Proposition 135.3 — Closure conversion is correct
Proof. Forwards, by induction on the derivation of
Index.
Abstraction. Both sides terminate immediately, with
Application. The premise gives
Backwards, the same three cases with the two sides exchanged; the relations are symmetric in the sense that each clause is an “if and only if”. ◻
Definition 135.2 is first order in its data: no value contains a metalanguage function. It is still higher order in its control, because the recursive call in the application clause is not a tail call.
Continuation-passing style
Definition 135.4 — The continuation-passing evaluator¶
Referenced from 11 locations
Every call is now a tail call, which is what makes the next step possible.
Proof of Proposition 135.5 — The transformation is correct
Proof. Both directions by induction on the respective derivations.
Index. Both clauses recur on
Abstraction.
Application. Write
the hypothesis at
;the definition of
;the hypothesis at
;
the calculation is
Defunctionalizing the continuation
The continuation space of definition 135.4 is inhabited by two abstractions:
Proposition 135.7 — Defunctionalization is correct¶
Interpret continuation data by
Referenced from 8 locations
Proof of Proposition 135.7 — Defunctionalization is correct
Proof. Simultaneous induction on the two derivations. The interpretation
The step this proof depends on is that no other abstraction inhabits the continuation space: definition 135.4 builds continuations in exactly two places. If a third were added, the data type would need a third constructor and
Remark 135.8 — The continuation is a stack¶
The data type
Referenced from 2 locations
Theorem 135.9 — The derived machine is Krivine's¶
Identify
Referenced from 5 locations
Proof of Theorem 135.9 — The derived machine is Krivine's
Proof. For the identification: inlining
For the displayed equivalence, compose proposition 135.3, proposition 135.5, proposition 135.7: the first relates
The four questions the opening asked are now answered by the derivation. Three components, because the evaluator has a term, an environment and a continuation. Thunks on the stack, because call by name wraps the argument. The abstraction rule pops onto the environment, because that is the application clause of definition 135.2. And the strategy is call by name, because that is the strategy of definition 135.1.
Exercise 135.1¶
Change one clause of definition 135.1 so that the argument of an application is evaluated before the call, and rerun the three transformations. Give the resulting machine’s states and transitions, and say which of them differ from Krivine’s. (Half a page; the continuation space acquires one more inhabiting abstraction.)
Referenced from 2 locations
Exercise 135.2¶
Add a constant
Referenced from 2 locations
Defunctionalization in general
Construction 135.10 — Defunctionalization¶
Fix a set
introduce a data type with one constructor per abstraction,
;introduce
, dispatching on the constructor;replace each
by ;replace each application
of a value of the function type by .
Referenced from 8 locations
Convention 135.11 — The closure condition¶
Referenced from 4 locations
Convention 135.11 is the hypothesis that makes step 4 well defined, and it is the one that a reader is most likely to skip. Its role is visible in the proof of proposition 135.7: the interpretation
Proposition 135.12 — The condition is not automatic¶
There is a program with two abstractions of one type, one call site, and a choice of
Referenced from 3 locations
Proof of Proposition 135.12 — The condition is not automatic
Proof. Take
Refunctionalization
Defunctionalization has a left inverse. Applying it to an arbitrary first-order program is not possible; applying it to a program in the image of construction 135.10 is mechanical.
Definition 135.13 — Defunctionalized form¶
A program is in defunctionalized form with respect to a data type
exactly one function
of the program eliminates values of , and it does so by a case analysis on the constructor;every other occurrence of
in the program builds a value of it or passes one on; and takes a value of and one further argument, and every call of is saturated.
Referenced from 7 locations
Construction 135.14 — Refunctionalization¶
Given a program in defunctionalized form, replace
Referenced from 6 locations
Theorem 135.15 — Round trip¶
Let
Referenced from 4 locations
Proof of Theorem 135.15 — Round trip
Proof.
For the round trip, follow the three replacements. Refunctionalization sends
The converse composition is not the identity: refunctionalizing a program in defunctionalized form and defunctionalizing the result recovers the program only if the set
Remark 135.16 — Two repairs for a machine that is almost in defunctionalized form¶
Most published abstract machines are not literally in defunctionalized form, and two syntactic changes usually suffice. Disentangling splits a single transition function that dispatches on several components at once into one function per mode of the machine, so that the component playing the role of the continuation is eliminated in one place; this restores clause 1 of definition 135.13. Merging apply functions replaces several functions that each eliminate the same data type by one, restoring clause 1 when disentangling has produced two eliminators for one type. Neither changes the machine’s transitions; both change which function performs them.
Referenced from 5 locations
Example 135.17 — Refunctionalizing a machine¶
Take the call-by-value machine on terms with names, with states
Referenced from 3 locations
Remark 135.18 — Refunctionalizing always yields a continuation-passing program¶
The observation of example 135.17 is general for abstract machines: the component being refunctionalized is the one that says what to do next, so the function it becomes is applied in tail position, and the resulting program is in continuation-passing style. That is a statement about the shape of the output, not a theorem about every machine: a machine whose control component is not in defunctionalized form after the repairs of remark 135.16 is not refunctionalized at all.
Referenced from 2 locations
Exercise 135.3¶
Give an abstract machine with a single transition function that dispatches simultaneously on the term and on the continuation, and show that it fails clause 1 of definition 135.13. Then disentangle it and check that the result satisfies all three clauses.
Referenced from 2 locations
Exercise 135.4¶
Exhibit a first-order program in defunctionalized form whose refunctionalization, when defunctionalized again with a different choice of
Referenced from 2 locations
Limits and seminar
The frozen sources are Reynolds (1972) for defunctionalization, Ager, Biernacki, Danvy and Midtgaard (2003) for the correspondence between evaluators and abstract machines, and Danvy and Millikin (2009) for refunctionalization and the two repairs of remark 135.16. The four evaluators of definition 135.1, definition 135.2, definition 135.4, definition 135.6 and the transition system of theorem 135.9 are theirs. Proposition 135.3, Proposition 135.5, Proposition 135.7 are stated in those papers as corollaries of general correctness results for closure conversion, the continuation-passing transformation and defunctionalization; the proofs written here are local, for the selected evaluator only, and are inductions on the big-step derivations of section 135.1. Proposition 135.12, Theorem 135.15 are local.
Four boundaries. First, nothing here is a general correctness theorem for defunctionalization: proposition 135.7 is about one continuation space with two inhabiting abstractions, and theorem 135.15 is a syntactic round-trip statement, not a semantic one. Second, the source language is the pure untyped lambda calculus; laziness with sharing, mutable state, control operators and data types are all absent, and each changes the derived machine. Third, the correspondence is between an evaluator and a machine, not between a machine and a reduction strategy: no theorem here says that Krivine’s machine implements a named reduction relation on terms. Fourth, a machine that distinguishes an instruction set from the terms it runs — a virtual machine — is outside the correspondence as stated; the derivation produces machines that operate on source terms directly.
[4]
Suggested first pass.
None of these problems is a prerequisite for a later chapter. Begin with exercise 135.5, then complete exercise 135.8.
Exercise 135.5¶
Landin’s machine has four components: a stack, an environment, a control and a dump. Disentangle its transition function into one function per component in control, identify which component is the defunctionalized continuation, and refunctionalize it. State the evaluator you obtain and say in one sentence why it is a continuation-passing program.
Referenced from 3 locations
Exercise 135.6¶
The naive fringe comparison, which flattens both trees and compares the lists, and the iterative one, which walks both trees with an explicit stack, are defunctionalized and refunctionalized counterparts. Write both, exhibit the data type and the apply function that connect them, and check definition 135.13 on the iterative version.
Referenced from 2 locations
Exercise 135.7¶
Extend definition 135.1 with a single mutable cell, threading a store through the evaluator. Rerun the three transformations and give the resulting machine. Then identify the one degree of freedom in the evaluator — the order in which the store and the continuation are threaded — and give the two different machines it produces.
Referenced from 2 locations
Exercise 135.8 — Practical: derive the machine¶
Practical project.defun-derivation Complete project defun-derivation. Implement the evaluators of definition 135.2, definition 135.6 together with the transition system of theorem 135.9, for the de Bruijn source language of this chapter, and a checker that runs a fixed list of closed terms through all three and compares the results. Implement also the two maps between the data type
identity: agree
church-two-succ-zero: agree
call-by-name-discards: agree
krivine-steps: 7
cont-is-stack: ok
The checker is independent evidence on the named inputs. It does not prove proposition 135.3 or proposition 135.5, which relate the two evaluators the implementation does not contain, and it does not implement refunctionalization or the repairs of remark 135.16.