A Rational Deconstruction of Landin's SECD Machine with the J Operator

Landin's SECD machine was the first abstract machine for applicative expressions, i.e., functional programs. Landin's J operator was the first control operator for functional languages, and was specified by an extension of the SECD machine. We present a family of evaluation functions corresponding to this extension of the SECD machine, using a series of elementary transformations (transformation into continu-ation-passing style (CPS) and defunctionalization, chiefly) and their left inverses (transformation into direct style and refunctionalization). To this end, we modernize the SECD machine into a bisimilar one that operates in lockstep with the original one but that (1) does not use a data stack and (2) uses the caller-save rather than the callee-save convention for environments. We also identify that the dump component of the SECD machine is managed in a callee-save way. The caller-save counterpart of the modernized SECD machine precisely corresponds to Thielecke's double-barrelled continuations and to Felleisen's encoding of J in terms of call/cc. We then variously characterize the J operator in terms of CPS and in terms of delimited-control operators in the CPS hierarchy. As a byproduct, we also present several reduction semantics for applicative expressions with the J operator, based on Curien's original calculus of explicit substitutions. These reduction semantics mechanically correspond to the modernized versions of the SECD machine and to the best of our knowledge, they provide the first syntactic theories of applicative expressions with the J operator.

Abstract. Landin's SECD machine was the first abstract machine for applicative expressions, i.e., functional programs. Landin's J operator was the first control operator for functional languages, and was specified by an extension of the SECD machine. We present a family of evaluation functions corresponding to this extension of the SECD machine, using a series of elementary transformations (transformation into continuation-passing style (CPS) and defunctionalization, chiefly) and their left inverses (transformation into direct style and refunctionalization). To this end, we modernize the SECD machine into a bisimilar one that operates in lockstep with the original one but that (1) does not use a data stack and (2) uses the caller-save rather than the callee-save convention for environments. We also identify that the dump component of the SECD machine is managed in a callee-save way. The caller-save counterpart of the modernized SECD machine precisely corresponds to Thielecke's double-barrelled continuations and to Felleisen's encoding of J in terms of call/cc. We then variously characterize the J operator in terms of CPS and in terms of delimited-control operators in the CPS hierarchy.
As a byproduct, we also present several reduction semantics for applicative expressions with the J operator, based on Curien's original calculus of explicit substitutions. These reduction semantics mechanically correspond to the modernized versions of the SECD machine and to the best of our knowledge, they provide the first syntactic theories of applicative expressions with the J operator.
The present work is concluded by a motivated wish to see Landin's name added to the list of co-discoverers of continuations. Methodologically, however, it mainly illustrates the value of Reynolds's defunctionalization and of refunctionalization as well as the expressive power of the CPS hierarchy (1) to account for the first control operator and the first abstract machine for functional languages and (2) to connect them to their successors. Our work also illustrates the value of Danvy and Nielsen's refocusing technique to connect environment-based abstract machines and syntactic theories in the form of reduction semantics for calculi of explicit substitutions.

Introduction
Forty years ago, Peter Landin unveiled the first control operator, J, to a heretofore unsuspecting world [81,82,84]. He did so to generalize the notion of jumps and labels for translating Algol 60 programs into applicative expressions, using the J operator to account for the meaning of an Algol label. For a simple example, consider the block begin s 1 ; goto L ; L : s 2 end where the sequencing between the statements ('basic blocks,' in compiler parlance [8]) s 1 and s 2 has been made explicit with a label and a jump to this label. This block is translated into the applicative expression λ().let L = J s ′ 2 in let () = s ′ 1 () in L () where s ′ 1 and s ′ 2 respectively denote the translation of s 1 and s 2 . The occurrence of J captures the continuation of the outer let expression and yields a 'program closure' that is bound to L. Then, s ′ 1 is applied to (). If this application completes, the program closure bound to L is applied: (1) s ′ 2 is applied to () and then, if this application completes, (2) the captured continuation is resumed, thereby completing the execution of the block.
Landin also showed that the notion of program closure makes sense not just in an imperative setting, but also in a functional one. He specified the J operator by extending the SECD machine [80,83].
Indeed abstract machines provide a natural meeting ground for theoretically-minded and experimentally-minded computer scientists: they are as close to an actual implementation as most theoreticians will ever get, and to an actual formalization as most experimentalists will ever go. For example, Plotkin [100] proved the correctness of the SECD machine in reference to a definitional interpreter due to Morris [91] and a variety of implementations take the SECD machine as their starting point [10,20,23,87].
1.2. The authors' thesis. Is there, however, such a gap between applicative expressions and abstract machines? The thrust of Steele's MSc thesis [110] was that after CPS transformation, 1 a λ-abstraction can be seen as a label and a tail call as a machine jump with the 1 'CPS' stands for 'Continuation-Passing Style;' this term is due to Steele [110]. In a CPS program, all calls are tail calls and functions thread a functional accumulator, the continuation, that represents 'the rest of the computation' [114]. CPS programs are either written directly or the result of a CPS transformation [39,100]. (See Appendix A.2.) The left inverse of the CPS transformation is the direct-style transformation [33,41]. machine registers holding the actual parameters. Furthermore the point of Reynolds's defunctionalization [102] is that higher-order programs can be given an equivalent first-order representation. 2 It nevertheless took 40 years for the SECD machine to be 'rationally deconstructed' into a compositional evaluation function [35], the point being that (1) the SECD machine is essentially in defunctionalized form, and (2) its refunctionalized counterpart is an evaluation function in CPS, which turns out to be compositional. This deconstruction laid the ground for a functional correspondence between evaluators and abstract machines [3,4,6,7,13,16,36,37,73,89,90,93].
It is therefore the authors' thesis [36,90] that the gap between abstract machines and applicative expressions is bridged by Reynolds's defunctionalization.
Our goal here is to show that the functional correspondence between evaluators and abstract machines also applies to the SECD machine with the J operator, which, as we show, also can be deconstructed into a compositional evaluation function. As a corollary, we present several new simulations of the J operator, and the first syntactic theories for applicative expressions with the J operator.
1.3. Deconstruction of the SECD machine with the J operator. Let us outline our deconstruction of the SECD machine before substantiating it in the next sections. We follow the order of the first deconstruction [35], though with a twist: for simplicity and without loss of generality, in the middle of the derivation, we first abandon the stackthreading, callee-save features of the SECD machine, which are non-standard, for the more familiar-and therefore less 'baroque'-stackless, caller-save features of traditional definitional interpreters [59,91,102,111]. (These concepts are reviewed in the appendices. The point here is that the SECD machine manages the environment in a callee-save fashion. ) We then identify that the dump too is managed in a callee-save fashion and we present the corresponding caller-save counterpart.
The SECD machine is defined as the iteration of a state-transition function operating over a quadruple-a data stack (of type S) containing intermediate values, an environment (of type E), a control stack (of type C), and a dump (of type D) and yielding a value (of type value): run : S * E * C * D -> value The first deconstruction [35] showed that together the C and D components represent the current continuation and that the D component represents the continuation of the current caller, if there is one. As already pointed out in Section 1.1, since Landin's work, the C and D components of his abstract machine have been unified into one component; reflecting this unification, control operators capture both what used to be C and D instead of only what used to be D.

Disentangling and refunctionalization (Section 2).
The above definition of run looks complicated because it has several induction variables, i.e., it dispatches over several components of the quadruple. Our deconstruction proceeds as follows: • We disentangle run into four mutually recursive transition functions, each of which has one induction variable, i.e., dispatches over one component of the quadruple (boxed in the signature below): run_c : S * E * C * D -> value run_d : value * D -> value run_t : term * S * E * C * D -> value run_a : value * value * S * E * C * D -> value The first function, run c, dispatches towards run d if the control stack is empty, run t if the top of the control stack contains a term, and run a if the top of the control stack contains an apply directive. This disentangled specification, as it were, is in defunctionalized form [43,44,102]: the control stack and the dump are defunctionalized data types, and run c and run d are the corresponding apply functions.
• Refunctionalization eliminates the two apply functions: run_t : term * S * E * C * D -> value run_a : value * value * S * E * C * D -> value where C = S * E * D -> value and D = value -> value C and D are now function types. As identified in the first rational deconstruction [35], the resulting program is a continuation-passing interpreter. This interpreter threads a data stack to hold intermediate results and uses a callee-save convention for environments to process subterms. (For information and comparison, Appendix B illustrates an interpreter with no data stack for intermediate results and a caller-save convention for environments, Appendix C illustrates an interpreter with no data stack for intermediate results and a callee-save convention for environments, and Appendix D illustrates an interpreter with a data stack for intermediate results and a caller-save convention for environments.) At this point, we could continue as in the first deconstruction [35] and exhibit the directstyle counterpart of this interpreter. The result, however, would be less simple and less telling than first making do without the data stack (Section 1.3.2) and second adopting the more familiar caller-save convention for environments (Section 1.3.3) before continuing the deconstruction towards a compositional interpreter in direct style (Section 1.3.4).

1.3.2.
A first modernization: eliminating the data stack (Section 3). In order to focus on the nature of the J operator, we first eliminate the data stack: run_t : term * E * C * D -> value run_a : value * value * E * C * D -> value where C = value * E * D -> value and D = value -> value (Two simpler interpreters are presented and contrasted in Appendices B and D. Again, in order to focus on the nature of the J operator, we adopt the more familiar callersave convention for environments. In passing, we also rename run t as eval and run a as apply: eval : term * E * C * D -> value apply : value * value * C * D -> value where C = value * D -> value and D = value -> value (Two simpler interpreters are presented and contrasted in Appendices B and C. The first, in Appendix B, uses a caller-save convention for environments, and the second, in Appendix C, uses a callee-save convention.)

Continuing the deconstruction: towards a compositional interpreter in direct style.
• A direct-style transformation eliminates the dump continuation: eval : term * E * C -> value apply : value * value * C -> value where C = value -> value The clause for the J operator and the main evaluation function are expressed using the delimited-control operators shift and reset [38]. 3 The resulting interpreter still threads an explicit continuation, even though it is not tail-recursive.
• Another direct-style transformation eliminates the control continuation: eval : term * E -> value apply : value * value -> value The clauses catering for the non-tail-recursive uses of the control continuation are expressed using the delimited-control operators shift 1 , reset 1 , shift 2 , and reset 2 [13, 38,46,75,94]. The resulting evaluator is in direct style. It is also in closure-converted form: the applicable values are a defunctionalized data type and apply is the corresponding apply function.
• Refunctionalization eliminates the apply function: The resulting evaluation function is compositional, and the corresponding syntax-directed encoding gives rise to new simulations of the J operator.

1.3.5.
A variant: from callee-save to caller-save dumps (Section 4). In Section 1.3.3, we kept the dump component because it is part of the SECD machine semantics of the J operator. We observe, however, that the dump is managed in a callee-save way. We therefore change gear and consider the caller-save counterpart of the interpreter: eval : term * E * C * D -> value apply : value * value * C -> value where C = value -> value and D = value -> value 1.4.1. Explicit, callee-save dumps (Section 7). We present a reduction semantics for Curien's calculus of closures extended with the J operator, and we derivationally link it to the callersave, stackless SECD machine of Section 7.1.

Implicit, caller-save dumps (Section 8).
We present another reduction semantics for Curien's calculus of closures extended with the J operator, and we derivationally link it to a version of the SECD machine which is not in defunctionalized form.

1.4.3.
Explicit, caller-save dumps (Section 9). We outline a third reduction semantics for Curien's calculus of closures extended with the J operator, and we show how it leads towards Thielecke's double-barrelled continuations. 1.4.4. Inheriting the dump through the environment (Section 10). We present a fourth reduction semantics for Curien's calculus of closures extended with the J operator, and we derivationally link it to a version of the CEK machine that reflects Felleisen's simulation of the J operator.
1.5. Prerequisites and domain of discourse: the functional correspondence. We mostly use pure ML as a meta-language. We assume a basic familiarity with Standard ML and with reasoning about pure ML programs as well as an elementary understanding of defunctionalization [43,44,102] and its left inverse, refunctionalization; of the CPS transformation [38,41,59,91,102,110] and its left inverse, the direct-style transformation; and of delimited continuations [13,38,46,56,75]. From Section 3.2, we use pure ML with delimited-control operators as a meta-language.
The function run implements the iteration of a transition function for the SECD machine: (s, e, c, d) is a state of the machine and each clause of the definition of run specifies a state transition.
The SECD machine is deterministic. It terminates if it reaches a state with an empty control stack and an empty dump; in that case, it produces a value on top of the data stack. It does not terminate for divergent source terms. It becomes stuck if it attempts to apply an integer or attempts to apply the successor function to a non-integer value, in that case an ML pattern-matching error is raised (alternatively, the codomain of run could be made value option and a fallthrough else clause could be added). The clause marked "1" specifies that the J operator, at any point, denotes the current dump; evaluating it captures this dump and yields a state appender that, when applied (in the clause marked "2"), yields a program closure. Applying a program closure (in the clause marked "3") restores the captured dump.
1.6. Prerequisites and domain of discourse: the syntactic correspondence. We assume a basic familiarity with reduction semantics as can be gathered in Felleisen's PhD thesis [50] and undergraduate lecture notes [52] and with Curien's original calculus of closures [14,31], which is the ancestor of calculi of explicit substitutions. We also review the syntactic correspondence between reduction semantics and abstract machines in Section E by deriving the CEK machine from Curien's calculus of closures for applicative order. 1.7. Overview. We first disentangle and refunctionalize Felleisen's version of the SECD machine (Section 2). We then modernize it, eliminating its data stack and making go from callee-save to caller-save environments, and deconstruct the resulting specification into a compositional evaluator in direct style; we then analyze the J operator (Section 3). Identifying that dumps are managed in a callee-save way in the modernized SECD machine, we also present a variant where they are managed in a caller-save way, and we deconstruct the resulting specification into another compositional evaluator in direct style; we then analyze the J operator (Section 4). Overall, the deconstruction takes the form of a series of elementary transformations. The correctness of each step is very simple: most of the time, it is a corollary of the correctness of the transformation itself.
We then review related work (Section 5) and outline the deconstruction of the original version of the SECD machine, which is due to Burge (Section 6).
We then present a reduction semantics for the J operator that corresponds to the specification of Section 3 (Section 7). We further present a syntactic theory of applicative expressions with the J operator using delimiters (Section 8), and we show how this syntactic theory specializes to a reduction semantics that yields the abstract machine of Section 4 (Section 9) and to another reduction semantics that embodies Felleisen's embedding of J into Scheme described in Section 4.5 (Section 10).
2. Deconstruction of the SECD machine with the J operator: disentangling and refunctionalization 2.1. A disentangled specification. In the starting specification of Section 1.5, all the possible transitions are meshed together in one recursive function, run. As in the first rational deconstruction [35], we factor run into four mutually recursive functions, each with one induction variable. In this disentangled definition, run c dispatches to the three other transition functions, which all dispatch back to run c: • run c interprets the list of control directives, i.e., it specifies which transition to take according to whether the list is empty, starts with a term, or starts with an apply directive. If the list is empty, it calls run d. If the list starts with a term, it calls run t, caching the term in an extra component (the first parameter of run t). If the list starts with an apply directive, it calls run a. • run d interprets the dump, i.e., it specifies which transition to take according to whether the dump is empty or non-empty, given a valid data stack; run t interprets the top term in the list of control directives; and run a interprets the top value in the data stack. Graphically: 2.2. A higher-order counterpart. In the disentangled definition of Section 2.1, there are two possible ways to construct a dump-nil and consing a triple-and three possible ways to construct a list of control directives-nil, consing a term, and consing an apply directive. One could phrase these constructions as two specialized data types rather than as two lists.
These data types, together with run d and run c as their apply functions, are in the image of defunctionalization. After refunctionalization, the higher-order evaluator reads as follows; 5 it is higher-order because c and d now denote functions: datatype value = INT of int | SUCC | FUNCLO of E * string * term | STATE_APPENDER of D | PGMCLO of value * D withtype S = value list (* data stack *) and E = value Env.env (* environment *) and D = value -> value (* dump continuation *) and C = S * E * D -> value (* control continuation *) val e_init = Env.extend ("succ", SUCC, Env.empty) (* run_t : term * S * E * C * D -> value *) (* run_a : value * value * S * E * C * D -> value *) fun run_t ( The resulting evaluator is in CPS, with two layered continuations c and d. It threads a stack of intermediate results (s), an environment (e), a control continuation (c), and a dump continuation (d). Except for the environment being callee-save, the evaluator follows a traditional eval-apply schema: run t is eval and run a is apply. Defunctionalizing it yields the definition of Section 2.1 and as illustrated in Appendix A, by construction, run t and run a in the defunctionalized version operate in lockstep with run t and run a in the refunctionalized version: 3. Deconstruction of the SECD machine with the J operator: no data stack and caller-save environments We want to focus on J, and the non-standard aspects of the evaluator of Section 2.2 (the callee-save environment and the data stack) are a distraction. We therefore modernize this evaluator into a more familiar caller-save, stackless form [59,91,102,111]. Let us describe this modernization in two steps: first we transform the evaluator to use a caller-save convention for environments (as outlined in Section 1.3.2 and illustrated in Appendices B and C), and second we transform it to not use a data stack (as outlined in Section 1.3.3 and illustrated in Appendices B and D).
The environments of the evaluator of Section 2.2 are callee-save because the apply function run a receives an environment e as an argument and "returns" one to its continuation c [8, pages 404-408]. Inspecting the evaluator shows that whenever run a is passed a control directive c and an environment e and applies c, then the environment e is passed to c. Thus, the environment is passed to run a only in order to thread it to the control continuation. The control continuations created in run a and evaluate2 ignore their environment argument, and the control continuations created in run t are passed an environment that is already in their lexical scope. Therefore, neither the apply function run a nor the control continuations need to be passed an environment at all.
Turning to the data stack, we first observe that the control continuations of the evaluator in Section 2.2 are always applied to a data stack with at least one element. Therefore, we can pass the top element of the data stack as a separate argument, changing the type of control continuations from S * E * D -> value to value * S * E * D -> value. We can thus eliminate the data stack following an argument similar to the one for environments in the previous paragraph: the run a function merely threads its data stack along to its control continuation; the control continuations created in run a and evaluate2 ignore their data-stack argument, and the control continuations created in run t are passed a data stack that is already in their lexical scope. Therefore, neither the apply function run a, the eval function run t, nor the control continuations need to be passed a data stack at all.

3.1.
A specification with no data stack and caller-save environments. The callersave, stackless counterpart of the evaluator of Section 2.2 reads as follows, renaming run t as eval and run a as apply in passing: datatype value = INT of int | SUCC | FUNCLO of E * string * term | STATE_APPENDER of D | PGMCLO of value * D withtype E = value Env.env (* environment *) and D = value -> value (* dump continuation *) and C = value * D -> value (* control continuation *) val e_init = Env.extend ("succ", SUCC, Env.empty) (* eval : term * E * C * D -> value *) (* apply : value * value * C * D -> value The new evaluator is still in CPS, with two layered continuations. In order to justify it formally, we consider the corresponding abstract machine as obtained by defunctionalization (shown in Section 7; the ML code for evaluate1' is not shown here). This abstract machine and the disentangled abstract machine of Section 2.1 operate in lockstep and we establish a bisimulation between them. The full details of this formal justification are found in the second author's PhD dissertation [90,Section 4.4]. Graphically: 'modernization': no data stack and caller-save environments The following proposition follows as a corollary of the bisimulation and of the correctness of defunctionalization:

3.2.
A dump-less direct-style counterpart. The evaluator of Section 3.1 is in continuation-passing style, and therefore it is in the image of the CPS transformation. In order to highlight the control effect of the J operator, we now present the direct-style counterpart of this evaluator. The clause for J captures the current continuation (i.e., the dump) in a state appender, and therefore its direct-style counterpart naturally uses the undelimited control operator call/cc [41]. With an eye on our next step, we do not, however, use call/cc but its delimited cousins shift and reset [13, 38,46] to write the direct-style counterpart.
Concretely, we use an ML functor to obtain an instance of shift and reset with value as the type of intermediate answers [46,56]: reset delimits the (now implicit) dump continuation in eval, and corresponds to its initialization with the identity function; and shift captures it in the clauses where J is evaluated and where a program closure is applied. There is one non-tail call to eval, to evaluate the body of a λ-abstraction; this context is captured by shift when J is evaluated: datatype value = INT of int | SUCC | FUNCLO of E * string * term | STATE_APPENDER of D | PGMCLO of value * D withtype E = value Env.env (* environment *) and C = value -> value (* control continuation *) and D = value -> value (* first-class dump continuation *) val e_init = Env.extend ("succ", SUCC, Env.empty) structure SR = make_Shift_and_Reset (type intermediate_answer = value) (* eval : term * E * C -> value *) (* apply : value * value * C -> value *) fun eval (LIT n, e, c) = c (INT n) | eval (VAR x, e, c) = c (Env.lookup (x, e)) | eval (LAM (x, t), e, c) = c (FUNCLO (e, x, t)) | eval (APP (t0, t1), e, c) = eval (t1, e, fn v1 => eval (t0, e, fn v0 => apply (v0, v1, c))) | eval (J, e, c) = SR.shift (fn d => d (c (STATE_APPENDER d))) (* * *) and apply (SUCC, INT n, c) The dump continuation is now implicit and is accessed using shift. The first occurrence of shift captures the current dump when J is evaluated. The second occurrence is used to discard the current dump when a program closure is applied. CPS-transforming this evaluator yields the evaluator of Section 3.1: Proposition 3.2 (full correctness). Given a program, evaluate2' and evaluate3' either both diverge or both yield values; and if these values have an integer type, they are the same integer.

3.3.
A control-less direct-style counterpart. The evaluator of Section 3.2 still threads an explicit continuation, the control continuation. It however is not in continuation-passing style because of the non-tail calls to c, eval, and apply (in the clauses marked "*" above) and the occurrences of shift and reset. This pattern of control is characteristic of the CPS hierarchy [13,38,46,75] (see also Footnote 3, page 5). We therefore use the delimitedcontrol operators shift 1 , reset 1 , shift 2 , and reset 2 to write the direct-style counterpart of this evaluator (shift 2 and reset 2 are the direct-style counterparts of shift 1 and reset 1 , and shift 1 and reset 1 are synonyms for shift and reset).
Concretely, we use two ML functors to obtain layered instances of shift and reset with value as the type of intermediate answers [46,56]: reset 2 delimits the (now twice implicit) dump continuation in eval; shift 2 captures it in the clauses where J is evaluated and where a program closure is applied; reset 1 delimits the (now implicit) control continuation in eval and in apply, and corresponds to its initialization with the identity function; and shift 1 captures it in the clause where J is evaluated: (* environment *) and D = value -> value (* first-class dump continuation *) val e_init = Env.extend ("succ", SUCC, Env.empty) structure SR1 = make_Shift_and_Reset (type intermediate_answer = value) structure SR2 = make_Shift_and_Reset_next (type intermediate_answer = value structure over = SR1) (* eval : term * E -> value *) (* apply : value * value -> value *) fun eval (LIT n, e) The control continuation is now implicit and is accessed using shift 1 . The dump continuation is still implicit and is accessed using shift 2 . CPS-transforming this evaluator yields the evaluator of Section 3.2: Proposition 3.3 (full correctness). Given a program, evaluate3' and evaluate4' either both diverge or both yield values; and if these values have an integer type, they are the same integer.

A compositional counterpart.
We now turn to the data flow of the evaluator of Section 3.3. As for the SECD machine without J [35], this evaluator is in defunctionalized form: each of the values constructed with SUCC, FUNCLO, PGMCLO, and STATE APPENDER is constructed at exactly one place and consumed at exactly one other (the apply function). We therefore refunctionalize them into the function space value -> value, which is shaded below: datatype value = INT of int | FUN of value -> value withtype E = value Env.env val e_init = Env.extend ("succ", FUN (fn (INT n) => INT (n+1)), Env.empty) structure SR1 = make_Shift_and_Reset (type intermediate_answer = value) structure SR2 = make_Shift_and_Reset_next (type intermediate_answer = value structure over = SR1) Unlike all the abstract machines and evaluators before, this evaluation function is compositional: all the recursive calls on the right-hand side are over proper sub-parts of the corresponding expression on the left-hand side. Defunctionalizing this evaluation function yields the evaluator of Section 3.3: 3.5. Assessment. From Section 3.1 to Section 3.4, we have modernized the SECD machine into a stackless machine with a caller-save convention for environments, and then deconstructed the modernized version of this machine into a series of equivalent specifications, starting (essentially) from a relation between states and ending with an evaluation function. The diagram below graphically summarizes the deconstruction. The evaluators in the top row are the defunctionalized counterparts of the evaluators in the bottom row. (The ML code for evaluate2'' and evaluate3'' is not shown here.) Using the tracing technique of Appendix A, we can show that evaluate2' and evaluate2'' operate in lockstep. We have however not proved this lockstep property for evaluate3' and evaluate3'' and for evaluate4' and evaluate4'', satisfying ourselves with Plotkin's Simulation theorem [100], suitably extended for shift and reset [76,77].
3.6. On the J operator. We now reap the fruits of the modernization and the reconstruction, and present a series of simulations of the J operator (Sections 3.6.1, 3.6.2, and 3.6.3). We then put the J operator into perspective (Section 3.6.4).
3.6.1. Three simulations of the J operator. The evaluator of Section 3.4 (evaluate4'') and the refunctionalized counterparts of the evaluators of Sections 3.2 and 3.1 (evaluate3'' and evaluate2'') are compositional. They can be viewed as syntax-directed encodings into their meta-language, as embodied in the first Futamura projection [60] and the original approach to denotational semantics [112]. Below, we state these encodings as three simulations of J: one in direct style, one in CPS with one layer of continuations, and one in CPS with two layers of continuations.
We assume a call-by-value meta-language with right-to-left evaluation. • In direct style, using shift 2 (S 2 ), reset 2 ( · 2 ), shift 1 (S 1 ), and reset 1 ( · 1 ), based on the compositional evaluator evaluate4'' in direct style: A program p is translated as p 1 2 . • In CPS with one layer of continuations, using shift (S) and reset ( · ), based on the compositional evaluator evaluate3'' in CPS with one layer of continuations: A program p is translated as p ′ λv.v . • In CPS with two layers of continuations (the outer continuation, i.e., the dump continuation, can be η-reduced in the first three clauses), based on the compositional evaluator evaluate2'' in CPS with two layers of continuations: Analysis: The simulation of literals, variables, and applications is standard. The control continuation of the body of each λ-abstraction is delimited, corresponding to it being evaluated with an empty control stack in the SECD machine. The J operator abstracts the control continuation and the dump continuation and immediately restores them, resuming the computation with a state appender which holds the abstracted dump continuation captive. Applying this state appender to a value v yields a program closure (boxed in the three simulations above). Applying this program closure to a value v ′ has the effect of discarding both the current control continuation and the current dump continuation, applying v to v ′ , and resuming the captured dump continuation with the result.
Assessment: The first rational deconstruction [35] already characterized the SECD machine in terms of the CPS hierarchy: the control stack is the first continuation, the dump is the second one (i.e., the meta-continuation), and abstraction bodies are evaluated within a control delimiter (i.e., an empty control stack). Our work further characterizes the J operator as capturing (a copy of) the meta-continuation.
3.6.2. The C operator and the CPS hierarchy. In the terminology of reflective towers [42], continuations captured with shift are "pushy"-at their point of invocation, they compose with the current continuation by "pushing" it on the meta-continuation. In the second encoding of J in Section 3.6.1, the term serves to discard the current continuation d ′ before applying the captured continuation d. Because of this use of shift to discard d ′ , the continuation d is composed with the identity continuation. In contrast, still using the terminology of reflective towers, continuations captured with call/cc [29] or with Felleisen's C operator [50] are "jumpy"-at their point of invocation, they discard the current continuation. If the continuation d were captured with C, then the term d (v v ′ λv ′′ .v ′′ ) would suffice to discard the current continuation.
The first encoding of J in Section 3.6.1 uses the pushy control operators S 1 (i.e., S) and S 2 . Murthy [94] and Kameyama [75] have investigated their jumpy counterparts in the CPS hierarchy, C 1 (i.e., C) and C 2 . Jumpy continuations therefore suggest two new simulations of the J operator. We show only the clauses for J, which are the only ones that change compared to Section 3.6.1. As before, we assume a call-by-value meta-language with right-to-left evaluation.
• In direct style, using C 2 , reset 2 ( · 2 ), C 1 , and reset 1 ( · 1 ): This simulation provides a new example of programming in the CPS hierarchy with jumpy delimited continuations.
• In CPS with one layer of continuations, using C and reset ( · ): The corresponding CPS simulation of J with two layers of continuations coincides with the one in Section 3.6.1.

The call/cc operator and the CPS hierarchy.
Like shift and C, call/cc takes a snapshot of the current context. However, unlike shift and C, in so doing call/cc leaves the current context in place. So for example, 1 + (call/cc λk.10) yields 11 because call/cc leaves the context 1 + [ ] in place, whereas both 1 + (Sλk.10) and 1 + (Cλk.10) yield 10 because the context 1 + [ ] is tossed away.
Therefore J can be simulated in CPS with one layer of continuations, using call/cc and exploiting its non-abortive behavior: The obvious generalization of call/cc to the CPS hierarchy does not work, however. One needs an abort operator as well in order for call/cc 2 to capture the initial continuation and the current meta-continuation. We leave the rest of this train of thought to the imagination of the reader.
3.6.4. On the design of control operators. We note that replacing C with S in Section 3.6.2 (resp. C 1 with S 1 and C 2 with S 2 ) yields a pushy counterpart for J, i.e., program closures returning to their point of activation. (Similarly, replacing C with S in the specification of call/cc in terms of C yields a pushy version of call/cc, assuming a global control delimiter.) One can also envision an abortive version of J that tosses away the context it abstracts. In that sense, control operators are easy to invent, though not always easy to implement efficiently. Nowadays, however, the litmus test for a new control operator lies elsewhere, for example: (1) Which programming idiom does this control operator reflect [29,38,41,102,108]? (2) What is the logical content of this control operator [66,97]? Even though it was the first control operator ever, J passes this litmus test. As pointed out by Thielecke, (1) besides reflecting Algol jumps and labels [81], J provides a generalized return [115, Section 2.1], and (2) the type of J λv.v is the law of the excluded middle [116,Section 5.2]. On the other hand, despite their remarkable fit to Algol labels and jumps (as illustrated in the beginning of Section 1), the state appenders denoted by J are unintuitive to use. For example, if a let expression is the syntactic sugar of a beta-redex (and x 1 is fresh), the observational equivalence does not hold in the presence of J due to the non-standard translation of abstractions, even though it does hold in the presence of call/cc, C, and shift for right-to-left evaluation. For example, given

Deconstruction of the SECD machine with the J operator: caller-save dumps
In Section 3, we modernized the SECD machine by removing the intermediate data stack and by managing the environment in a caller-save rather than callee-save fashion. We left the 'non-modern' feature of the dump continuation alone because it was part of the SECD-machine semantics of the J operator. In this section, we turn our attention to this dump continuation, and we identify that like the environment in the original SECD machine, the dump continuation is managed in a callee-save fashion. Indeed the apply function receives a dump continuation from its caller and passes it in turn to the control continuation.

4.1.
A specification with caller-save dump continuations. Let us modernize the SECD machine further by managing dump continuation in a caller-save fashion. Our reasoning is similar to that used in Section 3 for the environment. Inspecting the evaluator evaluate2' shows that when either eval or apply receives a control continuation c and a dump continuation d as arguments and applies c, the dump continuation d is passed to c. Therefore, when the control continuation passed to eval or apply is fn (v, d) => d v and the dump continuation is some d', d' can be substituted for d in the body of the control continuation. After this change, inspecting the control continuations reveals that the ones created in apply and evaluate2' ignore their dump-continuation arguments, and the ones created in eval are passed a dump continuation that is already in their lexical scope. Therefore, the control continuations do not need to be passed a dump continuation. Since the dump continuation was passed to apply solely for the purpose of threading it to the control continuation, apply does not need to be passed a dump continuation either.
The evaluator of Section 3.1 with caller-save dump continuations reads as follows: datatype value = INT of int | SUCC | FUNCLO of E * string * term | STATE_APPENDER of D | PGMCLO of value * D withtype E = value Env.env (* environment *) and D = value -> value (* dump continuation *) and C = value -> value (* control continuation *) val e_init = Env.extend ("succ", SUCC, Env.empty) (* eval : term * E * C * D -> value *) (* apply : value * value * C -> value This evaluator still passes two continuations to eval. However, the dump continuation is no longer passed as an argument to the control continuation. Thus, the two continuations have the same type. The dump continuation is a snapshot of the control continuation of the caller. It is reset to be the continuation of the caller when evaluating the body of a function closure and it is captured in a state appender by the J operator. Applying a program closure discards the current control continuation in favor of the captured dump continuation. As in Section 3.1, the abstract machine corresponding to evaluate2' alt (obtained by defunctionalization and displayed in Section 8) operates in lockstep with the abstract machine corresponding to evaluate2' (obtained by defunctionalization and displayed in Section 7). The following proposition is a corollary of this bisimulation and the correctness of defunctionalization: (1) A direct-style transformation with respect to the control continuation yields an evaluator in direct style. (2) Refunctionalizing the applicable values yields a compositional, higher-order evaluator in direct style. Graphically: 4.3. Two other simulations of the J operator. As in Section 3.6.1, the compositional evaluators of Section 4.2 can be viewed as syntax-directed translations into their metalanguage. Below, we state these encodings as two further simulations of the J operator: one in CPS with an additional return continuation, and one in direct-style with a return continuation.
• In CPS with an additional return continuation, based on evaluate3' alt: • In direct style with a return continuation, based on evaluate3' alt': NB. Operationally, the two occurrences of reset surrounding the body of the shiftexpression are unnecessary. They could be omitted.
Assessment: Transformed terms are passed a pair of continuations, the usual continuation of the call-by-value CPS transform and a return continuation. Abstractions set the return continuation to be the continuation at their point of invocation, i.e., the continuation of their caller. The J operator captures the current return continuation in a program closure (boxed above).

4.4.
Thielecke. In his work on comparing control constructs [116], Thielecke introduced a 'double-barrelled' CPS transformation, where terms are passed an additional 'jump continuation' in addition to the usual continuation of the call-by-value CPS transformation. By varying the transformation of abstractions, he was able to account for first-class continuations, exceptions, and jumping. His double-barrelled CPS transformation, including a clause for his JI operator (i.e., J λx.x) and modified for right-to-left evaluation, reads as follows: The continuation c is the continuation of the usual call-by-value CPS transformation. The continuation d is a return continuation, i.e., a snapshot of the continuation of the caller of a function abstraction. It is set to be the continuation of the caller in the body of each function abstraction and it is captured as a first-class function by the JI operator. The extra continuation passed to each abstraction is not necessary (for the encoding of JI), and can be eliminated from the translation of abstractions and applications, as we did in Section 4.1.

O. DANVY AND K. MILLIKIN
As noted by Thielecke and earlier Landin, J can be expressed in terms of JI as: The β-expansion is necessary to move the occurrence of JI outside of the outer abstraction, because λ-abstractions are CPS-transformed in a non-standard way. By CPS-transforming this definition and eliminating the extra continuation for function abstractions, we derive the same double-barrelled encoding of Landin's J operator as in Section 4.3: Analysis: In essence, Thielecke's simulation corresponds to an abstract machine which is the caller-save counterpart of Landin's machine with respect to the dump.

4.5.
Felleisen. Felleisen showed how to embed Landin's extension of applicative expressions with J into the Scheme programming language [51]. The embedding is defined using Scheme syntactic extensions (i.e., macros). J is treated as a dynamic identifier that is bound in the body of every abstraction, similarly to the dynamically bound identifier 'self' in an embedding of Smalltalk into Scheme [84]. The control aspect of J is handled through Scheme's control operator call/cc. Here are the corresponding simulations: • In direct style, using either of call/cc, C, or shift (S), and a control delimiter ( · ): Analysis: The simulation of variables and applications is standard. The continuation of the body of each λ-abstraction is captured, and the identifier J is dynamically bound to a function closure (the state appender) which holds the continuation captive. Applying this function closure to a value v yields a program closure (boxed in the simulations above). Applying this program closure to a value v ′ has the effect of applying v to v ′ and resuming the captured continuation with the result, abandoning the current continuation.
The evaluator corresponding to these simulations always has a binding of J in the environment when evaluating the body of an abstraction (see Section 10). Under the assumption that J is never shadowed in a program, passing this value as a separate argument to the evaluator leads one towards the definition of evaluate2' alt in Section 4.1 (see Section 9). 5. Related work 5.1. Landin and Burge. Landin [82] introduced the J operator as a new language feature motivated by three questions about labels and jumps: • Can a language have jumps without having assignments?
• Is there some component of jumping that is independent of labels?
• Is there some feature that corresponds to functions with arguments in the same sense that labels correspond to procedures without arguments? Landin gave the semantics of the J operator by extending the SECD machine. In addition to using J to model jumps in Algol 60 [81], he gave examples of programming with the J operator, using it to represent failure actions as program closures where it is essential that they abandon the context of their application.
In his textbook [21, Section 2.10], Burge adjusted Landin's original specification of the J operator. Indeed, in Landin's extension of the SECD machine, J could only occur in the context of an application. Burge adjusted the original specification so that J could occur in arbitrary contexts. To this end, he introduced the notion of a "state appender" as the denotation of J.
Thielecke [115] gave a detailed introduction to the J operator as presented by Landin and Burge. Burstall [22] illustrated the use of the J operator by simulating threads for parallel search algorithms, which in retrospect is the first simulation of threads in terms of first-class continuations ever.

5.2.
Reynolds. Reynolds [102] gave a comparison of J to escape, the binder form of Scheme's call/cc [29]. 6 He gave encodings of Landin's J (i.e., restricted to the context of an application) and escape in terms of each other.
His encoding of escape in terms of J reads as follows: (escape k in t) * = let k = J λv.v in t * As Thielecke notes [115], this encoding is only valid immediately inside an abstraction. Indeed, the dump continuation captured by J only coincides with the continuation captured by escape if the control continuation is the initial one (i.e., immediately inside a control delimiter). Thielecke therefore generalized the encoding by adding a dummy abstraction: From the point of view of the rational deconstruction of Section 3, this dummy abstraction implicitly inserts a control delimiter. Reynolds's converse encoding of J in terms of escape reads as follows: where k does not occur free in t 0 and t 1 . For the same reason as above, this encoding is only valid immediately inside an abstraction and therefore it can be generalized by adding a dummy abstraction: Felleisen's version delays the consumption of the dump until the function, in the program closure, completes, whereas Burge's version does not. The modification is unobservable because a program cannot capture the control continuation and because applying the argument of a state appender pushes the data stack, the environment, and the control stack on the dump. Felleisen's modification can be characterized as wrapping a control delimiter around the argument of a dump continuation, similarly to the simulation of static delimited continuations in terms of dynamic ones [18]. Burge's version, however, is not in defunctionalized form. In Section 6, we put it in defunctionalized form without resorting to a control delimiter and we outline the corresponding compositional evaluation functions and simulations.

Deconstruction of the original SECD machine with the J operator
We now outline the deconstruction of Burge's specification of the SECD machine with the J operator.
6.1. Our starting point: Burge's specification. As pointed out in Section 5.3, Felleisen's version of the SECD machine applies the value contained in a program closure before restoring the components of the captured dump. Burge's version differs by restoring the components of the captured dump before applying the value contained in the program closure. In other words, • Felleisen's version applies the value contained in a program closure with an empty data stack, a dummy environment, an empty control stack, and the captured dump, whereas • Burge's version applies the value contained in a program closure with the captured data stack, environment, control stack, and previous dump. The versions induce a minor programming difference because the first makes it possible to use J in any context whereas the second restricts J to occur only inside a λ-abstraction.
Burge's specification of the SECD machine with J follows. Ellipses mark what does not change from the specification of Section 1.5: Just as in Section 2.1, Burge's specification can be disentangled into four mutually-recursive transition functions. The disentangled specification, however, is not in defunctionalized form. We put it next in defunctionalized form without resorting to a control delimiter, and then outline the rest of the rational deconstruction. YIELD is used to tag values returned by function closures (in the clause marked "1" above), and THROW is used to tag values sent to program closures (in the clause marked "3"). THROW tags a pair of values, which will be applied in run d (by calling run a in the clause marked "2"). 6.4. The rest of the rational deconstruction. The evaluator of Section 6.3 can be transformed exactly as the higher-order evaluator of Section 2.2: (1) Eliminating the data stack and the callee-save environment yields a traditional evalapply evaluator, with run t as eval and run a as apply. The evaluator is in CPS with two layers of continuations. (2) A first direct-style transformation with respect to the dump yields an evaluator that uses shift and reset (or C and a global reset, or again call/cc and a global reset) to manipulate the implicit dump continuation. (3) A second direct-style transformation with respect to the control stack yields an evaluator in direct style that uses the delimited-control operators shift 1 , reset 1 , shift 2 , and reset 2 (or C 1 , reset 1 , C 2 , and reset 2 ) to manipulate the implicit control and dump continuations. (4) Refunctionalizing the applicable values yields a compositional, higher-order, directstyle evaluator corresponding to Burge's specification of the J operator. The result is presented as a syntax-directed encoding next.
6.5. Three simulations of the J operator. As in Section 3.6.1, the compositional counterpart of the evaluators of Section 6.4 can be viewed as syntax-directed encodings into their meta-language. Below, we state these encodings as three simulations of J: one in direct style, one in CPS with one layer of continuations, and one in CPS with two layers of continuations. Again, we assume a call-by-value meta-language with right-to-left evaluation and with a sum (to distinguish values returned by functions and values sent to program closures), a case expression (for the body of λ-abstractions) and a destructuring let expression (at the top level).
• In direct style, using either of shift 2 , reset 2 , shift 1 , and reset 1 or C 2 , reset 2 , C 1 , and reset 1 , based on the compositional evaluator in direct style: • In CPS with one layer of continuations, using either of shift and reset, C and reset, or call/cc and reset, based on the compositional evaluator in CPS with one layer of continuations: • In CPS with two layers of continuations, based on the compositional evaluator in CPS with two layers of continuations: Analysis: The simulation of literals, variables, and applications is standard. The body of each λ-abstraction is evaluated with a control continuation injecting the resulting value into the sum type 7 to indicate normal completion and resuming the current dump continuation, and with a dump continuation inspecting the resulting sum to determine whether to continue normally or to apply a program closure. Continuing normally consists of invoking the control continuation with the resulting value and the dump continuation. Applying a program closure consists of restoring the components of the dump and then performing the application. The J operator abstracts both the control continuation and the dump continuation and immediately restores them, resuming the computation with a state appender holding the abstracted dump continuation captive. Applying this state appender to a value v yields a program closure (boxed in the three simulations above). Applying this program closure to a value v ′ has the effect of discarding both the current control continuation and the current dump continuation, injecting v and v ′ into the sum type to indicate exceptional completion, and resuming the captured dump continuation. It is an error to evaluate J outside of a λ-abstraction.
6.6. Related work. Kiselyov's encoding of dynamic delimited continuations in terms of the static delimited-continuation operators shift and reset [78] is similar to this alternative encoding of the J operator in that both encodings tag the argument to the meta-continuation to indicate whether it represents a normal return or a value thrown to a first-class continuation. In addition though, Kiselyov uses a recursive meta-continuation in order to encode dynamic delimited continuations.

A syntactic theory of applicative expressions with the J operator: explicit, callee-save dumps
Symmetrically to the functional correspondence between evaluation functions and abstract machines that was sparked by the first rational deconstruction of the SECD machine [3,4,6,7,13,16,35,36], a syntactic correspondence exists between calculi and abstract machines, as investigated by Biernacka, Danvy, and Nielsen [12,14,15,34,36,45]. This syntactic correspondence is also derivational, and hinges not on defunctionalization but on a 'refocusing' transformation that mechanically connects an evaluation function defined as the iteration of one-step reduction, and an abstract machine.
The goal of this section is to present the reduction semantics and the reduction-based evaluation function that correspond to the modernized SECD machine of Section 3.1. We successively present this machine (Section 7.1), the syntactic correspondence (Section 7.2), a reduction semantics for applicative expressions with the J operator (Section 7.3), and the derivation from this reduction semantics to this SECD machine (Section 7.4). We consider a calculus of explicit substitutions because the explicit substitutions directly correspond to the environments of the modernized SECD machine. In turn, this calculus of explicit substitutions directly corresponds to a calculus with actual substitutions.

7.2.
From reduction semantics to abstract machine. Consider a calculus together with a reduction strategy expressed as a Felleisen-style reduction semantics satisfying the unique-decomposition property [50]. In such a reduction semantics, a one-step reduction function is defined as the composition of three functions: decomposition: a total function mapping a value term to itself and decomposing a non-value term into a potential redex and a reduction context (decomposition is a function because of the unique-decomposition property); contraction: a partial function mapping an actual redex to its contractum; and plugging: a total function mapping a term and a reduction context to a new term by filling the hole in the context with the term. The one-step reduction function is partial because it is the composition of two total functions and a partial function.
An evaluation function is traditionally defined as the iteration of the one-step reduction function: The resulting 'refocused' evaluation function is defined as the iteration of refocusing and contraction. CPS transformation and defunctionalization make it take the form of a statetransition function, i.e., an abstract machine. Short-circuiting its intermediate transitions yields abstract machines that are often independently known [45].
Biernacka and Danvy then showed that the refocusing technique could be applied to the very first calculus of explicit substitutions, Curien's simple calculus of closures [31], and that depending on the reduction order, it gave rise to a collection of both known and new environment-based abstract machines such as Felleisen et al.'s CEK machine (for left-to-right applicative order), the Krivine machine (for normal order), Krivine's machine (for normal order with generalized reduction), and Leroy's ZINC machine (for right-to-left applicative order with generalized reduction) [14]. They then turned to context-sensitive contraction functions, as first proposed by Felleisen [50], and showed that refocusing mechanically gives rise to an even larger collection of both known and new environment-based abstract machines for languages with computational effects such as Krivine's machine with call/cc, the λµ-calculus, static and dynamic delimited continuations, input/output, stack inspection, proper tail-recursion, and lazy evaluation [15].
The next section presents the calculus of closures corresponding to the abstract machine of Section 7.1.

7.3.
A reduction semantics for applicative expressions with the J operator. The λ ρJ-calculus is an extension of Biernacka and Danvy's λ ρ-calculus [14], which is itself a minimal extension of Curien's original calculus of closures λρ [31] to make it closed under one-step reduction. We use it here to formalize Landin's applicative expressions with the J operator as a reduction semantics. To this end, we present its syntactic categories (Section 7.3.1); a plug function mapping a closure and a two-layered reduction context into a closure by filling the given context with the given closure (Section 7.3.2); a contraction function implementing a context-sensitive notion of reduction (Section 7.3.3) and therefore mapping a potential redex and its reduction context into a contractum and a reduction context (possibly another one); and a decomposition function mapping a non-value term into a potential redex and a reduction context (Section 7.3.4). We are then in position to define a one-step reduction function (Section 7.3.5), and a reduction-based evaluation function (Section 7.3.6).
Before delving into this section, the reader might want to first browse through Section E, in the appendix. This section has the same structure as the present one but instead of the SECD machine, it addresses the CEK machine, which is simpler. 7.3.1. Syntactic categories. We consider a variant of the λ ρJ-calculus with names instead of de Bruijn indices, and with two layers of contexts C and D that embody the right-to-left applicative-order reduction strategy favored by Landin: C is the control context and D is the dump context. In the syntactic category of closures, D and D • v respectively denote a state appender and a program closure, and c (which is shaded below) marks the boundary between the context of a β-redex that has been contracted, i.e., a function closure that has been applied, and the body of the λ-abstraction in this function closure: (programs) p : (terms) t : Values are therefore a syntactic subcategory of closures, and in this section, we make use of the syntactic coercion ↑ mapping a value into a closure.

7.3.2.
Plugging. Plugging a closure in the two layered contexts is defined by induction over these two contexts. We express this definition as a state-transition system with two intermediate states, C, c, D plug/cont and D, c plug/dump , an initial state C, c, D plug/cont , and a final state c. The transition function from the state C, c, D plug/cont incrementally peels off the given control context and the transition function from the state D, c plug/dump dispatches over the given dump context: We can now define a total function plug over closures, control contexts, and dump contexts that fills the given closure into the given control context, and further fills the result into the given dump context: (Beta succ ) SU CC n , C, D → n + 1 , C, D Three of these contraction rules depend on the contexts: the J rule captures a copy of the dump context and yields a state appender; the β-rule for function closures resets the control context and pushes it on the dump context; and the β-rule for program closures resets the control context and reinstates a previously captured copy of the dump context. Among the potential redexes, only the ones listed above are actual ones. The other applications of one value to another are stuck.
We now can define by cases a partial function contract over potential redexes that contracts an actual redex and its two layers of contexts into the corresponding contractum and contexts: There are many ways to define a total function mapping a value closure to itself and a non-value closure to a potential redex and a reduction context. In our experience, the following definition is a convenient one. It is a state-transition system with three intermediate states, c, C, D dec/clos , C, v, D dec/cont , and D, v dec/dump , an initial state c, [ ], • dec/clos and two final states VAL (v) and DEC (r, C, D). If possible, the transition function from the state c, C, D dec/clos decomposes the given closure c and accumulates the corresponding two layers of reduction context, C and D. The transition function from the state C, v, D dec/cont dispatches over the given control context, and the transition function from the state D, v dec/dump dispatches over the given dump context.
We now can define a total function decompose over closures that maps a value closure to itself and a non-value closure to a decomposition into a potential redex, a control context, and a dump context. This total function uses three auxiliary functions decompose ′ clos , decompose ′ cont , and decompose ′ dump : For any closure c, control context C, and dump context D, and decompose (c) = decompose ′ clos (c, [ ], •).

7.3.5.
One-step reduction. We are now in position to define a partial function reduce over closed closures that maps a value closure to itself and a non-value closure to the next closure in the reduction sequence. This function is defined by composing the three functions above: The function reduce is partial because of contract, which is undefined for stuck closures. iterate (VAL (v)) = v iterate (DEC (r, C, D)) = iterate (decompose (plug (contract (r, C, D))))

A RATIONAL DECONSTRUCTION OF LANDIN'S SECD MACHINE WITH THE J OPERATOR 37
The function evaluate is partial because a given closure might be stuck or reducing it might not converge. = v iterate (DEC (r, C, D)) = iterate (refocus (contract (r, C, D))) and refocus is optimally defined as continuing the decomposition in the current reduction context [45]:

7.4.2.
Lightweight fusion: making do without driver loop. In effect, iterate is as the 'driver loop' of a small-step abstract machine that refocuses and contracts. Instead, let us fuse contract and iterate and express the result with rewriting rules over a configuration r, C, D iter . We clone the rewriting rules for decompose ′ clos , decompose ′ cont , and decompose ′ dump into refocusing rules, respectively indexing the configuration c, C, D dec/clos as c, C, D eval , the configuration C, v, D dec/cont as C, v, D cont , and the configuration D, v dec/dump as D, v dump : • instead of rewriting to VAL (v), the cloned rules rewrite to v; • instead of rewriting to DEC (r, C, D), the cloned rules rewrite to r, C, D iter .
The following proposition summarizes the situation: Proof: straightforward. The two machines operate in lockstep.

7.4.3.
Inlining and transition compression. The abstract machine of Section 7.4.2, while interesting in its own right (it is 'staged' in that the contraction rules are implemented separately from the congruence rules [14,69]), is not minimal: a number of transitions yield a configuration whose transition is uniquely determined. Let us carry out these hereditary, "corridor" transitions once and for all: The eval-clauses for n , SU CC (which only occurs in the initial environment), c 0 c 1 , D , and D • v and the iter-clauses for x[e], (t 0 t 1 )[e], and J all have disappeared: they were only transitory. The eval-clause for c has also disappeared: it is a dead clause here since plug has been refocused away.  (2) flatten the configuration v v ′ , C, D iter into a quadruple v, v ′ , C, D apply , we obtain an abstract machine that coincides with the caller-save, stackless SECD machine of Section 7.1.
The following proposition captures that the SECD machine implements the reduction semantics of Section 7.3. Proof: this proposition is a simple corollary of the above series of propositions and of the observation just above. 7.5. Summary and conclusion. All in all, the syntactic and the functional correspondences provide a method to mechanically build compatible small-step semantics in the form of calculi (reduction semantics) and abstract machines, and big-step semantics in the form of evaluation functions. We have illustrated this method here for applicative expressions with the J operator, providing their first big-step semantics and their first reduction semantics. 8. A syntactic theory of applicative expressions with the J operator: implicit, caller-save dumps The J operator capture the continuation of the caller and accordingly, the SECD machine is structured as the expression continuation of the current function up to its point of call (the C component) and as a list of the delimited expression continuations of the previously called functions (the D component). This architecture stands both for the original SECD machine (Section 2) and for its modernized instances, whether the dump is managed in a callee-save fashion (Section 3) or in a caller-save fashion (Section 4). In this section, we study a single representation of the context that is dynamically scanned in search for the context of the caller, as in Felleisen et al.'s initial take on delimited continuations [54] and in John Clements's PhD thesis work on continuation marks [27]. We start from a reduction semantics (Section 8.1) and refocus it into an abstract machine (Section 8.2). 8.1. Reduction semantics. We specify the reduction semantics as in Sections 7.3 and E.1, i.e., with its syntactic categories, a plugging function, a notion of contraction, a decomposition function, a one-step reduction function, and a reduction-based evaluation function. 8.1.1. Syntactic categories. We consider a variant of the λ ρJ-calculus with one layer of context C and with delimiters c and C (shaded below) to mark the boundary between the context of a β-redex that has been contracted, i.e., a function closure that has been applied, and the body of the λ-abstraction in this function closure which is undergoing reduction: (programs) p ::= t[(succ, SU CC) · ∅] (terms) t : Again, in the syntactic category of closures, C and C • v respectively denote a state appender and a program closure. Also again, values are therefore a syntactic subcategory of closures, and we make use of the syntactic coercion ↑ mapping a value into a closure.

8.1.2.
Plugging. Plugging a closure in a context is defined by induction over this context: The notion of reduction is specified by the following contextsensitive contraction rules over actual redexes: where previous maps a context to its most recent delimited context, if any: Two of the contraction rules depend on the context: the J rule captures a copy of the context of the most recent caller and yields a state appender, and the β-rule for program closures reinstates a previously captured copy of the context. As for the β-rule for function closures, it introduces a delimiter.   Alternatively (if we allow J to be used outside the body of a lambda-term and we let it denote the empty context), this machine evaluates a program t by starting in the configuration t, (succ, SU CC) · ∅, [ ] eval . It halts with a value v if it reaches a configuration [ ], v cont . In either case, the machine is not in defunctionalized form [43,44]. Therefore, one cannot immediately map it into an evaluation function in CPS, as in Sections 2, 3, and 4. The next two sections present two alternatives, each of which is in defunctionalized form and operates in lockstep with the present abstract machine. 9. A syntactic theory of applicative expressions with the J operator: explicit, caller-save dumps Instead of marking the context and the intermediate closures, as in Section 8, one can cache the context of the caller in a separate register, which leads one towards evaluate1' alt in Section 4.2. For an analogy, in some formal specifications of Prolog [17,49], the cut continuation denotes the previous failure continuation and is cached in a separate register.
In the β-rule for function closures, J is dynamically bound to the current context.   In either case, the machine is in defunctionalized form. Refunctionalizing it yields a continuation-passing evaluation function. Refunctionalizing its closures and mapping the result back to direct style yields the compositional evaluation functions displayed in Section 4.5, i.e., Felleisen's embedding of the J operator in Scheme [51].

Summary and conclusion
We have presented a rational deconstruction of the SECD machine with the J operator, through a series of alternative implementations, in the form of abstract machines and compositional evaluation functions, all of which are new. We have also presented the first syntactic theories of applicative expressions with the J operator. In passing, we have shown new applications of refocusing and defunctionalization and new examples of control delimiters and of both pushy and jumpy delimited continuations in programming practice.
Even though they were the first of their kind, the SECD machine and the J operator remain computationally relevant today: • Architecturally, and until the advent of JavaScript run-time systems [57], the SECD machine has been superseded by abstract machines with a single control component instead of two (namely C and D). In some JavaScript run-time systems, however, methods have a local stack similar to C to implement and manage their expression continuation, and a global stack similar to D to implement and manage command continuations, i.e., the continuation of their caller. • Programmatically, and until the advent of first-class continuations in JavaScript [28], the J operator has been superseded by control operators that capture the current continuation (i.e., both C and D) instead of the continuation of the caller (i.e., D). In the Rhino implementation of JavaScript, however, the control operator captures the continuation of the caller of the current method, i.e., the command continuation instead of both the expression continuation and the command continuation. At any rate, as we have shown here, both the SECD machine and the J operator fit the functional correspondence [3,4,6,7,13,16,35,36] as well as the syntactic correspondence [12,14,15,34,36,45], which made it possible for us to mechanically characterize them in new and precise ways.
All of the points above make us conclude that new abstract machines should be defined in defunctionalized form today, or at least be made to work in lockstep with an abstract machine in defunctionalized form.

On the origin of first-class continuations
We have shown that jumping and labels are not essentially connected with strings of imperatives and in particular, with assignment. Second, that jumping is not essentially connected with labels. In performing this piece of logical analysis we have provided a precisely limited sense in which the "value of a label" has meaning. Also, we have discovered a new language feature, not present in current programming languages, that promises to clarify and simplify a notoriously untidy area of programming-that concerned with success/failure situations, and the actions needed on failure.
-Peter J. Landin, 1965 [82, page 133] It was Strachey who coined the term "first-class functions" [113, Section 3.5.1]. 8 In turn it was Landin who, through the J operator, invented what we know today as first-class continuations [58]: like Reynolds for escape [102], Landin defined J in an unconstrained way, i.e., with no regard for it to be compatible with the last-in, first-out allocation discipline prevalent for control stacks since Algol 60. 9 Today, 'continuation' is an overloaded term, that may refer • to the original semantic description technique for representing 'the meaning of the rest of the program' as a function, the continuation, as multiply co-discovered in the early 1970's [103]; or • to the programming-language feature of first-class continuations as typically provided by a control operator such as J, escape, or call/cc, as invented by Landin. Whether a semantic description technique or a programming-language feature, the goal of continuations was the same: to formalize Algol's labels and jumps. But where Wadsworth and Abdali gave a continuation semantics to Algol, and as illustrated in the beginning of Section 1, Landin translated Algol programs into applicative expressions in direct style. In turn, he specified the semantics of applicative expressions with the SECD machine, i.e., using first-order means. The meaning of an Algol label was an ISWIM 'program closure' as obtained by the J operator. Program closures were defined by extending the SECD machine, i.e., still using first-order means.
Landin did not use an explicit representation of the rest of the computation in his direct semantics of Algol 60, and for that reason he is not listed among the co-discoverers of continuations [103]. Such an explicit representation, however, exists in the SECD machine, in first-order form-the dump-which represents the rest of the computation after returning from the current function call.
In an earlier work [35], Danvy has shown that the SECD machine, even though it is first-order, directly corresponds to a compositional evaluation function in CPS-the tool of choice for specifying control operators since Reynolds's work [102]. In particular, the dump directly corresponds to a functional representation of control, since it is a defunctionalized continuation. In the light of defunctionalization, Landin therefore did use an explicit representation of the rest of the computation that corresponds to a function, and for that reason we wish to see his name added to the list of co-discoverers of continuations. We then give fib an extra argument, the continuation: fun fib_c (n, k) = if n <= 1 then k n else fib_c (n -1, fn v1 => fib_c (n -2, fn v2 => k (v1 + v2))) fun main1 n = fib_c (n, fn v => v) So for example, evaluating main1 5 yields 5.
A.4. The Fibonacci function in CPS with a trace. We can easily show that applying main1 and main2 as defined above to the same integer yields the same result, but we want to show a stronger property, namely that they operate in lockstep. To this end, we equip fib c with a trace recording its calls with the value of its first argument. (It would be simple to trace its returns as well, i.e., the calls to the continuation.) Representing the trace as a list, the Fibonacci function in CPS reads as follows: D.2. The abstract machine. As in Appendix C, one may wish to note that functions using local callee-save data stacks are not properly tail-recursive, though functions using global or local caller-save data stacks can be made to be. As in Appendix B and C, closure converting the data values of this evaluator, CPS transforming its control flow, and defunctionalizing its continuations yields an abstract machine. This machine is another variant of the CEK machine with a data stack; its terms, values, and environments remain the same: The second difference is that there is an extra context constructor, RET, to represent the continuation of the non-tail call to the evaluator over the body of function abstractions (i.e., a continuation that restores the caller's data stack and pushes the function return value on top). The new transition interprets a RET constructor by restoring the data stack of the caller and pushing the returned value on top of it before returning. It is simple to construct a bisimulation between this stack-threading machine and the CEK machine.
Appendix E. From reduction semantics to abstract machine As a warmup to Sections 7.3 and 7.4, we present a reduction semantics for applicative expressions (Section E.1) and we derive the CEK machine from this reduction semantics (Section E.2). E.1. A reduction semantics for applicative expressions. The λ ρ-calculus is a minimal extension of Curien's original calculus of closures λρ [31] to make it closed under onestep reduction [14]. We use it here to illustrate how to go from a reduction semantics to an abstract machine. To this end, we present its syntactic categories (Section E.1.1); a plug function mapping a closure and a reduction context into a closure by filling the given context with the given closure (Section E.1.2); a contraction function implementing a context-insensitive notion of reduction (Section E.1.3) and therefore mapping a potential 56 redex into a contractum; and a decomposition function mapping a non-value term into a potential redex and a reduction context (Section E.1.4). We are then in position to define a one-step reduction function (Section E.1.5) and a reduction-based evaluation function (Section E.1.6). E.1.1. Syntactic categories. We consider a variant of the λ ρ-calculus with names instead of de Bruijn indices, and with the usual reduction context C embodying a left-to-right applicative-order reduction strategy. Values are therefore a syntactic subcategory of closures, and in this section, we make use of the syntactic coercion ↑ mapping a value into a closure.
E.1.2. Plugging. Plugging a closure in a context is defined by induction over this context. We express this definition as a state-transition system with one intermediate state, For closed closures (i.e., closures with no free variables), all potential redexes are actual ones. We now can define by cases a total function contract that maps a redex to the corresponding contractum: E.1.4. Decomposition. There are many ways to define a total function mapping a value closure to itself and a non-value closure to a potential redex and a reduction context. In our experience, the following definition is a convenient one. It is a state-transition system with two intermediate states, c, C dec/clos and C, v dec/cont , an initial state c, [ ] dec/clos and two final states VAL (v) and DEC (r, C). If possible, the transition function from the state c, C dec/clos decomposes the given closure c and accumulates the corresponding reduction context C. The transition function from the state C, v dec/cont dispatches over the given context. We now can define a total function decompose over closures that maps a value closure to itself and a non-value closure to a decomposition into a potential redex, a control context, and a dump context. This total function uses two auxiliary functions decompose ′ clos and decompose ′ cont : decompose : Closure → Value + (PotRed × Context) decompose ′ clos : Closure × Context → Value + (PotRed × Context) decompose ′ cont : Context × Value → Value + (PotRed × Context) Definition E.3. For any closure c, value v, and context C, if c, C dec/clos → * DEC (r, C ′ ) and decompose (c) = decompose ′ clos (c, [ ]). E.1.5. One-step reduction. We are now in position to define a total function reduce over closed closures that maps a value closure to itself and a non-value closure to the next closure in the reduction sequence. This function is defined by composing the three functions above: Proof: straightforward. The two machines operate in lockstep.

E.2.3.
Inlining and transition compression. The abstract machine of Section E.2.2, while interesting in its own right (it is 'staged' in that the contraction rules are implemented separately from the congruence rules [14,69]), is not minimal: a number of transitions yield a configuration whose transition is uniquely determined. Let us carry out these hereditary, "corridor" transitions once and for all: The configuration r, C iter has disappeared and so is the case for c 0 c 1 : they were only transitory.  ) and flatten the configuration (t, e), C eval into a triple t, e, C eval , we obtain an abstract machine that coincides with the caller-save, stackless CEK machine of Section B.2.
E.3. Conclusion and perspectives. Appendix B illustrated the functional correspondence between the functional implementation of a denotational or natural semantics and of an abstract machine, the CEK machine, for the λ-calculus with left-to-right applicative order. The present appendix illustrates the syntactic correspondence between the functional implementation of a reduction semantics and of an abstract machine, again the CEK machine, for the λ-calculus with left-to-right applicative order. Together, the functional correspondence and the syntactic correspondence therefore demonstrate the natural fit of the CEK machine in the semantic spectrum of the λ-calculus with explicit substitutions and left-to-right applicative order.