REFLECTIONS OF CLOSURES by ZACHARY J. SULLIVAN A DISSERTATION Presented to the Department of Computer Science and the Division of Graduate Studies of the University of Oregon in partial fulfillment of the requirements for the degree of Doctor of Philosophy December 2023 DISSERTATION APPROVAL PAGE Student: Zachary J. Sullivan Title: Reflections of Closures This dissertation has been accepted and approved in partial fulfillment of the requirements for the Doctor of Philosophy degree in the Department of Computer Science by: Zena M. Ariola Chair Boyana Norris Core Member Michal Young Core Member Benjamin Young Institutional Representative and Krista Chronister Vice Provost for Graduate Studies Original approval signatures are on file with the University of Oregon Division of Graduate Studies. Degree awarded December 2023 2 Β© 2023 Zachary J. Sullivan All rights reserved. 3 DISSERTATION ABSTRACT Zachary J. Sullivan Doctor of Philosophy Department of Computer Science December 2023 Title: Reflections of Closures The idea that programs are data forms the bedrock of functional programming languages, but it is also found in object-oriented languages and recent iterations of systems languages. Since passing and returning programs as data is incompatible with the architecture of modern machines, implementations of such a feature gives rise to closures, which package code with the environment that it needs to run. The first implementations of these objects are as part of the runtime system of an abstract machine. However, to be able to optimize these structures, compiler writers often choose instead to embed this structure in their code when compiling to lower-level languages in a transformation called closure conversion. While this transformation and closures more generally are well studied with respect to certain types of programming languages, how such a language interacts with different evaluation strategies still remains unstudied in a theoretical setting. Moreover, the current approaches to performing, optimizing, and proving correct this transformation lack the flexibility of other language features. This thesis develops these ideas by presenting closure conversions for missing evaluation strategies, specifying a new implementation approach that allows for the flexible implementation and optimization of closures, and formalizing them in an intermediate language that captures multiple notions of closures and evaluation strategies 4 in one. Our approach follows from first principles meaning that our closures are a reflection of the environment-based abstract machines that birth them. We develop an approach to reasoning about closures that connects their equational properties with the abstract machines on which they run. Thereby, we can prove not only that closure conversion does not change the output of programs, but that closure conversion removes the need for the runtime system to capture closures. This dissertation includes previously published, co-authored material. 5 CURRICULUM VITAE NAME OF AUTHOR: Zachary J. Sullivan GRADUATE AND UNDERGRADUATE SCHOOLS ATTENDED: University of Oregon, Eugene, OR, USA Indiana University, Bloomington, IN, USA DEGREES AWARDED: Master of Science, Computer Science, 2018, University of Oregon Bachelor of Science, Computer Science, 2016, Indiana University AREAS OF SPECIAL INTEREST: Compilation Design of Programming Languages Verification PROFESSIONAL EXPERIENCE: Year Round Intern. Sandia CA. 2019-Present. Graduate Employee. University of Oregon. 2017-Present. PUBLICATIONS: Zachary J. Sullivan, Paul Downen, and Zena M. Ariola. Closure Conversion in Little Pieces. International Symposium on Principles and Practice of Declarative Programming. 2023. Zachary J. Sullivan, Paul Downen, and Zena M. Ariola. Strictly Capturing Non-strict Closures. Workshop on Partial Evaluation and Program Manipulation. 2021. Paul Downen, Zachary Sullivan, Zena M. Ariola, and Simon Peyton Jones. Making a Faster Curry with Extensional Types. Haskell Symposium. 2019. 6 Paul Downen, Zachary Sullivan, Zena M. Ariola, and Simon Peyton Jones. Codata in Action. European Symposium on Programming. 2019. 7 ACKNOWLEDGEMENTS This dissertation would not have been possible without the many people who helped me out along the way. My advisor, Zena, guided me throughout my entire time in Oregon. She, more than anyone, drove me to clearly understand and articulate the necessary parts of my work that I tended to gloss over. Paul Downen helped me not only with the technical knowledge necessary for this work, but also played a huge role along with Zena in influencing my research ideas. Sandia National Laboratory supported most of my PhD financially. Additionally, the community there played a role in motivating the correctness ideas found in much of my work. My mentors, Johnson-Freyd and Sam Pollard, each took the time to listen to my raw, unfiltered thoughts when I was moving towards a new idea. A special thanks to Sam and Anthony Dario, who provided feedback in polishing and presenting this document. Lastly, I would like to thank those closest to me. My parents made many sacrifices to put me in a position to succeed in my schooling while also providing unconditional support for anything I might do. My older siblings, being successful in their own endeavours, were role models that motivated me to realize my goals. My friends and especially my girlfriend, Dewi, made my time in graduate school amazing. For all of this, I am grateful. 8 TABLE OF CONTENTS Chapter Page I. INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.1. The Emergence of Closures . . . . . . . . . . . . . . . . . . . . . . 14 1.2. Reflecting Closures in a Language . . . . . . . . . . . . . . . . . . . 16 1.3. Reasoning about Closures . . . . . . . . . . . . . . . . . . . . . . . 17 1.4. Outline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 II. MACHINES AND THEIR CALCULI . . . . . . . . . . . . . . . . . . . . . 20 2.1. The SECD Machine and Call-by-Value . . . . . . . . . . . . . . . . . 23 2.2. The Krivine Machine and Call-by-Name . . . . . . . . . . . . . . . . 26 2.3. The Sestoft Machine and Call-by-Need . . . . . . . . . . . . . . . . 28 III. CLOSURE CONVERSIONS . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.1. The Canonical Closure Conversion . . . . . . . . . . . . . . . . . . 35 3.2. Non-strict Closure Conversions . . . . . . . . . . . . . . . . . . . . 45 3.3. Sharing Closure Conversion . . . . . . . . . . . . . . . . . . . . . . 53 IV. ABSTRACT CLOSURES . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 4.1. Why Abstract Closures . . . . . . . . . . . . . . . . . . . . . . . . 63 4.2. Closures for Different Evaluation Strategies . . . . . . . . . . . . . . 66 4.3. Deriving Closure Conversions . . . . . . . . . . . . . . . . . . . . . 70 4.4. Using Abstract Closures . . . . . . . . . . . . . . . . . . . . . . . . 71 V. CBPVS: A COMMON INTERMEDIATE LANGUAGE . . . . . . . . . . . . 75 5.1. CBPV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 5.2. Adding Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 5.3. Subsuming Call-by-Need . . . . . . . . . . . . . . . . . . . . . . . . 85 9 Chapter Page VI. CLOSURES AND MACHINES FOR CBPVS . . . . . . . . . . . . . . . . . . 94 6.1. An Environment Machine for CBPV . . . . . . . . . . . . . . . . . . 94 6.2. CBPVS with Closures . . . . . . . . . . . . . . . . . . . . . . . . . 97 6.3. The CBPVS Machine . . . . . . . . . . . . . . . . . . . . . . . . . . 99 6.4. Backwards Simulation . . . . . . . . . . . . . . . . . . . . . . . . . 101 6.5. Observational Equivalence . . . . . . . . . . . . . . . . . . . . . . . 112 VII. A MODEL OF TYPES OVER THE CBPVS MACHINE . . . . . . . . . . . . 118 7.1. Logical Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 7.2. Semantic Equality . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 7.3. Soundness of CBPVS . . . . . . . . . . . . . . . . . . . . . . . . . . 186 7.4. Adequacy of Closure Conversions . . . . . . . . . . . . . . . . . . . 186 VIII. DISCUSSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 8.1. Related Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 8.2. Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 8.3. Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 REFERENCES CITED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 10 LIST OF FIGURES Figure Page 2.1. Church’s πœ†-calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.2. Types for πœ†-expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.3. The SECD Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.4. The Call-by-Value Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.5. The Krivine Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.6. The Call-by-Name Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.7. The Sestoft Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.8. A Call-by-Need Calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.1. Strict Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.2. Closure Conversion Target Language . . . . . . . . . . . . . . . . . . . . . 37 3.3. Target Language Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.4. Canonical Closure Conversion . . . . . . . . . . . . . . . . . . . . . . . . 40 3.5. Strict Closure Conversion Logical Relations . . . . . . . . . . . . . . . . . 41 3.6. Non-strict Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 3.7. A Non-strict Closure Conversion . . . . . . . . . . . . . . . . . . . . . . . 49 3.8. Non-strict Closure Conversion Logical Relations . . . . . . . . . . . . . . . 50 3.9. Lazy Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 3.10. Target Language extended with Sums and Mutation . . . . . . . . . . . . . 57 3.11. Mutable Target Language Evaluation . . . . . . . . . . . . . . . . . . . . . 58 3.12. Memoizing Non-strict Closure Conversion . . . . . . . . . . . . . . . . . . 59 4.1. Syntactic Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 4.2. Call-by-Value with Closures . . . . . . . . . . . . . . . . . . . . . . . . . 66 11 Figure Page 4.3. Call-by-Name with Closures . . . . . . . . . . . . . . . . . . . . . . . . . 68 4.4. Call-by-Need with Closures . . . . . . . . . . . . . . . . . . . . . . . . . . 69 4.5. Example of Environment Sharing with Abstract Closures . . . . . . . . . . 73 5.1. Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.2. Typing Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.3. CBPV Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 5.4. Compiling CBN and CBV to CBPV . . . . . . . . . . . . . . . . . . . . . . 79 5.5. CBPVS: CBPV with Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . 80 5.6. CBPVS Typing Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 5.7. CBPVS Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 5.8. Compiling CBNeed to CBPVS . . . . . . . . . . . . . . . . . . . . . . . . . 86 5.9. More Flexible Call-by-Need Axioms . . . . . . . . . . . . . . . . . . . . . 87 6.1. CBPV Machine Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 6.2. Building CBPV Machine Values . . . . . . . . . . . . . . . . . . . . . . . . 96 6.3. CBPV Machine Transitions . . . . . . . . . . . . . . . . . . . . . . . . . . 96 6.4. CBPVS with Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 6.5. CBPVS Machine Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 6.6. Building CBPVS Machine Values and Heap Objects . . . . . . . . . . . . . 101 6.7. CBPVS Machine Transitions . . . . . . . . . . . . . . . . . . . . . . . . . 102 6.8. CBPVS Machine Decoding . . . . . . . . . . . . . . . . . . . . . . . . . . 103 7.1. CBPVS Logical Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 12 CHAPTER I INTRODUCTION Higher-order functions are those that may take other functions as arguments. These are the essential feature for functional programming languages based on Church’s πœ†- calculus [13]. A canonical example of why this is useful is the map function: map 𝑓 [] = [] map 𝑓 (π‘₯ :: xs) = 𝑓 π‘₯ :: map 𝑓 xs With such a function, which takes any function 𝑓 as an argument, we turn one list into another considering while applying 𝑓 each element. For example, we may now write programs like map (+1) [1, 2, 3] and map print [1, 2, 3]. In a language like C, we could write a similar function using arrays instead of recursively defined lists and assuming the void type for the elements of the array: void βˆ— map(void (βˆ—π‘“ ) void, void βˆ— π‘₯𝑠, int 𝑙𝑒𝑛) { for (int 𝑖 = 0; 𝑖 + +; 𝑖 < len){ xs[𝑖] = (βˆ—π‘“ ) (xs[𝑖]); } } However, there is an important difference between function pointers in C and the function that can be passed to higher-order functions like map: the former must be defined at the top level of a program, whereas the latter may be specified by being nested deep within the structure of a programβ€”i.e. its lexical scopeβ€”or even returned as a result of other programs. For example, we can pass the following function, which is nested within a 13 let-expression, to map as the formal parameter 𝑓 : let π‘₯ be 21 in πœ†π‘¦. π‘₯ + 𝑦 In evaluation, some representation of the unevaluated function πœ†π‘¦. π‘₯ +𝑦 will be bound to 𝑓 when the body of map is run. Because of its lexical scope, π‘₯ should be bound to 21 and 𝑦 should be found as an argument when the code π‘₯ + 𝑦 is finally run. It is not only higher-order functions that involve the passing of lexically-scoped, unevaluated expressions. Indeed, languages with lazy evaluation or non-strictness also wait to evaluate expressions until later. Laziness can be found in languages as old as ALGOL-60, but is found today in more popular languages like Haskell or in the memoizable types of OCaml. For instance, the following Haskell program: let π‘₯ = 21 in [1, 2, π‘₯ + 2] will immediately return a list of three elements; however, the third element π‘₯ + 2 will remain an unevaluated until some other code forces it to become a value, e.g. by printing it. Therefore, we end up with the same need to maintain the lexical structure of the unevaluated code when we return. 1.1 The Emergence of Closures Though C’s code pointers are not as flexible, they can be directly represented by the instruction-set architecture’s of modern machines. When passing unevaluated expressions as values in amodernmachine, the nested, lexical structure of these languages must be captured in some way as fixed machine code. The language’s operational semantics is often specified with a substitution operation, which is an intuitive, high-level description; however, using substitutions runs counter to the goal of generating fixed code 14 since it must create new expressions dynamically. To cope with this, implementations instead keep a local store mapping variables to values; these values are looked up when the variable is needed. The unevaluated expressions of these languages are encoded as closures, which are structures containing some code and the environment for which it needs to run. Closures do not appear explicitly in source code so there is a question of whether their usage correctly reflects our source semantics. Landin’s SECD-machine [24] is one of the earliest implementations of the πœ†-calculus; it made use of closures. However, Plotkin [46] later found that his implementation did not actually capture the the semantics of Church’s calculus [13], since it always evaluated the arguments of functions. Plotkin specified a new calculus that was reified by the SECD-machine called the call-by-value πœ†-calculus. Later, Krivine [23] would succeed in specifying a machine that captured Church’s theory, which a theory we now refer to as call-by-name. A notable difference between these two machines is their use of closures: the SECD-machine generated closures only for the functions in the language whereas the Krivine-machine generated closures for any expression in the language when it was a function argument. As optimizations of the call-by-name machines, lazy machines [48] evaluated function arguments at most once by passing closures as a references and updating them with their evaluated form when forced. Indeed, here the source semantics did not properly capture what was occurring in the machine. The source semantics that these machines implemented was described was later specified as call-by-need by Ariola et al. [9]. We refer to these three methods of computation as evaluation strategies and they all treat closures differently in their abstract machines. Another approach to implementation of functional languages is to compile them to lower-level languages for which we already have a compiler, e.g. C. Therein, a transformation called closure conversion encodes in the target language a data structure 15 that captures the environment, which the unevaluated code requires, along with a global function, which knows how to re-instantiate that environment before executing. All previous work on such a transformation [34, 36, 3, 38, 39] describes the transformation necessary for compiling call-by-value programs. Thus, like the SECD-machine, their transformation only builds closures around functions. The first contribution presented in this thesis is that we describe the missing closure conversions transformations for the call-by-name and call-by-need evaluation strategies [52]. Like their machines, the call-by-name closure conversion transformation generates closure code for function arguments and the call-by-need closure conversion generates extra code that performs the memoization of closure evaluation. We are sure to emphasize the importance of the effect the transformation has on the kind of target language it employs: the target language need not have lexically-scoped passing of delayed computations. 1.2 Reflecting Closures in a Language Treating closure conversion as a compilation between high- and low-level intermediate languagesβ€”as is the case with previous workβ€”is less than ideal for optimizing compilers. An effective approach for optimization is to have a core intermediate language wherein a large amount of optimizations are done by local transformations [44, 51, 5, 39]. Being a global transformation, closure conversion has been excluded from this approach. Another contribution in this thesis is that we propose a new approach to closure conversionwhich enables it toworkwithin such optimizing compilers [53]. We build on the concept of abstract closures [21, 34, 11], which are reflections of runtime closures as objects within language itself. Specifically, abstract closures are delayed code paired with a delayed substitution. Using them allows us to make closure conversion a local transformation within an intermediate language, instead of between high- and low-level languages. 16 To formalize the idea, we create a single intermediate language for the optimization of closures that supports the compilation of call-by-name, call-by-value, and call-by-need evaluation strategies. To support the first two, we start with call-by-push-value [27], a language that has a strong enough theory to subsume both call-by-name and call-by- value. We present a new extension to this language that allows it to support the call- by-need evaluation strategy as well; this is why it is called CBPVS or call-by-push-value plus sharing. We then show how to add closures to such a language and specify a closure conversion transformation. To demonstrate that our language is suitable for optimization, aside from the strong equational theory that it gets from being derived from call-by-push- value, we show how closure optimizations that already exist in the literature [50, 19] are local rewrites. 1.3 Reasoning about Closures Our new approach to closures gives us strong reasoning properties about the relationship between our language and our operational semantics. Not only does closure conversion preserve the evaluation of programs, but its application also allows us to use a simpler operational semantics. This latter property we refer to as the adequacy of closure conversion. To prove it, we develop operational semantics for our source and target languages with delayed runtime environments such that we can precisely show that this property along with semantics preservation. We believe that closure conversion should be proved adequate with respect to a particular abstract machine, since closures arise from their implementation in these machines. An inadequate version of the transformation would still require that the machine construct closures within its runtime. We extend previous the logical relation reasoning approaches [3, 34] for closure conversion to work over this new operational semantics. 17 For our new approach to closure conversionβ€”i.e. within the intermediate languageβ€” verifying the correctness of our approach to the transformation is a corollary of the soundness of the theory over these delayed runtime environments. That is, all transformations that are expressible within the equational theory, including closure conversion, are correct by construction. This is in contrast to previous work including our extension just mentioned [3, 52, 34] that constructs a bespoke logical relation between the source and target languages for each new closure conversion. The final contribution of this work is prove that our language CBPVS is sound with respect an abstract machine with delayed substitutions. This verifies our new approach to closure conversion, shows that we correctly added closures to a new language, and as a corollary that the transformation is adequate. In so doing, we created new proof techniques using logical relations for working with delayed substitutions, a sharing heap, and extensional equational theories all at once. 1.4 Outline Chapter 2 presents important abstract machines and the call-by-name, call-by-value, and call-by-need πœ†-calculi that reflect those machines. Chapter 3 describes closure conversion which embeds closures in a lower-level language. Here, we present our contribution [52] that extended the transformation to call-by-name and call-by-need languages. Chapter 4 argues for a new approach to reasoning about closures and performing closure conversions within a single compiler intermediate language. We show how this applies to each evaluation strategy separately. Chapter 5 presents a common compiler intermediate language, CBPVS, that unifies the languages of the previous chapter. Chapter 6 shows how closures arise in CBPV and CBPVS by developing environment abstract machines. Chapter 7 proves the correctness of CBPVS’s equational theory including closures with respect to this abstract machine. Thereafter, it describes 18 what it means for closure conversions to be adequate, proves how our use of abstract closures satisfies it. This dissertation is based on the work of two papersβ€”i.e. Strictly Capturing Non- strict Closures [52] and Closure Conversion in Little Pieces [53]β€”and their appendices that were authored by Zachary J. Sullivan, Paul Downen, and Zena M. Ariola. In both of the published papers, Zachary J. Sullivan was the primary contributor while being closely advised by Paul Downen and ZenaM. Ariola for the technical aspects, design, and framing of work. 19 CHAPTER II MACHINES AND THEIR CALCULI The earliest approaches to mechanizing the πœ†-calculus were presented as abstract machines; that is, state transitions systems represented at a level suitable for easy mapping to an instruction-set architecture. For various reasons that we will explore, the machines themselves diverged from the original calculus [13] that they were meant to implement. As a reflection of the different machine evaluation behavior, different evaluation strategies, or different source semantics, were created to characterize how the programswould run. Analogously, the work in this dissertationwill be a further reflection on these implementations. Specifically, we focus on their closures. This chapter presents three forms of semantics for the πœ†-calculus and their interaction: equational theories, type theories, and abstract machines. The first kind of semantics are equational theories. Therein, we define a set of axioms relating two expressions of a language. These axioms are combined with the following rules to make up the theory: Refl. 𝑁 = 𝑀 Sym. 𝑀 = 𝑁 𝑁 = 𝐿 Trans 𝑀 = 𝑁. [ ] [ ] Comp.𝑀 = 𝑀 𝑀 = 𝑁 𝑀 = 𝐿 𝐢 𝑀 = 𝐢 𝑁 The first three rules make the theory and equivalence relation. The last of these rules is compatibility; it states that for any context, an expression with a hole, if two expressions are equal, then they are equal when plugged into that context. Such a rule is essential for flexibility when optimizing since it allows us to preform local rewrites anywhere within a program. 20 𝑀, 𝑁, 𝐿 ∈ Expression ::= b | π‘₯ | πœ†π‘₯.𝑀 | 𝑀 𝑁 (a) Syntax πœ†π‘₯ .𝑀 =𝛼 πœ†π‘¦.𝑀 [𝑦/π‘₯] (πœ†π‘₯. 𝑀) 𝑁 =𝛽 𝑀 [𝑁 /π‘₯] πœ†π‘₯ .𝑀 π‘₯ =πœ‚ 𝑀 (b) Axioms Figure 2.1. Church’s πœ†-calculus Let us consider Church’s πœ†-calculus [13] presented Figure 2.1 as our first example of an equational theory. It contains only a few syntactic constructions that make up the expressions of the language. The anonymous function πœ†π‘₯. 𝑀 takes an argument and binds it to π‘₯ in the expression 𝑀 . The application form 𝑀 𝑁 will call the function 𝑀 with the argument 𝑁 . Finally, we reference the bound variables with the variable expression. Along with the syntax, Figure 2.1 specifies three axioms. The first, 𝛼 , states that any two functions are equivalent if they are the same except for the name of their formal parameter. The second, 𝛽 , describes howwe compute with functions: if a function is applied, then it is equal to replacing the occurrence of the variable with the argument within the function’s body. The third, πœ‚, says that a function is equivalent to a new function that immediately applies it to its argument. This last is equivalent to function extensionality 𝑀 π‘₯ = 𝑁 π‘₯ =β‡’ 𝑀 = 𝑁 stating that if two functions behave the same when applied to the same arguments, then they are the same. The axioms make use of a meta-syntactic function called substitution. Generically, 𝑀 [𝑁 /π‘₯] means that we recursively traverse the expressions 𝑀 and replace free 21 π‘₯ :𝜏 ∈ Ξ“ var Ξ“, π‘₯ :𝜏 ⊒ 𝑀 : 𝜎 β†’ Ξ“ ⊒ 𝑀 : 𝜎 β†’ 𝜏 Ξ“ ⊒ 𝑁 : 𝜎⊒ β†’Ξ“ b : 𝐡𝐡 Ξ“ ⊒ π‘₯ : 𝐼𝜏 Ξ“ ⊒ πœ†π‘₯. 𝑀 : 𝜏 β†’ 𝜎 Ξ“ ⊒ 𝑀 𝑁 : 𝐸𝜏 Figure 2.2. Types for πœ†-expressions. occurrences of π‘₯ with 𝑁 to generate a new expression. The set of expressions capable of being substituted,𝑀 in the definition below, are referred to as the values of the calculus. Definition 2.1 (Substitution). b[𝑀/π‘₯] = b π‘₯ [𝑀/π‘₯] = 𝑀 𝑦 [𝑀/π‘₯] = 𝑦 (πœ†π‘₯. 𝑁 ) [𝑀/π‘₯] = πœ†π‘₯. 𝑁 (πœ†π‘¦. 𝑁 ) [𝑀/π‘₯] = πœ†π‘¦. 𝑁 [𝑀/π‘₯] (𝑁 𝐿) [𝑀/π‘₯] = 𝑁 [𝑀/π‘₯] 𝐿[𝑀/π‘₯] The second notion of semantics are typing rules. Those for the simply-typed πœ†- calculus are presented in Figure 2.2. These are β€œstatic” in the sense that they do not change how we evaluate programs, but we use them to ensure that the program is well formed. The typing rules are important for πœ‚ axioms, in particular, which only apply when they are applied to programs of the correct type. This is not a problem in calculi with only functions types, since everything can be treated as a function; however, it does not make sense to πœ‚ expand a pair into a function. We codify this restriction by giving the following definition of syntactic equality: Ξ“ ⊒ 𝑀 : 𝜏 Ξ“ ⊒ 𝑁 : 𝜏 𝑀 = 𝑁 Ξ“ ⊒ 𝑀 = 𝑁 : 𝜏 22 𝑆 ∈ Stack ::= πœ€ | V Β· 𝑆 𝐸 ∈ Machine Environment ::= πœ€ | 𝐸,V/π‘₯ 𝐢 ∈ Control ::= πœ€ | 𝑀 ·𝐢 | ap ·𝐢 𝐷 ∈ Dump ::= πœ€ | (𝑆, 𝐸,𝐢, 𝐷) V ∈ Machine Value ::= b | (𝐸, πœ†π‘₯ . 𝑀) Configuration ::= βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ 𝐢 βˆ₯ 𝐷⟩⟩ (a) Machine Syntax βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ b ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’1 ⟨⟨b Β· 𝑆 βˆ₯ 𝐸 βˆ₯ 𝐢 βˆ₯ 𝐷⟩⟩ βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ π‘₯ ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’2 ⟨⟨π‘₯ [𝐸] Β· 𝑆 βˆ₯ 𝐸 βˆ₯ 𝐢 βˆ₯ 𝐷⟩⟩ βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ πœ†π‘₯ .𝑀 ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’3 ⟨⟨(𝐸, πœ†π‘₯ . 𝑀) Β· 𝑆 βˆ₯ 𝐸 βˆ₯ 𝐢 βˆ₯ 𝐷⟩⟩ βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ 𝑀 𝑁 ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’4 βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ 𝑁 ·𝑀 Β· ap ·𝐢 βˆ₯ 𝐷⟩⟩ ⟨⟨(𝐸′, πœ†π‘₯ . 𝑀) Β· V Β· 𝑆 βˆ₯ 𝐸 βˆ₯ ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’5 βŸ¨βŸ¨πœ€ βˆ₯ 𝐸′,V/π‘₯ βˆ₯ 𝑀 Β· πœ€ βˆ₯ (𝑆, 𝐸,𝐢, 𝐷)⟩⟩ ⟨⟨V Β· πœ€ βˆ₯ 𝐸 βˆ₯ πœ€ βˆ₯ (𝑆′, 𝐸′,𝐢′, 𝐷′)⟩⟩ β†¦βˆ’β†’6 ⟨⟨V Β· 𝑆′ βˆ₯ 𝐸′ βˆ₯ 𝐢′ βˆ₯ π·β€²βŸ©βŸ© (b) Transitions Figure 2.3. The SECD Machine We will only have one type system for expressions, but we will present several calculi and abstract machines which capture different notions of dynamically evaluating these expressions. While substitution is useful for intuitive explanations of calculi, it is not good for implementation on machines since we must generate fixed code sequences for programs. Thus, our abstract machines will be presented with delayed substitutions, wherein β€œsubstitution” only occurs if the variable is demanded at runtime. 2.1 The SECD Machine and Call-by-Value The earliest cited πœ†-calculus abstract machine was Landin’s SECDmachine [24]. The machine is named for the four parts of its state: 𝑆 , an intermediate result stack; 𝐸, an environment containing a mapping from variables to values; 𝐢 , a control stack; and 𝐷 , a dump of a machine state. Evaluation of the machine is a transition, denoted (β†¦βˆ’β†’), from machine state to machine state. 23 Figure 2.3 gives the syntax and transition rules for the machine. The result stack holds only values and the environment maps to values. The notion of value for the SECDmachine, and many other abstract machines, is different from the notion often used for reduction theory, structural operational semantics, and equational theories wherein values are the subset of the whole language which are substitutable. Instead, values refer to objects that can be mapped to from the machine’s environment; hence, we sometime refer to them as machine values to contrast them with those of the source language. For an object that behaves like an integer, constants like 4 are values whereas arithmetic expressions like 3 + 1 must be evaluated before they can be placed on the result stack or in the environment. In the case of functions, the SECD machine constructs function closures, (𝐸, πœ†π‘₯ .𝑦), which pair a πœ†-expression with some environment. The control stack is so named because the next state transition always depends on the value at the top of this stack. When the top of the control stack is an application expression, the application is deconstructed and an application marker, the function, and the argument are placed on the control stack, in that order. This deconstruction can be seen as searching for the next expression to evaluate. In this case, we evaluate the function argument then the function itself. When both the argument and the function are evaluated to a value, an application marker will be at the top of the control stack which triggers the application. The dump of the SECD machine is used to return from function calls. When a function is applied, in transition 5, the state of the machine is saved. The state is re- instantiated when the function returns, in transition 6, and after the machine value computed by the function call is added to the result stack. Note that returning from a function call returns to the environment before that call. This means that any unevaluated code that is returned ought to have saved its environment in a closure. 24 Definition 2.2 (SECD Evaluation). Eval βˆ—SECD(𝑀) = b where βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝑀 Β· πœ€ βˆ₯ πœ€βŸ©βŸ© βˆ’β†¦ β†’ ⟨⟨b Β· πœ€ βˆ₯ 𝐸 βˆ₯ πœ€ βˆ₯ πœ€βŸ©βŸ©. As an example, consider the evaluation trace for the program (πœ†π‘₯ . πœ†π‘¦. π‘₯) 4 2 with an arbitrary starting 𝑆 , 𝐸, 𝐢 , and 𝐷 (i.e. anywhere in a program): βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ (πœ†π‘₯. πœ†π‘¦. π‘₯) 4 2 ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨π‘† βˆ₯ 𝐸 βˆ₯ 2 Β· (πœ†π‘₯. πœ†π‘¦. π‘₯) 4 Β· ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ ⟨⟨2 Β· 𝑆 βˆ₯ 𝐸 βˆ₯ (πœ†π‘₯. πœ†π‘¦. π‘₯) 4 Β· ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ ⟨⟨2 Β· 𝑆 βˆ₯ 𝐸 βˆ₯ 4 Β· πœ†π‘₯ . πœ†π‘¦. π‘₯ Β· ap Β· ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ ⟨⟨4 Β· 2 Β· 𝑆 βˆ₯ 𝐸 βˆ₯ πœ†π‘₯ . πœ†π‘¦. π‘₯ Β· ap Β· ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ ⟨⟨(𝐸, πœ†π‘₯ . πœ†π‘¦. π‘₯) Β· 4 Β· 2 Β· 𝑆 βˆ₯ 𝐸 βˆ₯ ap Β· ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨πœ€ βˆ₯ 𝐸, 4/π‘₯ βˆ₯ πœ†π‘¦. π‘₯ Β· πœ€ βˆ₯ (2 Β· 𝑆, 𝐸, ap ·𝐢, 𝐷)⟩⟩ β†¦βˆ’β†’ ⟨⟨((𝐸, 4/π‘₯), πœ†π‘¦. π‘₯) Β· πœ€ βˆ₯ 𝐸, 4/π‘₯ βˆ₯ πœ€ βˆ₯ (2 Β· 𝑆, 𝐸, ap ·𝐢, 𝐷)⟩⟩ β†¦βˆ’β†’ ⟨⟨((𝐸, 4/π‘₯), πœ†π‘¦. π‘₯) Β· 2 Β· 𝑆 βˆ₯ 𝐸 βˆ₯ ap ·𝐢 βˆ₯ 𝐷⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨πœ€ βˆ₯ 𝐸, 4/π‘₯, 2/𝑦 βˆ₯ π‘₯ Β· πœ€ βˆ₯ (𝑆, 𝐸,𝐢, 𝐷)⟩⟩ β†¦βˆ’β†’ ⟨⟨4 Β· πœ€ βˆ₯ 𝐸, 4/π‘₯, 2/𝑦 βˆ₯ πœ€ βˆ₯ (𝑆, 𝐸,𝐢, 𝐷)⟩⟩ β†¦βˆ’β†’ ⟨⟨4 Β· 𝑆 βˆ₯ 𝐸 βˆ₯ 𝐢 βˆ₯ 𝐷⟩⟩ This machine does not match the behavior of the 𝛽 law in Church’s theory. If we consider the program (πœ†π‘₯.𝑦) Ξ©, where Ξ© is the infinitely looping expression (πœ†π‘₯ . π‘₯ π‘₯) (πœ†π‘₯. π‘₯ π‘₯), then it would reduce to the normal form 𝑦 in Church’s calculus, but would loop forever in the machine. This is because the machine must continue to evaluate the argument of a function until it reaches a machine value. The property of evaluating function arguments before continuing is referred to as being strictly evaluated. Noting the difference in the strictness of the machine and Church’s calculus, Plotkin [46] specified a new calculus called call-by-value in Figure 2.4. There is a sub-syntax 25 𝑉 ,π‘Š ∈ Value ::= b | π‘₯ | πœ†π‘₯. 𝑀 (a) Syntax (πœ†π‘₯ .𝑀) 𝑉 =𝛽 𝑀 [𝑉 /π‘₯] πœ†π‘₯.𝑉 π‘₯ =πœ‚ 𝑉 (b) Axioms Figure 2.4. The Call-by-Value Calculus of values that determine when the 𝛽 law is applicable. Just like the SECD machine, a call-by-value calculus yields no normal form for the program (πœ†π‘₯.𝑦) Ξ© because Ξ© has no normal form and must be evaluated. The πœ‚ axiom for functions in call-by-value must be restricted to values; otherwise, an πœ‚-reduction could turn a value into a non-value breaking its connection with the SECD machine. That connection is captured in the following proposition proved by Plotkin [46]. Proposition 2.1. EvalSECD(𝑀) = b if and only if ⊒ 𝑀 =CBV b : 𝐡. 2.2 The Krivine Machine and Call-by-Name The Krivine machine [23] is the earliest abstract machine that actually captured Church’s calculus, despite remaining unpublished folklore until 2007. An essential aspect in this machine is to delay the evaluation of arguments until later. As published, the machine operates on a special version of DeBruijn indices [14], but we present, instead, a machine that operates on variables to make it easier to read. The machine’s syntax and transitions are shown in Figure 2.5. Like the SECD machine, the Krivine machine has a notion of call stack; but here it contains only arguments to functions. Whereas SECD has a stack for values and a dump for returning from function calls, the Krivine machine encodes all of this information with its single stack. 26 𝐾 ∈ Continuation ::= πœ€ | V Β· 𝐾 Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£,V/π‘₯ V ∈ Machine Value ::= (Ξ£, 𝑀) Configuration ::= ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ (a) Machine Syntax ⟨⟨Σ βˆ₯ π‘₯ βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ where π‘₯ [Ξ£] = (Ξ£β€², 𝑀) ⟨⟨Σ βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ V Β· 𝐾⟩⟩ β†¦βˆ’β†’ ⟨⟨Σ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀 𝑁 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’ ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ (Ξ£, 𝑁 ) Β· 𝐾⟩⟩ (b) Transitions Figure 2.5. The Krivine Machine (πœ†π‘₯. 𝑀) 𝑁 =𝛽 𝑀 [𝑁 /π‘₯] πœ†π‘₯ .𝑀 π‘₯ =πœ‚ 𝑀 Figure 2.6. The Call-by-Name Calculus Since the machine does not evaluate the arguments to functionsβ€”making it non- strictβ€”and unevaluated arguments may contain free variables, the machine must have closures for everything that is added to its local environment. These closures are constructed eagerly when they are pushed on the stack; an observation that will become relevant in later chapters. Unlike the SECD machine, which implements what Plotkin called call-by-value, the Krivine machine implements call-by-name by avoiding the evaluation of its argument and proceeding directly to evaluating the left-hand side of the application. The axioms for call-by-name are indeed those given by Church in Figure 2.1. Definition 2.3 (Krivine Machine Evaluation). EvalKAM(𝑀) = b where βŸ¨βŸ¨πœ€ βˆ₯ 𝑀 βˆ₯ πœ€βŸ©βŸ© βˆ’β†¦ β†’βˆ— ⟨⟨Σ βˆ₯ b βˆ₯ πœ€βŸ©βŸ©. 27 As an example of execution, consider again the program (πœ†π‘₯ . πœ†π‘¦. π‘₯) 4 2: ⟨⟨Σ βˆ₯ (πœ†π‘₯. πœ†π‘¦. π‘₯) 4 2 βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’ ⟨⟨Σ βˆ₯ (πœ†π‘₯ . πœ†π‘¦. π‘₯) 4 βˆ₯ (Ξ£, 2) Β· 𝐾⟩⟩ β†¦βˆ’β†’ ⟨⟨Σ βˆ₯ πœ†π‘₯ . πœ†π‘¦. π‘₯ βˆ₯ (Ξ£, 4) Β· (Ξ£, 2) Β· 𝐾⟩⟩ βˆ’β†¦ β†’ ⟨⟨Σ, (Ξ£, 4)/π‘₯ βˆ₯ πœ†π‘¦. π‘₯ βˆ₯ (Ξ£, 2) Β· 𝐾⟩⟩ βˆ’β†¦ β†’ ⟨⟨Σ, (Ξ£, 4)/π‘₯, (Ξ£, 2)/𝑦 βˆ₯ π‘₯ βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’ ⟨⟨Σ βˆ₯ 4 βˆ₯ 𝐾⟩⟩ An important difference between the SECDmachine and the Krivine machine, which is evident in their evaluation of the above expression beside how they handle function arguments, is how they handle functions. Notice that the SECD machine first evaluates the function and returns it on the stack before applying it, whereas the Krivine machine merely pushes the argument on the stack and enters the left-hand side and will never return a function closure. Thus, we never see the Krivine machine create a closure for the function in this example code, but the SECD machine does even though it is entered immediately. Proposition 2.2. EvalKAM(𝑀) = b if and only if ⊒ 𝑀 =CBN b : 𝐡. 2.3 The Sestoft Machine and Call-by-Need Since it delays the evaluation of function arguments, the Krivine machine will evaluate those arguments every time that the variable that binds them appears. A more efficient way to perform this non-strict evaluation is by memoization. Memoization is a core idea of computer science. It is found in the study of algorithms as dynamic programming wherein we may make a divide and conquer algorithm significantly faster when sub-parts of the problem are shared. A simple example of this is computing the nth 28 Fibonacci number with a recursive algorithm: fib 𝑛 = if 𝑛 = 0 ∨ 𝑛 = 1 then 1 else fib (𝑛 βˆ’ 1) + fib (𝑛 βˆ’ 2) Such a program runs in 𝑂 (𝑛2) time since we perform two recursive function calls for each 𝑛. Using memoization in a programming language like Haskell, on the other hand, we may share the work that is redundant in the recursive calls. That is, fib (𝑛 βˆ’ 2) makes use of fib (𝑛 βˆ’ 1). fibs = 1 : 1 : zipWith (+) fibs (tail fibs) fib 𝑛 = get 𝑛 fibs Now the recursive calls to fib will access the same memory cell that has been memoized and this program runs in 𝑂 (𝑛) time. Though there have been other machines that implement this memoized non-strict evaluation, we present the machine of Sestoft [48] in Figure 2.7 because it is the simplest abstract machine that uses closures and closely matches the way such languages are implemented today.1 First to note about this machine is that it does not operate directly on πœ†-expressions; instead a preprocessing to administrative normal form (ANF) [18] is done first. Essentially, we give names to all function arguments. The machine configurations are similar to that of the Krivine machine containing a local environment, an expression (in ANF), and a stack. It is extended to a heap that contains closures for any expression. Local environments only point to these heap cells; this restriction is possible because 1Another, older approach to these memoized non-strict languages is via graph reduction [54, 22, 12]. Indeed, closures which pair an environment with code is not all that different than considering partial application of super-combinators. 29 ANF(π‘₯) = π‘₯ ANF(πœ†π‘₯. 𝑀) = πœ†π‘₯.ANF(𝑀) ANF(𝑀 𝑁 ) = let π‘₯ be ANF(𝑁 ) in ANF(𝑀) π‘₯ (a) Compilation to A-normal Form Ξ¦ ∈ Heap ::= πœ€ | Ξ¦, 𝑙 ↦→ (Ξ£, 𝑀) Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£, 𝑙/π‘₯ 𝑆 ∈ Stack ::= 𝑙 Β· 𝑆 | #𝑙 Β· 𝑆 Machine State ::= ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ (b) Machine Syntax ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ b βˆ₯ #𝑙 Β· 𝐾⟩⟩ βˆ’β†¦ β†’1 ⟨⟨Φ, 𝑙 ↦→ (Ξ£, b) βˆ₯ Ξ£ βˆ₯ b βˆ₯ 𝐾⟩⟩ ⟨⟨(Ξ¦, π‘₯ [Ξ£] ↦→ (Ξ£β€², 𝑀))Ξ¦β€² βˆ₯ Ξ£ βˆ₯ π‘₯ βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’ β€² β€²2 ⟨⟨ΦΦ βˆ₯ Ξ£ βˆ₯ 𝑀 βˆ₯ #𝑙 Β· 𝐾⟩⟩ ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ #𝑙 Β· 𝐾⟩⟩ βˆ’β†¦ β†’3 ⟨⟨Φ, 𝑙 ↦→ (Ξ£, πœ†π‘₯ . 𝑀) βˆ₯ Ξ£ βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ πœ†π‘₯ .𝑀 βˆ₯ 𝑙 Β· 𝐾⟩⟩ β†¦βˆ’β†’4 ⟨⟨Φ βˆ₯ Ξ£, 𝑙/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑀 π‘₯ βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’5 ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑀 βˆ₯ π‘₯ [Ξ£] Β· 𝐾⟩⟩ ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ let π‘₯ be𝑀 in 𝑁 βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’6 ⟨⟨Φ, 𝑙 →↦ (Ξ£, 𝑀) βˆ₯ Ξ£, 𝑙/π‘₯ βˆ₯ 𝑁 βˆ₯ 𝐾⟩⟩ (c) Transitions Figure 2.7. The Sestoft Machine 𝑉 ,π‘Š ∈ Value ::= b | π‘₯ | πœ†π‘₯ .𝑀 𝐸, 𝐹 ∈ Evaluation Cxt . ::= β–‘ | 𝐸 𝑁 | let π‘₯ be𝑀 in 𝐸 | let π‘₯ be 𝐸 in 𝐹 [π‘₯] (a) Syntax (πœ†π‘₯. 𝑀) 𝑁 =𝛽 let π‘₯ be 𝑁 in𝑀 πœ†π‘₯.𝑉 π‘₯ =πœ‚ 𝑉 let π‘₯ be 𝑉 in𝑀 =π‘₯ 𝑀 [𝑉 /π‘₯] 𝐸 [let π‘₯ be𝑀 in 𝑁 ] =πœ… let π‘₯ be𝑀 in 𝐸 [𝑁 ] let π‘₯ be (let 𝑦 be𝑀 in 𝑁 ) in 𝐿 =πœ’ let 𝑦 be𝑀 in let π‘₯ be 𝑁 in 𝐿 (b) Axioms Figure 2.8. A Call-by-Need Calculus 30 we have already converted expressions to ANF before running them on this machine. Compared to the Krivine machine, there is also another stack frame, denoted #𝑙 ·𝑆 , which is used for memoizing the evaluation of a heap closure. Like Krivine, when a function is reached, it merely pulls its argument off the stack. The argument is pushed on the stack for an application just like the Krivine machine too; the difference being that we push the heap location of that argument. The argument already has a heap location because of ANF. We see in the last rule that the argument, which was given a name by the ANF transformation, is allocated as a closure on the heap. The rules that memoize are 1, 2, and 3. When a variable is demanded (rule 2), its closure in the heap is entered and a memoization frame is pushed. When the evaluation of that closure has reached a memoizable normal form, e.g. a πœ†-expression, the heap label of the memoization frame is added back to the heap with the updated closure. Definition 2.4 (Sestoft Machine Evaluation). EvalSM(𝑀) = bwhere βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝑀 βˆ₯ πœ€βŸ©βŸ© β†¦βˆ’β†’βˆ— βŸ¨βŸ¨Ξ“ βˆ₯ 𝐸 βˆ₯ b βˆ₯ πœ€βŸ©βŸ©. Ariola et al. [8, 7] and Maraist et al. [28] captured this shared evaluation of function arguments in the call-by-need axiomitization of the πœ†-calculus. Therein, a computation can be shared by constructing a let-expression that binds it, only forcing the reduction of the bound expression when the evaluation of the variable is required, and substituting its value thereafter.2 This is apparent in the axioms given in Figure 2.8 wherein the 𝛽 rule for functions creates a binding and the π‘₯ rule for let-expressions performs a substitution only when the bound expression is a value. In call-by-need, we can think of values as expressions that are safe to substitute without duplicating work. In addition to those axioms, rules for lifting and reassociating let-expressions are required to expose reducible 2Ariola et al. [9] show that the let-expression is not necessary since sharing can be captured by not reducing the function application. 31 expressions. The πœ… rule is required for lifting expressions out of evaluation contexts and the πœ’ rule is used to reassociate let-expressions. Note that the calculus has the weaker function πœ‚ laws of call-by-value; otherwise, a value would be changed to a non-value. In call-by-need, blurring this distinction means duplicating work. Conjecture 2.1. EvalSM(𝑀) = b if and only if ⊒ 𝑀 = b : 𝐡. The connection between the Sestoft machine and the call-by-need πœ†-calculus is not found in the literature to our knowledge. In Chapter 7, we will see how to connect a sharing equational theory with a memoizing environment abstract machine. Remark 2.1 (Push/Enter versus Eval/Apply). Marlow and Peyton Jones [29] highlight the distinction of two different methods of treating functions in an operational semantics: push/enter and eval/apply. The first will place an argument on the stack and enter the function code; when a function is reached, it merely pull their argument from the stack and place it in the local environment. On the other hand, eval/apply machines will evaluate a function and push it on the stack as a closure value before entering its closure. Marlow and Peyton Jones draw attention to the difference because it matters for fast, curried function calls. We too are interested in the distinction because they differ with respect to closures; push/enter does not need to construct a function closure during application because the function can simply grab its argument from the stack. Of the machines presented above the strict call- by-value machine, i.e. SECD, is eval/apply whereas the two non-strict machines given are push/enter. However, there are examples of strict push/enter machines [26] and non-strict eval/apply machines [29]. 32 CHAPTER III CLOSURE CONVERSIONS This chapter is a revised version of Strictly Capturing Non-strict Closures [52] co-authored with Paul Downen and Zena M. Ariola. Zachary J. Sullivan is the primary author with the guidance of Paul Downen and Zena M. Ariola. Instead of having a complex runtime system that knows to construct and enter closures at runtime as we see in the machines from the previous chapter, we now look at another approach to handling the nested, lexical structure of languages with passable code: to compile away that structure into a lower-level language. This approach, referred to as closure conversion, embeds the delayed code of the source as products and global functions in the target language. A typical target language for such a transformation is C, which has both of these features. Previous work has investigated the efficiency [6, 5, 56, 49] and correctness [34, 3, 36, 40, 38] of closure conversion, and explored its application in more expressive languages with dependent types [11] and mutable references [30]. This line of work, however, mostly applies to just strict languages. Non-strict languages are rarely discussed, if at all. Some work [6, 38] focused on languages in continuation passing style (CPS), which subsumes call-by-value and call-by- name semantics, but call-by-need is still left out. A call-by-need CPS exists [37], but it requires a mutable store and is not used in compilers for lazy languages. Rather, these compilers, such as those for Lazy ML [10] and Miranda [41], rely on other methods such as lambda-lifting. Haskell’s premier optimizing compiler, GHC [43], does use closures, but they are only considered as a small part of low-level code generation. Extending our understanding of the closure conversion transformation to non-strict languages is not such an easy feat. As we saw in the machines of the previous chapter, 33 non-strict languages create different sorts of closures: every function argument or variable binding is delayed, creating closures that are not needed in a strict language. But just making more closures is not enough: closures must be strict. That is to say that in a low-level language without automatic runtime closure support, the compile-time code for creating closures cannot be lazily evaluated because by then it is too late to capture the long-gone static environment. Instead, the environment must be captured now when it is available, without inadvertently evaluating anything in the environment. Closure conversion in a non-strict language is a delicate dance between the lazy and the eager. This chapter examines the canonical approach to this transformation and then describes our work extending it to non-strict evaluation strategies with and without sharing. After reviewing the strict closure conversion (Section 3.1), we show how closure conversion of a non-strict language cannot be embedded into a purely non-strict target language (Section 3.2), but rather strictness is needed in the target language to create closures at the right moment. Similarly, we show thereafter how sharing introduces yet another unintended interaction (Section 3.3): some closures need to be memoized when they are run, but others don’t. To eliminate unnecessary details, we present both source and target language’s operation semantics as big-step semantics instead of abstract machines. The key difference from the machines is that we do need to consider the continuation or stack. The big-step semantics are described by a judgment of the form Conf . ⇓ R where R is a final result. We still use a delayed substitution in the semantics because it is an essential feature in showing how closure conversion impacts how we may run our program. 34 3.1 The Canonical Closure Conversion We first look at the closure conversion that is widely discussed in the literature. Consider the following program: let π‘₯ be (let 𝑦 be 2 + 1 in πœ†π‘§.𝑦) in (π‘₯ 3) + (π‘₯ 4) (3.1) Note that when π‘₯ is called, 𝑦 is no longer in scope. To remember it when the function is called, we can save its value, i.e. 3, in a data structure. In other words, we closure convert the program to: let π‘₯ be (let 𝑦 be 2 + 1 in pack βŸ¨βŸ¨π‘¦βŸ©, πœ†βŸ¨βŸ¨π‘¦βŸ©, π‘§βŸ©. π‘¦βŸ©) in (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 3⟩) + (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 4⟩) Here, the πœ†-expression πœ†π‘§.𝑦 in the source is replaced with a data structure containing a representation of the environment and a closed functionwhich accesses that environment. Now, unlike the machine from the previous chapter, the function definition and call site themselves encode in the code the packing and unpacking its local environment to find the binding of 𝑦. In this example, we needed to generate both an unpack expression and then case expression for destructing the generated closure objects. Wemake use of patternmatching as syntactic sugar for doing a case expression immediately after the binding. So for πœ†- expressions, we have ⟨ ⟩ defπœ† π‘₯0, . . . , π‘₯𝑛 . 𝑀 = πœ†π‘§. case 𝑧 of {⟨π‘₯0, . . . , π‘₯π‘›βŸ© β†’ 𝑀}. 35 Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£,V/π‘₯ V,W ∈ Machine Value ::= b | (Ξ£, πœ†π‘₯ . 𝑀) Conf ∈ Configuration ::= ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© (a) Syntax ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ V ⟨⟨Σ βˆ₯ b⟩⟩ ⇓ b ⟨⟨Σ βˆ₯ π‘₯⟩⟩ ⇓ π‘₯ [Ξ£] ⟨⟨Σ βˆ₯ πœ†π‘₯ .π‘€βŸ©βŸ© ⇓ (Ξ£, πœ†π‘₯ . 𝑀) ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ£β€², πœ†π‘₯ . 𝐿) ⟨⟨Σ βˆ₯ 𝑁 ⟩⟩ ⇓W βŸ¨βŸ¨Ξ£β€²,W/π‘₯ βˆ₯ 𝐿⟩⟩ ⇓ V ⟨⟨Σ βˆ₯ 𝑀 𝑁 ⟩⟩ ⇓ V (b) Evaluation Rules Figure 3.1. Strict Evaluation And similarly for unpack-expressions. So in our example, unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 3⟩ pattern matches on an existential package and then a product. If the pattern match is nested like this, then there will be nested case expressions. We use existential types in addition to products here to make closure conversion a type-preserving transformation. Without existentially quantifying over the type of the environment (following from Minamide et al. [34]), the two following programs, for instance, of type int β†’ int would have different types: πœ†π‘₯ .𝑦 πœ†π‘₯ . π‘₯ The first would closure convert into a pair with the first component being an empty product and the second would have a unary product in the first component. 3.1.1 Source Language. The syntax of configurations and evaluation rules for strictly evaluating an expression are presented in Figure 3.1. In the syntax, notice that machine values are identical to those of the SECD machine. When evaluating, the πœ†- expression rule knows how to automatically construct a closure and the application rule 36 𝜏, 𝜎 ∈ Type ::= 𝐡 | 𝜏 β†’ 𝜎 | 𝜏0 Γ— Β· Β· Β· Γ— πœπ‘› | 𝑋 | βˆƒπ‘‹ . 𝜏 Ξ“ ∈ Type Env. ::= πœ€ | Ξ“, π‘₯ :𝜏 Ξ” ∈ TypeVar .Env. ::= πœ€ | Ξ”, 𝑋 𝑀, 𝑁, 𝐿 ∈ Expression ::= b | π‘₯ | πœ†π‘₯ .𝑀 | 𝑀 𝑁 | βŸ¨π‘€0, . . . , π‘€π‘›βŸ© | case𝑀 of {⟨π‘₯0, . . . , π‘₯π‘›βŸ© β†’ 𝑁 } | pack𝑀 | unpack𝑀 as π‘₯ in 𝑁 (a) Syntax π‘₯ :𝜏 ∈ Ξ“ var Ξ”; Ξ“ ⊒ b : 𝐡𝐡 Ξ”; Ξ“ ⊒ π‘₯ : 𝜏 πœ€, π‘₯ :𝜏 ⊒ 𝑀 : 𝜎 β†’ Ξ”; Ξ“ ⊒ 𝑀 : 𝜏 β†’ 𝜎 Ξ”; Ξ“ ⊒ 𝑁 : 𝜏 Ξ”; Ξ“ ⊒ πœ†π‘₯ .𝑀 : 𝜏 β†’ 𝐼 β†’πœŽ Ξ”; 𝐸Γ ⊒ 𝑀 𝑁 : 𝜎 Ξ”; Ξ“ ⊒ 𝑀0 : 𝜏0 Β· Β· Β· Ξ”; Ξ“ ⊒ 𝑀𝑛 : πœπ‘› ⊒ ⟨ ⟩ Γ— Β· Β· Β· Γ— Γ—; : 𝐼Δ Ξ“ 𝑀0, . . . , 𝑀𝑛 𝜏0 πœπ‘› Ξ”; Ξ“ ⊒ 𝑀 : 𝜎0 Γ— Β· Β· Β· Γ— πœŽπ‘› Ξ”; Ξ“ ⊒, π‘₯0:𝜎0, . . . , π‘₯𝑛:πœŽπ‘› ⊒ 𝑁 : 𝜏 Ξ”; Ξ“ ⊒ ×𝐸case𝑀 of {⟨π‘₯0, . . . , π‘₯π‘›βŸ© β†’ 𝑁 } : 𝜏 Ξ”; Ξ“ ⊒ 𝑀 : 𝜏 [𝜎/𝑋 ] βˆƒ Ξ”; Ξ“ ⊒ 𝑀 : βˆƒπ‘‹ . 𝜎 Ξ”, 𝑋 ; Ξ“, π‘₯ :𝜎 ⊒ 𝑁 : 𝜏 βˆƒ Ξ”; Ξ“ ⊒ pack𝑀 : βˆƒπ‘‹ . 𝜏 𝐼 Ξ”; Ξ“ ⊒ unpack𝑀 as π‘₯ in 𝑁 : 𝜏 𝐸 (b) Typing Rules Figure 3.2. Closure Conversion Target Language knows how to unpack it, instantiate its local environment, and jump into the body with the value of the actual parameter. Definition 3.1 (Strict Big-Step Evaluation). EvalSBS(𝑀) = b where βŸ¨βŸ¨πœ€ βˆ₯ π‘€βŸ©βŸ© ⇓ b. This approach to evaluation coincides with the SECD machine when they reach a value. The following is a result by Plotkin [46]. Proposition 3.1. EvalSECD(𝑀) = EvalSBS(𝑀). 3.1.2 Target Language. Such a transformation requires two features in the target language that we have yet to specify formally: products and existential types. The syntax and typing rules for these are presented in Figure 3.2. We have new types 37 for products and existential types along with the type variables that are introduced by the existential types. Elements of the product type are introduced by βŸ¨π‘€0, . . . , π‘€π‘›βŸ© and eliminated by case expressions, which bind their sub-components. Note that single angle brackets ⟨. . . ⟩ are used for expressions and double angle brackets ⟨⟨. . . ⟩⟩ are used for operational semantics. Elements of existential types are introduced by pack 𝑀 and eliminated by unpack expressions, which bind a pack expression’s sub-component. The typing rules have been expanded with Ξ” which contains the live type variables. There is an important restriction in the βˆƒπΈ rule, where we see that the type variable 𝑋 is available to type check 𝑁 , but it is not available in the whole unpack expression’s type-variable environment; without such a restriction, we could leak the type hidden by the existential. There is another change in the target language’s typing rules that is especially relevant to the adequacy of closure conversion: the function type is global in the sense that it only knows about its formal parameter. Before closure conversion, some program of a function type would implicitly carry around its environment in a closure; but after closure conversion, some program of a function type is merely an object that we can jump to at runtime with its formal parameter on the stack. The former requires some runtime support, whereas the latter is easily implementable on a stack machine. The evaluation rules for the target language are given in Figure 3.3. In the strict source semantics, the set of machine values was not a subset of the surface language because evaluation rules must form and return closures instead of πœ†-expressions. In contrast, the closed functions of the target language are already values; they can be compiled simply into function pointers. For evaluation, the πœ†-expression simply returns itself; it does not construct a closure since the function must already be closed except for its formal parameter as we saw in the typing rules. At the call site, the target application 38 Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£,V/π‘₯ V ∈ Machine Value ::= b | πœ†π‘₯ .𝑀 | ⟨V0, . . . ,Vπ‘›βŸ© | pack V Conf ∈ Configuration ::= ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© (a) Syntax ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ V ⟨⟨Σ βˆ₯ b⟩⟩ ⇓ b ⟨⟨Σ βˆ₯ π‘₯⟩⟩ ⇓ π‘₯ [Ξ£] ⟨⟨Σ βˆ₯ πœ†π‘₯ .π‘€βŸ©βŸ© ⇓ πœ†π‘₯ .𝑀 ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ πœ†π‘₯. 𝐿 ⟨⟨Σ βˆ₯ 𝑁 ⟩⟩ ⇓ V βŸ¨βŸ¨πœ€,V/π‘₯ βˆ₯ 𝐿⟩⟩ ⇓W ⟨⟨Σ βˆ₯ 𝑀 𝑁 ⟩⟩ ⇓W ⟨⟨Σ βˆ₯ 𝑀0⟩⟩ ⇓ V0 Β· Β· Β· ⟨⟨Σ βˆ₯ π‘€π‘›βŸ©βŸ© ⇓ V𝑛 ⟨⟨Σ βˆ₯ βŸ¨π‘€0, . . . , π‘€π‘›βŸ©βŸ©βŸ© ⇓ ⟨V0, . . . ,Vπ‘›βŸ© ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ ⟨V0, . . . ,Vπ‘›βŸ© ⟨⟨Σ,V0/π‘₯0, . . . ,V𝑛/π‘₯𝑛 βˆ₯ 𝑁 ⟩⟩ ⇓W ⟨⟨Σ βˆ₯ case𝑀 of {⟨π‘₯0, . . . , π‘₯π‘›βŸ© β†’ 𝑁 }⟩⟩ ⇓W ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ V ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ V ⟨⟨Σ,V/π‘₯ βˆ₯ 𝑁 ⟩⟩ ⇓W ⟨⟨Σ βˆ₯ packπ‘€βŸ©βŸ© ⇓ pack V ⟨⟨Σ βˆ₯ unpack𝑀 as π‘₯ in 𝑁 ⟩⟩ ⇓W (b) Evaluation Rules Figure 3.3. Target Language Evaluation 39 CC(b) = b CC(π‘₯) = π‘₯ CC(πœ†π‘₯. 𝑀) = pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩.CC(𝑀)⟩ where FV(πœ†π‘₯. 𝑀) = {𝑦0, . . . , 𝑦𝑛} CC(𝑀 𝑁 ) = unpack CC(𝑀) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’,CC(𝑁 )⟩ (a) Expression Translation CC𝑉 (𝐡) = 𝐡 CC𝑉 (𝜏 β†’ 𝜎) = βˆƒπ‘‹ .𝑋 Γ— (𝑋 Γ— CC𝑉 (𝜏) β†’ CC𝑉 (𝜎)) CCΞ“ (πœ€) = πœ€ CCΞ“ (Ξ“, π‘₯ :𝜏) = CCΞ“ (Ξ“), π‘₯ :CC𝑉 (𝜏) (b) Type Translations Figure 3.4. Canonical Closure Conversion rule correspondingly expects to find just a πœ†-expression, and jumps into a function body with only a binding for its parameter in the otherwise empty environment. Definition 3.2 (Target Big-Step Evaluation). EvalTBS(𝑀) = b where βŸ¨βŸ¨πœ€ βˆ₯ π‘€βŸ©βŸ© ⇓ b. 3.1.3 Transformation. The full transformation from a simply-typed πœ†-calculus into this target language is shown in Figure 3.4. In the translation of expressions, functions are transformed into packages containing a closed function and a data structure. The generated closed function knows how to access this data structure to re-instantiate the local environment in its body via patter matching. Applications 𝑀 𝑁 are transformedβ€” assuming𝑀 will evaluate to a closureβ€”into code extracting the environment and function from 𝑀 , and then calling that function with the environment and argument 𝑁 . Since functions become data structures, we must translate the type of a program as well. Function types are translated to an existential which hides the type of environment used. Thus, two functions with the same type but different environments will still have the same type after closure conversion. 40 MJ𝜏K = {(Conf𝑠,Conf𝑑 ) | βˆ€V𝑠 .Conf𝑠 ⇓ V𝑠 =β‡’ βˆƒ(V𝑠,V𝑑 ) ∈ VJ𝜏K.Conf𝑑 ⇓ V𝑑 } VJ𝐡K = {(b, b) | b ∈ 𝐡} VJ𝜏0 β†’ 𝜏1K = {((Σ𝑠, πœ†π‘₯ . 𝑀𝑠), pack ⟨⟨W0, . . . ,Wπ‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩. 𝑀𝑑 ⟩) | βˆ€(V𝑠,V𝑑 ) ∈ VJ𝜏0K. (βŸ¨βŸ¨Ξ£π‘ ,π‘Šπ‘ /π‘₯ βˆ₯ π‘€π‘ βŸ©βŸ©, βŸ¨βŸ¨πœ€,W0/𝑦0, . . . ,W𝑛/𝑦𝑛,V𝑑/π‘₯ βˆ₯ 𝑀𝑑 ⟩⟩) ∈ MJ𝜏1K} EJΞ“K = {(Σ𝑠, Σ𝑑 ) | βˆ€(π‘₯ :𝜏) ∈ Ξ“. (π‘₯ [Σ𝑠], π‘₯ [Σ𝑑 ]) ∈ VJ𝜏K} Figure 3.5. Strict Closure Conversion Logical Relations As a result of using existential types, Minamide et al. showed that such a transformation preserves well-typed programs. This can be proved by induction over the typing derivation. Theorem 3.1 (Type Preservation). If Ξ“ ⊒ 𝑀 : 𝜏 , then CCΞ“ (Ξ“) ⊒ CC(𝑀) : CC𝑉 (𝜏). 3.1.4 Operational Semantics Preservation. While the theorem above shows that our static checks are preserved, in implementation we care that the dynamic behavior of the program is preserved from the encoding. The common approach to semantic preservation of typed closure conversion, as seen in Minamide et al. [34], must step outside of these evaluation theories. They construct a cross-language logical relation over a substituting big-step semantics; that is, it relates source expressions to their closure converted form in the target language. Because we are concerned with observing the difference between the closure-constructing runtime system of the source language and the simpler target runtime, we have specified environment big-step semantics instead; thus, we must extend their proof approach to such a setting. We specify a family of relations in Figure 3.5. First,MJ𝜏K relates closed source and target configurations that behave like source 𝜏 expressions. When a source configuration evaluates to a value, then the target must evaluate to a related value. Second,VJ𝜏K relates machine values that behave like source 𝜏 machine values. For base types, this means they 41 are equivalent after conversion. For functions, it must be the case that when given related arguments, that we can construct related configurations that enter the functions with arguments. Third, EJΞ“K relates environments that behave like source environments Ξ“. This just means that the environments contain all related values and completely cover Ξ“. Lemma 3.1 (Strengthening). If ⟨⟨Σ Ξ£β€² βˆ₯ π‘€βŸ©βŸ© ⇓ V and FV(𝑀) ∩ Dom(Ξ£β€²) = βˆ…, then ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ V in the target language. Proof. By induction on the derivation of ⟨⟨Σ Ξ£β€² βˆ₯ π‘€βŸ©βŸ© ⇓ V. β–‘ Lemma 3.2 (Fundamental Lemma). If Ξ“ ⊒ 𝑀𝑠 : 𝜏 and (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K, then (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘€π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑀𝑠)⟩⟩) ∈ MJ𝜏K. Proof. By induction on the typing derivation of Ξ“ ⊒ 𝑀𝑠 : 𝜏 , for a generic (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K: Case Ξ“ ⊒ b : 𝐡: So𝑀𝑠 = b, CC(b) = b, and we must show that (βŸ¨βŸ¨Ξ£π‘  βˆ₯ b⟩⟩, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ b⟩⟩) ∈ MJ𝐡K. The only evaluations are βŸ¨βŸ¨Ξ£π‘  βˆ₯ b⟩⟩ ⇓ b in the source and βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ b⟩⟩ ⇓ b in the target. We have (b, b) ∈ VJ𝐡K by definition. Therefore, (βŸ¨βŸ¨Ξ£π‘  βˆ₯ b⟩⟩, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(b)⟩⟩) ∈ MJ𝐡K. Case Ξ“ ⊒ π‘₯ : 𝜏 because π‘₯ :𝜏 ∈ Ξ“: So𝑀𝑠 = π‘₯ , CC(π‘₯) = π‘₯ , and we must show that (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘₯⟩⟩, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ π‘₯⟩⟩) ∈ MJ𝜏K. The only evaluations are βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘₯⟩⟩ ⇓ π‘₯ [Σ𝑠] in the source and βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ π‘₯⟩⟩ ⇓ π‘₯ [Σ𝑑 ] in the target. From the assumptions (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K and π‘₯ :𝜏 ∈ Ξ“, we know (π‘₯ [Σ𝑠], π‘₯ [Σ𝑑 ]) ∈ VJ𝜏K by definition of EJΞ“K. 42 Therefore, (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘₯⟩⟩, βŸ¨Ξ£π‘‘ βˆ₯ π‘₯⟩) ∈ MJ𝜏K by the definition. Case Ξ“ ⊒ πœ†π‘₯.𝑁𝑠 : 𝜏1 β†’ 𝜏2 because Ξ“, π‘₯ :𝜏1 ⊒ 𝑁𝑠 : 𝜏2: So 𝜏 = 𝜏1 β†’ 𝜏2,𝑀𝑠 = πœ†π‘₯.𝑁𝑠 , and CC(πœ†π‘₯.𝑁𝑠) = pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩.CC(𝑁𝑠)⟩ where FV(πœ†π‘₯. 𝑁𝑠) = {𝑦0, . . . , 𝑦𝑛}. We must show that (βŸ¨βŸ¨Ξ£π‘  βˆ₯ πœ†π‘₯ .π‘π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(πœ†π‘₯.𝑁𝑠)⟩⟩) ∈ MJ𝜏1 β†’ 𝜏2K. The unique evaluations are βŸ¨βŸ¨Ξ£π‘  βˆ₯ πœ†π‘₯ .π‘π‘ βŸ©βŸ© ⇓ (Σ𝑠, πœ†π‘₯ .𝑁𝑠) in the source and βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(πœ†π‘₯.𝑁𝑠)⟩⟩ ⇓ pack βŸ¨βŸ¨π‘¦0 [Σ𝑑 ], . . . , 𝑦𝑛 [Σ𝑑 ]⟩, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩.CC(𝑁𝑠)⟩ in the target. Proving ((Σ𝑠, πœ†π‘₯ .𝑁𝑠), pack βŸ¨βŸ¨π‘¦0 [Σ𝑑 ], . . . , 𝑦𝑛 [Σ𝑑 ]⟩, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩.CC(𝑁𝑠)⟩) ∈ VJ𝜏1 β†’ 𝜏2K still needs to be shown. Thus, suppose an arbitrary (W𝑠,W𝑑 ) ∈ VJ𝜏1K: Note that ((Σ𝑠,W𝑠/π‘₯), (Σ𝑑 ,W𝑑/π‘₯)) ∈ EJΞ“, π‘₯ :𝜏1K by definition of E and the assumption (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K. From the inductive hypothesis on Ξ“, π‘₯ :𝜏1 ⊒ 𝑁𝑠 : 𝜏2, we know (βŸ¨βŸ¨Ξ£π‘ ,W𝑠/π‘₯ βˆ₯ π‘π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ ,W𝑑/π‘₯ βˆ₯ CC(𝑁𝑠)⟩⟩) ∈ MJ𝜏2K. Assuming βŸ¨βŸ¨Ξ£π‘ ,W𝑠/π‘₯ βˆ₯ π‘π‘ βŸ©βŸ© ⇓ V𝑠 in the source, there must be a (V𝑠,V𝑑 ) ∈ VJ𝜏2K such that βŸ¨βŸ¨Ξ£π‘‘ ,W𝑑/π‘₯ βˆ₯ CC(𝑁𝑠)⟩⟩ ⇓ V𝑑 in the target by the definition ofMJ𝜏2K. Expanding, βŸ¨βŸ¨πœ€,𝑦0 [Σ𝑑 ]/𝑦0, . . . , 𝑦𝑛 [Σ𝑑 ]/𝑦𝑛,W𝑑/π‘₯ βˆ₯ CC(𝑁𝑠)⟩⟩ ⇓ V𝑑 in the target as well by strengthening (Lemma 3.1) the evaluation βŸ¨βŸ¨Ξ£π‘‘ ,W𝑑/π‘₯ βˆ₯ CC(𝑁𝑠)⟩⟩ ⇓ V𝑑 . 43 Case Ξ“ ⊒ 𝑁𝑠 𝑂𝑠 : 𝜏 because Ξ“ ⊒ 𝑁𝑠 : πœβ€² β†’ 𝜏 and Ξ“ ⊒ 𝑂 ′𝑠 : 𝜏 : So𝑀𝑠 = 𝑁𝑠 𝑂𝑠 , CC(𝑁𝑠 𝑂𝑠) = unpack CC(𝑁𝑠) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’,CC(𝑂𝑠)⟩. We must show that (βŸ¨βŸ¨Ξ£π‘  βˆ₯ 𝑁𝑠 π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠 𝑂𝑠)⟩⟩) ∈ MJ𝜏K. Thus, we suppose that βŸ¨βŸ¨Ξ£π‘  βˆ₯ 𝑁𝑠 π‘‚π‘ βŸ©βŸ© ⇓ V𝑠 : The conclusion of that derivation must be an instance of the application evaluation from inversion, which gives us the following evaluation derivations in the source: 1. βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘π‘ βŸ©βŸ© ⇓ (Ξ£1𝑠, πœ†π‘₯ .𝐿𝑠), 2. βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘‚π‘ βŸ©βŸ© ⇓W𝑠 , and 3. ⟨⟨Σ1𝑠,π‘Šπ‘ /π‘₯ βˆ₯ πΏπ‘ βŸ©βŸ© ⇓ V𝑠 . From the first inductive hypothesis, we know (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠)⟩⟩) ∈ MJπœβ€² β†’ 𝜏K. It follows by definition ofM that there is some ((Ξ£1𝑠, πœ†π‘₯ .𝐿𝑠), pack ⟨⟨Wβ€²0, . . . ,Wβ€²π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩. 𝐿𝑑 ⟩) ∈ VJπœβ€² β†’ 𝜏K such that βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠)⟩⟩ ⇓ pack ⟨⟨Wβ€²0, . . . ,Wβ€²π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩. 𝐿𝑑 ⟩ in the target. From the second inductive hypothesis, we know (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑂𝑠)⟩⟩) ∈ MJπœβ€²K. Likewise, it follows that there is a (W𝑠,W ) ∈ VJπœβ€²π‘‘ K such that βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑂𝑠)⟩⟩ ⇓W𝑑 in the target. We also have (⟨⟨Σ ,W /π‘₯ βˆ₯ 𝐿 ⟩⟩, βŸ¨βŸ¨πœ€,W′𝑠 𝑑 𝑠 0/𝑦, . . . ,W′𝑛/𝑦,W𝑑/π‘₯ βˆ₯ 𝐿𝑑 ⟩⟩) ∈ MJ𝜏K, from ((Ξ£ β€²1𝑠, πœ†π‘₯ .𝐿𝑠), pack ⟨⟨W0, . . . ,Wβ€²π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩. 𝐿𝑑 ⟩) ∈ VJπœβ€² β†’ 𝜏K. It follows that there is a (V𝑠,V𝑑 ) ∈ VJ𝜏K such that βŸ¨βŸ¨πœ€,Wβ€²0/𝑦, . . . ,W′𝑛/𝑦,W𝑑/π‘₯ βˆ₯ 𝐿𝑑 ⟩⟩ ⇓ V𝑑 in the target. 44 Expanding, we get that βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ unpack CC(𝑁𝑠) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’,CC(𝑂𝑠)⟩⟩⟩ ⇓ V𝑑 as well by applications of the evaluation rules for unpack, case, and application. Therefore, (βŸ¨βŸ¨Ξ£π‘  βˆ₯ 𝑁𝑠 π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠 𝑂𝑠)⟩⟩) is in the relation MJ𝜏K by definition. β–‘ Corollary 3.1 (Evaluation Preservation). If Ξ“ ⊒ 𝑀 : 𝜏 and EvalSBS(𝑀) = b, then EvalTBS(CC(𝑀)) = b. 3.2 Non-strict Closure Conversions Though not emphasized by the work, the closure conversion above is presented for strict languages alone [34, 36, 3, 38, 39]. The functions of a strict source language, wherein values coincide with normal forms, are transformed into in a strict target language. Can we do the same thing for non-strict languages? That is, can we convert a non-strict source language to a non-strict target language that lacks automatic closure management at run- time? To answer these questions, we first need to know how non-strict data types are evaluated, since closures will be constructed with them when following the common approach. In strict languages, data are evaluated before they are considered values capable of substitution; in contrast, non-strict data are not evaluated until forced by their context, i.e. until they are pattern matched by a case expression. For example, a non-strict existential package has the following semantics, based on delayed evaluation rules for data in lazy languages, e.g. Launchbury’s natural semantics extended with constructors 45 [25]: ⟨Σ βˆ₯ packπ‘€βŸ© ⇓ (Ξ£, pack𝑀) ⟨Σ βˆ₯ π‘€βŸ© ⇓ (Ξ£β€², pack 𝐿) ⟨Σ, π‘₯ ↦→ (Ξ£β€², 𝐿) βˆ₯ 𝑁 ⟩ ⇓ R ⟨Σ βˆ₯ unpack𝑀 as π‘₯ in 𝑁 ⟩ ⇓ R To avoid evaluating inside of the data constructor until pattern matching, a non-strict evaluator must return a closure to capture the environment needed to evaluate it later. But this gets us nowhere! The point of closure conversion is to eliminate the need for automatic closure management at runtime; yet, when trying to eliminate automatic closure management, we introduced a new type . . . that requires automatic closure management at runtime. Our goal is to simulate these non-strict rules above in the text of the program, so the instructions for capturing and restoring the environment are in the compile-time code, not the runtime system. The root of the problem for non-strict closure conversion, then, is that before pack returns, it needs to look up the current definitions of its free variables in scope, so that these bindings can actually be captured in the environment value it contains. In other words, pack must be strictβ€”to some degreeβ€”in its argument. But we also must be careful to not introduce too much strictness. In a non-strict evaluation of example (3.1), let π‘₯ be (let 𝑦 be 2 + 1 in πœ†π‘§.𝑦) in (π‘₯ 3) + (π‘₯ 4) we must not evaluate the expression 2 + 1 bound to 𝑦 when the closure is formed; rather, computation of 𝑦 itself must still be delayed until its value is forced. Thankfully, this complication, too, is solved by closure conversion. In general, bound, delayed computations, like let 𝑦 be 2 + 1 in . . . might also refer to other free variables, so bound expressions must be closure converted like functions were for strict closure conversion. As a consequence, delayed computations bound by let- and πœ†-expressions will also be 46 Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£,V/π‘₯ V,W ∈ Machine Value ::= (Ξ£, 𝑀) R ∈ Result ::= b | (Ξ£, πœ†π‘₯ . 𝑀) Conf ∈ Configuration ::= ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© (a) Syntax ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ R π‘₯ [Ξ£] = (Ξ£β€², 𝑀) βŸ¨βŸ¨Ξ£β€² βˆ₯ π‘€βŸ©βŸ© ⇓ R ⟨⟨Σ βˆ₯ b⟩⟩ ⇓ b ⟨⟨Σ βˆ₯ π‘₯⟩⟩ ⇓ R ⟨⟨Σ βˆ₯ πœ†π‘₯ .π‘€βŸ©βŸ© ⇓ (Ξ£, πœ†π‘₯ . 𝑀) ⟨⟨Σ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ£β€², πœ†π‘₯ . 𝐿) βŸ¨βŸ¨Ξ£β€², (Ξ£, 𝑁 )/π‘₯ βˆ₯ 𝐿⟩⟩ ⇓ R ⟨⟨Σ βˆ₯ 𝑀 𝑁 ⟩⟩ ⇓ R (b) Evaluation Rules Figure 3.6. Non-strict Evaluation converted to valuesβ€”in the sense of strict evaluationβ€”ensuring that they are not evaluated too early. In brief, a non-strict closure conversion must transform πœ†-expressions, application arguments, and let-bound expressions into strictly-constructed packages of their free variables and a closed function. Applying such a transformation to our example program would produce the following output (to keep the example simple, we did not construct closures for π‘₯ , 3, and 4): let π‘₯ be (let 𝑦 be pack ⟨⟨⟩, πœ†βŸ¨βŸ©. 2 + 1⟩ in pack βŸ¨βŸ¨π‘¦βŸ©, πœ†βŸ¨βŸ¨π‘¦βŸ©, π‘§βŸ©. unpack 𝑦 as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 π‘’βŸ©) in (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 3⟩) + (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 4⟩) In addition to the function closures needed in strict closure conversion, we have added a closure construction for the binding of 𝑦. 47 3.2.1 Source Language. The syntax and evaluation rules for a non-strict evaluation are given in Figure 3.6. In a non-strict evaluator, all the values in the environment are thunk closures. In contrast to the strict setting, the values stored in the environment are different from the results of evaluation; thus, we see a separate notion of results to which configurations evaluate. Examining the evaluation rules, the variable rule unpacks and evaluates the thunk that finds in the environment. The application rule must handle two different types of closures: it must unpack the function closure returned from evaluating the left-hand side and it must construct a thunk closure for the formal parameter following closely the closure conversion for this case. This behavior for applications, and the fact that function closures are results, conveys that this machine is more closely related to an eval/apply style abstract machine than the Krivine machine. That being said, such evaluation still has the same termination behavior as the Krivine machine. Definition 3.3 (Non-Strict Big-Step Evaluation). EvalNSBS(𝑀) = b where βŸ¨βŸ¨πœ€ βˆ₯ π‘€βŸ©βŸ© ⇓ b. The following proposition is similar to that for the SECD machine that Plotkin [46]. We have not proved it here. Conjecture 3.1. EvalKAM(𝑀) = EvalNSBS(𝑀). 3.2.2 Target Language. Since every function and let-expression in the target languagewill be strict and they are generated from those of the source language, the target language of the non-strict closure conversion is indeed that of strict closure conversion. 3.2.3 Transformation. Non-strict closure conversion is presented in Figure 3.7. Variables are converted into code for unpacking thunk closures. Applications are converted into code that turns arguments into thunk closures while unpacking the function closure and applying it. The non-strict transformation is careful to distinguish 48 CC(b) = b CC(π‘₯) = unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 𝑒 CC(πœ†π‘₯. 𝑀) = pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩.CC(𝑀)⟩ where FV(𝑀) βˆ’ {π‘₯} = {𝑦0, . . . , 𝑦𝑛} CC(𝑀 𝑁 ) = unpack CC(𝑀) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑁 )⟩⟩ where FV(𝑁 ) = {𝑦0, . . . , 𝑦𝑛} (a) Expression Translation CC𝑅 (𝐡) = 𝐡 CC𝑅 (𝜏 β†’ 𝜎) = βˆƒπ‘‹ .𝑋 Γ— (𝑋 Γ— CC𝑉 (𝜏) β†’ CC𝑅 (𝜎)) CC𝑉 (𝜏) = βˆƒπ‘‹ .𝑋 Γ— (𝑋 β†’ CC𝑅 (𝜏)) CCΞ“ (πœ€) = πœ€ CCΞ“ (Ξ“, π‘₯ :𝜏) = CCΞ“ (Ξ“), π‘₯ :CC𝑉 (𝜏) (b) Type Translations Figure 3.7. A Non-strict Closure Conversion thunk closures from function closures. Whereas the former contains a closed function from some environment, the latter contains a closed function that takes a pair of some environment and a formal parameter. Extending the strict type translation to a non-strict language requires a different translation for values and results. Intuitively, the three type translations can be thought of as a translation of expressions that we intend to evaluate to results (CC𝑅) versus placing themdirectly in the environment (CC𝑉 ), alongwith translation of the environment needed for evaluating an expression (CCΞ“). The result type translation of a function has changed from the strict closure conversion to reflect that it now accepts only thunks as arguments. Like strict closure conversion, the non-strict transformation preserves typing derivations. Theorem 3.2 (Type Preservation). If Ξ“ ⊒ 𝑀 : 𝜏 , then CCΞ“ (Ξ“) ⊒ CC(𝑀) : CC𝑅 (𝜏). 49 MJ𝜏K = {(Conf𝑠,Conf𝑑 ) | βˆ€R𝑠 .Conf𝑠 ⇓ R𝑠 =β‡’ βˆƒ(R𝑠,V𝑑 ) ∈ RJ𝜏K.Conf𝑑 ⇓ V𝑑 } VJ𝜏K = {((Σ𝑠, 𝑀𝑠), pack ⟨⟨V0, . . . ,Vπ‘›βŸ©, πœ†βŸ¨π‘₯0, . . . , π‘₯π‘›βŸ©. 𝑀𝑑 ⟩) | (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘€π‘ βŸ©βŸ©, βŸ¨βŸ¨πœ€,V0/π‘₯0, . . . ,V𝑛/π‘₯𝑛 βˆ₯ 𝑀𝑑 ⟩⟩) ∈ MJ𝜏K} RJ𝐡K = {(b, b) | b ∈ 𝐡} RJ𝜏0 β†’ 𝜏1K = {((Σ𝑠, πœ†π‘₯ . 𝑀𝑠), pack ⟨⟨W0, . . . ,Wπ‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩. 𝑀𝑑 ⟩) | βˆ€(V𝑠,V𝑑 ) ∈ VJ𝜏0K. (βŸ¨βŸ¨Ξ£π‘ ,π‘Šπ‘ /π‘₯ βˆ₯ π‘€π‘ βŸ©βŸ©, βŸ¨βŸ¨πœ€,W0/𝑦0, . . . ,W𝑛/𝑦𝑛,V𝑑/π‘₯ βˆ₯ 𝑀𝑑 ⟩⟩) ∈ MJ𝜏1K} EJΞ“K = {(Σ𝑠, Σ𝑑 ) | βˆ€(π‘₯ :𝜏) ∈ Ξ“. (Σ𝑠 (π‘₯), Σ𝑑 (π‘₯)) ∈ VJ𝜏K} Figure 3.8. Non-strict Closure Conversion Logical Relations Such a non-strict closure conversion is dependent on the operational semantics of the target language. For our work in PEPM [52], we used a natural semantics, which must evaluate programs to results. Therefore, the case of functions must capture a closure as a final result. However, if we use the Krivine machine, then the evaluation context is maintained while evaluating the function of an application. Therein, we can get away with only constructing closures for function arguments since the function’s environment will still be available! We will see in later chapters how to avoid this redundant closure in machines with push/enter style function evaluation. 3.2.4 Operational Semantics Preservation. Using a similar delayed evaluation logical relation technique to the strict case, we may prove that evaluation is preserved by this conversion. Repeating the theme of distinguishing values and results, the family of logical relations from strict closure-conversion can be modified to work for the non-strict transformation with similar modifications to those of the semantics and type translations. Thus, the non-strict family of relations in Figure 3.8 includes a separate relation for values and results. The V relation from the strict closure conversion has become the result relation R for non-strict closure conversion; it relates source results to target machine values. The relation for values,V , is wholly new. A source value, which is a thunk closure, is related 50 to a target package when they form related configurations by unpacking and applying their respective enclosed environments. As before, the fundamental lemma of this logical relation implies correct evaluation. Lemma 3.3 (Fundamental Lemma). If Ξ“ ⊒ 𝑀𝑠 : 𝜏 and (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K, then (βŸ¨Ξ£π‘  βˆ₯ π‘€π‘ βŸ©, βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑀𝑠)⟩) ∈ MJ𝜏K. Proof. By induction on the typing derivation of Ξ“ ⊒ 𝑀𝑠 : 𝜏 , for a generic (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K. The cases for base types and function introduction are analogous to Lemma 3.2. The remaining two cases are: Case Ξ“ ⊒ π‘₯ : 𝜏 because π‘₯ :𝜏 ∈ Ξ“. So 𝑀𝑠 = π‘₯ , CC(π‘₯) = unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 𝑒 , and we must show that (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘₯⟩⟩, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(π‘₯)⟩⟩) ∈ MJ𝜏K. From the assumptions (Σ𝑠, Σ𝑑 ) ∈ EJΞ“K and π‘₯ :𝜏 ∈ Ξ“, we know (π‘₯ [Σ𝑠], π‘₯ [Σ𝑑 ]) ∈ VJ𝜏K by definition of EJΞ“K. Furthermore, the definition of V yields that π‘₯ [Ξ£ ′𝑠] = (Σ𝑠, 𝑀𝑠) and π‘₯ [Σ𝑑 ] = pack ⟨⟨⟨V0, . . . ,Vπ‘›βŸ©, πœ†βŸ¨βŸ¨π‘₯0, . . . , π‘₯π‘›βŸ©βŸ©. 𝑀𝑑 ⟩⟩ such that (βŸ¨βŸ¨Ξ£β€²π‘  βˆ₯ π‘€π‘ βŸ©βŸ©, βŸ¨βŸ¨πœ€,V0/π‘₯0, . . . ,V𝑛/π‘₯𝑛 βˆ₯ 𝑀𝑑 ⟩⟩) ∈ MJ𝜏K. Assume the source evaluation βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘₯⟩⟩ ⇓ R𝑠 . By inversion on this derivation, βŸ¨βŸ¨Ξ£β€²π‘  βˆ₯ π‘€π‘ βŸ©βŸ© ⇓ R𝑠 . We are guaranteed related results byMJ𝜏K. That is, βŸ¨βŸ¨πœ€,V0/π‘₯0, . . . ,V𝑛/π‘₯𝑛 βˆ₯ 𝑀𝑑 ⟩⟩ ⇓ V𝑑 such that (R𝑠,V𝑑 ) ∈ RJ𝜏K. Expanding, we have βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(π‘₯)⟩⟩ ⇓ V𝑑 from the above evaluation combined with unpack, case, and application rules of the target. Therefore, (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘₯⟩⟩, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(π‘₯)⟩⟩) ∈ MJ𝜏K follows by definition. Case Ξ“ ⊒ 𝑁𝑠 𝑂𝑠 : 𝜏 because Ξ“ ⊒ 𝑁𝑠 : πœβ€² β†’ 𝜏 and Ξ“ ⊒ 𝑂 : πœβ€²π‘  . 51 So𝑀𝑠 = 𝑁𝑠 𝑂𝑠 , FV(𝑂𝑠) = {𝑦0, . . . , 𝑦𝑛} and CC(𝑁𝑠 𝑂𝑠) is unpack CC(𝑁𝑠) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑂𝑠)⟩⟩. and we must show thatMJ𝜏K contains (βŸ¨βŸ¨Ξ£π‘  βˆ₯ 𝑁𝑠 π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠 𝑂𝑠)⟩⟩) Suppose that βŸ¨βŸ¨Ξ£π‘  βˆ₯ 𝑁𝑠 π‘‚π‘ βŸ©βŸ© ⇓ R𝑠 in the source. The conclusion of that derivation must be an instance of the application rule by inversion, which gives us 1. ⟨⟨Σ ′𝑠 βˆ₯ π‘π‘ βŸ©βŸ© ⇓ (Σ𝑠, πœ†π‘₯ .𝐿𝑠) and 2. βŸ¨βŸ¨Ξ£β€²π‘ , (Σ𝑠,𝑂𝑠)/π‘₯ βˆ₯ πΏπ‘ βŸ©βŸ© ⇓ R𝑠 . From the first inductive hypothesis, we know (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠)⟩⟩) ∈ MJπœβ€² β†’ 𝜏K. Thus, ((Σ′𝑠, πœ†π‘₯ .𝐿𝑠), pack ⟨⟨W0, . . . ,Wπ‘›βŸ©, πœ†βŸ¨βŸ¨π‘§0, . . . , π‘§π‘›βŸ©, π‘₯⟩. 𝐿𝑑 ⟩) ∈ RJπœβ€² β†’ 𝜏K where βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠)⟩⟩ ⇓ pack⟨⟨W0, . . . ,Wπ‘šβŸ©, πœ†βŸ¨βŸ¨π‘§0, . . . , π‘§π‘šβŸ©, π‘₯⟩. 𝐿𝑑 ⟩ by definition ofM. By the pack, product, and variable evaluation rules, we know that βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑂𝑠)⟩⟩⟩ evaluates to the target machine value pack βŸ¨βŸ¨π‘¦0 [Σ𝑑 ], . . . , 𝑦𝑛 [Σ𝑑 ]⟩, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑂𝑠)⟩. We show ((Σ𝑠,𝑂𝑠), pack βŸ¨βŸ¨π‘¦0 [Σ𝑑 ], . . . , 𝑦𝑛 [Σ𝑑 ]⟩, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑂𝑠)⟩) ∈ VJπœβ€²K by showing that (⟨⟨Σ βˆ₯ π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨πœ€,𝑦0 [Σ𝑑 ]/𝑦0, . . . , 𝑦𝑛 [Σ𝑑 ]/𝑦𝑛 βˆ₯ CC(𝑂𝑠)⟩⟩) ∈ MJπœβ€²K. Thus, suppose βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘‚π‘ βŸ©βŸ© ⇓ S𝑠 : From the second inductive hypothesis, we know (βŸ¨βŸ¨Ξ£π‘  βˆ₯ π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑂𝑠)⟩⟩) ∈ MJπœβ€²K. And thus, there is some (S𝑠,X ′𝑑 ) ∈ RJ𝜏 K such that βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑂𝑠)⟩ ⇓ X𝑑 . We can conclude that βŸ¨βŸ¨πœ€,𝑦0 [Ξ£]/𝑦0, . . . , 𝑦𝑛 [Ξ£]/𝑦𝑛 βˆ₯ CC(𝑂𝑠)⟩⟩ ⇓ X𝑑 if βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑂𝑠)⟩ ⇓ X𝑑 by strengthening (Lemma 3.1). 52 By the property of RJπœβ€² β†’ 𝜏K with the related values above in VJπœβ€²K, we know that (βŸ¨βŸ¨Ξ£β€²π‘ , (Σ𝑠,𝑂𝑠)/π‘₯ βˆ₯ πΏπ‘ βŸ©βŸ©, βŸ¨βŸ¨πœ€,W0/𝑧0, . . . ,Wπ‘š/π‘§π‘š,Y/π‘₯ βˆ₯ 𝐿𝑑 ⟩⟩) ∈ MJ𝜏K where Y is the package pack βŸ¨βŸ¨π‘¦0 [Σ𝑑 ], . . . , 𝑦𝑛 [Σ𝑑 ]⟩, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑂𝑠)⟩. From this property and (2) above, we know that there is some (R𝑠,V𝑑 ) ∈ RJ𝜏K such that βŸ¨βŸ¨πœ€,W0/𝑧0, . . . ,Wπ‘š/π‘§π‘š,Y/π‘₯ βˆ₯ 𝐿𝑑 ⟩⟩) ⇓ V𝑑 . By the unpack, case, and application evaluation rules, we know that βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ unpackCC(𝑁𝑠) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑂𝑠)⟩⟩⟩⟩ ⇓ V𝑑 . Therefore, (βŸ¨βŸ¨Ξ£π‘  βˆ₯ 𝑁𝑠 π‘‚π‘ βŸ©βŸ©, βŸ¨βŸ¨Ξ£π‘‘ βˆ₯ CC(𝑁𝑠 𝑂𝑠)⟩⟩) is inMJ𝜏K by definition. β–‘ Corollary 3.2 (Evaluation Preservation). If Ξ“ ⊒ 𝑀 : 𝜏 and EvalNSBS(𝑀) = b, then EvalTBS(CC(𝑀)) = b. 3.3 Sharing Closure Conversion When we applied strict closure conversion to our non-strict language, we found that closures need to be strict and that we need to close over arguments of functions. This forced us to use a strict target language even when closure converting non-strict programs. Running an analogous experiment, consider the non-strict, sharing evaluation of the resulting program from non-strict closure conversion (again, avoiding the closures necessary for π‘₯ , 3, and 4) of the program in (3.1). let π‘₯ be (let 𝑦 be pack ⟨⟨⟩, πœ†βŸ¨βŸ©. 2 + 1⟩ in pack βŸ¨βŸ¨π‘¦βŸ©, πœ†βŸ¨βŸ¨π‘¦βŸ©, π‘§βŸ©. unpack 𝑦 as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 π‘’βŸ©) in (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 3⟩) + (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 4⟩) 53 Since the transformation replaces every binding with a strict binding, we are left with a program with only strict bindings. Thus, the two evaluations of the thunk bound to 𝑦 are no longer shared. A proper lazy closure conversion should share computations; that is, thunk closures must be evaluated at most one time. An obvious solution is to add a restricted form of mutable references to the target language and replace thunks after their evaluation. Instead of closure converting a function argument to a thunk, it will be converted into a pointer to a heap-allocated, tagged thunk. We will use the following shorthand for tagged heap storage: def store𝑀 = new (inr𝑀) At the thunk’s call site, i.e. a variable lookup in the source, we will generate code that checks the tag to determine whether to simply return a value or to evaluate the thunk and update the pointer. This, we capture in a memoization macro: def memo π‘₯ = case !π‘₯ of inl 𝑣 β†’ 𝑣 inr 𝑑 β†’ unpack 𝑑 as (𝑦, 𝑧) in let 𝑣 = 𝑧 𝑦 in let _ = (π‘₯ := inl 𝑣) in 𝑣 In our example, applying these ideas to the thunk created for 𝑦 yields the following target program: let π‘₯ be (let 𝑦 be store (pack ⟨⟨⟩, πœ†βŸ¨βŸ©. 2 + 1⟩) in pack βŸ¨βŸ¨π‘¦βŸ©, πœ†βŸ¨βŸ¨π‘¦βŸ©, π‘§βŸ©. memo π‘¦βŸ©) in (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 3⟩) + (unpack π‘₯ as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, 4⟩) 54 Ξ¦ ∈ Heap ::= πœ€ | Ξ¦, 𝑙 ↦→ (Ξ£, 𝑀) | Ξ¦, 𝑙 ↦→ A Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£, 𝑙/π‘₯ A ∈ Answer ::= b | (Ξ£, πœ†π‘₯ . 𝑀) R ∈ Result ::= (Ξ¦,A) Configuration ::= ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© (a) Syntax 𝑙 βˆ‰ Dom(Ξ¦) Ξ¦β€²(𝑙) = 𝑃 βˆ€π‘™β€² ∈ (Dom(Ξ¦β€²) βˆ’ {𝑙}).Ξ¦(𝑙′) = Ξ¦β€²(𝑙′) alloc(Ξ¦, 𝑃) = (𝑙,Ξ¦β€²) 𝑙 ∈ Dom(Ξ¦) Ξ¦β€²(𝑙) = 𝑃 βˆ€π‘™β€² ∈ (Dom(Ξ¦β€²) βˆ’ {𝑙}).Ξ¦(𝑙′) = Ξ¦β€²(𝑙′) update(Ξ¦, 𝑙, 𝑃) = Ξ¦β€² (b) Heap Semantics ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ R Ξ¦(π‘₯ [Ξ£]) = A ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ b⟩⟩ ⇓ (Ξ¦, b) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘₯⟩⟩ ⇓ (Ξ¦,A) Ξ¦(π‘₯ [Ξ£]) = (Ξ£β€², 𝑀) ⟨⟨Φ βˆ₯ Ξ£β€² βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€²,A) update(Ξ¦β€², π‘₯ [Ξ£],A) = Ξ¦β€²β€² ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘₯⟩⟩ ⇓ (Ξ¦β€²β€²,A) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ πœ†π‘₯ .π‘€βŸ©βŸ© ⇓ (Ξ¦, (Ξ£, πœ†π‘₯ . 𝑀)) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², (Ξ£β€², πœ†π‘₯ . 𝐿)) alloc(Ξ¦β€², (Ξ£, 𝑁 )) = (𝑙,Ξ¦β€²β€²) βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€², 𝑙/π‘₯ βˆ₯ 𝐿⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑀 𝑁 ⟩⟩ ⇓ R (c) Evaluation Rules Figure 3.9. Lazy Evaluation We arrive at a lazy closure conversion in modifying the non-strict transformation by inserting these thunk mutating macros at the locations where source variable bindings are introduced (i.e. let-bound expressions and function arguments) and eliminated (i.e. variable lookup). 3.3.1 Source Language. As the source operational semantics for our lazy closure conversion, the syntax and evaluation rules for a sharing non-strict evaluator are given in Figure 3.9. The major difference in this semantics versus the ones that we 55 presented for strict and non-strict evaluation is the addition of the heap. As a result, we must now distinguish results, values, and answers. Answers are the set of normalized expressions and the result of evaluation now contains both an updated heap and an answer. Configurations include a heap and an environment. Whereas heaps hold thunks and answers at specified locations, environments are only a mapping from variables to locations into the heap. We model heaps as objects for which we only know how to allocate, update, and lookup. Since our heaps remain abstract, our heap semantics specifies only the properties that allocation and update operations must satisfy. Allocation requires that we are allocating a fresh variable, the new heap correctly returns the expression being allocated, and everything else in the heap remains unchanged. Update requires that the variable is already in the heap, that the new heap correctly returns the value, and that everything else in the heap remains unchanged. Just like the other two big-step evaluators, the rule for πœ†-expressions must construct a function closure. Like the non-strict language, the application rule constructs a thunk closure, but here it is added to the heap and a pointer to it is passed in the environment. The differential treatment between closure types is more obvious in a shared non-strict evaluator: function closures are returned from evaluations, whereas thunk closures are passed as pointers to the heap where they can be updated. As we noticed with the non-strict big-step semantics, such a semantics acts more like an eval/apply style machine since the left-hand side of an application is evaluated to a function closure which is then applied to its argument. For the memoization aspect of sharing to work, there is no way of avoiding function closures if we wanted a more push/enter style big-step semantics. This is because it is precisely this normal form, with its environment, that we must memoize. 56 𝜏, 𝜎 ∈ Type ::= Β· Β· Β· | 𝜏 + 𝜎 | ref 𝜏 𝑀, 𝑁, 𝐿 ∈ Expression ::= Β· Β· Β· | inl𝑀 | inr𝑀 | case𝑀 of {inl π‘₯ β†’ 𝑁 ; inr 𝑦 β†’ 𝐿} | new𝑀 | !𝑀 | 𝑀 := 𝑁 (a) Additional Syntax Ξ”; Ξ“ ⊒ 𝑀 : 𝜏 Ξ”; Ξ“ ⊒ 𝑀 : 𝜎 Ξ”; Ξ“ ⊒ +𝐼1 +inl 𝐼2𝑀 : 𝜏 + 𝜎 Ξ”; Ξ“ ⊒ inr𝑀 : 𝜏 + 𝜎 Ξ”; Ξ“ ⊒ 𝑀 : πœŽπ‘™ + πœŽπ‘Ÿ Ξ”; Ξ“, π‘₯ :πœŽπ‘™ ⊒ 𝑁 : 𝜏 Ξ”; Ξ“, π‘₯ :πœŽπ‘Ÿ ⊒ 𝐿 : 𝜏 Ξ”; Ξ“ ⊒ +𝐸case𝑀 of {inl π‘₯ β†’ 𝑁 ; inr π‘₯ β†’ 𝐿} : 𝜏 Ξ”; Ξ“ ⊒ 𝑀 : 𝜏 Ξ”; Ξ“ ⊒ 𝑀 : ref 𝜏 Ξ”; Ξ“ ⊒ 𝑀 : ref 𝜏 Ξ”; Ξ“ ⊒ 𝑁 : 𝜏 Ξ”; Ξ“ ⊒ new𝑀 : ref𝐼 ; refref 𝜏 Ξ” Ξ“ ⊒ !𝑀 : 𝜏 𝐸 Ξ”; Ξ“ ⊒ 𝑀 := : 1 Mut𝑁 (b) Additional Typing Rules Figure 3.10. Target Language extended with Sums and Mutation Definition 3.4 (Shared Non-Strict Big-Step Evaluation). EvalSNSBS(𝑀) = b where βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ π‘€βŸ©βŸ© ⇓ b. Like with the other machines and big-step semantics, we believe this evaluation to coincide with the Sestoft machine. Conjecture 3.2. EvalSM(𝑀) = EvalSNSBS(𝑀). 3.3.2 Target Language. In order to handle the added problem of updating thunks, the strict target language for lazy closure conversion extends the previous target language with sums and mutable references. The additional typing rules for this target language are given in Figure 3.10. Heap manipulation in this language is via reference types, Γ  la Standard ML [33]. This can be seen in the Mut rule wherein a reference to an integer, for instance, is a different type ref int that can only be updated with another integer. Assignment expressions will return a value of the empty product type (i.e. 1) which we denote by ⟨⟩. 57 Ξ¦ ∈ Heap ::= πœ€ | Ξ¦, 𝑙 ↦→ V Ξ£ ∈ Machine Env. ::= πœ€ | Ξ£,V/π‘₯ V ∈ Value ::= b | πœ†π‘₯ .𝑀 | ⟨V0, . . . ,Vπ‘›βŸ© | pack V | inl V | inr V | 𝑙 R ∈ Result ::= (Ξ¦,V) Configuration ::= ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© (a) Syntax ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ b⟩⟩ ⇓ (Ξ¦, b) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘₯⟩⟩ ⇓ (Ξ¦, π‘₯ [Ξ£]) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ πœ†π‘₯ .π‘€βŸ©βŸ© ⇓ (Ξ¦, πœ†π‘₯ . 𝑀) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², πœ†π‘₯ . 𝐿) βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑁 ⟩⟩ ⇓ (Ξ¦β€²β€²,V) βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ πœ€,V/π‘₯ βˆ₯ 𝐿⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑀 𝑁 ⟩⟩ ⇓ R ⟨⟨Φ0 βˆ₯ Ξ£ βˆ₯ 𝑀0⟩⟩ ⇓ (Ξ¦1,V0) Β· Β· Β· βŸ¨βŸ¨Ξ¦π‘› βˆ₯ Ξ£ βˆ₯ π‘€π‘›βŸ©βŸ© ⇓ (Φ𝑛+1,V𝑛) ⟨⟨Φ0 βˆ₯ Ξ£ βˆ₯ βŸ¨π‘€0, . . . , π‘€π‘›βŸ©βŸ©βŸ© ⇓ (Φ𝑛+1, ⟨V0, . . . ,Vπ‘›βŸ©) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², ⟨V0, . . . ,Vπ‘›βŸ©) ⟨⟨Φ βˆ₯ Ξ£,V0/π‘₯0, . . . ,V𝑛/π‘₯𝑛 βˆ₯ 𝑁 ⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ case𝑀 of {⟨π‘₯0, . . . , π‘₯π‘›βŸ© β†’ 𝑁 }⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€²,V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ packπ‘€βŸ©βŸ© ⇓ (Ξ¦β€², pack V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², pack V) βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£,V/π‘₯ βˆ₯ 𝑁 ⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ unpack𝑀 as π‘₯ in 𝑁 ⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€²,V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€²,V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ inlπ‘€βŸ©βŸ© ⇓ (Ξ¦β€², inl V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ inrπ‘€βŸ©βŸ© ⇓ (Ξ¦β€², inr V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², inl V) βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£,V/π‘₯ βˆ₯ 𝑁 ⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ case𝑀 of {inl π‘₯ β†’ 𝑁 ; inr 𝑦 β†’ 𝐿}⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², inr V) βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£,V/π‘₯ βˆ₯ 𝐿⟩⟩ ⇓ R ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ case𝑀 of {inl π‘₯ β†’ 𝑁 ; inr 𝑦 β†’ 𝐿}⟩⟩ ⇓ R ⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ© ⇓ (Ξ¦β€²,V) alloc(Ξ¦β€², 𝑙,V) = (𝑙,Ξ¦β€²β€²) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², 𝑙) Ξ¦β€²(𝑙) = V ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ newπ‘€βŸ©βŸ© ⇓ (Ξ¦β€²β€², 𝑙) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ !π‘€βŸ©βŸ© ⇓ (Ξ¦β€²,V) ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ π‘€βŸ©βŸ© ⇓ (Ξ¦β€², 𝑙) βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑁 ⟩⟩ ⇓ (Ξ¦β€²β€²,V) update(Ξ¦β€²β€², 𝑙,V) = Ξ¦β€²β€²β€² ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑀 := 𝑁 ⟩⟩ ⇓ (Ξ¦β€²β€²β€², ⟨⟩) (b) Evaluation Rules Figure 3.11. Mutable Target Language Evaluation 58 CC(b) = b CC(π‘₯) = case !π‘₯ of inl 𝑣 β†’ 𝑣 inr 𝑑 β†’ unpack 𝑑 as βŸ¨π‘’, 𝑓 ⟩ in π‘₯ := inl (𝑓 𝑒); !π‘₯ CC(πœ†π‘₯. 𝑀) = pack βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, π‘₯⟩.CC(𝑀)⟩ where FV(πœ†π‘₯. 𝑀) = {𝑦0, . . . , 𝑦𝑛} CC(𝑀 𝑁 ) = let π‘₯ be (new (inr βŸ¨βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©, πœ†βŸ¨π‘¦0, . . . , π‘¦π‘›βŸ©.CC(𝑁 )⟩)) in unpack CC(𝑀) as βŸ¨π‘’, 𝑓 ⟩ in 𝑓 βŸ¨π‘’, π‘₯⟩ where FV(𝑁 ) = {𝑦0, . . . , 𝑦𝑛} (a) Expression Translation CC𝐴 (𝐡) = 𝐡 CC𝐴 (𝜏 β†’ 𝜎) = βˆƒπ‘‹ .𝑋 Γ— (𝑋 Γ— CC𝑉 (𝜏) β†’ CC𝐴 (𝜎)) CC𝑉 (𝜏) = ref (CC𝐴 (𝜏) + (βˆƒπ‘‹ .𝑋 Γ— (𝑋 β†’ CC𝐴 (𝜏)))) CCΞ“ (πœ€) = πœ€ CCΞ“ (Ξ“, π‘₯ :𝜏) = CCΞ“ (Ξ“), π‘₯ :CC𝑉 (𝜏) (b) Type Translations Figure 3.12. Memoizing Non-strict Closure Conversion The operational semantics is given in Figure 3.11. Unlike the syntax and typing rules, which were a direct extension of the old target language, all of the evaluation rules differ because they must pass the heap around explicitly. For instance, the product evaluation rule is limited to left-to-right evaluation of its components. In the non-mutable target language, this order was irrelevant. The new mutable references rules make use of the same heap interface as our lazy semantics. The rule for a new expression evaluates its argument to a value, places that value in the heap, and returns its location in memory. The dereference rule evaluates its argument to a location and returns the value at that location. Finally, the mutation rule will evaluate the left-hand side to get the location where the right-hand side’s value will go. After the update, a mutation will return the empty product ⟨⟩. 59 3.3.3 Transformation. The lazy closure conversion is found in Figure 3.12. Our lazy source language’s different variable lookup rules are encoded in a single case expression: either the heap location contains a thunk or a normal form. The application case is the same as in the non-strict closure conversion case, but the thunk is tagged as a thunk with inr and it is placed in the heap with new instead of in the local environment. The type translation reflects the heap allocation with a ref type and the thunk tagging with a sum type in the CC𝑉 (𝜏) translation. Interestingly, the cases for already normalized expressions (i.e. constants of base types and manifest functions) are the same for strict, non-strict, and lazy closure conversion. Theorem 3.3 (Type Preservation). If Ξ“ ⊒ 𝑀 : 𝜏 , then CCΞ“ (Ξ“) ⊒ CC(𝑀) : CC𝑅 (𝜏). 3.3.4 Operational Semantics Preservation. As part of the PEPM submission [52] that this chapter is based on, the delayed-substitution logical relation for a sharing non-strict language was left undone. By PPDP [53], we have discovered how to expand on the non-strict relation to make them work here. Chapter 7 presents such an extension. 60 CHAPTER IV ABSTRACT CLOSURES This chapter contains published and unpublished co-authored material. It is a revision of the work Closure Conversion in Little Pieces [53] co-authored with Paul Downen and Zena M. Ariola. Zachary J. Sullivan is the primary author under the guidance of Paul Downen and Zena M. Ariola. Abstract machines expressed closures as part of the runtime system of the language and closure conversion expressed closures by a transformation between a high-level source language and a different language which does not have the ability to pass nested, unevaluated code. However, it would be really convenient for the transformation to be expressed in the same language. Specifically, we would like the following to hold: Theorem 4.1. If Ξ“ ⊒ 𝑀 : 𝜏 , then Ξ“ ⊒ 𝑀 = CC(𝑀) : 𝜏 . That is, we want an expression 𝑀 to be axiomatically equal, via the typical 𝛽 and πœ‚ axioms, to its closure converted form CC(𝑀). Such a language enables not only the simple definition of the transformation but for optimized versions, e.g. those that share environments, to be implemented locally and incrementally. Indeed, it is the compatibility and transitivity of equational theories that allow these closures optimizations to compose with themselves and other optimizations within a compiler. There are also benefits to reasoning about correctness. Whereas in previous work [34, 52] different closure conversion techniques correspond to different cross-language logical relations, closure transformations encoded via the axioms of a compiler intermediate language (IL) are proven correct merely by the soundness of these axioms. That is, for a sound equational theory, axiomatic equality implies contextual equivalence. 61 Working within a single equational theory as the main focus of optimizations has a history of success in compilers [44, 51, 5, 39]. A key idea therein is that a core IL is modified repeatedly, in a series of passes, by a set of small, local transformations. Some global transformations, e.g. strictness analysis, are still necessary but are less modular. Inlining, constant folding, and common sub-expression elimination are all examples of local transformations. Local transformations may be built from smaller ones, e.g. common sub-expression elimination is a case of 𝛽 expansion when we give a name to a repeated sub-program. Such an approach has even been successful for optimization problems that are typically handled in lower-level code, like join points [31] and unboxed types [42], by extending the IL to capture some essential properties of these concepts. Once included, the low-level parts may be optimized with existing optimizations; for instance, redundant unboxing operations can be eliminated via common sub-expression elimination. To date, closures have been excluded from this local approach because closure conversion [34, 36, 3, 38, 39, 52] as a data representation of code does not make this goal easy. For example, consider using the strict closure conversion from the previous chapter (Figure 3.4): CC(πœ†π‘₯.𝑦 + 𝑧) = pack βŸ¨βŸ¨π‘¦, π‘§βŸ©, πœ†βŸ¨π‘’, π‘₯⟩. case 𝑒 of {βŸ¨π‘¦, π‘§βŸ© β†’ 𝑦 + 𝑧}⟩ If we want Theorem 4.1 to be true, then we immediately run into a problem since the type has changed from a function to a existential pair. Therefore, to say that something is π›½πœ‚ equal to its closure converted form is false because we cannot apply an existential pair as we can a function. Of course, we could remedy this problem by changing all of the calling contexts of a function, but then we have a global transformation thereby losing the local reasoning that enables optimization in little pieces. Our solution to this problem is not to consider closure conversion a data representation for functions, instead we build on the 62 work on abstract closures [21, 34, 11]. These are special objects for which we may give bespoke semantics, distinct from a usual function’s semantics. An abstract closure object β€œknows” about the relationship between the environment and code parts of a closure; that is, the environment part of the closure will be substituted at the same time as the formal parameter. This chapter presents the following contributions: defines closure conversion not as a global cross-language transformation but in terms of little pieces that correspond to provable equalities. Thereby, closure conversion is correct by construction and we elevate closure conversion to be on par with other optimizations. In other words, it is done within the IL itself; and thus, closure conversion optimizations can be expressed by standard IL transformations. 4.1 Why Abstract Closures If our goal is to promote reasoning about closures from a low-level runtime or code generation phase of compilation to an equational theory suitable for optimizations, then the canonical closure conversion presents more problems than just being a global transformation. Instead of a transformation between a different source and target language, in some works [39, 3] the two languages are the same. Alas, this still does not work well with equational theories. If it did, then it should be the case that the transformation preserves equality, by the transitivity of the theory: 𝑀 = 𝑁 implies CC(𝑀) = CC(𝑁 ) For example, let us attempt to preserve the call-by-value 𝛽 axiom: CC((πœ†π‘₯. 𝑀) 𝑉 ) = CC(𝑀 [𝑉 /π‘₯]) 63 For any closure conversion, preserving this law is hard since the transformation changes the number of free variables in the function body; therefore, it does not commute with substitution: CC(𝑀) [CC(𝑉 )/π‘₯] β‰  CC(𝑀 [𝑉 /π‘₯]) For an example of why this is not true, let 𝑀 be πœ†π‘§. π‘₯ and we will need to prove the following: CC( ?πœ†π‘§. π‘₯) [CC(𝑉 )/π‘₯] = CC((πœ†π‘§. π‘₯) [𝑉 /π‘₯]) The variable π‘₯ will be part of the closure on the left but not on the right; and therefore, the following equation does not hold (assume 𝑉 is closed): (pack ⟨⟨π‘₯⟩, πœ†βŸ¨βŸ¨π‘₯⟩, π‘§βŸ©. π‘₯⟩) [CC(𝑉 )/π‘₯] = pack ⟨⟨CC(𝑉 )⟩, πœ†βŸ¨βŸ¨π‘₯⟩, π‘§βŸ©. π‘₯⟩ β‰  pack ⟨⟨⟩, πœ†βŸ¨βŸ¨βŸ©, π‘§βŸ©.CC(𝑉 )⟩ ⟨π‘₯⟩ β‰  ⟨⟩ A problem also arises in preserving πœ‚-laws where we need to show that CC(πœ†π‘₯.𝑉 π‘₯) = CC(𝑉 ). If 𝑉 is a πœ†-expression, then we may prove this with 𝛽 ; but if 𝑉 is a variable, say 𝑧, then we get stuck, as shown below: pack βŸ¨βŸ¨π‘§βŸ© ?, πœ†βŸ¨βŸ¨π‘§βŸ©, π‘₯⟩. unpack 𝑧 as βŸ¨π‘’, 𝑓 ⟩ in𝑓 βŸ¨π‘’, π‘₯⟩⟩ = 𝑧 Both of these failures are because closure conversion creates products that have a distinct relation between the first and second components: the second will always expect the first as an argument when applied. However, products and functions do not have this property in general. This is why we step outside of the equational theory and use 64 𝜍 ∈ Environment ::= πœ€ | 𝜍,𝑉 /π‘₯ Ξ“ ⊒ 𝜍 : Ξ“β€² Ξ“ ⊒ 𝑉 : 𝜏 ⊒ ΓΓ 𝐼 Ξ“πΌπœ€ : πœ€ 𝐡 Ξ“ ⊒ (𝜍,𝑉 /π‘₯) : (Ξ“β€², π‘₯ :𝜏) 𝐼 Figure 4.1. Syntactic Environments logical relations, which capture the lost information, to prove the correctness of closure conversion. Non-strict closure conversions add more troubles for a local transformation. First, the target language of non-strict closures is a strict language, so it does not work by necessity. Moreover, the sharing non-strict closure conversion requires mutation in the target language. If source and target were the same here, then our ability to reason would be greatly reduced since mutable languages provide much weaker guarantees than the πœ†-calculi that we have seen so far. Working directly in the syntax, abstract closures [21, 34, 11] solve all of the above problems, though previous work has not given them an equational theory nor specified them for non-strict calculi. They have the same type as the non-closure versions of functions and consume the same applicative contexts. Thus, they solve the global transformation problem and enable type-preserving reductions. Additionally, consuming the same contexts allows their πœ‚ laws to be preserved. The environment and the formal parameter of a function are substituted at the same time when entering the code part. Thus, they solve the disconnection of environment and code that happens with the product encoding thereby enabling us to equate closures that capture different environments. Finally, we will be able to specify non-strict semantics for them thereby allowing us to remain within a non-strict language while doing closure conversion. 65 𝑀, 𝑁, 𝐿 ∈ Expression ::= 𝑉 | 𝑀 𝑁 𝑉,π‘Š ∈ Value ::= b | π‘₯ | {𝜍, πœ†π‘₯ . 𝑀} πœ†π‘₯ .𝑀 = {πœ€, πœ†π‘₯ . 𝑀} (a) Syntax (b) Syntactic Sugar Ξ“ ⊒ 𝜍 : Ξ“β€² ΓΓ′, π‘₯ :𝜏 ⊒ 𝑀 : 𝜎 β†’ {𝜍, πœ†π‘₯ . 𝑀} 𝑉 =𝛽 𝑀 [𝜍,𝑉 /π‘₯] ⊒ { } : β†’ 𝐼Γ 𝜍, πœ†π‘₯ . 𝑀 𝜏 𝜎 πœ†π‘₯.𝑉 π‘₯ =πœ‚ 𝑉 (c) New Introduction Rule (d) Axioms Figure 4.2. Call-by-Value with Closures 4.2 Closures for Different Evaluation Strategies Adding abstract closures to our different calculi begins with a notion of delayed substitution, which we call environments. Figure 4.1 presents the typing rules and syntax of these. We have not specified what values 𝑉 are there because the objects in an environment will differ depending on evaluation strategy. 4.2.1 Call-by-Value. A call-by-value calculus with closures is presented in Figure 4.2. Abstract closures {𝜍, πœ†π‘₯ . 𝑀} pair a function together with a syntactic environment. Note that the closure replaces the function form of the original calculus, but we can recover that using the syntactic sugar of an abstract closure in an empty environment. We have the same type system as the original simply typed πœ†-calculus, but have replaced the typing rule for functions with that of closures. Examining that rule, we see that the body of the function extends the current environment Ξ“ with the one from the environment Ξ“β€² and the formal parameter π‘₯ . Since Ξ“ is included in this environment, abstract closures do not necessarily need to capture all of there free variables in their environment; this is essential for closure conversion in little pieces. The 𝛽 law for functions has been replaced with one for closures wherein we merely perform the delayed substitution when the function is applied along with the substitution for the formal parameter. Note the similarity to the SECD machine’s step number 5 66 (Figure 2.3) and strict big-step semantics application case (Figure 3.1). The πœ‚ law remains unchanged and applies only to πœ†-expressions with an empty environment. Indeed, the more general πœ‚ law, which we call πœ‚β€²β†’, with a non-empty environment: {𝜍, πœ†π‘₯ .𝑉 π‘₯} =πœ‚β€²β†’ 𝑉 [𝜍] can be derived as follows: 𝑉 [𝜍] =πœ‚β†’ πœ†π‘₯.𝑉 [𝜍] π‘₯ =subst. πœ†π‘₯. (𝑉 π‘₯) [𝜍, π‘₯/π‘₯] =𝛽→ πœ†π‘₯. {𝜍, πœ†π‘₯ .𝑉 π‘₯} π‘₯ =πœ‚β†’ {𝜍, πœ†π‘₯ .𝑉 π‘₯} Since we now have a notion of closures that ties the environment and code part together in both the type system and equational theory, we are able to fix the problem of syntactically equating closures which have captured different numbers of variables; this failed before since the canonical closure conversion did not commute with substitution. For example, we can now equate these two abstract closures where one has an extra variable: {(πœ€,𝑦/𝑦), πœ†π‘₯ . 𝑀} =πœ‚β†’ {(πœ€,𝑦/𝑦, 𝑧/𝑧), πœ†π‘₯ . {(πœ€,𝑦/𝑦), πœ†π‘₯ . 𝑀} π‘₯} =𝛽→ {(πœ€,𝑦/𝑦, 𝑧/𝑧), πœ†π‘₯ . 𝑀} 4.2.2 Call-by-Name. A call-by-name calculus with closures is presented in Figure 4.3. Matching the Krivine machine, which builds closures for function arguments, we place abstract closures around function arguments. Contrary to call-by-value that constructs closures for function introduction, we need them for function elimination; and 67 𝑀, 𝑁, 𝐿 ∈ Expression ::= b | π‘₯ | πœ†π‘₯. 𝑀 | 𝑀 {𝜍, 𝑁 } 𝑉 ,π‘Š ∈ Value = Expression 𝑀 𝑁 = 𝑀 {πœ€, 𝑁 } (a) Syntax (b) Syntactic Sugar Ξ“ ⊒ 𝑀 : 𝜎 β†’ 𝜏 Ξ“ ⊒ 𝜍 : Ξ“β€² ΓΓ′ ⊒ : (πœ†π‘₯ .𝑀) 𝑉 =𝑁 𝜎 𝛽 𝑀 [𝑉 /π‘₯]β†’ ⊒ { } : 𝐸 πœ†π‘₯ .𝑀 π‘₯ =Ξ“ πœ‚ 𝑀𝑀 𝜍, 𝑁 𝜏 𝑀 {𝜍, 𝑁 } =cl 𝑀 (𝑁 [𝜍]) (c) New Elimination Rule (d) Axioms Figure 4.3. Call-by-Name with Closures thus, that is the typing rule which we replace. The axioms from call-by-name remain the same here, but we add a new axiom cl for entering an argument’s closure. We changed the look of the 𝛽 law, but since call-by-name values are any expression, we have lost nothing. It may seem unsatisfying to see that the cl axiom β€œenters” the closure before function application, whereas the Krivine machine does not enter a function until the variable evaluation is forced. However, this fits with the flexibility of an equational theory and we are primarily focused on stating where in our code that the operational semantics will construct closures. Indeed, a rule more like the Krivine machines evaluation: (πœ†π‘₯. 𝑀) {𝜍, 𝑁 } = 𝑀 [𝑁 [𝜍]/π‘₯] is derivable simply by using cl and then 𝛽 . 4.2.3 Call-by-Need. A call-by-need calculus with closures is presented in Figure 4.4. With the addition of the memoizing expression, there are now more places where unevaluated code with free variables may be substituted to other parts of the program in an environment machine. Although they are not substituted by the axioms of the theory, the call-by-need evaluation context let π‘₯ be 𝐸 in 𝐹 [π‘₯] suggests that 68 𝑀, 𝑁, 𝐿 ∈ Expression ::= 𝑉 | 𝑀 𝑁 | let π‘₯ be {𝜍,𝑀} in 𝑁 𝑉,π‘Š ∈ Value ::= b | π‘₯ | {𝜍, πœ†π‘₯ . 𝑀} (a) Syntax πœ†π‘₯ .𝑀 = {πœ€, πœ†π‘₯ . 𝑀} let π‘₯ be𝑀 in 𝑁 = let π‘₯ be {πœ€, 𝑀} in 𝑁 (b) Syntactic Sugar Ξ“ ⊒ 𝜍 : Ξ“β€² ΓΓ′, π‘₯ :𝜏 ⊒ 𝑀 : 𝜎 β†’ Ξ“ ⊒ 𝜍 : Ξ“ β€² ΓΓ′ ⊒ 𝑀 : 𝜎 Ξ“, π‘₯ :𝜎 ⊒ 𝑁 : 𝜏 Ξ“ ⊒ {𝜍, πœ†π‘₯ . 𝑀} : 𝜏 β†’ 𝐼𝜎 Ξ“ ⊒ let π‘₯ be {𝜍,𝑀} : letin 𝑁 𝜏 (c) New Typing Rules {𝜍, πœ†π‘₯ . 𝑀} 𝑁 =𝛽 let π‘₯ be 𝑁 in𝑀 [𝜍] πœ†π‘₯.𝑉 π‘₯ =πœ‚ 𝑉 let π‘₯ be 𝑉 in𝑀 =π‘₯ 𝑀 [𝑉 /π‘₯] 𝐸 [let π‘₯ be𝑀 in 𝑁 ] =πœ… let π‘₯ be𝑀 in 𝐸 [𝑁 ] let π‘₯ be (let 𝑦 be𝑀 in 𝑁 ) in 𝐿 =πœ’ let 𝑦 be𝑀 in let π‘₯ be 𝑁 in 𝐿 let π‘₯ be {𝜍,𝑀} in 𝑁 =cl let π‘₯ be𝑀 [𝜍] in 𝑁 (d) Axioms Figure 4.4. Call-by-Need with Closures 69 while we are evaluating 𝐹 [π‘₯] inside of the let-binding we will need to β€œjump” to the location 𝐸 to evaluate there. In an environment machine, this amounts to entering a different environment at runtime; therefore, it requires a closure as we see in the lazy abstract machine of Sestoft [48]. Thus, there are two spaces for abstract closures in the calculus: one for functions that works like that of the call-by-value closures and one for let-expressions that can be seen as the memoizing version of the call-by-name closures. Reflecting the machines as before, we see these two kinds of closures constructed in the Sestoft machine’s rules 3 and 6 (Figure 2.7). For the let-expression closure, we add a new law called cl whichβ€”like the similarly named law from call-by-nameβ€”allows us to perform the delayed substitution at any time. For the function closure, we have a new 𝛽 law that performs the delayed substitution of the function while creating a memoizable binding for the argument. Indeed, we can derive the call-by-value abstract closure law: {𝜍, πœ†π‘₯ . 𝑀} 𝑉 =𝛽 let π‘₯ be 𝑉 in𝑀 [𝜍] =π‘₯ 𝑀 [𝜍] [𝑉 /π‘₯] =subst. 𝑀 [𝜍,𝑉 /π‘₯] 4.3 Deriving Closure Conversions As an example of Theorem 4.1, we can now construct a naΓ―ve closure conversion transformation syntactically. We do this by deriving a simple rewriting rule that adds one free variable at a time. In the call-by-value with closure calculus, we would have the following rule: 𝑦 ∈ FV(πœ†π‘₯. 𝑀) βˆ’ Dom(𝜍) {𝜍, πœ†π‘₯ . 𝑀} βˆ’β†’CC {(𝜍,𝑦/𝑦), πœ†π‘₯ . 𝑀} For each application of the rule, the local environment 𝜍 grows by an identity substitution 𝑦/𝑦. If we started from an empty environment, then the entire 𝜍 after closure conversion 70 is the identity. In the case where 𝜍 already had some non-identity part within, e.g. {(πœ€, 3/π‘₯,𝑦/𝑦), πœ†π‘§. 𝑀}, the delayed substitution is preserved. We show next that the rewrite rule is derivable, where we let the environment 𝜍 be 𝑉0/𝑧0, . . . ,𝑉𝑛/𝑧𝑛 and 𝑦 be a free variable in FV(πœ†π‘₯. 𝑀) βˆ’ Dom(𝜍): {𝜍, πœ†π‘₯ . 𝑀} =subst. {𝜍, πœ†π‘₯ . 𝑀 [𝑧0/𝑧0, . . . , 𝑧𝑛/𝑧𝑛, 𝑦/𝑦, π‘₯/π‘₯]} =𝛽→ {𝜍, πœ†π‘₯ . {(𝑧0/𝑧0, . . . , 𝑧𝑛/𝑧𝑛, 𝑦/𝑦), πœ†π‘₯ . 𝑀} π‘₯} =πœ‚β€²β†’ {(𝑧0/𝑧0, . . . , 𝑧𝑛/𝑧𝑛, 𝑦/𝑦), πœ†π‘₯ . 𝑀}[𝜍] =subst. {(𝜍,𝑦/𝑦), πœ†π‘₯ . 𝑀} We say that an expression is closure converted when it is a normal form with respect to the CC-rule. Such normal forms are unique up to the reordering of the substitutions. A closure conversion procedure can be derived by applying the transformation until this normal form is reached. Definition 4.1 (NaΓ―ve Closure Conversion). NCC(𝐴) = 𝐡 iff 𝐴 βˆ’β†’βˆ—CC 𝐡 and 𝐡 is in CC-normal form. We can define similar rules and thus a closure conversion for our call-by-name and call-by-need closure calculi. 4.4 Using Abstract Closures The above closure conversion is a flat closure representation containing all of the free variables in a simple product-like data structure; this is but one approach for choosing a layout for a closure’s environment. There is a diverse collection of work on closure analysis and optimizations [39, 19, 50, 34], but they assume a global closure conversion phase. Using a language with abstract closures allows us to do these locally after the naΓ―ve transformation has been applied. Here, we focus on two of these examples. 71 4.4.1 Choosing an Environment Representation. Minamide et al. [34] combine the environments of different closures to save space when allocating a closure, at the cost of possible space leaks [50] and extended lookup times for closure variables. To do this with abstract closures, we need an easy way to combine sub-parts of environments together so they may be shared with other closures. Whereas in the closure laws above, we only substitute a flat environment of values, we now wish to represent environments with nested structures via pattern matching on finite products. Like empty closures and let-expressions, pattern matching can be considered syntactic sugar. For instance, the pattern-matching closure {(πœ€,𝑉 / ⟨π‘₯, βŸ¨π‘¦, π‘§βŸ©βŸ©), πœ†π‘€ .𝑀} desugars into the following: {(πœ€,𝑉 /𝑣), πœ†π‘€ . case 𝑣 of {⟨π‘₯, π‘£β€²βŸ© β†’ case 𝑣′ of {βŸ¨π‘¦, π‘§βŸ© β†’ 𝑀}}} Using this sugar, the environment sharing of the example from Shao andAppel [50] is a derivable equality in our language. Examining the first expression in Figure 4.5, we have already run our naΓ―ve closure conversion. The program allocates three closures named β„Ž, 𝑔, and 𝑗 , which all contain the variables 𝑀 , π‘₯ , 𝑦, and 𝑧. To save space, we may derive an equality wherein these three closures point to a single sub-environment containing those values. We πœ‚ expand the program saving the same variables in each closure, but this time we pair the variables that they have in common together. A 𝛽 reduction in the body allows us to remove the old closure structure. Finally, we 𝛽 expand to have a pointer 𝑒 to share the product; and therefore, the value of variables will not be duplicated to allocate these closures in a runtime system that passes products by reference. This is an example of taking naΓ―ve closure conversion as a starting point and transforming our code further to optimize sub-programs. So not only does𝑀 = NCC(𝑀), 72 let 𝑔 be {(πœ€, 𝑔/𝑔, 𝑣/𝑣,𝑀/𝑀, π‘₯/π‘₯,𝑦/𝑦, 𝑧/𝑧), πœ†π‘ž. 𝐴} in let β„Ž be {(πœ€, β„Ž/β„Ž,𝑒/𝑒,𝑀/𝑀, π‘₯/π‘₯,𝑦/𝑦, 𝑧/𝑧), πœ†π‘ž. 𝐡} in let 𝑗 be {(πœ€, 𝑖/𝑖,𝑀/𝑀, π‘₯/π‘₯,𝑦/𝑦, 𝑧/𝑧), πœ†π‘ž.𝐢} in 𝐷 =3πœ‚β†’ { } { (πœ€, 𝑔/𝑔, 𝑣/𝑣, βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©),let 𝑔 be inπœ†π‘ž. {(πœ€, 𝑔/𝑔, 𝑣/𝑣,𝑀/𝑀, π‘₯/π‘₯,𝑦/𝑦, 𝑧/𝑧), πœ†π‘ž. 𝐴} π‘ž } { (πœ€, β„Ž/β„Ž,𝑒/𝑒, βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©),let β„Ž be inπœ†π‘ž. {(πœ€, β„Ž/β„Ž,𝑒/𝑒,𝑀/𝑀, π‘₯/π‘₯,𝑦/𝑦, 𝑧/𝑧), πœ†π‘ž.}𝐡} π‘ž (πœ€, 𝑖/𝑖, βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), let 𝑗 be in πœ†π‘ž. {(πœ€, 𝑖/𝑖,𝑀/𝑀, π‘₯/π‘₯,𝑦/𝑦, 𝑧/𝑧), πœ†π‘ž.𝐢} π‘ž 𝐷 =3 𝛽→ let 𝑔 be {(πœ€, 𝑔/𝑔, 𝑣/𝑣, βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), πœ†π‘ž. 𝐴} in let β„Ž be {(πœ€, β„Ž/β„Ž,𝑒/𝑒, βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), πœ†π‘ž. 𝐡} in let 𝑗 be {(πœ€, 𝑖/𝑖, βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), πœ†π‘ž.𝐢} in 𝐷 =𝛽let let 𝑒 be βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ© in let 𝑔 be {(πœ€, 𝑔/𝑔, 𝑣/𝑣, 𝑒 / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), πœ†π‘ž. 𝐴} in let β„Ž be {(πœ€, β„Ž/β„Ž,𝑒/𝑒, 𝑒 / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), πœ†π‘ž. 𝐡} in let 𝑗 be {(πœ€, 𝑖/𝑖, 𝑒 / βŸ¨π‘€, π‘₯,𝑦, π‘§βŸ©), πœ†π‘ž.𝐢} in 𝐷 Figure 4.5. Example of Environment Sharing with Abstract Closures but also 𝑀 = (EnvShare β—¦ NCC) (𝑀). Moreover, this transformation preserves the CC- normal form property of NCC(𝑀). 4.4.2 Choosing Environment Passing Technique. Another optimization presented for closures is lambda-lifting [19, 39]. In essence, lambda-lifting as an optimization is meant to pass parts of a code’s environment on the call stack instead of its closure environment. It is enabled by 𝛽 expansion on the free variables of functions whose code is visible from the call site, also referred to in the literature as known functions. For instance, consider the following example where the closure bound to 𝑓 is transformed 73 and whose body𝑀 has the free variable 𝑦: let 𝑓 be {(𝜍,𝑦/𝑦), πœ†π‘₯ . 𝑀} in . . . 𝑓 3 . . . =𝛽→ . . . {(𝜍,𝑦/𝑦), πœ†π‘₯ . 𝑀} 3 . . . =𝛽→ . . . 𝑀 [𝜍,𝑦/𝑦, 3/π‘₯] . . . =𝛽→ . . . {𝜍, πœ†π‘¦, π‘₯ . 𝑀} 𝑦 3 . . . =𝛽let let 𝑓 be {𝜍, πœ†π‘¦, π‘₯ . 𝑀} in . . . 𝑓 𝑦 3 . . . Again, we start with a program that is already in CC-normal form. To avoid passing 𝑦 within the closure’s environment, which may require more allocation, the function closure has it added as an extra formal parameter and at the call site it is added as an extra argument. In the special case where the rest of the environment 𝜍 is empty, such an optimization may completely avoid allocating space for the environment part of a closure. Such a transformation only depends on being able to 𝛽 expand and havingmulti-arity functions, so many existing ILs can already do this. The advantage of having closures in our IL is that we may encode both environments sharing and lambda-lifting directly in the syntax and have the two optimizations interact with one another. Indeed, the final program here could have been specified incrementally, by first applying the naΓ―ve closure conversion followed by environment sharing and lambda-lifting. Additionally, transformations unrelated to closures will need to respect them as closures, in contrast to closure conversions that represent functions as normal products. 74 CHAPTER V CBPVS: A COMMON INTERMEDIATE LANGUAGE This chapter contains published and unpublished co-authored material. It contains revisions of the work Closure Conversion in Little Pieces [53] co- authored with Paul Downen and Zena M. Ariola. Zachary J. Sullivan is the primary author under the guidance of Paul Downen and Zena M. Ariola. We have seen how closures arise from implementing the πœ†-calculus on modern machines and we presented a new approach to reasoning about closures as part of the calculus. However, we presented only a sketch of how it may be done for different evaluation strategies. Formalizing the relationship between abstract closures and the abstract machine’s on which they run is a large task for just one language as we will see in the coming chapters. Thus, instead of doing the work three times for call-by- value, call-by-name, and call-by-need, we propose a single intermediate language that we formalize. We base our new intermediate language on Levy’s call-by-push-value (CBPV) [27], which was originally motivated by a similar duplication of work in the denotational semantics for the call-by-value and call-by-name evaluation strategies. Unfortunately, CBPV is not equipped to handle call-by-need. Thus, we first need to describe how to extend the language to include sharing in a manner that preserves all of the equational theories of call-by-name, call-by-value, and call-by-need. 5.1 CBPV CBPV (Figure 5.1) achieves its strong equational theoryβ€”thereby making a suitable target for call-by-name and call-by-valueβ€”by separating the objects that have different 𝛽 and πœ‚ laws. There is a syntactic distinction between expressions that are, which we call values and will write in green, and expressions that do, i.e. computations, which we 75 𝜏, 𝜎 ∈ Type ::= 𝜏 | 𝜏 𝜏, 𝜎 ∈ Value Type ::= 𝐡 | 𝜏 βŠ— 𝜎 | π‘ˆ 𝜏 𝜏, 𝜎 ∈ Computation Type ::= 𝜏 & 𝜎 | 𝜏 β†’ 𝜎 | 𝐹 𝜏 𝐴, 𝐡,𝐢 ∈ Expression ::= 𝑉 | 𝑀 𝑉,π‘Š ∈ Value ::= b | π‘₯ | βŸ¨π‘‰ ,π‘Š ⟩ | {force β†’ 𝑀} 𝑀, 𝑁 ∈ Computation ::= case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} | {fst β†’ 𝑀 ; snd β†’ 𝑁 } | 𝑀.fst | 𝑀.snd | πœ†π‘₯ .𝑀 | 𝑀 𝑉 | ret 𝑉 | 𝑀 to π‘₯ in 𝑁 | 𝑉.force Figure 5.1. Syntax π‘₯ :𝜏 ∈ Ξ“ var Ξ“, π‘₯ :𝜏 ⊒ 𝑀 : 𝜎 β†’ Ξ“ ⊒ 𝑀 : 𝜎 β†’ 𝜏 Ξ“ ⊒ 𝑉 : 𝜎𝐼 →𝐸 Ξ“ ⊒ b : 𝐡𝐡 Ξ“ ⊒ π‘₯ : 𝜏 Ξ“ ⊒ πœ†π‘₯. 𝑀 : 𝜏 β†’ 𝜎 Ξ“ ⊒ 𝑀 𝑉 : 𝜏 Ξ“ ⊒ 𝑀 : 𝜏 Ξ“ ⊒ 𝑁 : 𝜌 Ξ“ ⊒ 𝑀 : 𝜏 & 𝜌 Ξ“ ⊒ 𝑀 : 𝜏 & 𝜌 Ξ“ ⊒ {fst β†’ 𝑀 ; snd β†’ 𝑁 } : &𝐼𝜏 & 𝜌 Ξ“ ⊒ &𝐸1 &𝑀.fst : 𝜏 Ξ“ ⊒ 𝑀.snd : 𝜌 𝐸2 Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ βŠ’π‘Š : 𝜎 Ξ“ ⊒ 𝑉 : 𝜎 βŠ— 𝜌 Ξ“, π‘₯ :𝜎,𝑦:𝜌 ⊒ 𝑀 : 𝜏 Ξ“ ⊒ ⟨ βŠ—πΌ βŠ—πΈπ‘‰ ,π‘Š ⟩ : 𝜏 βŠ— 𝜎 Ξ“ ⊒ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} : 𝜏 Ξ“ ⊒ 𝑀 : 𝜏 Ξ“ ⊒ 𝑉 : π‘ˆ 𝜏 Ξ“ ⊒ { π‘ˆ π‘ˆforce β†’ 𝑀} : 𝐼 πΈπ‘ˆ 𝜏 Ξ“ ⊒ 𝑉.force : 𝜏 Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ ⊒ 𝑀 : 𝐹 𝜎 Ξ“, π‘₯ :𝜎 ⊒ 𝑁 : 𝜏 Ξ“ ⊒ 𝐹 𝐹ret 𝑉 : 𝐹 𝜏 𝐼 Ξ“ ⊒ 𝑀 to π‘₯ in 𝑁 : 𝜏 𝐸 Figure 5.2. Typing Rules write in orange. Indeed, there are two different product types: one is a computation, the & type, which will be the target of a lazy style of product and the other, the βŠ— type, is a value for the strict products. The former is defined by the projections .fst and .snd, whereas the latter is constructed as pair that is eliminated by a case expression; the products that we have used thus far are the latter. Note that we depart from the syntax of Levy for expressions containing computations that wait for method calls, e.g. thunk 𝑀 is written as {force β†’ 𝑀}, to emphasize how they behave like objects. This is because we will introduce more expressions of a similar kind later in this chapter. 76 By the rules of the syntax, arguments to function calls and the interrogated expression of the case expression are already values and no reduction will be needed; thisβ€”in contrast with call-by-value where wemust evaluate expressions to get to a valueβ€” conveys the idea that values are, and that they can be predicted based on their type alone. Moreover, as we see from the syntax and typing rules Figure 5.2, variables can only range over value types, and so substitutions only occur with values. On the other hand, computations are the only expressions that are allowed to do work to find an answer, so a computation that returns values of type 𝜏 will have type 𝐹 𝜏 . For example, a computation returning ⟨4, 2⟩ will be written ret ⟨4, 2⟩ in a manner reminiscent of returning from a statement in C. A to-expression, which consumes computations of type 𝐹 𝜏 , may need to evaluate its interrogated computation before being able to match on the pattern and extract a value to bind it to π‘₯ . Despite only values being substitutable, the language is still able to pass unevaluated code because we may delay a computation as a value by shifting it. The object-like shift for delaying a computation as a value, written as {force β†’ 𝑀}, is eliminated by𝑉.force. Conversely, the ret- and to-expressions shift from values into computations. We will see later that these shifts play a key role in both closure conversion and sharing. For now, note that an important difference between data-like and object-like shifts is that the former creates a binding upon elimination whereas the latter does not. 5.1.1 Equational Theory. Examining the equational theory in Figure 5.3, we see that it has much of the same 𝛽 laws as call-by-value. However, the requirement that the argument of a function and the subject of a case expression is a value becomes a syntactic restriction, whereas in a call-by-value calculus the requirement is imposed at runtime. Examining the πœ‚ laws, we see that CBPV has the πœ‚ law for call-by-name functions in 77 (πœ†π‘₯ .𝑀) 𝑉 =𝛽→ 𝑀 [𝑉 /π‘₯] {fst β†’ 𝑀 ; snd β†’ 𝑁 }.fst =𝛽&1 𝑀 {fst β†’ 𝑀 ; snd β†’ 𝑁 }.snd =𝛽&2 𝑁 case βŸ¨π‘‰ ,π‘Š ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} =π›½βŠ— 𝑀 [𝑉 /π‘₯,π‘Š /𝑦] {force β†’ 𝑀}.force =𝛽 π‘€π‘ˆ (ret 𝑉 ) to π‘₯ in𝑀 =𝛽 𝑀 [𝑉 /π‘₯]𝐹 πœ†π‘₯ .𝑀 π‘₯ =πœ‚β†’ 𝑀 {fst β†’ 𝑀.fst; snd β†’ 𝑀.snd} =πœ‚& 𝑀 case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧]} =πœ‚βŠ— 𝑀 [𝑉 /𝑧] {force β†’ 𝑉.force} =πœ‚ π‘‰π‘ˆ 𝑀 to π‘₯ in 𝐸 [ret π‘₯] =πœ‚ 𝐸 [𝑀]𝐹 𝐸 ∈ Evaluation Context ::= β–‘ | 𝐸 𝑉 | 𝐸.fst | 𝐸.snd | 𝐸 to π‘₯ in𝑀 Figure 5.3. CBPV Axioms contrast to the restrictions that we see in the call-by-value and call-by-need.1 Additionally, there are laws for the two shift types. The 𝛽 andπœ‚ laws for the value shiftπ‘ˆ 𝜏 are analogous to those of the & type. For 𝐹 𝜏 , the 𝛽 law is analogous to the pattern matching in a case expression, but its πœ‚ law is more restricted. That is, it can only be applied when the reconstructed data appears in an evaluation context; note that this is a slightly more general law than originally given by Levy. 5.1.2 Subsuming Call-by-Value and Call-by-Name. The compilation to CBPV for use as an intermediate language is given in Figure 5.4. Both translations are composed of sub-translations for types, type environments, and expressions. For call-by- name, arguments are compiled into shifts which delay evaluation until they are forced in the variable case. Because of the delayed evaluation of all function arguments, we see that the type environment translation is π‘ˆ of the translated argument type. In call- by-value, we must compile functions, which are treated as values in the source, into delayed computations since functions are computations in CBPV. This way, a function 1CBPV’s strong πœ‚ laws for computation types and value types follow closely the observations about call-by-name and call-by-value types in work on the duality of programming languages [55, 15]. 78 β†’ = β†’ π‘₯ = π‘₯ .force𝜏 𝜌 π‘ˆ 𝜏 𝜌 𝑏 = ret 𝑏 𝐡 = 𝐹 𝐡 Γ— & πœ†π‘₯ .𝑀 = πœ†π‘₯. π‘€πœ 𝜎 = 𝜏 𝜎 𝑀 𝑁 = 𝑀 {force β†’ 𝑁 } πœ€ = πœ€ βŸ¨π‘€, 𝑁 ⟩ = {fst β†’ 𝑀 ; snd β†’ 𝑁 } Ξ“, π‘₯ :𝜏 = Ξ“, π‘₯ :π‘ˆ 𝜏 fst𝑀 = 𝑀.fst snd𝑀 = 𝑀.snd (a) Call-by-Name (CBN) β†’ π‘₯ = ret π‘₯𝜏 𝜎 = π‘ˆ (𝜏 β†’ 𝐹 𝜎) = 𝑏 = ret 𝑏𝑏 𝐡 Γ— = βŠ— πœ†π‘₯ .𝑀 = ret {force β†’ πœ†π‘₯ .𝑀}𝜏 𝜎 𝜏 𝜎 𝑀 𝑁 = 𝑀 toπ‘₯ in 𝑁 to𝑦 in π‘₯ .force 𝑦 πœ€ = πœ€ βŸ¨π‘€, 𝑁 ⟩ = 𝑀 toπ‘₯ in 𝑁 to𝑦 in ret ⟨π‘₯,π‘¦βŸ© Ξ“, π‘₯ :𝜏 = Ξ“, π‘₯ :𝜏 case𝑀 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑁 } = 𝑀 to 𝑧 in case 𝑧 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑁 } (b) Call-by-Value (CBV) Figure 5.4. Compiling CBN and CBV to CBPV in the source is turned into 𝐹 of the translated function value. Both translations also include a notion of product as well, the call-by-name version of a product is treated as the computation product type & whereas the call-by-value version is treated as the value product βŠ—. These transformations preserve not only types, but also the equational theories of the source languages. The following theorems are found in Levy [27] and show that CBPV is suitable as an intermediate language. Theorem 5.1 (CBN Compilation Preserves Equations). If Ξ“ ⊒ 𝑀 =CBN 𝑁 : 𝜏 , then Ξ“ ⊒ 𝑀 =CBPV 𝑁 : 𝜏 using the call-by-name translation. Theorem 5.2 (CBV Compilation Preserves Equations). If Ξ“ ⊒ 𝑀 =CBV 𝑁 : 𝜏 , then Ξ“ ⊒ 𝑀 =CBPV 𝑁 : 𝐹 𝜏 using the call-by-value translation. 79 𝜏, 𝜎 ∈ Value Type ::= 𝐡 | 𝜏 βŠ— 𝜎 | π‘ˆ 𝜏 | ?Μƒ? 𝜏 𝜏, 𝜎 ∈ Shared Type ::= π‘ˆ 𝜏 | 𝐹 𝜏 𝜏, 𝜎 ∈ Comp. Type ::= 𝜏 & 𝜎 | 𝜏 β†’ 𝜎 | 𝐹 𝜏 | 𝐹 𝜏 𝑉 ,π‘Š ∈ Value ::= b | π‘₯ | βŸ¨π‘‰ ,π‘Š ⟩ | {force β†’ 𝑀} | box 𝑉 𝑉 ,π‘Š ∈ Shared Value ::= π‘Ž | val 𝑉 | {enter β†’ 𝑀} 𝑅, 𝑆 ∈ Shared Comp. ::= 𝑉 | 𝑀.eval | 𝐡 [𝑅] 𝑀, 𝑁 ∈ Comp. ::= {fst β†’ 𝑀 ; snd β†’ 𝑁 } | 𝑀.fst | 𝑀.snd | πœ†π‘₯.𝑀 | 𝑀𝑉 | 𝑉.force | ret 𝑉 | 𝐡 [𝑀] | 𝑅.enter | {eval β†’ 𝑅} 𝐡 ∈ Block Ctxt . ::= 𝑃 toπ‘₯ inβ–‘ | 𝑅 memoπ‘Ž inβ–‘ | case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ β–‘} | case 𝑉 of {box π‘Ž β†’ β–‘} 𝑃,𝑄 ∈ Comp. Expr . ::= 𝑅 | 𝑀 𝜍 ∈ Env. ::= πœ€ | 𝜍,𝑉 /π‘₯ | 𝜍,𝑉 /π‘Ž Figure 5.5. CBPVS: CBPV with Sharing 5.2 Adding Sharing To serve as a suitable intermediate language for a call-by-need source, we need to support sharing within CBPV itself. Our new language, which we refer to as CBPVS for short (β€œS” for sharing), is shown in Figure 5.5. The first place to start when extending our intermediate language with sharing is to, like in call-by-need, add a binding construct that gives names to the computation that we wish to share and only evaluates it when needed. Such a binding may look like 𝑀 memo π‘Ž in 𝑁 . Of course, wewould like to save computations that return values (those of type 𝐹 𝜏): imagine having𝑀 be the program 1 + 2 to π‘₯ in ret π‘₯ . Tomaximize sharing, we also need to be able to memoize the evaluation of intermediate computations of all types. For instance, we would only want to perform the 𝛽 reduction on the argument 42 once, where 𝑀 is (πœ†π‘₯.πœ†π‘¦. ret π‘₯) 42, if we were to bind it to a variable and apply it in multiple parts of the program. In general, the point at which we may substitute without work duplication is when an introduction form for a computation type is reached, i.e. ret 𝑉 , 80 {fst β†’ 𝑀 ; snd β†’ 𝑁 }, and πœ†π‘₯. 𝑀 . We could merely declare these forms β€œcomputational values” that are substituted without duplicating work. However, we would then have to sacrifice our strong πœ‚ law for CBPV function types for the weaker one found in call-by- need, which would mean that the compilation of the other evaluation strategies would no longer be equivalence preserving. Instead, we package computations that will be shared under a third syntactic category which stands apart from values and computations. This way, computations can keep their axioms from CBPV. The new syntactic category that we introduce, which we write in purple, is for shared computations and its substitutable forms are the subset of shared values. Shared computations will be 𝛽 reducible similar to computations, but with the addition of variables that refer only to them. There is an overlap of the block structures of the languagewhere both computations and shared computations can patternmatch on values, sequence computations, and bind shared computations. This is captured in the idea of block contexts, which contain one of these structures with a hole at the bottom. Where computations and shared computations overlap, we describe them as computable expressions and write them in the color black. Since we will not be using computation introduction forms for sharing, like in πœ†π‘₯. ret 42, we need a shift from computations to shared values, which we write {enter β†’ πœ†π‘₯. ret 42} and give the type π‘ˆ (𝜏 β†’ 𝐹 N). Similarly, we want a shift from values, which we write val 42 and give the type 𝐹 N. The introduction forms of these shifts are thememoizable sub-syntax of shared computations: shared values. The opposite direction is true as well. We will want to embed shared computations within a data structure; this we do with the shift box 𝑉 with the type ?Μƒ? 𝜏 . And we want shared computations to be capable of being embedded within the normal computations to make use of computation types within a program: {eval β†’ 𝑅} with the type 𝐹 𝜏 . Indeed, 81 computational types like functions and & can only contain shared sub-computations through such a shift; for example, {fst β†’ {eval β†’ 𝑅}; fst β†’ {eval β†’ 𝑆}}. In summary, the new shifts into shared expressions, π‘ˆ 𝜏 and 𝐹 𝜏 , are used to capture the CBPV values and computations that a shared expression reduced to, whereas that new shifts from shared expressions ?Μƒ? 𝜏 and 𝐹 𝜏 are there so thatwe canmake use of the existing value and computation types when building shared computations. 5.2.1 Typing Rules. The typing rules for CBPVS are given in Figure 5.6; for the subset that is CBPV, the rule remain the same except that the typing context Ξ“ is now composed of both value and shared variables. For sharing, we must break the convention that CBPV only substitutes values; note that Levy himself breaks the convention with complex values [27] and other work adding memoization to CBPV does as well [32]. The type system reveals the similarities between the shared shifts and the ones that already existed in CBPV. Like the sequencing to-expression consuming values shifted to computations, the shared to-expression will bind a shifted value of type 𝐹 𝜏 in another computation or shared computation. 5.2.2 Equational Theory. The axioms for CBPVS are given in Figure 5.7. The rules are divided into three sets wherein the first two are the usual 𝛽 and πœ‚ laws and the last includes rules for lifting and reassociating shared binders as in call-by-need. In general, we see that the 𝛽 and πœ‚ laws for shared computations and values operate in a similar manner to the otherπ‘ˆ and 𝐹 types already in CBPV. Concerningπœ‚, there is a notable difference between the laws for the ?Μƒ? types and those for 𝐹 and 𝐹 even though they all reconstruct a data-like expression; that is, the former does not have a restriction that the reconstructed data appears within an evaluation context. This lack of a restriction in the axiom, despite containing a shared expression, is possible because of the syntactic restriction to shared values for box 𝑉 . Without the syntactic 82 π‘₯ :𝜏 ∈ Ξ“ Ξ“ ⊒ b : 𝐡𝐡 Ξ“ ⊒ : varπ‘₯ 𝜏 Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ βŠ’π‘Š : 𝜎 Ξ“ ⊒ 𝑉 : 𝜎 βŠ— 𝜌 Ξ“, π‘₯ :𝜎,𝑦:𝜌 ⊒ 𝑃 : 𝜏 Ξ“ ⊒ βŸ¨π‘‰ ,π‘Š ⟩ : 𝜏 βŠ— βŠ—πΌπœŽ Ξ“ ⊒ {⟨ ⟩ β†’ } βŠ—: 𝐸case 𝑉 of π‘₯,𝑦 𝑃 𝜏 Ξ“ ⊒ 𝑀 : 𝜏 Ξ“ ⊒ 𝑅 : π‘ˆ 𝜏 ⊒ { π‘ˆ π‘ˆΞ“ force β†’ 𝐼𝑀} : π‘ˆ 𝜏 Ξ“ ⊒ 𝑅.force : 𝐸𝜏 Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ ⊒ 𝑀 : 𝐹 𝜎 Ξ“, π‘₯ :𝜎 ⊒ 𝑃 : 𝜏 𝐹 𝐹 Ξ“ ⊒ ret 𝑉 : 𝐹 𝜏 𝐼 Ξ“ ⊒ 𝑀 to π‘₯ in 𝑃 : 𝜏 𝐸 Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ ⊒ 𝑉 : ?Μƒ? 𝜎 Ξ“, π‘Ž:𝜎 ⊒ 𝑃 : 𝜏 ?Μƒ? Ξ“ ⊒ box : 𝐼 Ξ“ ⊒ case of {box β†’ } : ?Μƒ?𝑉 ?Μƒ? 𝜏 𝑉 π‘Ž 𝑃 𝜏 𝐸 π‘Ž:𝜏 ∈ Ξ“ ⊒ : svar Ξ“ ⊒ 𝑅 : 𝜎 Ξ“, π‘Ž:𝜎 ⊒ 𝑃 : 𝜏 Ξ“ Ξ“ ⊒ memo in : Hπ‘Ž 𝜏 𝑅 π‘Ž 𝑃 𝜏 Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ ⊒ 𝑅 : 𝐹 𝜎 Ξ“, π‘₯ :𝜎 ⊒ 𝑃 : 𝜏 𝐹𝐼 Ξ“ ⊒ val 𝑉 : 𝐹 𝜏 Ξ“ ⊒ 𝑅 to π‘₯ in 𝑃 : 𝐹𝜏 𝐸 Ξ“ ⊒ 𝑀 : 𝜏 π‘ˆ Ξ“ ⊒ 𝑅 : π‘ˆ 𝜏 Ξ“ ⊒ {enter β†’ 𝑀} : πΌπ‘ˆ 𝜏 Ξ“ ⊒ 𝑅.enter : π‘ˆπœ 𝐸 Ξ“ ⊒ 𝑀 : 𝜏 Ξ“ ⊒ 𝑁 : 𝜎 & Ξ“ ⊒ 𝑀 : 𝜏 & 𝜎 Ξ“ ⊒ 𝑀 : 𝜏 & 𝜎 Ξ“ ⊒ {fst β†’ 𝑀 ; snd β†’ } : & 𝐼𝑁 𝜏 𝜎 Ξ“ ⊒ & &𝑀.fst : 𝐸1𝜏 Ξ“ ⊒ 𝑀.snd : 𝜎 𝐸2 Ξ“, π‘₯ :𝜏 ⊒ 𝑀 : 𝜎 β†’ Ξ“ ⊒ 𝑀 : 𝜏 β†’ 𝜎 Ξ“ ⊒ 𝑉 : 𝜏 ⊒ 𝐼 →𝐸Γ πœ†π‘₯ .𝑀 : 𝜏 β†’ 𝜎 Ξ“ ⊒ 𝑀 𝑉 : 𝜎 Ξ“ ⊒ 𝑅 : 𝜏 𝐹 Ξ“ ⊒ 𝑀 : 𝐹 𝜏 Ξ“ ⊒ { 𝐼eval β†’ 𝑅} : 𝐹 𝜏 Ξ“ ⊒ 𝑀.eval : 𝐹𝜏 𝐸 Figure 5.6. CBPVS Typing Rules 83 (πœ†π‘₯ .𝑀) 𝑉 =β†’ 𝑀 [𝑉 /π‘₯] {fst β†’ 𝑀 ; snd β†’ 𝑁 }.fst =&1 𝑀 {fst β†’ 𝑀 ; snd β†’ 𝑁 }.snd =&2 𝑁 case βŸ¨π‘‰ ,π‘Š ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝑃} =βŠ— 𝑃 [𝑉 /π‘₯,π‘Š /𝑦] {force β†’ 𝑀}.force =π‘ˆ 𝑀 (ret 𝑉 ) to π‘₯ in 𝑃 =𝐹 𝑃 [𝑉 /π‘₯] case (box 𝑉 ) of {box π‘Ž β†’ 𝑃} =?Μƒ? 𝑃 [𝑉 /π‘Ž] (val 𝑉 ) to π‘₯ in 𝑃 =𝐹 𝑃 [𝑉 /π‘₯] {enter β†’ 𝑀}.enter =π‘ˆ 𝑀 {eval β†’ 𝑅}.eval =𝐹 𝑅 (a) 𝛽-laws πœ†π‘₯. 𝑀 π‘₯ =β†’ 𝑀 {fst β†’ 𝑀.fst; snd β†’ 𝑀.snd} =& 𝑀 case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑃 [⟨π‘₯,π‘¦βŸ©/𝑧]} =βŠ— 𝑃 [𝑉 /𝑧] {force β†’ 𝑉.force} =π‘ˆ 𝑉 𝑀 to π‘₯ in 𝐸 [ret π‘₯] =𝐹 𝐸 [𝑀] case 𝑉 of {box π‘Ž β†’ 𝑃 [box π‘Ž/π‘₯]} =?Μƒ? 𝑃 [𝑉 /π‘₯] 𝑅 to π‘₯ in 𝐸 [val π‘₯] =𝐹 𝐸 [𝑅] {enter β†’ 𝑉 .enter} =π‘ˆ 𝑉 {eval β†’ 𝑀.eval} =𝐹 𝑀 (b) πœ‚-laws 𝐸 [𝑅 memo π‘Ž in 𝑃] =πœ… 𝑅 memo π‘Ž in 𝐸 [𝑃] (𝑅 memo 𝑏 in 𝑆) memo π‘Ž in 𝑃 =πœ’ 𝑅 memo 𝑏 in (𝑆 memo π‘Ž in 𝑃) 𝑉 memo π‘Ž in 𝐢 [π‘Ž] =deref 𝑉 memo π‘Ž in 𝐢 [𝑉 ] 𝑅 memo π‘Ž in 𝑃 =GC 𝑃 𝑅 =name 𝑅 memo π‘Ž in π‘Ž (c) Other laws where 𝐸, 𝐹 ::= β–‘ | 𝐸 𝑉 | 𝐸.fst | 𝐸.snd | 𝐸 to π‘₯ in 𝑃 | 𝐸.enter | 𝐸.eval | 𝑅 memo π‘Ž in 𝐸 | 𝐸 memo π‘Ž in 𝐹 [π‘Ž] Figure 5.7. CBPVS Axioms 84 restriction, a program like the following will duplicate work: case ⟨42, box π‘…βŸ© of {⟨π‘₯,π‘¦βŸ© β†’ . . . 𝑦 . . . 𝑦 . . . } βˆ’β†’π›½ . . . box 𝑅 . . . box 𝑅 . . . This duplication will happen whenever a box-shift is nested inside of another value. Note that we can still describe a program like the one above where 𝑅 is shared, but this time we will need to bind the non-duplicated part to a memo-expression first: 𝑅 memo π‘Ž in case ⟨42, box π‘ŽβŸ© of {⟨π‘₯,π‘¦βŸ© β†’ . . . π‘₯ . . . π‘₯ . . . } βˆ’β†’π›½ 𝑅 memo π‘Ž in . . . box π‘Ž . . . box π‘Ž . . . Now the shared computation 𝑅 is shared among the various places where π‘Ž may occur. Whereas πœ‚ for ?Μƒ? is flexible because of a syntactic restriction, the law forπ‘ˆ types has a value restriction. This is for the same reason as the call-by-need value restriction for function type πœ‚: we must preserve that the expression is a shared value before and after an πœ‚ reduction. In CBPV, we were able to derive the sequencing laws of to-expressions with the generalized πœ‚ law for 𝐹 ; we may do this for 𝐹 as well. This is not true for lifting shared memoization bindings out of an evaluation context since the expression does not force its bound expression and that expression may be of any shared type. Therefore, the equational theory has a πœ… law specifically for this as in call-by-need. 5.3 Subsuming Call-by-Need Figure 5.8 shows how a call-by-need source program will be compiled into our intermediate language. The transformation turns both types and expressions into their shared version in CBPVS. Those familiar with the subsumption of call-by-name and call- by-value into CBPV may see the transformation as merging the two: functions must 85 π‘₯ = π‘₯ b = val b πœ†π‘₯. 𝑀 = {enter β†’ πœ†π‘¦. case 𝑦 of 𝜏 β†’ 𝜎 = π‘ˆ (?Μƒ? 𝜏 β†’ 𝐹 𝜎) {box π‘₯ β†’ {eval β†’ 𝑀}}} N = 𝐹 N 𝑀 𝑁 = 𝑀 memo π‘Ž in 𝑁 memo 𝑏 in 𝜏 Γ— 𝜎 = 𝐹 (?Μƒ? 𝜏 βŠ— ?Μƒ? 𝜎) (π‘Ž.enter (box 𝑏)) .eval πœ€ = πœ€ let π‘₯ be𝑀 in 𝑁 = 𝑀 memo π‘₯ in 𝑁 Ξ“, π‘₯ :𝜏 = Ξ“, π‘₯ :𝜏 βŸ¨π‘€, 𝑁 ⟩ = 𝑀 memo π‘Ž in 𝑁 memo 𝑏 in val ⟨box π‘Ž, box π‘βŸ© case𝑀 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑁 } = 𝑀 to 𝑧 in case 𝑧 of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝑁 } Figure 5.8. Compiling CBNeed to CBPVS delay their argument type with ?Μƒ? instead of π‘ˆ , return their result with 𝐹 instead of 𝐹 , and the whole computation must be delayed with π‘ˆ instead of π‘ˆ . For expressions, the transformation has striking similarities to the call-by-value compilation. First, functions are placed in an enter-expression and expect their argument to come in a box-value; this means that arguments of a function must be given a shared binding before entering the function. Second, in an application, we must give names to the parts whose evaluation we want to share; in the call-by-value transformation, it is the parts that we simply want to evaluate. Though it is only the argument part that we wish to share, we must also give a name to the function part in order to preserve the ordering of memoized binders from the source. Similarly, we must give memoized binders to the sub-components of products. In so doing, we have preserved the Haskell-like product property that the sub-components will share their evaluation. For brevity, the compilation from call-by-need makes use of nested pattern matching in the case expression transform, i.e. in unpacking a box-value inside of a product. Like with CBPV, nested pattern matching is equivalent to doing a pattern match one at a time in CBPVS. 86 (πœ†π‘₯ .𝑀) 𝑁=𝛽→ let π‘₯ be 𝑁 in𝑀 case βŸ¨π‘€, 𝑁 ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿}=π›½βŠ— let π‘₯ be𝑀 in let 𝑦 be 𝑁 in 𝐿 πœ†π‘₯.𝑉 π‘₯=πœ‚β†’ 𝑉 case𝑀 of {⟨π‘₯,π‘¦βŸ© β†’ 𝐸 [⟨π‘₯,π‘¦βŸ©]}=πœ‚βŠ— 𝐸 [𝑀] (let π‘₯ be𝑀 in 𝑁 ) 𝐿=lift1 let π‘₯ be𝑀 in (𝑁 𝐿) 𝑀 (let π‘₯ be 𝑁 in 𝐿)=lift2 let π‘₯ be 𝑁 in (𝑀 𝐿) πœ†π‘₯. let 𝑦 be 𝑉 in𝑀=lift3 let 𝑦 be 𝑉 in πœ†π‘₯. 𝑀 case (let π‘₯ be𝑀 in 𝑁 ) of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿}=lift4 let π‘₯ be𝑀 in (case 𝑁 of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿}) let π‘₯ be (let 𝑦 be𝑀 in 𝑁 ) in 𝐿=mergelet 𝑦 be𝑀 in let π‘₯ be 𝑁 in 𝐿 let π‘₯ be 𝑉 in 𝐢 [π‘₯]=deref let π‘₯ be 𝑉 in 𝐢 [𝑉 ] let π‘₯ be𝑀 in 𝑁=GC 𝑁 𝑀=name let π‘₯ be𝑀 in π‘₯ where 𝑉 ,π‘Š ∈ Value ::= π‘₯ | b | πœ†π‘₯. 𝑀 | βŸ¨π‘‰ ,π‘Š ⟩ 𝐸, 𝐹 ∈ EvalCxt ::= β–‘ | 𝐸 𝑁 | case 𝐸 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑁 } | let π‘₯ be𝑀 in 𝐸 | let π‘₯ be 𝐸 in 𝐹 [π‘₯] Figure 5.9. More Flexible Call-by-Need Axioms Lemma 5.1 (Compilation Commutes with Substitution). Syntactically, we have Ξ“ ⊒ 𝑀 [𝑉 /π‘₯] = 𝑀 [𝑉 /π‘₯] : 𝜏 . Proof. Follows by the definitions of substitution for the two languages and induction on the structure of the expression. β–‘ Lemma 5.2 (CBNeed Compilation Preserves Values). For some source value 𝑉 , there is some target valueπ‘Š such that CBPVS ⊒ 𝑉 =π‘Š : 𝜏 . Proof. By the induction on the syntax of source values. The cases for π‘₯ , b, and πœ†π‘₯. 𝑀 hold immediately with reflexivity. The case for βŸ¨π‘‰ ,π‘Š ⟩ follows by its inductive hypotheses followed by deref reductions. β–‘ Note that we prove our subsumption theorem with respect to the call-by-need calculus in Figure 5.9. It presents a more flexible call-by-need than that of Figure 2.8, 87 which includes more lifting rules from Ariola and Felleisen [7] and the garbage collection rules fromMaraist et al. [28]. Wewanted CBPVS to preserve the most laws possible. Since the laws of the original CBPV part of CBPVS were left unchanged, the call-by-name and call-by-value compilations to CBPV still preserve equations for CBPVS. Theorem 5.3 (CBNeed Compilation Preserves Equations). If Ξ“ ⊒ 𝑀 =CBNeed 𝑁 : 𝜏 , then Ξ“ ⊒ 𝑀 =CBPVS 𝑁 : Ξ“. Proof. By induction on the equality derivation. The cases for reflexivity, symmetry, transitivity, and compatibility follow by their inductive hypotheses and the respective rule for CBPVS. Thus, we need only show it holds for the axioms; in each case, we show that the translation of left side of the equation is equal to the translation of the right side: Case 𝛽→: (πœ†π‘₯ .𝑀) 𝑁 = let π‘₯ be 𝑁 in𝑀 (πœ†π‘₯ .𝑀) 𝑁 =defn. {enter β†’ πœ†π‘¦. case 𝑦 of {box π‘₯ β†’ {eval β†’ 𝑀}}} memo π‘Ž in =deref=GC 𝑁 memo 𝑏 in (π‘Ž.enter (box 𝑏)) .eval 𝑁 memo 𝑏 in =𝛽?̌? ({enterβ†’ πœ†π‘¦. case𝑦 of {box π‘₯ β†’ {eval β†’ 𝑀}}}.enter (box 𝑏)) .eval 𝑁 memo 𝑏 in (πœ†π‘¦. case 𝑦 of {box π‘₯ β†’ {eval β†’ 𝑀}} (box 𝑏)) .eval =𝛽→ 𝑁 memo 𝑏 in (case (box 𝑏) of {box π‘₯ β†’ {eval β†’ 𝑀}}).eval =𝛼 𝑁 memo π‘₯ in (case (box π‘₯) of {box π‘₯ β†’ {eval β†’ 𝑀}}).eval =𝛽 ?Μƒ? 𝑁 memo π‘₯ in {eval β†’ 𝑀}.eval =𝛽 𝐹 𝑁 memo π‘₯ in𝑀 =defn. let π‘₯ be 𝑁 in𝑀 88 Case π›½βŠ—: case βŸ¨π‘€, 𝑁 ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿} = let π‘₯ be𝑀 in let 𝑦 be 𝑁 in 𝐿 case βŸ¨π‘€, 𝑁 ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿} =defn. 𝑀 memo π‘Ž in 𝑁 memo 𝑏 in val ⟨box π‘Ž, box π‘βŸ© =πœ… to 𝑦 in case 𝑦 of {⟨box π‘₯, . . . , box π‘₯⟩ β†’ 𝐿} 𝑀 memo π‘Ž in 𝑁 memo 𝑏 in =𝛽 𝐹 (val ⟨box π‘Ž, box π‘βŸ© to 𝑦 in case 𝑦 of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐿}) 𝑀 memo π‘Ž in 𝑁 memo 𝑏 in =𝛼 case ⟨box π‘Ž, box π‘βŸ© of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐿} 𝑀 memo π‘₯ in 𝑁 memo 𝑦 in =π›½βŠ—=𝛽?̌? case ⟨box π‘₯, box π‘¦βŸ© of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐿} 𝑀 memo π‘₯ in 𝑁 memo 𝑦 in 𝐿 =defn. let π‘₯ be𝑀 in let 𝑦 be 𝑁 in 𝐿 Case πœ‚β†’: πœ†π‘₯.𝑉 π‘₯ = 𝑉 89  ο£± ο£± πœ†π‘₯ .𝑉π‘₯ =defn.   enterβ†’ πœ†π‘¦. case𝑦 of   𝑉 memo π‘Ž in π‘₯ memo 𝑏 in  box π‘₯β†’ evalβ†’ =deref=GC   (    π‘Ž.enter (box 𝑏)) .eval       π‘₯ memo 𝑏 inο£³enterβ†’ πœ†π‘¦. case𝑦 of ο£³box π‘₯β†’ ο£³evalβ†’ ( ( ))   𝑉 .enter box 𝑏 .eval   =deref=GC {enterβ†’ πœ†π‘¦. case 𝑦 of {box π‘₯ β†’ {eval β†’ (𝑉 .enter (box π‘₯)) .eval}}} =πœ‚ 𝐹 {enter β†’ πœ†π‘¦. case 𝑦 of {box π‘₯ β†’ 𝑉 .enter (box π‘₯)}} =πœ‚ ?Μƒ? {enter β†’ πœ†π‘¦.𝑉 .enter 𝑦} =πœ‚β†’ {enter β†’ 𝑉 .enter} =πœ‚?̌? 𝑉 Case πœ‚βŠ—: case𝑀 of {⟨π‘₯,π‘¦βŸ© β†’ 𝐸 [⟨π‘₯,π‘¦βŸ©]} = 𝐸 [𝑀] case𝑀 of {⟨π‘₯,π‘¦βŸ© β†’ 𝐸 [⟨π‘₯,π‘¦βŸ©]} =defn. 𝑀 to 𝑧 in case 𝑧 of (= = )2deref GC {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐸 [π‘₯ memo π‘Ž in 𝑦 memo 𝑏 in val ⟨box π‘Ž, box π‘βŸ©]} 𝑀 to 𝑧 in case 𝑧 of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐸 [val ⟨box π‘₯, box π‘¦βŸ©]} =πœ‚βŠ—=πœ‚?Μƒ? 𝑀 to 𝑧 in 𝐸 [val 𝑧] =πœ‚ 𝐹 𝐸 [𝑀] Case lift1: (let π‘₯ be𝑀 in 𝑁 ) 𝐿 = let π‘₯ be𝑀 in (𝑁 𝐿) (let π‘₯ be𝑀 in 𝑁 ) 𝐿 =defn. (𝑀 memo π‘₯ in 𝑁 ) memo π‘Ž in 𝐿 memo 𝑏 in (π‘Ž.enter (box 𝑏)) .eval =πœ’ 𝑀 memo π‘₯ in 𝑁 memo π‘Ž in 𝐿 memo 𝑏 in (π‘Ž.enter (box 𝑏)) .eval =defn. let π‘₯ be𝑀 in (𝑁 𝐿) 90 Case lift2: 𝑀 (let π‘₯ be 𝑁 in 𝐿) = let π‘₯ be 𝑁 in (𝑀 𝐿) 𝑀 (let π‘₯ be 𝑁 in 𝐿) =defn. 𝑀 memo π‘Ž in (𝑁 memo π‘₯ in 𝐿) memo 𝑏 in (π‘Ž.enter (box 𝑏)) .eval =πœ… 𝑁 memo π‘₯ in𝑀 memo π‘Ž in 𝐿 memo 𝑏 in (π‘Ž.enter (box 𝑏)) .eval =defn. let π‘₯ be 𝑁 in (𝑀 𝐿) Case lift3: πœ†π‘₯. let 𝑦 be 𝑉 in𝑀 = let 𝑦 be 𝑉 in πœ†π‘₯ .𝑀 πœ†π‘₯. let 𝑦 be 𝑉 in𝑀 =defn. {enter β†’ πœ†π‘§. case 𝑧 of {box π‘₯ β†’ {eval β†’ 𝑉 memo 𝑦 in𝑀}}} =βˆ—deref=GC {enter β†’ πœ†π‘§. case 𝑧 of {box π‘₯ β†’ {eval β†’ 𝑀 [𝑉 /π‘₯]}}} = =βˆ—GC deref 𝑉 memo 𝑦 in {enter β†’ πœ†π‘§. case 𝑧 of {box π‘₯ β†’ {eval β†’ 𝑀}}} =defn. let 𝑦 be 𝑉 in πœ†π‘₯ .𝑀 Case lift4: case (let π‘₯ be𝑀 in 𝑁 ) of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿} = let π‘₯ be𝑀 in (case 𝑁 of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿}) case (let π‘₯ be𝑀 in 𝑁 ) of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿} =defn. (𝑀 memo π‘₯ in 𝑁 ) to 𝑧 in case 𝑧 of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐿} =πœ… 𝑀 memo π‘₯ in 𝑁 to 𝑧 in case 𝑧 of {⟨box π‘₯, box π‘¦βŸ© β†’ 𝐿} =defn. let π‘₯ be𝑀 in (case 𝑁 of {⟨π‘₯,π‘¦βŸ© β†’ 𝐿}) Case merge: let π‘₯ be (let 𝑦 be𝑀 in 𝑁 ) in 𝐿 = let 𝑦 be𝑀 in let π‘₯ be 𝑁 in 𝐿 91 let π‘₯ be (let 𝑦 be𝑀 in 𝑁 ) in 𝐿 =defn. (𝑀 memo 𝑦 in 𝑁 ) memo π‘₯ in 𝐿 =πœ’ 𝑀 memo 𝑦 in (𝑁 memo π‘₯ in 𝐿) =defn. let 𝑦 be𝑀 in let π‘₯ be 𝑁 in 𝐿 Case deref : let π‘₯ be 𝑉 in 𝐢 [π‘₯] = let π‘₯ be 𝑉 in 𝐢 [𝑉 ] Note that Lemma 5.2 gives us that 𝑉 =π‘Š . let π‘₯ be 𝑉 in 𝐢 [π‘₯] =defn. 𝑉 memo π‘₯ in 𝐢 [π‘₯] =deref 𝑉 memo π‘₯ in 𝐢 [𝑉 ] =defn. let π‘₯ be 𝑉 in 𝐢 [𝑉 ] Case GC: let π‘₯ be𝑀 in 𝑁 = 𝑁 let π‘₯ be𝑀 in 𝑁 =defn. 𝑀 memo π‘₯ in 𝑁 =GC 𝑁 Case name: 𝑀 = let π‘₯ be𝑀 in π‘₯ 92 𝑀 =name 𝑀 memo π‘Ž in π‘Ž =defn. let π‘Ž be𝑀 in π‘Ž β–‘ 93 CHAPTER VI CLOSURES AND MACHINES FOR CBPVS This chapter contains published and unpublished co-authored material. It contains revisions of the work Closure Conversion in Little Pieces [53] co- authored with Paul Downen and Zena M. Ariola. Zachary J. Sullivan is the primary author under the guidance of Paul Downen and Zena M. Ariola. While CBPVS captures call-by-name, call-by-value, and call-by-need in a single intermediate language, we have not yet specified an operational semantics in the manner of the abstract machines presented earlier in this dissertation. Moreover, we do not yet know how to extend our intermediate language with closures that are connected to this machine. This chapter does both. To start, we design an environment abstract machine for CBPV to inform where we will need closures in such a language. Thereafter, we are able to describe where abstract closures must be included in CBPVS. We extend the CBPV machine to include sharing and show how abstract closures in the CBPVS are a superset of machine representations of closures. Finally, we begin to formally connect the calculus with the machine by proving a backwards simulation and defining observational equivalence of CBPVS expressions. 6.1 An Environment Machine for CBPV The first place to start when designing an environment abstract machine for CBPV is discovering where closures are required. In Section 1.4, we saw that call-by-value required closures for functions alone, whereas call-by-name and call-by-need required closures for arguments of functions. In general, closures need to save the values that would otherwise be substituted by the operational semantics and that occur in reducible code. In CBPV, this quality is dictated by the syntactic categories: only values have the 94 Conf ∈ Configuration ::= ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ Ξ£ ∈ Machine Environment ::= πœ€ | Ξ£,V/π‘₯ V,W ∈ Machine Value ::= b | ⟨V,W⟩ | (Ξ£, {force β†’ 𝑀}) 𝐾 ∈ Stack ::= β˜… | 𝐹 Β· 𝐾 𝐹 ∈ Frame ::= β–‘ V | β–‘.fst | β–‘.snd | (Ξ£,β–‘ to π‘₯ in𝑀) Figure 6.1. CBPV Machine Syntax potential to be bound to variables and passed to other parts of the program. Indeed, the only location where these expressions contain unevaluated code is in the shift from computations: {force β†’ 𝑀}. Thus, this is where we must add closures. Surprisingly, we do not need closures for functions. A function is a computation and therefore is never bound to a variable unless it is shifted to a value. Compiling a call-by-value program will put the function into a thunk and that instead is where the free variables need to be captured. Compiling a call-by-name program will put a function argument into a thunk, thus creating a closure in the same location as we would’ve seen when running the program on the Krivine machine. Our machine is essentially Levy’s CK-machine [27] augmented with an environment that delays substitutions. Its syntax is presented in Figure 6.1. Machine environments Ξ£ are local, i.e. they may disappear when an intermediate result is returned, which is why we use closures. The continuation part of the machine is a list of stack frames which for the most part are evaluation contexts. Exceptionally, the to-expression frame (Ξ£,β–‘ to π‘₯ in𝑀) also contains a local environment to re-instantiate when we evaluate𝑀 after an intermediate result is returned. Such a frame may be implemented using stack pointers in a C-like runtime; that is, returning to one of these saved environments is simply moving the stack frame back to that location. The machine uses machine values instead of the ones in the full equational theory. Syntactic values can contain variables, but machine ones only refer to objects that can 95 Build𝑉 : Machine Environment Γ— Value β†’ Machine Value Build𝑉 (Ξ£, π‘₯) = π‘₯ [Ξ£] Build𝑉 (Ξ£, b) = b Build𝑉 (Ξ£, βŸ¨π‘‰ ,π‘Š ⟩) = ⟨Build𝑉 (Ξ£,𝑉 ), Build𝑉 (Ξ£,π‘Š )⟩ Build𝑉 (Ξ£, {force β†’ 𝑀}) = (Ξ£, {force β†’ 𝑀}) Figure 6.2. Building CBPV Machine Values ⟨⟨Σ βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’ β€²1 ⟨⟨Σ,W/π‘₯,W /𝑦 βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = ⟨W,Wβ€²βŸ© ⟨⟨Σ βˆ₯ 𝑀 to π‘₯ in 𝑁 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’2 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝑁 ) Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ ret 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in𝑀) Β· 𝐾⟩⟩ β†¦βˆ’β†’3 βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀.fst βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’4 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀.snd βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’5 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.snd Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {fst→𝑀 ; snd→𝑁 } βˆ₯ β–‘.fst Β· 𝐾⟩⟩ β†¦βˆ’β†’6 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {fst→𝑀 ; snd→𝑁 } βˆ₯ β–‘.snd Β· 𝐾⟩⟩ β†¦βˆ’β†’7 ⟨⟨Σ βˆ₯ 𝑁 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀 𝑉 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’8 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘ Build𝑉 (Ξ£,𝑉 ) Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ β–‘ V Β· 𝐾⟩⟩ β†¦βˆ’β†’9 ⟨⟨Σ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑉.force βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’10 βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = (Ξ£β€², {force β†’ 𝑀}) Figure 6.3. CBPV Machine Transitions be pattern matched or forced; indeed, values are a superset of machine values and thus environments are a superset of machine environments as well. To transform between syntactic values and machine values, we must apply the delayed substitution manipulated by the machine; this is given by the build rules in Figure 6.2. In most cases, this is a standard substitution application; however, the case for force-expressions is different since they contain unevaluated code. To generate a fixed sequence of code for the body, building a machine value cannot perform a substitution on it. Therefore, we capture the current machine environment Ξ£ in a closure. The evaluation transitions are given in Figure 6.3. Since in CBPV values are and computations do, there are only rules for evaluating computations. Values, on the other 96 hand, are built from the local environment when needed. In a manner similar to the Krivine machine, when evaluating a function application, we push the argument on the call stack (capturing a closure if necessary) and jump into the function body; when a πœ†- expression is encountered, we can add that machine value to the local environment. The to-expression and projection-expressions operate in a similar manner by pushing a stack frame, which will be consumed when an introduction form of the computation is reached. Note that anywhere Build is called is a location where our runtime system may have to create a closure. Closures are entered only when we force a value in the transition 10. 6.2 CBPVS with Closures In the CBPV environment machine, we must create closures force-expressions since they delay unevaluated code within a substitutable variable. Similarly, the CBPVS enter- expression delays a computation within a shared computation may be substituted and thus will need to be a closure. Additionally, since the memo-expressions of CBPVS will behave in the same manner as call-by-need let-expressions, we will have closures like {𝜍, 𝑅} memo π‘Ž in 𝑃 . The new syntax for CBPVS with closures is given in Figure 6.4. We merely replace force-, enter-, and memo-expressions with forms that contain an environment. Note that environments now contain a mixture of values and shared values. As with abstract closures from Section 3.3.4, there is syntactic sugar for when the environment of a closure is empty: {force β†’ 𝑀}, {enter β†’ 𝑀}, and 𝑅 memo π‘Ž in 𝑃 . The typing rules for the new closure forms Figure 6.4c follow the same pattern as those that we saw in Chapter 4: the local environment 𝜍 : Ξ“β€² extends the current type environment Ξ“ for the body of the closure. All of the other typing rules for CBPVS remain unchanged. The closure axioms for CBPVS are presented in Figure 6.4d. We have only new 𝛽-laws as the πœ‚-laws remain unchanged. The 𝛽 laws for force- and enter-closures work similar to 97 𝑉 ,π‘Š ∈ Value ::= b | π‘₯ | βŸ¨π‘‰ ,π‘Š ⟩ | {𝜍, force β†’ 𝑀} | box 𝑉 𝑉 ,π‘Š ∈ Shared Value ::= π‘Ž | val 𝑉 | {𝜍, enter β†’ 𝑀} 𝑅, 𝑆 ∈ Shared Comp. ::= 𝑉 | 𝑀.eval | 𝐡 [𝑅] 𝑀, 𝑁 ∈ Comp. ::= {fst β†’ 𝑀 ; snd β†’ 𝑁 } | 𝑀.fst | 𝑀.snd | πœ†π‘₯.𝑀 | 𝑀𝑉 | 𝑉.force | ret 𝑉 | 𝐡 [𝑀] | 𝑅.enter | {eval β†’ 𝑅} 𝐡 ∈ Block Ctxt . ::= 𝑃 toπ‘₯ inβ–‘ | {𝜍, 𝑅} memoπ‘Ž inβ–‘ | case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ β–‘} | case 𝑉 of {box π‘Ž β†’ β–‘} 𝑃,𝑄 ∈ Comp. Expr . ::= 𝑅 | 𝑀 𝜍 ∈ Env. ::= πœ€ | 𝜍,𝑉 /π‘₯ | 𝜍,𝑉 /π‘Ž (a) Syntax {force β†’ 𝑀} = {πœ€, force β†’ 𝑀} {enter β†’ 𝑀} = {πœ€, enter β†’ 𝑀} 𝑅 memo π‘Ž in 𝑃 = {πœ€, 𝑅} memo π‘Ž in 𝑃 (b) Syntactic Sugar β€² β€² Ξ“ ⊒ 𝜍 : Ξ“β€² ΓΓ′ ⊒ 𝑀 : 𝜏 Ξ“ ⊒ 𝜍 : Ξ“ ΓΓ ⊒ 𝑀 : 𝜏 π‘ˆ π‘ˆπΌ Ξ“ ⊒ {𝜍, force β†’ 𝐼𝑀} : π‘ˆ 𝜏 Ξ“ ⊒ {𝜍, enter β†’ 𝑀} : π‘ˆ 𝜏 Ξ“ ⊒ 𝜍 : Ξ“β€² ΓΓ′ ⊒ 𝑅 : 𝜎 Ξ“, π‘Ž:𝜎 ⊒ 𝑃 : 𝜏 H Ξ“ Ξ“ ⊒ {𝜍, 𝑅} memo π‘Ž in 𝑃 : 𝜏 Ξ“ ⊒ πΌπœ€ : πœ€ 𝐡 Ξ“ ⊒ 𝜍 : Ξ“β€² Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ ⊒ 𝜍 : Ξ“β€² Ξ“ ⊒ 𝑉 : 𝜏 Ξ“ ⊒ (𝜍,𝑉 / ) Ξ“: ( 𝐼 1π‘₯ Ξ“β€², π‘₯ :𝜏) 𝐼 Ξ“ ⊒ (𝜍,𝑉 /π‘Ž) : ( β€² Γ𝐼 2Ξ“ , π‘Ž:𝜏) 𝐼 (c) Closure Typing Rules {𝜍, force β†’ 𝑀}.force =𝛽 𝑀 [𝜍]π‘ˆ {𝜍, enter β†’ 𝑀}.enter =𝛽 𝑀 [𝜍]?̌? {𝜍, 𝑅} memo π‘Ž in 𝑃 =cl 𝑅 [𝜍] memo π‘Ž in 𝑃 where 𝐸, 𝐹 ::= β–‘ | 𝐸 𝑉 | 𝐸.fst | 𝐸.snd | 𝐸 to π‘₯ in 𝑃 | 𝐸.enter | 𝐸.eval | {𝜍, 𝑅} memo π‘Ž in 𝐸 | {𝜍, 𝐸} memo π‘Ž in 𝐹 [π‘Ž] (d) Closure Axioms Figure 6.4. CBPVS with Closures 98 the call-by-value function closures fromChapter 4: the delayed environment is substituted as part of the 𝛽 axiom. On the other hand, the cl law for the memo-closures, which is in addition to the memoization laws of CBPVS, allows the closure to be entered at any time like the call-by-name argument closures and the call-by-need memo-closures. Using the syntactic sugar, we see that the memo-expression laws are all restricted to the case where the environment is empty; this is sufficient to subsume call-by-need and perform closure conversion in little pieces. As in Section 4.3, we can derive a naΓ―ve closure conversion from the equational theory. For each of the three closure locations, we have a similar rule for incrementally adding free variables: π‘₯ ∈ FV(𝑀) βˆ’ Dom(𝜍) {𝜍, force β†’ 𝑀} βˆ’β†’CC {(𝜍, π‘₯/π‘₯), force β†’ 𝑀} π‘₯ ∈ FV(𝑀) βˆ’ Dom(𝜍) {𝜍, enter β†’ 𝑀} βˆ’β†’CC {(𝜍, π‘₯/π‘₯), enter β†’ 𝑀} π‘₯ ∈ FV(𝑅) βˆ’ Dom(𝜍) {𝜍, 𝑅} memo π‘Ž in 𝑃 βˆ’β†’CC {(𝜍, π‘₯/π‘₯), 𝑅} memo π‘Ž in 𝑃 Note that we use black 𝑉 and π‘₯ here for values and variables that may be shared or not. 6.3 The CBPVS Machine Extending the CBPV environment machine to handle shared expressions requires a heap to manage memoization and extra rules for the shared expressions. We also need to support abstract closures within the machine itself. Figure 6.5 presents the syntax for this machine. Since they are a reflection of the runtime closures, the abstract closures from our equational theory are a superset of the machine closures used by the abstract machines. Heaps are mappings from labels to closures, which will include both unevaluated and evaluated shared expressions. Machine environments are extended 99 Conf ∈ Configuration ::= ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ Ξ¦ ∈ Heap ::= πœ€ | Ξ¦, 𝑙 →↦ {Ξ£, 𝑅} I ∈ Machine Shared Intro. ::= val V | {Ξ£, enter β†’ 𝑀} V,W ∈ Machine Shared Value ::= 𝑙 | I Ξ£ ∈ Machine Environment ::= πœ€ | Ξ£,V/π‘₯ | Ξ£,V/π‘Ž V,W ∈ Machine Value ::= 𝑏 | ⟨V,W⟩ | {Ξ£, force β†’ 𝑀} | box V 𝐾 ∈ Stack ::= β˜… | 𝐹 Β· 𝐾 𝐹 ∈ Frame ::= β–‘ V | β–‘.fst | β–‘.snd | (Ξ£,β–‘ to π‘₯ in 𝑃) | (Ξ£,β–‘ to π‘₯ in 𝑃) | β–‘.enter | β–‘.eval | (Ξ¦, 𝑙) Figure 6.5. CBPVS Machine Syntax to include substitutions of shared variables to either machine-shared introductions or pointers to memoizable heap objects. Machine-shared introductions are the shared expressions in the machine that may be safely duplicated. Stack frames are extended to include evaluation contexts for the new shifts and a memoization frame (Ξ¦, 𝑙), which corresponds to the evaluation context 𝐸 memo π‘Ž in 𝐹 [π‘Ž]. Figure 6.6 gives new building definitions extending the previous definitions to include box-expressions, environments that include shared values, and adding in a definition for buildingmachine-shared values and heap objects. For the closure cases now, we can make use of the abstract closure objects since they are runtime objects. We return the whole machine environment as well as build the syntactic environment. Therefore, it is possible that we have duplicated bindings when capturing the closure. This version of the rule is necessary for our abstract machine to accept programs both before and after a closure conversion. However, after closure conversion we will not need anything from the existing machine environment that is not specified in the closure (Theorem 7.2). Figure 6.7 specifies the additional machine transitions for the sharing extensionwhile making use of all of the rules from the CBPV machine. We have divided it into the additional rules that do not manipulate the heap and the ones that do. Amemo-expression 100 Build𝑉 : Machine Env. Γ— Value β†’ Machine Value Build𝑉 (Ξ£, b) = b Build𝑉 (Ξ£, π‘₯) = π‘₯ [Ξ£] Build𝑉 (Ξ£, βŸ¨π‘‰ ,π‘Š ⟩) = ⟨Build𝑉 (Ξ£,𝑉 ), Build𝑉 (Ξ£,π‘Š )⟩ Build𝑉 (Ξ£, {𝜍, force β†’ 𝑀}) = {Ξ£ Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀} Build𝑉 (Ξ£, box 𝑉 ) = Build𝑉 (Ξ£,𝑉 ) Build𝜍 : Mach. Env. Γ— Env. β†’ Mach. Env. Build𝜍 (Ξ£, πœ€) = πœ€ Build𝜍 (Ξ£, (𝜍,𝑉 /π‘₯)) = Build𝜍 (Ξ£, 𝜍), Build𝑉 (Ξ£,𝑉 )/π‘₯ Build𝜍 (Ξ£, (𝜍,𝑉 /π‘Ž)) = Build𝜍 (Ξ£, 𝜍), Build𝑉 (Ξ£,𝑉 )/π‘Ž Build𝑉 : Mach. Env. Γ— Shared Value β†’ Mach. Shared Value Build𝑉 (Ξ£, π‘Ž) = π‘Ž[Ξ£] Build𝑉 (Ξ£, val 𝑉 ) = val Build𝑉 (Ξ£,𝑉 ) Build𝑉 (Ξ£, {𝜍, enter→𝑀}) = {Ξ£ Build𝜍 (Ξ£, 𝜍), enter β†’ 𝑀} Buildπ‘Ž : Mach. Env. Γ— {{𝜍, 𝑅}} β†’ {{Ξ£, 𝑅}} Buildπ‘Ž (Ξ£, {𝜍, 𝑅}) = {Ξ£ Build𝜍 (Ξ£, 𝜍), 𝑅} Figure 6.6. Building CBPVS Machine Values and Heap Objects will build a heap object with the Buildπ‘Ž rules before evaluating the body. When a shared variable is evaluated and it points to a heap object, then a memoization frame is added and the closure it points to is evaluated. Otherwise, the shared variablewill point to amachine- shared value that is in the local environment, which is returned. Memoization frames are consumed when evaluating a shared expression that may be built into a machine introduction; in that case, the built object is added to the reconstructed heap. Definition 6.1 (CBPVS Evaluator). EvalS(𝑃) = b where βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝑃 βˆ₯ β˜…βŸ©βŸ© βˆ’β†¦ β†’βˆ— ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ©. 6.4 Backwards Simulation Taking steps in our environment machine reflects to equalities in our calculus. This we prove by first defining a decoding of configurations to expressions (Figure 6.8) and then show that every transition in both abstract machines corresponds to a derivable 101 ⟨⟨Σ βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑅} βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’ ⟨⟨Σ,W/π‘₯,Wβ€²11 /𝑦 βˆ₯ 𝑅 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = ⟨W,Wβ€²βŸ© ⟨⟨Σ βˆ₯ case 𝑉 of {box π‘Ž β†’ 𝑃} βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’12 ⟨⟨Σ,V/π‘Ž βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = box V ⟨⟨Σ βˆ₯ 𝑃 to π‘₯ in 𝑄 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’13 ⟨⟨Σ βˆ₯ 𝑃 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝑄) Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ ret 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in 𝑃) Β· 𝐾⟩⟩ β†¦βˆ’β†’14 βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ val 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in 𝑃) Β· 𝐾⟩⟩ βˆ’β†¦ β†’15 βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑅.enter βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’16 ⟨⟨Σ βˆ₯ 𝑅 βˆ₯ β–‘.enter Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {𝜍, enter β†’ 𝑀} βˆ₯ β–‘.enter Β· 𝐾⟩⟩ βˆ’β†¦ β†’ βŸ¨βŸ¨Ξ£β€²17 βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = {Ξ£β€², enter β†’ 𝑀} ⟨⟨Σ βˆ₯ 𝑀.eval βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’18 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {eval β†’ 𝑅} βˆ₯ β–‘.eval Β· 𝐾⟩⟩ βˆ’β†¦ β†’19 ⟨⟨Σ βˆ₯ 𝑅 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ π‘Ž βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’20 βŸ¨βŸ¨πœ€ βˆ₯ I βˆ₯ 𝐾⟩⟩ where π‘Ž[Ξ£] = I (a) Additional Stateless Transitions ⟨⟨Σ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’ βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑃 β€² βˆ₯ πΎβ€²βŸ©βŸ© ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’21 ⟨⟨Φ βˆ₯ Ξ£β€² βˆ₯ 𝑃 β€² βˆ₯ πΎβ€²βŸ©βŸ© ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ {𝜍, 𝑅} memo π‘Ž in 𝑃 βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’22 ⟨⟨Φ, 𝑙 ↦→ Buildπ‘Ž (Ξ£, {𝜍, 𝑅}) βˆ₯ Ξ£, 𝑙/π‘Ž βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ ⟨⟨(Ξ¦0, π‘Ž[Ξ£] ↦→ {Ξ£β€², 𝑅})Ξ¦1 βˆ₯ Ξ£ βˆ₯ π‘Ž βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’23 ⟨⟨Φ β€²0 βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ (Ξ¦1, 𝑙) Β· 𝐾⟩⟩ ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ (Ξ¦β€², 𝑙) Β· 𝐾⟩⟩ β†¦βˆ’β†’ β€²24 ⟨⟨(Ξ¦, 𝑙 →↦ {πœ€, I})Ξ¦ βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = I (b) Stateful Transitions Figure 6.7. CBPVS Machine Transitions 102 ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ = Ξ¦[⟨⟨Σ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩] ⟨⟨Σ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ = 𝐾 [𝑃 [Ξ£]] β˜… = β–‘ 𝐹 Β· 𝐾 = 𝐾 [𝐹 ] Ξ¦, 𝑙 ↦→ {Ξ£, 𝑅} = Ξ¦[{Ξ£, 𝑅} memo 𝑙 in β–‘] πœ€ = β–‘ β–‘ V = β–‘ V β–‘.fst = β–‘.fst β–‘.snd = β–‘.snd (Ξ£,β–‘ to π‘₯ in 𝑃) = (β–‘ to π‘₯ in 𝑃) [Ξ£] β–‘.enter = β–‘.enter β–‘.eval = β–‘.eval (Ξ¦, 𝑙) = β–‘ memo 𝑙 in Ξ¦[𝑙] Figure 6.8. CBPVS Machine Decoding equality. Since machine values are included in values andmachine environments included in environments, the decoding is a simple unfolding of the stack followed by applying the delayed substitution of the configuration. There are two properties essential to proving backwards simulation. First, the decoding of a machine configuration must be well typed because we must use πœ‚ in order equate the different closure forms of type π‘ˆ 𝜏 . Second, the decoding of any stack is an evaluation context; we must be able to commute heaps with stacks via the πœ… law of memo-expressions. Lemma 6.1 (Built Values equal Applied Substitutions). Ξ“ ⊒ Build𝑉 (Ξ£,𝑉 ) =CBPV 𝑉 [Ξ£] : 𝜏 Proof. Follows by induction on 𝑉 . For π‘₯ , 𝑏, and βŸ¨π‘Š,π‘Š β€²βŸ©, the definition of substitution and Build𝑉 are identical; thus, built values are equal to substituted values by reflexivity in the equational theory and the inductive hypotheses in the case for products. For the final 103 case, we have Build𝑉 (Ξ£, {𝜍, force β†’ 𝑀}) =defn. {Ξ£ Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀} =subst. {Ξ£ Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀 [𝜍id.]} =π›½π‘ˆ {Ξ£ Build𝜍 (Ξ£, 𝜍), force β†’ {𝜍id., force β†’ 𝑀}.force} =πœ‚π‘ˆ {Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀 [Ξ£]} =I.H. {𝜍 [Ξ£], force β†’ 𝑀 [Ξ£]} =subst. {𝜍, force β†’ 𝑀}[Ξ£] β–‘ Theorem 6.1 (Backward Simulation). If Ξ“ ⊒ Conf : 𝜏 and Conf β†¦βˆ’β†’ Conf β€², then Ξ“ ⊒ Conf =CBPV Conf β€² : 𝜏 . Proof. Follows by the cases of the machine transitions: Case: ⟨⟨Σ βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’1 ⟨⟨Σ,W/π‘₯,Wβ€²/𝑦 βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ where Build ′𝑉 (Ξ£,𝑉 ) = ⟨W,W ⟩. ⟨⟨Σ βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [case 𝑉 [Ξ£] of ({⟨π‘₯,π‘¦βŸ© β†’ 𝑀}[Ξ£])] =Lemma 6.1 𝐾 [case ⟨W,Wβ€²βŸ© of ({⟨π‘₯,π‘¦βŸ© β†’ 𝑀}[Ξ£])] =π›½βŠ— 𝐾 [𝑀 [Ξ£,W/π‘₯,Wβ€²/𝑦]] =defn. ⟨⟨Σ,W/π‘₯,Wβ€²/𝑦 βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ 104 Case: ⟨⟨Σ βˆ₯ 𝑀 to π‘₯ in 𝑁 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’2 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝑁 ) Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀 to π‘₯ in 𝑁 βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑀 to π‘₯ in 𝑁 ) [Ξ£]] =subst. 𝐾 [𝑀 [Ξ£] (to π‘₯ in 𝑁 ) [Ξ£]] =defn. ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝑁 ) Β· 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ ret 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in𝑀) Β· 𝐾⟩⟩ β†¦βˆ’β†’3 βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ ret 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in𝑀) Β· 𝐾⟩⟩ =defn. 𝐾 [(ret (𝑉 [Ξ£])) (to π‘₯ in𝑀) [Ξ£β€²]] =Lemma 6.1 𝐾 [(ret Build𝑉 (Ξ£,𝑉 )) (to π‘₯ in𝑀) [Ξ£β€²]] =𝛽𝐹 𝐾 [𝑀 [Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯]] =defn. βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯𝑀 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ 𝑀.fst βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’4 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀.fst βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑀.fst) [Ξ£]] =subst. 𝐾 [(𝑀 [Ξ£]).fst] =defn. ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ 𝑀.snd βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’5 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.snd Β· 𝐾⟩⟩ Follows in a similar manner to the case above. 105 Case: ⟨⟨Σ βˆ₯ {fst→𝑀 ; snd→𝑁 } βˆ₯ β–‘.fst Β· 𝐾⟩⟩ β†¦βˆ’β†’6 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {fst→𝑀 ; snd→𝑁 } βˆ₯ β–‘.fst Β· 𝐾⟩⟩ =defn. 𝐾 [({fst→𝑀 ; snd→𝑁 }[Ξ£]).fst] =subst. 𝐾 [{fst→𝑀 [Ξ£]; snd→𝑁 [Ξ£]}.fst] =𝛽&1 𝐾 [𝑀 [Ξ£]] =defn. ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ {fst→𝑀 ; snd→𝑁 } βˆ₯ β–‘.snd Β· 𝐾⟩⟩ β†¦βˆ’β†’7 ⟨⟨Σ βˆ₯ 𝑁 βˆ₯ 𝐾⟩⟩ Follows in a similar manner to the case above. Case: ⟨⟨Σ βˆ₯ 𝑀 𝑉 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’8 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘ Build𝑉 (Ξ£,𝑉 ) Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀 𝑉 βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑀 𝑉 ) [Ξ£]] =subst. 𝐾 [𝑀 [Ξ£] 𝑉 [Ξ£]] =Lemma 6.1 𝐾 [𝑀 [Ξ£] Build𝑉 (Ξ£,𝑉 )] =defn. ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘ Build𝑉 (Ξ£,𝑉 ) Β· 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ β–‘ V Β· 𝐾⟩⟩ β†¦βˆ’β†’9 ⟨⟨Σ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ β–‘ V Β· 𝐾⟩⟩ =defn. 𝐾 [(πœ†π‘₯. 𝑀) [Ξ£] V] =𝛽→ 𝐾 [𝑀 [Ξ£,V/π‘₯]] =defn. ⟨⟨Σ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ 106 Case: ⟨⟨Σ βˆ₯ 𝑉.force βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’10 βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = {Ξ£β€², force β†’ 𝑀}. ⟨⟨Σ βˆ₯ 𝑉.force βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑉.force) [Ξ£]] =subst. 𝐾 [(𝑉 [Ξ£]).force] =Lemma 6.1 𝐾 [{Ξ£β€², force β†’ 𝑀}.force] =π›½π‘ˆ 𝐾 [𝑀 [Ξ£β€²]] =defn. βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑅} βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’11 ⟨⟨Σ,W/π‘₯,Wβ€²/𝑦 βˆ₯ 𝑅 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = ⟨W,Wβ€²βŸ©. ⟨⟨Σ βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑅} βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [case 𝑉 [Ξ£] of ({⟨π‘₯,π‘¦βŸ© β†’ 𝑅}[Ξ£])] =Lemma 6.1 𝐾 [case ⟨W,Wβ€²βŸ© of ({⟨π‘₯,π‘¦βŸ© β†’ 𝑅}[Ξ£])] =π›½βŠ— 𝐾 [𝑅 [Ξ£,W/π‘₯,Wβ€²/𝑦]] =defn. ⟨⟨Σ,W/π‘₯,Wβ€²/𝑦 βˆ₯ 𝑅 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ case 𝑉 of {box π‘Ž β†’ 𝑃} βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’12 ⟨⟨Σ,V/π‘Ž βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ where Build𝑉 (Ξ£,𝑉 ) = box V. 107 ⟨⟨Σ βˆ₯ case 𝑉 of {box π‘Ž β†’ 𝑃} βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [case 𝑉 [Ξ£] of ({box π‘Ž β†’ 𝑃}[Ξ£])] =Lemma 6.1 𝐾 [case box V of ({box π‘Ž β†’ 𝑃}[Ξ£])] =𝛽 ?Μƒ? 𝐾 [𝑃 [Ξ£,V/π‘Ž]] =defn. ⟨⟨Σ,V/π‘₯ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ 𝑃 to π‘₯ in 𝑄 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’13 ⟨⟨Σ βˆ₯ 𝑃 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝑄) Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑃 to π‘₯ in 𝑄 βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑃 to π‘₯ in 𝑄) [Ξ£]] =subst. 𝐾 [𝑃 [Ξ£] (to π‘₯ in 𝑄) [Ξ£]] =defn. ⟨⟨Σ βˆ₯ 𝑃 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝑄) Β· 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ ret 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in 𝑃) Β· 𝐾⟩⟩ β†¦βˆ’β†’14 βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ ret 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in 𝑃) Β· 𝐾⟩⟩ =defn. 𝐾 [(ret (𝑉 [Ξ£])) (to π‘₯ in 𝑃) [Ξ£β€²]] =Lemma 6.1 𝐾 [(ret Build𝑉 (Ξ£,𝑉 )) (to π‘₯ in 𝑃) [Ξ£β€²]] =𝛽𝐹 𝐾 [𝑃 [Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯]] =defn. βŸ¨βŸ¨Ξ£β€², Build(Ξ£,𝑉 )/π‘₯ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ val 𝑉 βˆ₯ (Ξ£β€²,β–‘ to π‘₯ in 𝑃) Β· 𝐾⟩⟩ βˆ’β†¦ β†’15 βŸ¨βŸ¨Ξ£β€², Build𝑉 (Ξ£,𝑉 )/π‘₯ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ 108 Follows in a similar manner to the case above. Case: ⟨⟨Σ βˆ₯ 𝑅.enter βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’16 ⟨⟨Σ βˆ₯ 𝑅 βˆ₯ β–‘.enter Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑅.enter βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑅.enter) [Ξ£]] =subst. 𝐾 [(𝑅 [Ξ£]).enter] =defn. ⟨⟨Σ βˆ₯ 𝑅 βˆ₯ β–‘.enter Β· 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ {enter β†’ 𝑀} βˆ₯ β–‘.enter Β· 𝐾⟩⟩ β†¦βˆ’β†’17 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {enter β†’ 𝑀} βˆ₯ β–‘.enter Β· 𝐾⟩⟩ =defn. 𝐾 [({enter β†’ 𝑀}[Ξ£]) .enter] =subst. 𝐾 [({enter β†’ 𝑀}.enter) [Ξ£]] =𝛽?̌? 𝐾 [𝑀 [Ξ£]] =defn. ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ 𝑀.eval βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’18 ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· 𝐾⟩⟩ ⟨⟨Σ βˆ₯ 𝑀.eval βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [(𝑀.eval) [Ξ£]] =subst. 𝐾 [(𝑀 [Ξ£]) .eval] =defn. ⟨⟨Σ βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· 𝐾⟩⟩ 109 Case: ⟨⟨Σ βˆ₯ {eval β†’ 𝑅} βˆ₯ β–‘.eval Β· 𝐾⟩⟩ β†¦βˆ’β†’19 ⟨⟨Σ βˆ₯ 𝑅 βˆ₯ 𝐾⟩⟩ ⟨⟨Σ βˆ₯ {eval β†’ 𝑅} βˆ₯ β–‘.eval Β· 𝐾⟩⟩ =defn. 𝐾 [({eval β†’ 𝑅}[Ξ£]).eval] =subst. 𝐾 [({eval β†’ 𝑅}.eval) [Ξ£]] =𝛽 𝐹 𝐾 [𝑅 [Ξ£]] =defn. ⟨⟨Σ βˆ₯ 𝑅 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ π‘Ž βˆ₯ 𝐾⟩⟩ βˆ’β†¦ β†’20 βŸ¨βŸ¨πœ€ βˆ₯ I βˆ₯ 𝐾⟩⟩ where π‘Ž[Ξ£] = I. ⟨⟨Σ βˆ₯ π‘Ž βˆ₯ 𝐾⟩⟩ =defn. 𝐾 [π‘Ž[Ξ£]] = 𝐾 [I] =subst. 𝐾 [I[πœ€]] =defn. βŸ¨βŸ¨πœ€ βˆ₯ I βˆ₯ 𝐾⟩⟩ Case: ⟨⟨Σ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑃 β€² βˆ₯ πΎβ€²βŸ©βŸ© ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’ ⟨⟨Φ βˆ₯ Ξ£β€²21 βˆ₯ 𝑃 β€² βˆ₯ πΎβ€²βŸ©βŸ© ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ =defn. Ξ¦[⟨⟨Σ βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩] =I.H. Ξ¦[βŸ¨βŸ¨Ξ£β€² βˆ₯ 𝑃 β€² βˆ₯ πΎβ€²βŸ©βŸ©] =defn. ⟨⟨Φ βˆ₯ Ξ£β€² βˆ₯ 𝑃 β€² βˆ₯ πΎβ€²βŸ©βŸ© 110 Case: ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑅 memo π‘Ž in 𝑃 βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’22 ⟨⟨Φ, 𝑙 ↦→ Buildπ‘Ž (Ξ£, 𝑅) βˆ₯ Ξ£, 𝑙/π‘Ž βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ Note that stacks are decoded into evaluation contexts. ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑅 memo π‘Ž in 𝑃 βˆ₯ 𝐾⟩⟩ =defn. Ξ¦[𝐾 [(𝑅 memo π‘Ž in 𝑃) [Ξ£]]] =subst. Ξ¦[𝐾 [𝑅 [Ξ£] memo π‘Ž in 𝑃 [Ξ£]]] =πœ… Ξ¦[𝑅 [Ξ£] memo π‘Ž in 𝐾 [𝑃 [Ξ£]]] = Ξ¦, π‘Ž ↦→ Buildπ‘Ž (Ξ£, 𝑅) [𝐾 [𝑃 [Ξ£]]] =𝛼 Ξ¦, 𝑙 ↦→ Buildπ‘Ž (Ξ£, 𝑅) [𝐾 [𝑃 [Ξ£, 𝑙/π‘Ž]]] =defn. ⟨⟨Φ, 𝑙 ↦→ Buildπ‘Ž (Ξ£, 𝑅) βˆ₯ Ξ£, 𝑙/π‘Ž βˆ₯ 𝑃 βˆ₯ 𝐾⟩⟩ Case: ⟨⟨(Ξ¦0, π‘Ž[Ξ£] ↦→ {Ξ£β€², 𝑅})Ξ¦1 βˆ₯ Ξ£ βˆ₯ π‘Ž βˆ₯ 𝐾⟩⟩ β†¦βˆ’β†’23 ⟨⟨Φ0 βˆ₯ Ξ£β€² βˆ₯ 𝑅 βˆ₯ (Ξ¦1, 𝑙) Β· 𝐾⟩⟩ Note that stacks are decoded into evaluation contexts. ⟨⟨(Ξ¦0, π‘Ž[Ξ£] ↦→ {Ξ£β€², 𝑅})Ξ¦1 βˆ₯ Ξ£ βˆ₯ π‘Ž βˆ₯ 𝐾⟩⟩ =defn. Ξ¦0, π‘Ž[Ξ£] ↦→ {Ξ£β€², 𝑅}[Ξ¦1 [𝐾 [π‘Ž[Ξ£]]]] = Ξ¦0, 𝑙 ↦→ {Ξ£β€², 𝑅}[Ξ¦1 [𝐾 [𝑙]]] =πœ… Ξ¦0 [𝐾 [{Ξ£β€², 𝑅} memo 𝑙 in Ξ¦1 [𝑙]]] =cl. Ξ¦ [𝐾 [𝑅 [Ξ£β€²0 ] memo 𝑙 in Ξ¦1 [𝑙]]] =defn. ⟨⟨Φ0 βˆ₯ Ξ£β€² βˆ₯ 𝑅 βˆ₯ (Ξ¦1, 𝑙) Β· 𝐾⟩⟩ Case: ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ (Ξ¦β€², 𝑙) Β· 𝐾⟩⟩ β†¦βˆ’β†’24 ⟨⟨(Ξ¦, 𝑙 ↦→ {πœ€, I})Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ 𝐾⟩⟩ 111 where Build𝑉 (Ξ£,𝑉 ) = I. ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ (Ξ¦β€², 𝑙) Β· 𝐾⟩⟩ =defn. Ξ¦[𝐾 [𝑉 [Ξ£] memo 𝑙 in Ξ¦β€²[𝑙]]] =deref . Ξ¦[𝐾 [𝑉 [Ξ£] memo 𝑙 in Ξ¦β€²[𝑉 [Ξ£]]] = Ξ¦[𝐾 [I memo 𝑙 in Ξ¦β€²[𝑉 [Ξ£]]]] =πœ… Ξ¦[I memo 𝑙 in Ξ¦β€²[𝐾 [𝑉 [Ξ£]]]] =defn. ⟨⟨(Ξ¦, 𝑙 ↦→ I)Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ 𝐾⟩⟩ =sugar ⟨⟨(Ξ¦, 𝑙 ↦→ {πœ€, I})Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑉 βˆ₯ 𝐾⟩⟩ β–‘ Corollary 6.1. If EvalS(𝑀) = b, then ⊒ 𝑀 = ret b : 𝐹 𝐡. 6.5 Observational Equivalence Since the machine forms our operational semantics for CBPVS, we define a notion of observational equivalence on top of it. And since this notion of equivalence is the semantics for which we will verify the correctness of our closure theory, it must support the whole language and be fine-grained enough to discuss parts of sharing. As with the evaluators seen previously, we consider only running computable expressions that return base values. We will begin by defining observationally equivalent machine configurations as configurations that mutually imply the same base value computations; intuitively, Conf 1 ≃ Conf 2 if and only if their behaviors imply each other. On top of this, we define a notion of observably equivalent expressions, wherein we place expressions in a closing context that returns a base value; intuitively, 𝐴 ≃ 𝐡 if and only if the behaviors of 𝐢 [𝐴] and 𝐢 [𝐡] in the machine imply each other for any closing computation. Making this work with sharing means muddying this common notion of observational equivalence. The notion of equivalent expressions is similar in that we 112 place them in closing computation contexts, but we must add more information to the notion of equivalent configurations. If we are evaluating a shared computation within a stack that demands an introduction formβ€”as it will if we are memoizing or pattern matching, then equivalent configurations must evaluate to an intermediate state that includes a machine introduction if and only if the other does; those future configurations must also be observably equivalent. The stacks that will force a shared computation are the elimination forms for each shared type and the memoization frame. We refer to this notion as strict stacks; they consume introduction forms. Definition 6.2 (Introductions and Strict Stacks). 𝐼 ∈ Introduction = Shared Value βˆ’ {π‘Ž} K ∈ VStack ::= (Ξ£,β–‘ to π‘₯ in 𝑃) Β· 𝐾 | β–‘.enter Β· 𝐾 | (Ξ¦, 𝑙) Β· K Formally, we define this observational equivalence with two relations. A base relation on configurations B and a shared introduction configuration IB . 113 Definition 6.3 (Observably Equivalent Configurations). Confl ≃ Conf def r = Confl B Confr ∧ Confl = βŸ¨βŸ¨Ξ¦π‘™ βˆ₯ Σ𝑙 βˆ₯ 𝑅𝑙 βˆ₯ Kπ‘™βŸ©βŸ© Confr = βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ π‘…π‘Ÿ βˆ₯ Kπ‘Ÿ ⟩⟩ =β‡’ Confl IB Confr Conf def βˆ—l B Confr = βˆ€π‘–, 𝑗 ∈ {𝑙, π‘Ÿ }.Confi β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦π‘– βˆ₯ Σ𝑖 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© =β‡’ Conf β†¦βˆ’β†’βˆ—j ⟨⟨Φ 𝑗 βˆ₯ Ξ£ 𝑗 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© βŸ¨βŸ¨Ξ¦π‘™ βˆ₯ Σ𝑙 βˆ₯ 𝑅𝑙 βˆ₯ Kπ‘™βŸ©βŸ© IB βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ π‘…π‘Ÿ βˆ₯ Kπ‘Ÿ ⟩⟩ def = βˆ€π‘–, 𝑗 ∈ {𝑙, π‘Ÿ }. βŸ¨βŸ¨Ξ¦π‘– βˆ₯ Σ𝑖 βˆ₯ 𝑅𝑖 βˆ₯ Kπ‘–βŸ©βŸ© βˆ’β†¦ β†’βˆ— βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ′𝑖 𝑖 βˆ₯ 𝐼 𝑖 βˆ₯ Kπ‘–βŸ©βŸ© =β‡’ ⟨⟨Φ 𝑗 βˆ₯ Ξ£ 𝑗 βˆ₯ 𝑅 𝑗 βˆ₯ K 𝑗 ⟩⟩ β†¦βˆ’β†’βˆ— βŸ¨βŸ¨Ξ¦β€²π‘— βˆ₯ Σ′𝑗 βˆ₯ 𝐼 𝑗 βˆ₯ K 𝑗 ⟩⟩ ∧ βŸ¨βŸ¨Ξ¦π‘– βˆ₯ Σ𝑖 βˆ₯ 𝐼 𝑖 βˆ₯ Kπ‘–βŸ©βŸ© B ⟨⟨Φ 𝑗 βˆ₯ Ξ£ 𝑗 βˆ₯ 𝐼 𝑗 βˆ₯ K 𝑗 ⟩⟩ Definition 6.4 (Observably Equivalent Expressions). ≃ def𝐴 𝐡 = βˆ€πΆ ∈ Context . πœ€ ⊒ 𝐢 [𝐴] : 𝐹 𝐡 ∧ πœ€ ⊒ 𝐢 [𝐡] : 𝐹 𝐡 =β‡’ βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝐢 [𝐴] βˆ₯ β˜…βŸ©βŸ© ≃ βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝐢 [𝐡] βˆ₯ β˜…βŸ©βŸ© What follows are extra properties that follow from our definition of observationally equivalent configurations. First, we have a recursive definition that allows us to build up a call stack given an evaluation context. This is used in observational equivalence property number (4) below. 114 Definition 6.5 (Building Stacks and Bindings). Build𝐾 (Ξ¦, Ξ£,β–‘, 𝐾) = (Ξ¦, Ξ£, 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸 𝑉 , 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸,β–‘ Build𝑉 (Ξ£,𝑉 ) Β· 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸.fst, 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸,β–‘.fst Β· 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸.snd, 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸,β–‘.snd Β· 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸 to π‘₯ in 𝑃, 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸, (Ξ£,β–‘ to π‘₯ in 𝑃) Β· 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸.enter, 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸,β–‘.enter Β· 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸.eval, 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸,β–‘.eval Β· 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝑅 memo π‘Ž in 𝐸, 𝐾) = Build𝐾 ((Ξ¦, 𝑙 ↦→ Buildπ‘Ž (Ξ£, 𝑅)), (Ξ£, 𝑙/π‘Ž), 𝐸, 𝐾) Build𝐾 (Ξ¦, Ξ£, 𝐸 memo π‘Ž in 𝐹 [π‘Ž], 𝐾) = Build𝐾 (Ξ¦, Ξ£, 𝐸, (Ξ¦β€², 𝑙) Β· 𝐾′) where Build𝐾 (πœ€, (Ξ£, 𝑙/π‘Ž), 𝐹 , 𝐾) = (Ξ¦β€², Ξ£β€², 𝐾′) Proposition 6.1 (Observational Equivalence Properties). 1. Conf β†¦βˆ’β†’βˆ— Conf β€² implies Conf ≃ Conf β€². 2. Observational equivalence relations for configurations (≃), expressions (≃), base value configurations (B), and shared introduction configurations (IB) are reflexive, symmetric, and transitive. 3. (Conf0 ≃ Conf1) ∧ (Conf0 β†¦βˆ’β†’βˆ— Conf β€² β€²0 ) implies Conf0 ≃ Conf1. 4. ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝐸 [𝑃] βˆ₯ 𝐾⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£β€² βˆ₯ 𝑃 βˆ₯ πΎβ€²βŸ©βŸ© where Build𝐾 (Ξ£, 𝐸, 𝐾) = (Ξ¦β€², Ξ£β€², 𝐾′). 5. IB βŠ† (≃). 6. ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ (Ξ¦β€², 𝑙) Β· K⟩⟩ ≃ ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ K⟩⟩ where Dom(Ξ¦β€²) ∩ Dom(Ξ¦) = βˆ…. Proof. 115 1. Suppose that Conf β†¦βˆ’β†’βˆ— Conf β€², we may conclude that Conf ≃ Conf β€² by the determinism of (β†¦βˆ’β†’). 2. These, we prove for Conf B Conf β€² as Conf I Conf β€²B is proved in a similar manner to B. The property for (≃) of configurations and expressions is derived therefrom. Reflexivity: Conf B Conf then follows immediately by its assumptions. Symmetry: Suppose Conf 0 B Conf 1. Then Conf 1 B Conf 0 by definition, by swapping the choice of indexes in the underlying implications. Transitivity: Suppose Conf 0 B Conf 1 and Conf 1 B Conf 2. Then Conf 0 B Conf 2 follows by composing the underlying implications from the assumptions: Conf 0 β†¦βˆ’β†’βˆ— ⟨⟨Φ0 βˆ₯ Ξ£0 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© =β‡’ Conf 1 β†¦βˆ’β†’βˆ— ⟨⟨Φ1 βˆ₯ Ξ£1 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© =β‡’ Conf 2 β†¦βˆ’β†’βˆ— ⟨⟨Φ2 βˆ₯ Ξ£2 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© Conf 2 β†¦βˆ’β†’βˆ— ⟨⟨Φ2 βˆ₯ Ξ£2 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© =β‡’ Conf 1 β†¦βˆ’β†’βˆ— ⟨⟨Φ1 βˆ₯ Ξ£1 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© =β‡’ Conf βˆ—0 βˆ’β†¦ β†’ ⟨⟨Φ0 βˆ₯ Ξ£0 βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ© 3. Follows by the first property of (≃) and transitivity. 4. Follows by induction on the evaluation context and the first property of (≃). Each evaluation context has a rule for constructing a larger stack, which is exactly replicated by the Build function for evaluation contexts. 5. Follows from assumptions and backwards closure. 116 6. We show ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ (Ξ¦β€², 𝑙) Β· πœ…βŸ©βŸ© IB ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ πœ…βŸ©βŸ©. The rest follows from property (5). Suppose ⟨⟨Φ βˆ— β€² β€²0 βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ (Ξ¦1, 𝑙) Β· πœ…βŸ©βŸ© βˆ’β†¦ β†’ ⟨⟨Φ0 βˆ₯ Ξ£ βˆ₯ 𝐼 βˆ₯ (Ξ¦1, 𝑙) Β· πœ…βŸ©βŸ©. The configuration takes one more step where Build (Σ′𝑉 , 𝐼 ) = I: βŸ¨βŸ¨Ξ¦β€²0 βˆ₯ Ξ£β€² βˆ₯ 𝐼 βˆ₯ (Ξ¦1, 𝑙) Β· πœ…βŸ©βŸ© β†¦βˆ’β†’ ⟨⟨(Ξ¦β€²0, 𝑙 ↦→ {πœ€, I})Ξ¦1 βˆ₯ Ξ£β€² βˆ₯ 𝐼 βˆ₯ πœ…βŸ©βŸ© By the determinism of (β†¦βˆ’β†’) and the fact that value stacks only consume introductions, we know ⟨⟨Φ0 βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ πœ…βŸ©βŸ© β†¦βˆ’β†’βˆ— βŸ¨βŸ¨Ξ¦β€²0 βˆ₯ Ξ£β€² βˆ₯ 𝐼 βˆ₯ πœ…βŸ©βŸ©. By reflexivity and that 𝐼 and Ξ£β€² cannot reference anything in the extended heap, we know ⟨⟨(Ξ¦β€²0, 𝑙 →↦ {{Ξ£β€², 𝐼 }})Ξ¦1 βˆ₯ Ξ£β€² βˆ₯ 𝐼 βˆ₯ πœ…βŸ©βŸ© IB βŸ¨βŸ¨Ξ¦β€² β€²0 βˆ₯ Ξ£ βˆ₯ 𝐼 βˆ₯ πœ…βŸ©βŸ©. Backwards closure of IB yields ⟨⟨Φ0 βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ (Ξ¦1, 𝑙) Β· πœ…βŸ©βŸ© IB ⟨⟨Φ0 βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ πœ…βŸ©βŸ©. The other direction follows with a similar determinism reasoning with the fact that value stacks only consume introductions. We conclude by IB βŠ† (≃). β–‘ 117 CHAPTER VII A MODEL OF TYPES OVER THE CBPVS MACHINE This chapter is a revision the appendix of Closure Conversion in Little Pieces [53] co-authored with Paul Downen and Zena M. Ariola. The proof structure is authored by Zachary J. Sullivan under the guidance of Paul Downen. We would like to know that our equational theory for CBPVS with closures is indeed reified by our CBPVS machine, especially since our call-by-name, call-by-value, and call-by-need approaches to closures rests on compiling the languages to CBPVS first. Specifically, we would like to show not only that the theory is sound with respect to the CBPVS machine (Theorem 7.1), but also that the abstract closures in the theory have a meaningful impact on the machine (Theorem 7.2) which we call the adequacy of closure conversion. This, we will do by constructing a semantic model over the CBPVS machine, which we will denote Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 . Like the syntactic equational and typing rules, semantic equality should be reflexive, transitive, symmetric, and compatible; in other words, it should be a congruence relation. The semantic model should imply that 𝑀 and 𝑁 are observationally equivalent in the machine. And since it is defined over the machine, we should be able to discuss the impact of closure constructed equalities on the machine. Such a model over an abstract machine or any other form of operational semantics is not an uncommon approach to proving correctness of compiler transformations, proving type safety (e.g. type-preserving mutable state [2]), normalization of programs (e.g. simply-typed call-by-need with control is normalizing [35]), and many other properties about the runtime system. What makes this work unique is that we wish to combine the following: 118 – our operational semantics is a delayed substitution semantics so that closures are visible sub-components, – our operational semantics includes a memoizing heap, – our operational semantics is stack based, and – we are interested in equational theories which contain non-computational axioms like πœ‚. The main structure of our model follows the ⊀⊀-closure approach of Pitts [45]. That is, we base our model on two families of relations defined inductively over the types in our language: the first is over computational units and the other is over stacks. Such an approach handles both the stack-based operational semantics and aids in reasoning about πœ‚ axioms. To handle delayed substitutions as we saw in Chapter 3, computational units are closed pairs of computational expressions and the local environment that they need to run. To handle the memoizing heap, these two families of relations are extended to Kripke relations, where the world is the heap which they depend on and an accessible world is a heap extended with new cells. After defining these two families of relations, we will define exactly the notion of semantic equivalence upon it. 7.1 Logical Relations We base our relations on the notion of observational equivalent configurations from the previous chapter (Definition 6.3). We wish to construct a relation on the expressions in CBPVS that have the same behavior when placed in a configuration. For instance, two computations 𝑀 and 𝑁 should be related in R when they produce observationally equivalence configurations in an empty machine: (𝑀, 𝑁 ) ∈ R iff βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝑀 βˆ₯ β˜…βŸ©βŸ© ≃ βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝑁 βˆ₯ β˜…βŸ©βŸ© 119 Since our typing rules and equational theory works over open terms, our logical relation ought to as well. Usually, this is done by developing a notion of related environments for a typing environment Ξ“ and then substituting thereafter to get closed expressions. In our context, however, substitution is delayed in the operational semantics. Ignoring for now the memoizing heap, we have relations over closures of local environments and computations like the following: ((Σ𝑙 , 𝑀), (Ξ£π‘Ÿ , 𝑁 )) ∈ R iff βŸ¨βŸ¨πœ€ βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β˜…βŸ©βŸ© ≃ βŸ¨βŸ¨πœ€π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ β˜…βŸ©βŸ© Such a relation is now open for expressions 𝑀 and 𝑁 , but they are still for top- level programs in the sense that they occur in the empty stack. For our model to be compatible, we must be able to bury these related expressions within any context. Of course, stacks can vary across machine configurations like computations expressions; imagine, for example, that we push a differently closure converted expression on the stack. Thus, our relations should consider an additional relation on stacks: ((Σ𝑙 , 𝑀), (Ξ£π‘Ÿ , 𝑁 )) ∈ R iff βˆ€(𝐾𝑙 , πΎπ‘Ÿ ) ∈ K . βŸ¨βŸ¨πœ€ βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨πœ€ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩ This approach to constructing relations is referred to as bi-orthogonality [35, 17, 16]. For each type, we will have a notion of stack and expression relations; the two different notions of relations will depend on each other. Since values and shared values are built into machine values and shared values before being placed on the stack making them closed, the relation on stacks does not need to be paired with a local environment. Note that since expressions paired with an environment and stacks may have free heap locations, these relations must be closed by a notion of heap as well. We include 120 them in the relations as well: ((Φ𝑙 , Σ𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ R iff βˆ€((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ K . βŸ¨βŸ¨Ξ¦π‘™ βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩ See that the related stacks are paired with a heap; this is because stacks may have free heap locations like local environments. Thus, we have arrive at the final structure of the relations that we will use to model types. Of course, shared computations are runnable as well, so we generalize from the exposition thus far. Definition 7.1 (Expression and Stack Relations). An expression relation is a relation P βŠ† (Heap Γ— Mach. Env. Γ— Computable Exp.)2 such that the machine environment closes over the free variables of computable expression and the heap closes over the free locations of the machine environment. A stack relation is a relation K βŠ† (Heap Γ— Stack)2 such that the heap closes over the free locations of the stack. Our logical relations should be closedwhenever we replace the current heapwith one in the future. For instance, if (Φ𝑙 , Σ𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ R are related computations that are stored within thunks in the heap, then they should still be related when we perform an update to the heap Φ𝑙 . Heap updates are frequent in shared code. We define precisely the notion of future heap as the following: Definition 7.2 (Accessible Heap). Ξ¦β€² βŠ’ Ξ¦ iff for any division (Ξ¦0, 𝑙 ↦→ {Ξ£, 𝑅})Ξ¦1 of Ξ¦, we know Ξ¦β€² is (Ξ¦β€²0, 𝑙 ↦→ {Ξ£, 𝑅})Ξ¦β€²1 such that Ξ¦β€²0 βŠ’ Ξ¦0 and Ξ¦β€²1 βŠ’ Ξ¦1. Proposition 7.1. (Heap, βŠ’) is an antisymmetric preorder. 121 Closing relations over a preorder captures the idea of a Kripke relation. We take the pair of heaps (Φ𝑙 ,Ξ¦π‘Ÿ ) to be a world and say that a relation has a Kripke property if it is closed under any accessible world. Definition 7.3 (Kripke Relation). A relation R is a Kripke relation if and only if Ξ¦β€² βŠ’ Ξ¦ , 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Φ𝑙 , 𝐴), (Ξ¦ β€² β€²π‘Ÿ , 𝐡)) ∈ R implies ((Ξ¦ , 𝐴), (Ξ¦π‘Ÿ , 𝐡)) ∈ R. We have a similar𝑙 definition for triples. Note that, Kripke logical relations for operational semantics with a heap are not new. In previous approaches like that of Ahmed et al. [4], we see that the world is modeled with a single heap typing among other things. Here, it is important that we have a part of the world for each side of the relation; this is because laws like πœ’ show that thunks in the heap may be evaluated at different times, but still be related. This property appears to be unique to our shared evaluation setting. To build up our logical relations, we define orthogonality operations CompRel and StackRelx over relations for computable expressions and stacks. The former operationwill give us all of the computations that when combined with the related stacks in StackRel will produce observationally equivalent configurations; similarly for the latter definition. Definition 7.4 (Kripke Orthogonal Operations). P = {((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) | βˆ€Ξ¦β€² βŠ’ Ξ¦ β€² β€² ′𝑙 𝑙 .βˆ€Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ .βˆ€((Ξ¦ , Σ𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ P .𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑃 βˆ₯ 𝐾 β€² 𝑙 π‘Ÿ 𝑙 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑄 βˆ₯ πΎπ‘Ÿ ⟩⟩} Kx = {((Φ𝑙 , Σ𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) | βˆ€Ξ¦β€² βŠ’ Φ𝑙 .βˆ€Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ .βˆ€((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€², πΎπ‘Ÿ )) ∈ K .𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑃 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑄 βˆ₯ 𝐾𝑙 π‘Ÿ ⟩⟩} These orthogonal operations have important qualities necessary for us to use them for our logical relations. First, they construct Kripke relations for arbitrary expression 122 x x and stack relations. Second, they are both contravariant. Third, their double application is an inclusion. And fourth, their triple application is equal to single application. Proposition 7.2 (Orthogonal Relations are Kripke Relations). For any P and K , P and Kx are Kripke relations. Proof. Given Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and some ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ P . ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 P is shown by considering some Ξ¦β€²β€² βŠ’ Ξ¦β€², Ξ¦β€²β€² β€² β€²β€² β€²β€² 𝑙 𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ and ((Ξ¦ , Σ𝑙 , 𝑃), (Ξ¦π‘Ÿ , Σ𝑙 π‘Ÿ , 𝑄)) ∈ P and then show βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 βˆ₯ 𝑃 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑄 βˆ₯ πΎπ‘Ÿ ⟩⟩. This follows from the property𝑙 of ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ P since Ξ¦β€²β€² βŠ’ Φ𝑙 by transitivity, Ξ¦β€²β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ by transitivity also, and𝑙 ((Ξ¦β€²β€², Ξ£ ′′𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ P.𝑙 The proof follows similarly for the second conjunct. β–‘ Proposition 7.3 (Orthogonal Inclusion). For Kripke relations P and K , P βŠ† P x and K βŠ† Kx . Proof. Considering an arbitrary pair ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ K , we must show that it is also inKx . Thus, consider further some Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² βŠ’ Ξ¦ β€² β€² x 𝑙 π‘Ÿ π‘Ÿ π‘Ÿ , and ((Ξ¦ , Σ𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ K ,𝑙 we must show βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑃 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑄 βˆ₯ πΎπ‘Ÿ ⟩⟩. This follows from the property𝑙 of ((Ξ¦β€², Σ𝑙 , 𝑃), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ Kx with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€² β€² β€²π‘Ÿ , and ((Ξ¦ , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ K𝑙 𝑙 𝑙 𝑙 (closed under accessible worlds). The first proposition is proved in a similar manner. β–‘ Proposition 7.4 (Orthogonal Contravariance). For Kripke relations P, Pβ€², K , and Kβ€², – P βŠ† Pβ€² implies P βŠ‡ Pβ€² . – K βŠ† Kβ€² implies Kx βŠ‡ Kβ€²x. Proof. Given P βŠ† Pβ€² and ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦ β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ P , we prove ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ P , by considering further some Ξ¦β€² βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², Σ𝑙 , 𝑃), (Φ′𝑙 𝑙 π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ P: 123 x x x x x x x x x x x ((Ξ¦β€², Σ𝑙 , 𝑃), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ Pβ€², by P βŠ† Pβ€².𝑙 ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ Pβ€² , by closure over future worlds.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑃 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑄 βˆ₯ πΎπ‘Ÿ ⟩⟩, by the property of Pβ€² with worlds Ξ¦β€² βŠ’ Φ′𝑙 𝑙 𝑙 and Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ and the expressions ((Ξ¦β€², Ξ£ β€² ′𝑙 𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ P . β–‘ Proposition 7.5 (Triple Orthogonal Elimination). For Kripke relations P and K , P = P x and Kx = Kx x. Proof. First, considering an arbitrary ((Φ𝑙 , Σ𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ Kx, we must show that the triple is inKx x. This follows by double orthogonal inclusion on the Kripke relation. Note that Kx is a Kripke relation because K is. Second, from (( xΦ𝑙 , Σ𝑙 , 𝑃), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ Kx , we must show that the pair is inKx; that is, βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑃 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€² β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑄 βˆ₯ πΎπ‘Ÿ ⟩⟩ for any Ξ¦ βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and𝑙 𝑙 ((Ξ¦β€², 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ K . By double orthogonal inclusion with the Kripke relation K , we𝑙 know that ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€² , 𝐾 )) ∈ Kxπ‘Ÿ π‘Ÿ . Thus, we may conclude this case by the property of𝑙 (( xΦ𝑙 , Σ𝑙 , 𝑃), (Ξ¦ x β€² β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑄)) ∈ K with Ξ¦ βŠ’ Φ𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 ), (Φ′𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ Kx .𝑙 𝑙 The second part of this proposition follows in a similar manner. β–‘ Without further ado, our logical relation definitions of types is presented in Figure 7.1. Since value types require no reduction, we do not need to make use of the orthogonal operations in order to specify related elements of a type. The interesting case for this work is that of machine values of type π‘ˆ 𝜏 , since abstract closures will have this type. Indeed, this relation is simple since abstract closures areβ€”by designβ€” the exact objects that the abstract machine will generate at runtime. Thus, it does not matter here whether the closure was captured via compilation or at runtime; we merely 124 x x x x x x x x x x x ValJ𝐡K = {((Φ𝑙 , b), (Ξ¦π‘Ÿ , b))} ValJπ‘ˆ 𝜏K = {((Φ𝑙 , {πœπ‘™ , force β†’ 𝑀}), (Ξ¦π‘Ÿ , {πœπ‘Ÿ , force β†’ 𝑁 })) | ((Φ𝑙 , Σ𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏K} ValJ𝜏 βŠ— 𝜎K = {((Φ𝑙 , ⟨V𝑙 ,Wπ‘™βŸ©), (Ξ¦π‘Ÿ , ⟨Vπ‘Ÿ ,Wπ‘Ÿ ⟩)) | ((Φ𝑙 ,V𝑙 ), (Ξ¦π‘Ÿ ,Vπ‘Ÿ )) ∈ ValJ𝜏K ∧ ((Φ𝑙 ,W𝑙 ), (Ξ¦π‘Ÿ ,Wπ‘Ÿ )) ∈ ValJ𝜎K} ValJ?Μƒ? 𝜏K = {((Φ𝑙 , box V), (Ξ¦π‘Ÿ , boxW)) | (Run(Φ𝑙 ,V), Run(Ξ¦π‘Ÿ ,W)) ∈ SharedJ𝜏K} Run(Ξ¦, 𝑙) = (Ξ¦, (πœ€, 𝑙/π‘Ž), π‘Ž) where Run(Ξ¦, I) = (Ξ¦, πœ€, I) ElimJ𝜏 β†’ 𝜎K = {((Φ𝑙 ,β–‘ V Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘W Β· πΎπ‘Ÿ )) | ((Φ𝑙 ,V), (Ξ¦π‘Ÿ ,W)) ∈ ValJ𝜏K ∧ ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜎K} CompJ𝜏 β†’ 𝜎K = ElimJ𝜏 β†’ 𝜎Kx StackJ𝜏 β†’ 𝜎K = CompJ𝜏 β†’ 𝜎K ElimJ𝜏 & 𝜎K = {((Φ𝑙 ,β–‘.fst Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘.fst Β· πΎπ‘Ÿ )) | ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K} βˆͺ {((Φ𝑙 ,β–‘.snd Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘.snd Β· πΎπ‘Ÿ )) | ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜎K} CompJ𝜏 & 𝜎K = ElimJ𝜏 & 𝜎Kx StackJ𝜏 & 𝜎K = CompJ𝜏 & 𝜎K IntroJ𝐹 𝜏K = {((Φ𝑙 , Σ𝑙 , ret 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , retπ‘Š )) | ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜏K} StackJ𝐹 𝜏K = IntroJ𝐹 𝜏K CompJ𝐹 𝜏K = StackJ𝐹 𝜏Kx ElimJ𝐹 𝜏K = {((Φ𝑙 ,β–‘.eval Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘.eval Β· πΎπ‘Ÿ )) | ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K} CompJ𝐹 𝜏K = ElimJ𝐹 𝜏Kx StackJ𝐹 𝜏K = CompJ𝐹 𝜏K IntroJ𝐹 𝜏K = {((Φ𝑙 , Σ𝑙 , val 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , valπ‘Š )) | ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜏K} VStackJ𝐹 𝜏K = IntroJ𝐹 𝜏K ∩ {((Φ𝑙 ,K𝑙 ), (Ξ¦π‘Ÿ ,Kπ‘Ÿ ))} SharedJ𝐹 𝜏K = VStackJ𝐹 𝜏Kx StackJ𝐹 𝜏K = SharedJ𝐹 𝜏K ElimJπ‘ˆ 𝜏K = {((Φ𝑙 ,β–‘.enter Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ )) | ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K} ValJπ‘ˆ 𝜏K = ElimJπ‘ˆ 𝜏Kx ∩ {((Φ𝑙 , Σ𝑙 ,𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,π‘Š ))} VStackJπ‘ˆ 𝜏K = ValJπ‘ˆ 𝜏K ∩ {((Φ𝑙 ,K𝑙 ), (Ξ¦π‘Ÿ ,Kπ‘Ÿ ))} SharedJπ‘ˆ 𝜏K = VStackJπ‘ˆ 𝜏Kx StackJπ‘ˆ 𝜏K = SharedJπ‘ˆ 𝜏K EnvJΞ“K = {((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) | (βˆ€π‘₯ :𝜏 ∈ Ξ“. ((Φ𝑙 , π‘₯ [Σ𝑙 ]), (Ξ¦π‘Ÿ , π‘₯ [Ξ£π‘Ÿ ])) ∈ ValJ𝜏K) ∧ (βˆ€π‘Ž:𝜏 ∈ Ξ“. ((Φ𝑙 , Σ𝑙 , π‘Ž), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , π‘Ž)) ∈ SharedJ𝜏K)} Figure 7.1. CBPVS Logical Relations 125 x x x x x x x x check that the environment and computation pairs are in CompJ𝜏K. For each computable type in general, we begin with a base definition of either their introduction or elimination forms and build up the rest of the relation with the orthogonal operations. Whereas the computation types are built from only the double orthogonal of the base definition, the shared computation types are built from more applications of the orthogonal operations. For instance, the ValJπ‘ˆ 𝜏K relation is the orthogonal of ElimJπ‘ˆ 𝜏K restricted to values. And we take the orthogonal of that for VStackJπ‘ˆ 𝜏K but restrict it to value stacks. These extra steps are essential for capturing both memoization and πœ‚ laws within the same relation. At the end of Figure 7.1, we include a relation on typing environments Ξ“. It says that related environments will have related variables. For shared variables, we must consider running the variables since they can either point to a value in the local environment, an unevaluated thunk, or an evaluated thunk. Proposition 7.6 (Logical Relations are Kripke Relations). – For any computation type 𝜏 , CompJ𝜏K is a Kripke relation. – For any shared type 𝜏 , SharedJ𝜏K is a Kripke relation. – For any value type 𝜏 , ValJ𝜏K is a Kripke relation. – For any type environment Ξ“, EnvJΞ“K is a Kripke relation. These in addition to their sub-components. Proof. By mutual induction on the structure of types: Case 𝐡: Considering Ξ¦β€² βŠ’ Ξ¦ ′𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Φ𝑙 , b), (Ξ¦π‘Ÿ , b)) ∈ ValJ𝐡K, ((Ξ¦β€², b), (Ξ¦β€²π‘Ÿ , b)) βˆˆπ‘™ 𝑙 ValJ𝐡K follows trivially by definition. 126 Case 𝜏 βŠ— 𝜎 : Considering future heaps Ξ¦β€² βŠ’ Ξ¦ ′𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Φ𝑙 , ⟨V𝑙 ,Wπ‘™βŸ©), (Ξ¦π‘Ÿ , ⟨Vπ‘Ÿ ,Wπ‘Ÿ ⟩)) βˆˆπ‘™ ValJ𝜏 βŠ— 𝜎K. By definition, we know that ((Φ𝑙 ,V𝑙 ), (Ξ¦π‘Ÿ ,Vπ‘Ÿ )) ∈ ValJ𝜏K and also that ((Φ𝑙 ,W𝑙 ), (Ξ¦π‘Ÿ ,Wπ‘Ÿ )) ∈ ValJ𝜏K. From the inductive hypotheses, we know that ((Ξ¦β€²,V ′𝑙 ), (Ξ¦π‘Ÿ ,Vπ‘Ÿ )) ∈ ValJ𝜏K and ((Ξ¦β€²,W𝑙 ), (Ξ¦β€²π‘Ÿ ,Wπ‘Ÿ )) ∈ ValJ𝜏K. By definition, we𝑙 𝑙 may conclude that ((Ξ¦β€², ⟨V𝑙 ,Wπ‘™βŸ©), (Ξ¦β€²π‘Ÿ , ⟨Vπ‘Ÿ ,Wπ‘Ÿ ⟩)) ∈ ValJ𝜏 βŠ— 𝜎K.𝑙 Caseπ‘ˆ 𝜏 : Considering the future heaps Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and that𝑙 ((Φ𝑙 , {Σ𝑙 , force β†’ 𝑀}) , (Ξ¦π‘Ÿ , {Σ𝑙 , force β†’ 𝑁 })) ∈ ValJπ‘ˆ 𝜏K. By definition, ((Φ𝑙 , Σ𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏K. By the inductive hypothesis, ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏K. Therefore, we may conclude this case by𝑙 definition. Case ?Μƒ? 𝜏 : Given Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Φ𝑙 , box V), (Ξ¦π‘Ÿ , boxW)) ∈ ValJ?Μƒ? 𝜏K.𝑙 (Run(Φ𝑙 ,V), Run(Ξ¦π‘Ÿ ,W)) ∈ SharedJ𝜏K follows by definition. By the inductive hypothesis, we know that (Run(Ξ¦β€²,V), Run(Ξ¦β€²π‘Ÿ ,W)) ∈ SharedJ𝜏K. Thus, by𝑙 definition, ((Ξ¦β€², box V), (Ξ¦β€²π‘Ÿ , boxW)) ∈ ValJ?Μƒ? 𝜏K.𝑙 Case 𝜏 : Similar to the cases above, we prove that IntroJ𝐹 𝜎K and ElimJπ‘ˆ 𝜎K using the inductive hypothesis. The rest of the relations are constructed with orthogonal 127 operations, which are Kripke relations. Note that the restrictions do not pose any problem for proving the Kripke property. Case 𝜏 : Similar to the cases for shared types. Case Ξ“: Follows because shared and value types are Kripke relations. β–‘ Proposition 7.7 (Shared Logical Relation Inclusion Properties). Forπ‘ˆ 𝜏 , ElimJπ‘ˆ 𝜏K βŠ† VStackJπ‘ˆ 𝜏K βŠ† StackJπ‘ˆ 𝜏K and ValJπ‘ˆ 𝜏K βŠ† SharedJπ‘ˆ 𝜏K. For 𝐹 𝜏 , IntroJ𝐹 𝜏K βŠ† SharedJ𝐹 𝜏K and VStackJ𝐹 𝜏K βŠ† StackJ𝐹 𝜏K Proof. Given ((Φ𝑙 ,β–‘.enter Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ ))∈ElimJπ‘ˆ 𝜏K, we must show that the pair is also in VStackJπ‘ˆ 𝜏K. By definition, this is to show the pair is ValJπ‘ˆ 𝜏K restricted to value stacks. Note that these stacks are syntactically value stacks. Thus, consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², Σ𝑙 ,𝑉 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ ,π‘Š )) ∈ ValJπ‘ˆ 𝜏K:𝑙 𝑙 By definition, ((Ξ¦β€², Σ𝑙 ,𝑉 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ ,π‘Š )) ∈ ElimJπ‘ˆ 𝜏Kx.𝑙 ((Ξ¦β€²,β–‘.enter Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ )) ∈ ElimJπ‘ˆ 𝜏K, by the closure over future heaps.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉 βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ π‘Š βˆ₯ β–‘.enter Β· πΎπ‘Ÿ ⟩⟩, by the property of the𝑙 related values with the eliminations in the worlds Ξ¦β€² βŠ’ Ξ¦β€² and Ξ¦β€² β€² 𝑙 𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ . Considering an arbitrary ((Φ𝑙 ,K𝑙 ), (Ξ¦π‘Ÿ ,Kπ‘Ÿ )) ∈ VStackJπ‘ˆ 𝜏K, we must show that the pair is also in StackJπ‘ˆ 𝜏K. By definition, this is to show the pair is SharedJπ‘ˆ 𝜏K . Thus, consider some Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² βŠ’ Ξ¦ , and ((Ξ¦β€², Ξ£ β€² 𝑙 𝑙 π‘Ÿ π‘Ÿ 𝑙 𝑙 , 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) ∈ SharedJπ‘ˆ 𝜏K: 128 x x By definition, ((Ξ¦β€², Σ𝑙 , 𝑅), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) ∈ VStackJπ‘ˆ 𝜏Kx.𝑙 ((Ξ¦β€²,K𝑙 ), (Ξ¦β€²π‘Ÿ ,K𝑙 π‘Ÿ )) ∈ VStackJπ‘ˆ 𝜏K, by closure over future heaps. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑆 βˆ₯ Kπ‘Ÿ ⟩⟩), by the property of the related expressions𝑙 with the related shared stacks in the worlds Ξ¦β€² βŠ’ Ξ¦β€² and Ξ¦β€²π‘Ÿ βŠ’ Φ′𝑙 𝑙 π‘Ÿ . Considering an arbitrary ((Φ𝑙 , Σ𝑙 ,𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,π‘Š )) ∈ ValJπ‘ˆ 𝜏K, we must show that the pair is also in SharedJπ‘ˆ 𝜏K. By definition, this is to show the pair is VStackJπ‘ˆ 𝜏Kx. Thus, consider some Ξ¦β€² βŠ’ Ξ¦ β€² β€² β€² 𝑙 𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦ ,K𝑙 ), (Ξ¦π‘Ÿ ,Kπ‘Ÿ ) ∈ VStackJπ‘ˆ 𝜏K:𝑙 By definition, ((Ξ¦β€²,K ), (Φ′𝑙 π‘Ÿ ,Kπ‘Ÿ ) ∈ ValJπ‘ˆ 𝜏K .𝑙 ((Ξ¦β€², Ξ£ ,𝑉 ), (Φ′𝑙 π‘Ÿ , Ξ£π‘Ÿ ,π‘Š )) ∈ ValJπ‘ˆ 𝜏K, by closure over future heaps.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ ′𝑙 βˆ₯ 𝑉 βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯π‘Š βˆ₯ Kπ‘Ÿ ⟩⟩, by the property of the related value stacks𝑙 with the related values in the worlds Ξ¦β€² βŠ’ Ξ¦β€² and Ξ¦β€²π‘Ÿ βŠ’ Φ′𝑙 𝑙 π‘Ÿ . The proofs for 𝐹 𝜏 relations follow in a similar manner. β–‘ Proposition 7.8 (Orthogonal Completeness of the Logical Relations). – For any computable type 𝜏 , both CompJ𝜏K = StackJ𝜏K and StackJ𝜏Kx = CompJ𝜏K. – For any shared type 𝜏 , both SharedJ𝜏K = StackJ𝜏K and StackJ𝜏Kx βŠ‡ SharedJ𝜏K. Proof. By induction on the structure of the computable type. Herein, we use triple orthogonal elimination liberally; this we may do because all semantic types are Kripke relations. 129 x x x Case 𝜏 β†’ 𝜎 : CompJ𝜏 β†’ 𝜎K =defn. ElimJ𝜏 β†’ 𝜎Kx x =tri. orth. ElimJ𝜏 β†’ 𝜎Kx =defn. CompJ x𝜏 β†’ 𝜎K = xdefn. StackJ𝜏 β†’ 𝜎K and StackJ𝜏 β†’ 𝜎K =defn. CompJ𝜏 β†’ 𝜎K . Case 𝜏 & 𝜎 follows in a similar manner to the case above since they were both defined via their eliminations. Case 𝐹 𝜏 : CompJ𝐹 𝜏K =defn. StackJ𝐹 𝜏Kx and StackJ𝐹 𝜏K =defn. IntroJ𝐹 𝜏K = xtri. orth. IntroJ𝐹 𝜏K =defn. StackJ𝐹 𝜏Kx =defn. CompJ𝐹 𝜏K . Case 𝐹 𝜏 : SharedJ𝐹 𝜏K =defn. VStackJ𝐹 𝜏Kx βŠ† xcontra. StackJ𝐹 𝜏K and StackJ𝐹 𝜏K =defn. SharedJ𝐹 𝜏K 130 x x x x x x x x x Caseπ‘ˆ 𝜏 : SharedJπ‘ˆ 𝜏K = VStackJπ‘ˆ 𝜏Kx βŠ† xcontra. StackJπ‘ˆ 𝜏K and StackJπ‘ˆ 𝜏K =defn. SharedJπ‘ˆ 𝜏K β–‘ Lemma 7.1 (Related Heap Extension). (Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ) ∈ EnvJΞ“K and ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆)) ∈ SharedJ𝜏K imply (((Φ𝑙 , π‘™π‘Ž ↦→ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅}), (Σ𝑙 , π‘™π‘Ž/π‘Ž)) , ((Ξ¦π‘Ÿ , π‘™π‘Ž ↦→ {Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆}), (Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž))) ∈ EnvJΞ“, π‘Ž:𝜏K. Proof. We only need to show that (((Φ𝑙 , π‘™π‘Ž →↦ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅}), (Σ𝑙 , π‘™π‘Ž/π‘Ž), π‘Ž) , ((Ξ¦π‘Ÿ , π‘™π‘Ž →↦ {Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆}), (Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž), π‘Ž)) ∈ SharedJ𝜏K given our assumption and the definition of EnvJΞ“, π‘Ž:𝜏K. By definition for any shared type, it is enough to show that the pair is in VStackJ𝜏Kx. Thus, suppose Ξ¦β€² βŠ’ (Φ𝑙 , π‘™π‘Ž →↦𝑙 {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅}), Ξ¦β€²π‘Ÿ βŠ’ (Ξ¦π‘Ÿ , π‘™π‘Ž →↦ {Ξ£π‘Ÿ Build β€² β€²πœ (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆}), and ((Ξ¦ ,K𝑙 ), (Φ𝑙 π‘Ÿ ,Kπ‘Ÿ )) ∈ VStackJ𝜏K: By the definition of heap extension, we know Ξ¦β€² = (Ξ¦β€²0, π‘™π‘Ž →↦ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅})Ξ¦ β€² 𝑙 𝑙 𝑙1 and Ξ¦β€²π‘Ÿ = (Ξ¦β€²π‘Ÿ0, π‘™π‘Ž →↦ {Ξ£ β€² β€²π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆})Ξ¦π‘Ÿ1. Additionally, we know Ξ¦ 0 βŠ’ Φ𝑙 and𝑙 Ξ¦β€²π‘Ÿ0 βŠ’ Ξ¦π‘Ÿ . 131 x On the left side, there is the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ 𝑙 𝑙 βˆ₯ π‘Ž βˆ₯ Kπ‘™βŸ©βŸ© β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ Build (Ξ£ , 𝜍 ) βˆ₯ 𝑅 βˆ₯ (Ξ¦β€² 𝑙0 𝑙 𝜍 𝑙 𝑙 1, 𝑙𝑙 π‘Ž) Β· Kπ‘™βŸ©βŸ© And similarly on the right. ((Ξ¦β€²0, Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅)𝑙 , (Ξ¦β€²π‘Ÿ0, Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆)) ∈ SharedJ𝜏K follows from our initial assumption with closure over accessible heaps. βŸ¨βŸ¨Ξ¦β€²0 βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 𝑙 , πœπ‘™ ) βˆ₯ 𝑅 βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ0 βˆ₯ Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ) βˆ₯ 𝑆 βˆ₯ Kπ‘Ÿ ⟩⟩ by the the property of the related expressions immediately above with Ξ¦β€² βŠ’ Ξ¦β€² 𝑙 𝑙0, Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ0, and ((Ξ¦β€²,K𝑙 ), (Ξ¦β€²π‘Ÿ ,Kπ‘Ÿ )) ∈ VStackJ𝜏K.𝑙 βŸ¨βŸ¨Ξ¦β€²0 βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ) βˆ₯ 𝑅 βˆ₯ Kπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€²0 βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ) βˆ₯ 𝑅 βˆ₯ (Ξ¦ β€² 1, π‘™π‘Ž) Β· Kπ‘™βŸ©βŸ©π‘™ 𝑙 by the memoizing closure property of (≃). We have a similar fact on the right side. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 𝑙 , πœπ‘™ ) βˆ₯ π‘Ž βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ) βˆ₯ π‘Ž βˆ₯ Kπ‘Ÿ ⟩⟩ by the closure properties of (≃). β–‘ 132 Lemma 7.2 (Build then Run). If ((Φ𝑙 , Σ𝑙 ,𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,π‘Š )) ∈ SharedJ𝜏K, then (Run(Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), Run(Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ SharedJ𝜏K. Proof. Follows from definitions. Note that the run function places locations in the smallest environment necessary. β–‘ What follows are three lemmas that behave similarly to show that inlining, garbage collection, and substitutions yield logically related expressions. They describe properties of our delayed substitution semantics; that we may eagerly substitute values and not change the observable behavior and that we may remove unused variables. Note that this second property is implied by the first. Lemma 7.3 (Contextual Inlining). Given any typed substitutable value Ξ“ ⊒ 𝑉 : 𝜏 and related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we know the following: Ξ“, π‘₯ :𝜏 ⊒ 𝐢 [π‘₯] : 𝜎 ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯),𝐢 [π‘₯]), (Ξ¦π‘Ÿ , (Ξ£π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝑉 )/π‘₯),𝐢 [𝑉 ])) ∈ CompJ𝜎K Ξ“, π‘₯ :𝜏 ⊒ 𝐢 [π‘₯] : 𝜎 ((Φ𝑙 , Build𝑉 ((Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯),𝐢 [π‘₯])), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝐢 [𝑉 ]))) ∈ ValJ𝜎K Ξ“, π‘₯ :𝜏 ⊒ 𝐢 [π‘₯] : 𝜎 ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯),𝐢 [π‘₯]), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,𝐢 [𝑉 ])) ∈ SharedJ𝜎K Ξ“, π‘₯ :𝜏 ⊒ 𝐢 [π‘₯] : 𝜎 (((Φ𝑙 , 𝑙 ↦→ Build𝑉 (Σ𝑙 ,𝑉 )), (Σ𝑙 , 𝑙/π‘₯),𝐢 [π‘₯]), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,𝐢 [𝑉 ])) ∈ SharedJ𝜎K Ξ“, π‘₯ :𝜏 ⊒ 𝜍 [π‘₯] : Ξ“β€² ((Φ𝑙 , Build𝜍 ((Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝜍 [π‘₯])), (Ξ¦π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , 𝜍 [𝑉 ]))) ∈ EnvJΞ“β€²K Proof. By mutual induction on the typing derivations. β–‘ 133 Lemma 7.4 (Garbage Collection). Given related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we know the following: Ξ“ ⊒ 𝑀 : 𝜎 ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜎K Ξ“ ⊒ 𝑉 : 𝜎 ((Φ𝑙 , Build𝑉 ((Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯),𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝑉 ))) ∈ ValJ𝜎K Ξ“ ⊒ 𝑅 : 𝜎 ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅)) ∈ SharedJ𝜎K Ξ“ ⊒ 𝑅 : 𝜎 (((Φ𝑙 , 𝑙 ↦→ Build𝑉 (Σ𝑙 ,𝑉 )), (Σ𝑙 , 𝑙/π‘₯), 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅)) ∈ SharedJ𝜎K Ξ“ ⊒ 𝜍 : Ξ“β€² ((Φ𝑙 , Build𝜍 ((Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝜍)), (Ξ¦π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , 𝜍))) ∈ EnvJΞ“β€²K Proof. By mutual induction on the typing derivations. β–‘ Corollary 7.1 (Substitutive Inlining). Given any typed substitutable value Ξ“ ⊒ 𝜍 : Ξ“β€² and ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we know the following: ΓΓ′ ⊒ 𝑀 : 𝜎 ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝜍])) ∈ CompJ𝜎K ΓΓ′ βŠ’π‘Š :𝜎 ((Φ𝑙 , Build𝑉 (Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍),π‘Š )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š [𝜍]))) ∈ ValJ𝜎K ΓΓ′ ⊒ 𝑅 : 𝜎 ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝜍])) ∈ SharedJ𝜎K ΓΓ′ ⊒ 𝜍 β€² : Ξ“β€²β€² ((Φ𝑙 , Build𝜍 (Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝜍 β€²)), (Ξ¦ β€²π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , 𝜍 [𝜍]))) ∈ EnvJΞ“β€²β€²K Lemma 7.5 (Building Related Stacks from Eval Contexts). If ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, ((Φ𝑙 , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K, Build𝐾 (Φ𝑙 , Σ𝑙 , 𝐸, 𝐾𝑙 ) = (Ξ¦β€², Ξ£β€², 𝐾′), and𝑙 𝑙 𝑙 Build𝐾 (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝐸, 𝐾 ) = (Ξ¦β€² , Ξ£β€² , πΎβ€²π‘Ÿ π‘Ÿ π‘Ÿ π‘Ÿ ), then ((Ξ¦β€², 𝐾′), (Ξ¦β€²π‘Ÿ , πΎβ€²π‘Ÿ )) ∈ StackJ𝜏K.𝑙 𝑙 Proof. By induction on the evaluation context. β–‘ 134 7.2 Semantic Equality Semantic equivalence is built from the logical relations by considering related instantiations of the type environment and then having related expressions for the type. Definition 7.5 (Semantic Equality). Ξ“ ⊨ 𝑀 β‰ˆ : def𝑁 𝜏 = βˆ€((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. ((Φ𝑙 , Σ𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏K def Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : 𝜏 = βˆ€((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. ((Φ𝑙 , Σ𝑙 , 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) ∈ SharedJ𝜏K def Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : 𝜏 = βˆ€((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜏K def Ξ“ ⊨ πœπ‘™ β‰ˆ 𝜍 β€²π‘Ÿ : Ξ“ = βˆ€((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. ((Φ𝑙 , Build𝜍 (Σ𝑙 , πœπ‘™ )), (Ξ¦π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ))) ∈ EnvJΞ“β€²K From here, we prove compatibility propositions that align with all of the typing rules for CBPVS in Figure 5.6. These propositions will be enough to show that our semantic equivalence relations are indeed a partial semantic congruence relation; partial in the sense that expressions need to be well-typed. This sections ends with a proof of the fundamental lemma that syntactic equivalence implies semantic equivalence; the proof of which has a case for each axiom of our theory. Proposition 7.9 (Compatibility var). If π‘₯ :𝜏 ∈ Ξ“, then Ξ“ ⊨ π‘₯ β‰ˆ π‘₯ : 𝜏 . Proof. Consider an arbitrary π‘₯ :𝜏 ∈ Ξ“ and ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. By the definition of EnvJΞ“K, ((Φ𝑙 , π‘₯ [Σ𝑙 ]), (Ξ¦π‘Ÿ , π‘₯ [Ξ£π‘Ÿ ])) ∈ ValJ𝜏K. Finally, from the definition of Build𝑉 , we may conclude that ((Φ𝑙 , Build𝑉 (Σ𝑙 , π‘₯)), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ , π‘₯))) ∈ ValJ𝜏K. β–‘ Proposition 7.10 (Compatibility b). Ξ“ ⊨ b β‰ˆ b : 𝐡. Proof. If ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, then, immediately from definitions, we know ((Φ𝑙 , Build𝑉 (Σ𝑙 , b)), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ , b))) ∈ ValJ𝐡K. β–‘ 135 Proposition 7.11 (Compatibility →𝐼 ). If Ξ“, π‘₯ :𝜏 ⊨ 𝑀 β‰ˆ 𝑁 : 𝜎 , then Ξ“ ⊨ πœ†π‘₯. 𝑀 β‰ˆ πœ†π‘₯ . 𝑁 : 𝜏 β†’ 𝜎 . Proof. Considering an arbitrary Ξ“, π‘₯ :𝜏 ⊨ 𝑀 β‰ˆ 𝑁 : 𝜎 , we show Ξ“ ⊨ πœ†π‘₯. 𝑀 β‰ˆ πœ†π‘₯. 𝑁 : 𝜏 β†’ 𝜎 by further supposing arbitrary environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K then showing ((Φ𝑙 , Σ𝑙 , πœ†π‘₯ . 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , πœ†π‘₯ . 𝑁 )) ∈ CompJ𝜏 β†’ 𝜎K. By definition, this is equivalent to showing that the pair is in ElimJ𝜏 β†’ 𝜎Kx. Thus, let us consider an arbitrary Ξ¦β€² βŠ’ Φ𝑙 ,𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , ((Ξ¦β€²,β–‘ V Β· 𝐾𝑙 ), (Φ′𝑙 π‘Ÿ ,β–‘W Β· πΎπ‘Ÿ )) ∈ ElimJ𝜏 β†’ 𝜎K: By definition, we have that ((Ξ¦β€²,V), (Ξ¦β€²π‘Ÿ ,W)) ∈ ValJ𝜏K and ((Ξ¦β€², 𝐾𝑙 ), (Φ′𝑙 𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜎K. On the left, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ πœ†π‘₯. 𝑀 βˆ₯ β–‘ V Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ and similarly on the right side. ((Ξ¦β€², (Σ𝑙 ,V/π‘₯)), (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,W/π‘₯))) ∈ EnvJΞ“, π‘₯ :𝜏K by definition with our assumed related𝑙 environments. Note that ((Ξ¦β€², Ξ£ ), (Φ′𝑙 π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K because the relation is closed𝑙 over accessible worlds. ((Ξ¦β€², (Σ𝑙 ,V/π‘₯), 𝑀), (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,W/π‘₯), 𝑁 )) ∈ CompJ𝜎K from our initial assumption about𝑙 the function bodies with the related extended environments above. And by Proposition 7.8 with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² β€² β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦ , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜎K, we𝑙 𝑙 𝑙 have βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ ,W/π‘₯ βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩.𝑙 With our closure properties of (≃), we have βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ πœ†π‘₯ .𝑀 βˆ₯ β–‘ V Β·πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯𝑙 πœ†π‘₯. 𝑁 βˆ₯ β–‘W Β· πΎπ‘Ÿ ⟩⟩. 136 β–‘ Proposition 7.12 (Compatibility →𝐸). If Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜎 β†’ 𝜏 and Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜎 , then Ξ“ ⊨ 𝑀 𝑉 β‰ˆ 𝑁 π‘Š : 𝜏 . Proof. Given Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜎 β†’ 𝜏 and Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜎 , we show Ξ“ ⊨ 𝑀 𝑉 β‰ˆ 𝑁 π‘Š : 𝜏 by considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 , 𝑀 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 π‘Š )) ∈ CompJ𝜏K. Since this by Proposition 7.8 is equivalent to showing that the pair is in StackJ𝜏Kx, we further consider an arbitrary Ξ¦β€² βŠ’ Ξ¦ β€² 𝑙 𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 By our initial assumptions with the related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K𝑙 (using the Kripke property to advance to a future world), we may conclude both that ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜎 β†’ 𝜏K and𝑙 ((Ξ¦β€², Build β€² 𝑙 𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜎K. On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 𝑉 βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑀 βˆ₯ β–‘ Build (Ξ£ ,𝑉 ) Β· 𝐾 ⟩⟩ 𝑙 𝑙 𝑉 𝑙 𝑙 Similarly on the right side. ((Ξ¦β€²,β–‘ Build𝑉 (Σ𝑙 ,𝑉 ) Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘ Build𝑉 (Σ𝑙 ,π‘Š ) Β· 𝐾𝑙 )) ∈ ElimJ𝜎 β†’ 𝜏K by definition.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘ Build𝑉 (Σ𝑙 ,𝑉 ) Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ β–‘ Build𝑉 (Ξ£π‘Ÿ ,π‘Š ) Β· πΎπ‘Ÿ ⟩⟩ by the𝑙 definition of CompJ𝜎 β†’ 𝜏K with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , and the above related stacks.𝑙 𝑙 By our closure properties of (≃), we may conclude that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ β€² 𝑙 𝑙 βˆ₯ 𝑀 𝑉 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 π‘Š βˆ₯ πΎπ‘Ÿ ⟩⟩. 137 β–‘ Proposition 7.13 (Compatibility &𝐼 ). If Ξ“ ⊨ 𝑀𝑙 β‰ˆ π‘€π‘Ÿ : 𝜏 and Ξ“ ⊨ 𝑁𝑙 β‰ˆ π‘π‘Ÿ : 𝜎 , then Ξ“ ⊨ {fst β†’ 𝑀𝑙 ; snd β†’ 𝑁𝑙 } β‰ˆ {fst β†’ π‘€π‘Ÿ ; snd β†’ π‘π‘Ÿ } : 𝜏 & 𝜎 . Proof. Given Ξ“ ⊨ 𝑀𝑙 β‰ˆ 𝑀𝑙 : 𝜏 and Ξ“ ⊨ π‘π‘Ÿ β‰ˆ π‘π‘Ÿ : 𝜎 , we prove Ξ“ ⊨ {fst β†’ 𝑀𝑙 ; snd β†’ 𝑁𝑙 } β‰ˆ {fst β†’ π‘€π‘Ÿ ; snd β†’ π‘π‘Ÿ } : 𝜏 & 𝜎 by considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving that ((Φ𝑙 , Σ𝑙 , {fst β†’ 𝑀𝑙 ; snd β†’ 𝑁𝑙 }) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , {fst β†’ π‘€π‘Ÿ ; snd β†’ π‘π‘Ÿ })) ∈ CompJ𝜏 & 𝜎K. By definition, this is equivalent to showing that the pair is in ElimJ𝜏 & 𝜎Kx. Thus, considering an arbitrary Ξ¦β€² βŠ’ Φ𝑙 ,Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and element of ElimJ𝜏 & 𝜎K there are two𝑙 cases to consider: Case ((Ξ¦β€²,β–‘.fst Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.fst Β· πΎπ‘Ÿ )):𝑙 ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K follows from the definition of ElimJ𝜏 & 𝜎K.𝑙 By the first of our initial assumptions with ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K𝑙 (closed with accessible worlds), ((Ξ¦β€², Σ𝑙 , 𝑀𝑙 ), (Φ′𝑙 π‘Ÿ , Ξ£π‘Ÿ , 𝑀𝑙 )) ∈ CompJ𝜏K follows. Proposition 7.8 with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , the related stacks above, we have that𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀𝑙 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ π‘€π‘Ÿ βˆ₯ πΎπ‘Ÿ ⟩⟩.𝑙 On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀𝑙 ; snd β†’ 𝑁𝑙 } βˆ₯ β–‘.fst Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀𝑙 βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© Similarly on the right. By the closure properties of (≃), we have βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀𝑙 ; snd β†’ 𝑁𝑙 } βˆ₯𝑙 β–‘.fst Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ {fst β†’ π‘€π‘Ÿ ; snd β†’ π‘π‘Ÿ } βˆ₯ β–‘.fst Β· πΎπ‘Ÿ ⟩⟩. 138 Case ((Ξ¦β€²,β–‘.snd Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.snd Β· 𝐾𝑙 π‘Ÿ )): This follows in a similar manner to the case above by using the second initial assumption. β–‘ Proposition 7.14 (Compatibility &𝐸1). If Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 & 𝜎 , then Ξ“ ⊨ 𝑀.fst β‰ˆ 𝑁 .fst : 𝜏 . Proof. Given Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 & 𝜎 , we show Ξ“ ⊨ 𝑀.fst β‰ˆ 𝑁 .fst : 𝜏 by first considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 , 𝑀.fst), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 .fst)) ∈ CompJ𝜏K. Using Proposition 7.8, this is the same as showing that the pair is in StackJ𝜏Kx. Thus, consider further an arbitrary Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ ((Ξ¦ , 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 𝑙 ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏 & 𝜎K, by our initial assumption with the related𝑙 environments (note closure over accessible worlds). On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀.fst βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· 𝐾𝑙 π‘™βŸ©βŸ© And similarly on the right. ((Ξ¦β€²,β–‘.fst ·𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.fst Β·πΎπ‘Ÿ )) ∈ StackJ𝜏 & 𝜎K by definition. This and Proposition 7.8𝑙 with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , and ((Ξ¦β€², Ξ£ ′𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏 & 𝜎K yields that𝑙 𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ β–‘.fst Β· πΎπ‘Ÿ ⟩⟩.𝑙 By the closure properties of (≃), we have βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀.fst βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Σ𝑙 π‘Ÿ βˆ₯ 𝑁 .fst βˆ₯ πΎπ‘Ÿ ⟩⟩. β–‘ 139 Proposition 7.15 (Compatibility &𝐸2). If Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 & 𝜎 , then Ξ“ ⊨ 𝑀.snd β‰ˆ 𝑁 .snd : 𝜎 . Proof. Follows in a similar manner to compatibility for &𝐸1. β–‘ Proposition 7.16 (Compatibility βŠ—πΌ ). If Ξ“ ⊨ 𝑉𝑙 β‰ˆ π‘‰π‘Ÿ : 𝜏 and Ξ“ ⊨ π‘Šπ‘™ β‰ˆ π‘Šπ‘Ÿ : 𝜎 , then Ξ“ ⊨ βŸ¨π‘‰π‘™ ,π‘Šπ‘™βŸ© β‰ˆ βŸ¨π‘‰π‘Ÿ ,π‘Šπ‘Ÿ ⟩ : 𝜏 βŠ— 𝜎 . Proof. Given Ξ“ ⊨ 𝑉𝑙 β‰ˆ 𝑉𝑙 : 𝜏 and Ξ“ βŠ¨π‘Šπ‘Ÿ β‰ˆπ‘Šπ‘Ÿ : 𝜎 , we show Ξ“ ⊨ βŸ¨π‘‰π‘™ ,π‘Šπ‘™βŸ© β‰ˆ βŸ¨π‘‰π‘Ÿ ,π‘Šπ‘Ÿ ⟩ : 𝜏 βŠ— 𝜎 by considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then showing that ((Φ𝑙 , Build𝑉 (Σ𝑙 , βŸ¨π‘‰π‘™ ,π‘Šπ‘™βŸ©)) , (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ , βŸ¨π‘‰π‘Ÿ ,π‘Šπ‘Ÿ ⟩))) ∈ ValJ𝜏 βŠ— 𝜎K. Next, Build𝑉 (Σ𝑙 , βŸ¨π‘‰π‘™ ,π‘Šπ‘™βŸ©) = ⟨Build𝑉 (Σ𝑙 ,𝑉𝑙 ), Build𝑉 (Σ𝑙 ,π‘Šπ‘™ )⟩ and similarly for the right side, follow by definition of building values. From our first initial assumption with the assumed related environments, we know ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉𝑙 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘‰π‘Ÿ ))) ∈ ValJ𝜏K and similarly for the other sub-component. We can conclude by the definition of ValJ𝜏 βŠ— 𝜎K. β–‘ Proposition 7.17 (Compatibility βŠ—πΈ). If Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜎 βŠ— 𝜌 and Ξ“, π‘₯ :𝜎,𝑦:𝜌 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , then Ξ“ ⊨ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑃} β‰ˆ caseπ‘Š of {⟨π‘₯,π‘¦βŸ© β†’ 𝑄} : 𝜏 . Proof. Given that Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : 𝜎 βŠ— 𝜌 and Ξ“, π‘₯ :𝜎,𝑦:𝜌 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , Ξ“ ⊨ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑃} β‰ˆ caseπ‘Š of {⟨π‘₯,π‘¦βŸ© β†’ 𝑄} : 𝜏 is true by considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 , case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , caseπ‘Š of {⟨π‘₯,π‘¦βŸ© β†’ 𝑁 })) ∈ CompJ𝜏K. We have chosen 𝜏 to be a computation type, 𝑃 = 𝑀 , and 𝑄 = 𝑁 , but the proof follows the same for shared types since we have the same transitions. By Proposition 7.8, this is 140 the same as showing that the pair is in StackJ𝜏Kx. Thus, we suppose an arbitrary Ξ¦β€² βŠ’ Ξ¦ , 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 By the first initial assumption with the related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) βˆˆπ‘™ EnvJΞ“K (using the Kripke property to advance to a future world), we know ((Ξ¦β€², Build 𝑙 𝑉 (Σ𝑙 ,𝑉 )) , (Ξ¦β€²π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜎 βŠ— 𝜌K. By this definition, we also know Build𝑉 (Σ𝑙 ,𝑉 ) = ⟨V,V⟩ and Build𝑉 (Ξ£π‘Ÿ ,π‘Š ) = ⟨W,Wβ€²βŸ© where the sub-parts are related in world Ξ¦β€² and Ξ¦β€²π‘Ÿ respectively.𝑙 On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘₯,Vβ€²/𝑦 βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ And similarly on the right side. ((Ξ¦β€², (Σ𝑙 ,V/π‘₯,Vβ€²/𝑦))𝑙 , (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,W/π‘₯,Wβ€²/𝑦))) ∈ EnvJΞ“, π‘₯ :𝜎,𝑦:𝜌K, by definition. And thus, wemay use our second initial assumptionwith these related environments to conclude that ((Ξ¦β€², (Σ𝑙 ,V/π‘₯,Vβ€²/𝑦), 𝑀),𝑙 (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,W/π‘₯,Wβ€²/𝑦), 𝑁 )) ∈ CompJ𝜏K. 141 By Proposition 7.8, the property of our related stacks in combination with Ξ¦β€² βŠ’ Ξ¦β€², 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , these related computations, gives us βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ ,V/π‘₯,V′𝑙 /𝑦 βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£ β€²π‘Ÿ ,W/π‘₯,W /𝑦 βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩. We may conclude βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀} βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯𝑙 caseπ‘Š of {⟨π‘₯,π‘¦βŸ© β†’ 𝑁 } βˆ₯ πΎπ‘Ÿ ⟩⟩ by the closure rules for (≃). β–‘ Proposition 7.18 (Compatibility π‘ˆπΌ ). If Ξ“ ⊨ πœπ‘™ β‰ˆ 𝜍 β€²π‘Ÿ : Ξ“ and ΓΓ′ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 , then Ξ“ ⊨ {πœπ‘™ , force β†’ 𝑀} β‰ˆ {πœπ‘Ÿ , force β†’ 𝑁 } : π‘ˆ 𝜏 . Proof. Given Ξ“ ⊨ 𝜍 β‰ˆ 𝜍 : Γ′𝑙 π‘Ÿ and ΓΓ′ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 , we show that Ξ“ ⊨ {πœπ‘™ , force β†’ 𝑀} β‰ˆ {πœπ‘Ÿ , force β†’ 𝑁 } : π‘ˆ 𝜏 by considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K then proving ((Φ𝑙 , Build𝑉 (Σ𝑙 , {πœπ‘™ , force β†’ 𝑀})) , (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ , {πœπ‘Ÿ , force β†’ 𝑁 }))) ∈ ValJπ‘ˆ 𝜏K. By the definition of building machine values and ValJπ‘ˆ 𝜏K, this can be proved by showing ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑀) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑁 )) ∈ CompJ𝜏K. Since we already know ((Φ𝑙 , Build𝜍 (Σ𝑙 , πœπ‘™ )), (Ξ¦π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ))) ∈ EnvJΞ“β€²K from our first initial assumption with the environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, the definition of EnvJΓΓ′K allows us to conclude ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ )), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ))) ∈ EnvJΓΓ′K. We may then conclude this proof by our second initial assumption with these extended, related environments. β–‘ Proposition 7.19 (Compatibility π‘ˆπΈ). If Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : π‘ˆ 𝜏 , then Ξ“ ⊨ 𝑉.force β‰ˆπ‘Š.force : 𝜏 . 142 Proof. Given Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : π‘ˆ 𝜏 , showing Ξ“ ⊨ 𝑉.force β‰ˆπ‘Š.force : 𝜏 requires considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 ,𝑉.force), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,π‘Š.force)) ∈ CompJ𝜏K. By Proposition 7.8, it suffices to show that the pair is in StackJ𝜏Kx. Thus, consider some Ξ¦β€² βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 𝑙 By our initial assumption with the related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K𝑙 (using the Kripke property), we have ((Ξ¦β€², Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦β€²π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) βˆˆπ‘™ ValJπ‘ˆ 𝜏K. By the definition of building values and ValJπ‘ˆ 𝜏K, Build𝑉 (Σ𝑙 ,𝑉 ) = {Ξ£β€², force β†’ 𝑀} and Build𝑉 (Ξ£π‘Ÿ ,π‘Š ) = {Ξ£β€²π‘Ÿ , force β†’ 𝑁 } where we know the𝑙 computations are related, i.e. ((Ξ¦β€², Ξ£β€², 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£β€²π‘Ÿ , 𝑁 )) ∈ CompJ𝜏K.𝑙 𝑙 On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉.force βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£β€² βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ 𝑙 And similarly for the right side. And by Proposition 7.8, the property of the related stacks with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² β€² 𝑙 𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and the related computations above, we can conclude that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£β€² βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ 𝑙 π‘Ÿ βˆ₯ Ξ£β€²π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩. We may conclude that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉.force βˆ₯ 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ π‘Š.force βˆ₯ πΎπ‘Ÿ ⟩⟩ by the𝑙 closure properties of (≃). β–‘ Proposition 7.20 (Compatibility 𝐹𝐼 ). If Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : 𝜏 , then Ξ“ ⊨ ret 𝑉 β‰ˆ retπ‘Š : 𝐹 𝜏 . Proof. Given Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜏 , showing Ξ“ ⊨ ret 𝑉 β‰ˆ retπ‘Š : 𝐹 𝜏 requires considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 , ret 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , retπ‘Š )) ∈ 143 CompJ𝐹 𝜏K. By the definition of CompJ𝐹 𝜏K and double orthogonal inclusion, it is enough to show that this triple is in IntroJ𝐹 𝜏K. This follows by combining our initial assumption with the related environments. β–‘ Proposition 7.21 (Compatibility 𝐹𝐸). If Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝐹 𝜎 and Ξ“, π‘₯ :𝜎 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , then Ξ“ ⊨ 𝑀 to π‘₯ in 𝑃 β‰ˆ 𝑁 to π‘₯ in 𝑄 : 𝜏 . Proof. Given Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝐹 𝜎 and Ξ“, π‘₯ :𝜎 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , showing Ξ“ ⊨ 𝑀 to π‘₯ in 𝑃 β‰ˆ 𝑁 to π‘₯ in 𝑄 : 𝜏 requires considering some ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving that ((Φ𝑙 , Σ𝑙 , 𝑀 to π‘₯ in 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 to π‘₯ in 𝑆)) ∈ SharedJ𝜏K. We pick 𝜏 to be a shared computation, 𝑃 = 𝑅, and 𝑄 = 𝑆 , but the proof follows the same for computations types since we have the same transitions. By Proposition 7.8, it suffices to show that the pair StackJ𝜏Kx. Thus, consider an arbitrary Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜏K: On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 to π‘₯ in 𝑅 βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝑅) Β· πΎπ‘™βŸ©βŸ©π‘™ And similarly on the right. ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝐹 𝜏K by our first initial assumption with the𝑙 environments ((Ξ¦β€², Ξ£ ′𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (closure under accessible worlds).𝑙 ((Ξ¦β€², (Σ𝑙 ,β–‘ to π‘₯ in 𝑅 Β· 𝐾𝑙 )), (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,β–‘ to π‘₯ in 𝑆) Β· πΎπ‘Ÿ )) ∈ StackJ𝐹 𝜏K, by considering an𝑙 arbitrary Ξ¦β€²β€² βŠ’ Ξ¦β€², Ξ¦β€²β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , and ((Ξ¦β€²β€², Ξ£β€², ret 𝑉 ), (Ξ¦β€²β€² β€²π‘Ÿ , Ξ£π‘Ÿ , retπ‘Š )) ∈ IntroJ𝐹 𝜏K:𝑙 𝑙 𝑙 𝑙 ((Ξ¦β€²β€², Build (Ξ£β€²,𝑉 )), (Φ′′𝑉 π‘Ÿ , Build (Σ′𝑉 π‘Ÿ ,π‘Š ))) ∈ ValJ𝜏K, by the definition of𝑙 𝑙 IntroJ𝐹 𝜏K. 144 On the left side, there is the transition βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€² βˆ₯ ret 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝑅) Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ 𝑙 βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 , Build𝑉 (Ξ£β€²,𝑉 )/π‘₯ βˆ₯ 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ 𝑙 And similarly on the right. By the definition of related environments: ((Ξ¦β€²β€², (Σ𝑙 , Build𝑉 (Ξ£β€²,𝑉 )/π‘₯)),𝑙 𝑙 (Ξ¦β€²β€²π‘Ÿ , (Ξ£ β€²π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š )/π‘₯))) ∈ EnvJΞ“, π‘₯ :𝜎K. Note ((Ξ¦β€²β€², Σ𝑙 ), (Ξ¦β€²β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K by closure under accessible worlds.𝑙 ((Ξ¦β€²β€², (Σ𝑙 , Build𝑉 (Ξ£β€²,𝑉 )/π‘₯), 𝑅)𝑙 𝑙 , (Ξ¦β€²β€²π‘Ÿ , (Ξ£π‘Ÿ , Build𝑉 (Ξ£β€²π‘Ÿ ,π‘Š )/π‘₯), 𝑆)) ∈ SharedJ𝜏K, follows by the second initial assumption with the related environments immediately above. By Proposition 7.8 on ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K with Ξ¦β€²β€² βŠ’ Ξ¦β€², Ξ¦β€²β€² ′𝑙 𝑙 𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and the related shared expressions above, we have βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£ , Build (Ξ£β€²,𝑉 )/π‘₯ βˆ₯ 𝑙 𝑙 𝑉 𝑙 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ , Build (Σ′𝑉 π‘Ÿ ,π‘Š )/π‘₯ βˆ₯ 𝑆 βˆ₯ πΎπ‘Ÿ ⟩⟩. βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€² βˆ₯ ret 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝑅) Β· 𝐾 β€²β€² β€²π‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ retπ‘Š βˆ₯𝑙 𝑙 (Ξ£π‘Ÿ ,β–‘ to π‘₯ in 𝑆) Β· πΎπ‘Ÿ ⟩⟩ by the closure properties of (≃). βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝑅) Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ (Ξ£π‘Ÿ ,β–‘ to π‘₯ in 𝑆) Β· πΎπ‘Ÿ ⟩⟩ by𝑙 Proposition 7.8 with the related computation and stacks above with Ξ¦β€² βŠ’ Ξ¦β€² and 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ . 145 Finally, βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 to π‘₯ in 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 to π‘₯ in 𝑆 βˆ₯ 𝐾𝑙 π‘Ÿ ⟩⟩ by the closure properties of (≃). β–‘ Proposition 7.22 (Compatibility svar). If π‘Ž:𝜏 ∈ Ξ“, then Ξ“ ⊨ π‘Ž β‰ˆ π‘Ž : 𝜏 . Proof. Consider an arbitrary π‘Ž:𝜏 ∈ Ξ“ and ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. We may conclude ((Φ𝑙 , Σ𝑙 , π‘Ž), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , π‘Ž)) ∈ SharedJ𝜏K by the definition of EnvJΞ“K. β–‘ Proposition 7.23 (Compatibility H ). If Ξ“ ⊒ 𝜍 β‰ˆ 𝜍 : Γ′𝑙 π‘Ÿ , ΓΓ′ ⊨ 𝑅 β‰ˆ 𝑆 : 𝜏 and Ξ“, π‘Ž:𝜏 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜎 , then Ξ“ ⊨ {πœπ‘™ , 𝑅} memo π‘Ž in 𝑃 β‰ˆ {πœπ‘Ÿ , 𝑆} memo π‘Ž in 𝑄 : 𝜎 . Proof. Considering some arbitrary Ξ“ ⊒ πœπ‘™ β‰ˆ 𝜍 β€²π‘Ÿ : Ξ“ , ΓΓ′ ⊨ 𝑅 β‰ˆ 𝑆 : 𝜏 , and Ξ“, π‘Ž:𝜏 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜎 , we show Ξ“ ⊨ {πœπ‘™ , 𝑅} memo π‘Ž in 𝑃 β‰ˆ {πœπ‘Ÿ , 𝑆} memo π‘Ž in 𝑄 : 𝜎 by considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and showing ((Φ𝑙 , Σ𝑙 , {πœπ‘™ , 𝑅} memo π‘Ž in𝑀) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , {πœπ‘Ÿ , 𝑆} memo π‘Ž in 𝑁 )) ∈ CompJ𝜎K. Note that we have picked 𝜎 to be a computation type 𝜎 , 𝑃 = 𝑀 , and𝑄 = 𝑁 ; the proof will follow similarly for a shared type since the same transitions exist. By Proposition 7.8, it is sufficient to show that the pair is in the set StackJ𝜎Kx. Note that for shared types, we show the pair is in VStackJ𝜎Kx by definition. Thus, consider some Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² 𝑙 𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜎K:𝑙 On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {πœπ‘™ , 𝑅} memo π‘Ž in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€², 𝑙 →↦ {Ξ£ Build (Ξ£ , 𝜍 ), 𝑅} βˆ₯ Ξ£ , 𝑙/π‘Ž βˆ₯ 𝑀 βˆ₯ 𝐾 ⟩⟩ 𝑙 𝑙 𝜍 𝑙 𝑙 𝑙 𝑙 And similarly on the right. 146 ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆)) ∈ SharedJ𝜏K by the first and second initial assumption together with our assumed related environments. Using Lemma 7.1, we know (((Ξ¦β€², π‘™π‘Ž ↦→ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅}), (Σ𝑙 , π‘™π‘Ž/π‘Ž))𝑙 , ((Ξ¦β€²π‘Ÿ , π‘™π‘Ž →↦ {Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆}), (Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž))) ∈ EnvJΞ“, π‘Ž:𝜏K. By the third initial assumption with the environment above, (((Ξ¦β€², π‘™π‘Ž ↦→ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅}), (Σ𝑙 , π‘™π‘Ž/π‘Ž), 𝑀)𝑙 , ((Ξ¦β€²π‘Ÿ , π‘™π‘Ž ↦→ {Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆}), (Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž), 𝑁 )) ∈ CompJ𝜎K. βŸ¨βŸ¨Ξ¦β€², 𝑙 →↦ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅} βˆ₯ Σ𝑙 , 𝑙/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , 𝑙 ↦→ {Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆} βˆ₯𝑙 Ξ£π‘Ÿ , 𝑙/π‘Ž βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩, by Proposition 7.8 on ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K𝑙 with the future heaps (Ξ¦β€², 𝑙 →↦ {Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑅}) βŠ’ Ξ¦β€² and (Φ′𝑙 𝑙 π‘Ÿ , 𝑙 ↦→ {Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑆}) βŠ’ Ξ¦β€²π‘Ÿ , and the related computations immediately above. (For shared types, we apply the property of the related shared expressions to the value stacks.) βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {πœπ‘™ , 𝑅} memo π‘Ž in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Σ𝑙 π‘Ÿ βˆ₯ {πœπ‘Ÿ , 𝑆} memo π‘Ž in 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩ by the closure properties of (≃). β–‘ Proposition 7.24 (Compatibility ?Μƒ?𝐼 ). If Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : 𝜏 , Ξ“ ⊨ box 𝑉 β‰ˆ boxπ‘Š : ?Μƒ? 𝜏 . 147 Proof. Given Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜏 , we show Ξ“ ⊨ box 𝑉 β‰ˆ boxπ‘Š : ?Μƒ? 𝜏 by considering some ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving that ((Φ𝑙 , Build𝑉 (Σ𝑙 , box 𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ , boxπ‘Š ))) ∈ ValJ?Μƒ? 𝜏K. By the definition of building, we may conclude that Build𝑉 (Σ𝑙 , box 𝑉 ) = box Build𝑉 (Σ𝑙 ,𝑉 ) and similarly for the right side. Our initial assumption with ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K allows us to conclude that ((Φ𝑙 , Σ𝑙 ,𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,π‘Š )) ∈ SharedJ𝜏K. We may conclude by the definition of ValJ?Μƒ? 𝜏K and Lemma 7.2. β–‘ Proposition 7.25 (Compatibility ?Μƒ?𝐸). If Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : ?Μƒ? 𝜎 and Ξ“, π‘Ž:𝜎 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , then Ξ“ ⊨ case 𝑉 of {box π‘Ž β†’ 𝑃} β‰ˆ caseπ‘Š of {box π‘Ž β†’ 𝑄} : 𝜏 . Proof. Given that Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : ?Μƒ? 𝜎 and Ξ“, π‘Ž:𝜎 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , we prove Ξ“ ⊨ case 𝑉 of {box π‘Ž β†’ 𝑃} β‰ˆ case π‘Š of {box π‘Ž β†’ 𝑄} : 𝜏 , by first considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then showing ((Φ𝑙 , Σ𝑙 , case𝑉 of {box π‘Ž β†’ 𝑀}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , caseπ‘Š of {box π‘Ž β†’ 𝑁 })) ∈ CompJ𝜏K. We have chosen 𝜏 to be a computation type, 𝑃 = 𝑀 , and𝑄 = 𝑁 , but the proof follows the same for shared types since we have the same transitions. By Proposition 7.8, this is the same as showing that the triple is in StackJ𝜌Kx. Thus, we suppose an arbitrary Ξ¦β€² βŠ’ Ξ¦ , 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜌K:𝑙 ((Ξ¦β€², Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦β€²π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ?Μƒ? 𝜎K by the first initial assumption𝑙 with the related environments ((Ξ¦β€², Ξ£ ), (Φ′𝑙 π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (making use of the𝑙 Kripke property). By this definition, we also know Build𝑉 (Σ𝑙 ,𝑉 ) = box V and Build𝑉 (Ξ£π‘Ÿ ,π‘Š ) = boxW with the property that (Run(Ξ¦β€²,V), Run(Φ′𝑙 π‘Ÿ ,W)) ∈ SharedJ𝜏K. 148 On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case 𝑉 of {box π‘Ž β†’ 𝑀} βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ 𝑙 𝑙 ,V/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© And similarly on the right side. ((Ξ¦β€², (Σ𝑙 ,V/π‘Ž)), (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,W/π‘Ž))) ∈ EnvJΞ“, π‘Ž:𝜎K, by definition and that running them𝑙 gives related shared expressions. And thus, we may use our second initial assumption with these related environments to conclude that ((Ξ¦β€², (Σ𝑙 ,V/π‘Ž), 𝑀)𝑙 , (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,W/π‘Ž), 𝑁 )) ∈ CompJ𝜏K. By Proposition 7.8, the property of our related stacks in combination with Ξ¦β€² βŠ’ Ξ¦β€², 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , and these related computations, gives us βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ ,W/π‘Ž βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case 𝑉 of {box π‘Ž β†’ 𝑀} βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ caseπ‘Š of {box π‘Ž β†’ 𝑁 } βˆ₯𝑙 πΎπ‘Ÿ ⟩⟩ by the closure rules for (≃). β–‘ Proposition 7.26 (Compatibility π‘ˆπΌ ). If Ξ“ ⊒ πœπ‘™ β‰ˆ πœπ‘Ÿ : Ξ“β€² and ΓΓ′ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 , then Ξ“ ⊨ {πœπ‘™ , enter β†’ 𝑀} β‰ˆ {πœπ‘Ÿ , enter β†’ 𝑁 } : π‘ˆ 𝜏 . Proof. Given Ξ“ ⊒ πœπ‘™ β‰ˆ πœπ‘Ÿ : Ξ“β€² and ΓΓ′ ⊨ 𝑀 β‰ˆ 𝑁 : 𝜏 , showing Ξ“ ⊨ {πœπ‘™ , enter β†’ 𝑀} β‰ˆ {πœπ‘Ÿ , enter β†’ 𝑁 } : π‘ˆ 𝜏 requires that we consider related 149 environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and show that ((Φ𝑙 , Σ𝑙 , {πœπ‘™ , enter β†’ 𝑀}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , {πœπ‘Ÿ , enter β†’ 𝑁 })) ∈ SharedJπ‘ˆ 𝜏K. As ValJπ‘ˆ 𝜏K βŠ† SharedJπ‘ˆ 𝜏K, it will suffice to show that the triple is in ValJπ‘ˆ 𝜏K. Thus, consider an arbitrary Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² βŠ’ Ξ¦ , and ((Φ′𝑙 π‘Ÿ π‘Ÿ ,β–‘.enter Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 ElimJπ‘ˆ 𝜏K: On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ 𝑙 𝑙 βˆ₯ {πœπ‘™ , enter β†’ 𝑀} βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ) βˆ₯ 𝑀 βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© And similarly on the right. ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K, by definition.𝑙 ((Ξ¦β€², Build (Ξ£ , 𝜍 )), (Ξ¦β€² , Build (Ξ£ , 𝜍 ))) ∈ EnvJΞ“β€²K from our first initial assumption 𝑙 𝜍 𝑙 𝑙 π‘Ÿ 𝜍 π‘Ÿ π‘Ÿ with the related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (using the Kripke𝑙 property). The extended environments are related ((Ξ¦β€², Σ𝑙 Build𝑙 𝜍 (Σ𝑙 , πœπ‘™ )) , (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ))) ∈ EnvJΓΓ′K by definition. 150 ((Ξ¦β€², Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ), 𝑀)𝑙 , (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ), 𝑁 )) ∈ CompJ𝜏K from these related environments with our second initial assumption. It follows that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , πœπ‘™ ) βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ) βˆ₯ 𝑁 βˆ₯ 𝐾𝑙 π‘Ÿ ⟩⟩, by Proposition 7.8 with the related computations above in the worlds Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€²π‘Ÿ βŠ’π‘™ 𝑙 Ξ¦β€²π‘Ÿ , and ((Ξ¦β€², 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {πœπ‘™ , enter β†’ 𝑀} βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ {πœπ‘Ÿ , enter β†’ 𝑁 } βˆ₯𝑙 β–‘.enter Β· πΎπ‘Ÿ ⟩⟩, by the closure properties of (≃). β–‘ Proposition 7.27 (Compatibilityπ‘ˆπΈ). If Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : π‘ˆ 𝜏 , then Ξ“ ⊨ 𝑅.enter β‰ˆ 𝑆.enter : 𝜏 . Proof. Given Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : π‘ˆ 𝜏 , showing that Ξ“ ⊨ 𝑅.enter β‰ˆ 𝑆.enter : 𝜏 requires considering further the related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 , 𝑅.enter), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑆 .enter)) ∈ CompJ𝜏K. By Proposition 7.8, it suffices to show that the pair is in the set StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ ,𝑙 and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅.enter βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ©π‘™ And similarly on the right. ((Ξ¦β€²,β–‘.enter Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.enter Β· 𝐾𝑙 π‘Ÿ )) ∈ StackJπ‘ˆ 𝜏K, by definition. 151 ((Ξ¦β€², Σ𝑙 , 𝑅), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) ∈ SharedJπ‘ˆ 𝜏K, by the initial assumption with the related𝑙 environments ((Ξ¦β€², Ξ£ ), (Φ′𝑙 π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (closure under accessible worlds).𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 βˆ₯ β–‘.enter Β· πΎπ‘Ÿ ⟩⟩ by the property of𝑙 ((Ξ¦β€², Σ𝑙 , 𝑅), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) ∈ SharedJπ‘ˆ 𝜏K with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² βŠ’ Ξ¦β€²π‘Ÿ π‘Ÿ , and ((Ξ¦β€²,β–‘.enter ·𝑙 𝑙 𝑙 𝑙 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ )) ∈ StackJπ‘ˆ 𝜏K. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅.enter βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑆.enter βˆ₯ πΎπ‘Ÿ ⟩⟩ by the closure properties of𝑙 (≃). β–‘ Proposition 7.28 (Compatibility 𝐹𝐼 ). If Ξ“ ⊨ 𝑉 β‰ˆπ‘Š : 𝜏 , then Ξ“ ⊨ val 𝑉 β‰ˆ valπ‘Š : 𝐹 𝜏 . Proof. Given Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜏 , showing both Ξ“ ⊨ val 𝑉 β‰ˆ valπ‘Š : 𝐹 𝜏 and Ξ“ ⊨ val 𝑉 β‰ˆ valπ‘Š : 𝐹 𝜏 require considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. By our initial assumption with these related environments, we may conclude that ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜏K. This is enough to conclude ((Φ𝑙 , Σ𝑙 , val 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , valπ‘Š )) ∈ IntroJ𝐹 𝜏K and by the inclusion properties of, with the definitions of the relations for this type, ((Φ𝑙 , Σ𝑙 , val 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , valπ‘Š )) ∈ SharedJ𝐹 𝜏K. β–‘ Proposition 7.29 (Compatibility 𝐹𝐸). If Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : 𝐹 𝜎 and Ξ“, π‘₯ :𝜎 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , then Ξ“ ⊨ 𝑅 to π‘₯ in 𝑃 β‰ˆ 𝑆 to π‘₯ in 𝑄 : 𝜏 . Proof. Given Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : 𝐹 𝜎 and Ξ“, π‘₯ :𝜎 ⊨ 𝑃 β‰ˆ 𝑄 : 𝜏 , showing Ξ“ ⊨ 𝑅 to π‘₯ in 𝑃 β‰ˆ 𝑆 to π‘₯ in 𝑄 : 𝜏 requires considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving that ((Φ𝑙 , Σ𝑙 , 𝑅 to π‘₯ in𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑆 to π‘₯ in 𝑁 )) ∈ CompJ𝜏K. We have chosen 𝜏 to be a computation, 𝑃 = 𝑀 , and𝑄 = 𝑁 , but the proof follows the same for shared types since we have the same transitions. By Proposition 7.8, it suffices to show that the 152 pair is in StackJ𝜏Kx. Thus, consider an arbitrary Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , ((Ξ¦β€², 𝐾 ), (Φ′𝑙 π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜏K: On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 to π‘₯ in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in𝑀) Β· πΎπ‘™βŸ©βŸ©π‘™ And similarly on the right. ((Φ𝑙 , Σ𝑙 , 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) ∈ SharedJ𝐹 𝜏K by our first initial assumption with the related environments ((Ξ¦β€², Ξ£ ), (Φ′𝑙 π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (closure under accessible worlds).𝑙 ((Ξ¦β€², (Σ𝑙 ,β–‘ to π‘₯ in𝑀 Β· 𝐾𝑙 )), (Ξ¦β€²π‘Ÿ , (Ξ£π‘Ÿ ,β–‘ to π‘₯ in 𝑁 ) Β· πΎπ‘Ÿ )) ∈ VStackJ𝐹 𝜏K and thus𝑙 StackJ𝐹 𝜏Kwith the inclusion properties of the relation, by considering an arbitrary Ξ¦β€²β€² βŠ’ Ξ¦β€², Ξ¦β€²β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€²β€², Ξ£β€², val 𝑉 ), (Ξ¦β€²β€² β€²π‘Ÿ , Ξ£π‘Ÿ , valπ‘Š )) ∈ IntroJ𝐹 𝜏K:𝑙 𝑙 𝑙 𝑙 ((Ξ¦β€²β€², Build (Σ′𝑉 ,𝑉 )), (Ξ¦β€²β€², Build (Ξ£β€² ,π‘Š ))) ∈ ValJ𝜏K by the definition of IntroJ𝐹 𝜏K.𝑙 𝑙 π‘Ÿ 𝑉 π‘Ÿ On the left side, there is the transition βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€² βˆ₯ val 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in𝑀) Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 , Build𝑉 (Ξ£β€²,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ 𝑙 And similarly on the right. ((Ξ¦β€²β€², (Σ𝑙 , Build𝑉 (Ξ£β€²,𝑉 )/π‘₯))𝑙 𝑙 , (Ξ¦β€²β€²π‘Ÿ , (Ξ£π‘Ÿ , Build (Σ′𝑉 π‘Ÿ ,π‘Š )/π‘₯))) ∈ EnvJΞ“, π‘₯ :𝜎K, by definition; note ((Ξ¦β€²β€², Ξ£ ), (Φ′′𝑙 π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K by closure under accessible𝑙 worlds. 153 ((Ξ¦β€²β€², (Σ𝑙 , Build (Σ′𝑉 ,𝑉 )/π‘₯), 𝑀)𝑙 𝑙 , (Ξ¦β€²β€²π‘Ÿ , (Ξ£π‘Ÿ , Build (Σ′𝑉 π‘Ÿ ,π‘Š )/π‘₯), 𝑁 )) ∈ CompJ𝜏K, by the second initial assumption with the related environments immediately above. By Proposition 7.8 on ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K with future heaps Ξ¦β€²β€² βŠ’ Φ′𝑙 𝑙 𝑙 and Ξ¦β€²β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , and the related shared expressions immediately above allow us to conclude that βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 , Build ′𝑉 (Ξ£ ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²π‘™ 𝑙 π‘Ÿ βˆ₯ Ξ£π‘Ÿ , Build𝑉 (Ξ£β€²π‘Ÿ ,π‘Š )/π‘₯ βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩. By the closure properties of (≃), βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€² βˆ₯ val 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in𝑀) Β· πΎπ‘™βŸ©βŸ© ≃𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²β€² β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ valπ‘Š βˆ₯ (Ξ£π‘Ÿ ,β–‘ to π‘₯ in 𝑁 ) Β· πΎπ‘Ÿ ⟩⟩. By Proposition 7.8 with the related shared computation and stacks above in the world Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€² , we know βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in𝑀) ·𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑆 βˆ₯𝑙 𝑙 𝑙 (Ξ£π‘Ÿ ,β–‘ to π‘₯ in 𝑁 ) Β· πΎπ‘Ÿ ⟩⟩. Finally, βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 to π‘₯ in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑆 to π‘₯ in 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩ by the closure𝑙 properties of (≃). β–‘ Proposition 7.30 (Compatibility 𝐹𝐼 ). If Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : 𝜏 , then Ξ“ ⊨ {eval β†’ 𝑅} β‰ˆ {eval β†’ 𝑆} : 𝐹 𝜏 . Proof. Given Ξ“ ⊨ 𝑅 β‰ˆ 𝑆 : 𝜏 , we prove that Ξ“ ⊨ {eval β†’ 𝑅} β‰ˆ {eval β†’ 𝑆} : 𝐹 𝜏 by considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and proving that ((Φ𝑙 , Σ𝑙 , {eval β†’ 𝑅}), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , {eval β†’ 𝑆})) ∈ CompJ𝐹 𝜏K. 154 By definition, this is equivalent to showing that the pair is in ElimJ𝐹 𝜏Kx. Thus, considering an arbitrary Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² βŠ’ Ξ¦, and ((Φ′𝑙 π‘Ÿ ,β–‘.eval Β· 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ ,β–‘.eval Β· πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 ElimJ𝐹 𝜏K: By definition of ElimJ𝐹 𝜏K, we know ((Ξ¦β€², 𝐾𝑙 ), (Φ′𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K. By the first of our initial assumptions with related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) βˆˆπ‘™ EnvJΞ“K (closed with accessible worlds), we know ((Ξ¦β€², Σ𝑙 , 𝑅), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑆)) βˆˆπ‘™ SharedJ𝜏K. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑆 βˆ₯ πΎπ‘Ÿ ⟩⟩, by the definition of ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜏K in the worlds Ξ¦β€² βŠ’ Ξ¦β€² and Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , with the related expressions above.𝑙 𝑙 On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {eval β†’ 𝑅} βˆ₯ β–‘.eval Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ Similarly on the right. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {eval β†’ 𝑅} βˆ₯ β–‘.eval Β· 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ {eval β†’ 𝑆} βˆ₯ β–‘.eval Β· πΎπ‘Ÿ ⟩⟩, by𝑙 the closure properties of (≃). β–‘ Proposition 7.31 (Compatibility 𝐹𝐸). If Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝐹 𝜏 , then Ξ“ ⊨ 𝑀.eval β‰ˆ 𝑁 .eval : 𝜏 . Proof. Given Ξ“ ⊨ 𝑀 β‰ˆ 𝑁 : 𝐹 𝜏 , we show Ξ“ ⊨ 𝑀.eval β‰ˆ 𝑁 .eval : 𝜏 by first considering ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then proving ((Φ𝑙 , Σ𝑙 , 𝑀.eval), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑁 .eval)) ∈ SharedJ𝜏K. By definition, this is the same as showing that the pair is in VStackJ𝜏Kx. Thus, consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€²,K𝑙 ), (Ξ¦β€²π‘Ÿ ,Kπ‘Ÿ )) ∈ VStackJ𝜏K:𝑙 𝑙 155 On the left side, we have the transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀.eval βˆ₯ Kπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· Kπ‘™βŸ©βŸ©π‘™ And similarly on the right. ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝐹 𝜏K, by our initial assumption with the related𝑙 environments above (note closure over accessible worlds). ((Ξ¦β€²,K𝑙 ), (Ξ¦β€²π‘Ÿ ,Kπ‘Ÿ )) ∈ StackJ𝜏K, since VStackJ𝜏K βŠ† StackJ𝜏K.𝑙 ((Ξ¦β€²,β–‘.eval Β·K𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.eval Β·Kπ‘Ÿ )) ∈ StackJ𝐹 𝜏K by definition. This and Proposition 7.8𝑙 with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and the related computations above yields that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 𝑙 𝑙 𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· K β€²π‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ β–‘.eval Β· Kπ‘Ÿ ⟩⟩. By the closure properties of (≃), we have βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀.eval βˆ₯ Kπ‘™βŸ©βŸ©) ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 .eval βˆ₯ Kπ‘Ÿ ⟩⟩. β–‘ Proposition 7.32 (Compatibility Γ𝐼 ). Ξ“ ⊨ πœ€ β‰ˆ πœ€ : πœ€.𝐡 Proof. Since the captured environment is empty, this case holds trivially for any related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. β–‘ Proposition 7.33 (Compatibility Γ𝐼 1). If Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜏 and Ξ“ ⊨ πœπ‘™ β‰ˆ πœπ‘Ÿ : Ξ“β€², then𝐼 Ξ“ ⊨ (πœπ‘™ ,𝑉 /π‘₯) β‰ˆ (πœπ‘Ÿ ,π‘Š /π‘₯) : (Ξ“β€², π‘₯ :𝜏). Proof. Given Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜏 and Ξ“ ⊨ πœπ‘™ β‰ˆ 𝜍 β€²π‘Ÿ : Ξ“ , we show Ξ“ ⊨ (πœπ‘™ ,𝑉 /π‘₯) β‰ˆ (πœπ‘Ÿ ,π‘Š /π‘₯) : (Ξ“β€², π‘₯ :𝜏) by considering arbitrary related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K then 156 proving that ((Φ𝑙 , Build𝜍 (Σ𝑙 , (πœπ‘™ ,𝑉 /π‘₯))) , (Ξ¦π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , (πœπ‘Ÿ ,π‘Š /π‘₯)))) ∈ EnvJΞ“β€², π‘₯ :𝜏K. By our first initial assumption with the related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we know ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜏K. And by the second, ((Φ𝑙 , Build𝜍 (Σ𝑙 , πœπ‘™ )), (Ξ¦π‘Ÿ , Build𝜍 (Ξ£π‘Ÿ , πœπ‘Ÿ ))) ∈ EnvJΞ“β€²K. Considering some arbitrary 𝑦:𝜎 ∈ Ξ“β€², π‘₯ :𝜏 , there are two cases to prove depending on whether π‘₯ = 𝑦. If so, then we have the related values at hand. Otherwise, we find the related shared expressions or values by looking further back in the constructed environment. β–‘ Proposition 7.34 (Compatibility Γ𝐼 2). If Ξ“ ⊨ 𝑉 β‰ˆ π‘Š : 𝜏 and Ξ“ ⊨ 𝜍 β‰ˆ 𝜍 : Γ′𝑙 π‘Ÿ , then𝐼 Ξ“ ⊨ (πœπ‘™ ,𝑉 /π‘Ž) β‰ˆ (πœπ‘Ÿ ,π‘Š /π‘Ž) : (Ξ“β€², π‘Ž:𝜏). Proof. Follows in a similar manner to compatibility for the Γ𝐼 1 rule. ░𝐼 Proposition 7.35 (Semantic Congruence). Semantic equivalence forms a congruence relation; it is: 1. Reflexive: If Ξ“ ⊒ 𝐴 : 𝜏 then Ξ“ ⊨ 𝐴 β‰ˆ 𝐴 : 𝜏 , 2. Symmetric: If Ξ“ ⊨ 𝐴 β‰ˆ 𝐡 : 𝜏 then Ξ“ ⊨ 𝐡 β‰ˆ 𝐴 : 𝜏 , 3. Transitive: If Ξ“ ⊨ 𝐴 β‰ˆ 𝐡 : 𝜏 and Ξ“ ⊨ 𝐡 β‰ˆ 𝐢 : 𝜏 then Ξ“ ⊨ 𝐴 β‰ˆ 𝐢 : 𝜏 , and 4. Compatible: If Ξ“ ⊨ 𝐴 β‰ˆ 𝐡 : 𝜏 and Ξ“β€² ⊒ 𝐢 [𝐷] : 𝜎 for all Ξ“ ⊒ 𝐷 : 𝜏 , then Ξ“β€² ⊨ 𝐢 [𝐴] β‰ˆ 𝐢 [𝐡] : 𝜎 . Lemma 7.6 (Fundamental Lemma). If Ξ“ ⊒ 𝐴 = 𝐡 : 𝜏 , then Ξ“ ⊨ 𝐴 β‰ˆ 𝐡 : 𝜏 . Proof. By induction on the equality derivation: 157 Case 𝛽→: Ξ“ ⊒ (πœ†π‘₯ .𝑀) 𝑉 = 𝑀 [𝑉 /π‘₯] : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we show ((Φ𝑙 , Σ𝑙 , (πœ†π‘₯ .𝑀) 𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /π‘₯])) ∈ CompJ𝜏K. By Proposition 7.8, it is enough to show that the pair is in StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 ), (Φ′𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 On the left, there are the transitions: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (πœ†π‘₯. 𝑀) 𝑉 βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ πœ†π‘₯ .𝑀 βˆ₯ β–‘ Build𝑉 (Σ𝑙 ,𝑉 ) Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© Note that Ξ“ ⊒ 𝑀 : 𝜎 β†’ 𝜏 and Ξ“ ⊒ 𝑉 : 𝜎 follows from the equality. ((Ξ¦β€², (Ξ£ 𝑙 𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝑀) , (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /π‘₯])) ∈ CompJ𝜏K, by Corollary 7.1 with the related environments above (considering closure under accessible heaps). And this pair is in StackJ𝜏Kx by Proposition 7.8. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /π‘₯] βˆ₯ 𝐾𝑙 π‘Ÿ ⟩⟩ by the property of the related computations with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² βŠ’ Ξ¦β€² , and 𝑙 𝑙 π‘Ÿ π‘Ÿ ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (πœ†π‘₯ .𝑀) 𝑉 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /π‘₯] βˆ₯ πΎπ‘Ÿ ⟩⟩ by the closure𝑙 properties of (≃). Case 𝛽&1: Ξ“ ⊒ {fst β†’ 𝑀 ; snd β†’ 𝑁 }.fst = 𝑀 : 𝜏 158 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show ((Φ𝑙 , Σ𝑙 , {fst β†’ 𝑀 ; snd β†’ 𝑁 }.fst) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏K. By Proposition 7.8, it is enough to show that the pair is in StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦ β€² ′𝑙 π‘Ÿ , and ((Ξ¦ , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 On the left, there is the transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀 ; snd β†’ 𝑁 }.fst βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀 ; snd β†’ 𝑁 } βˆ₯ β–‘.fst Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© Note that Ξ“ ⊒ 𝑀 : 𝜏 follows from the equality. And by the reflexivity of (β‰ˆ) with the related environments, ((Φ𝑙 , Σ𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏K. Using Proposition 7.8, this pair is in the set StackJ𝜏Kx. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ 𝐾 β€²π‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩ follows from the property of the𝑙 related computations above with Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² βŠ’ Ξ¦ , and ((Ξ¦β€², 𝐾 ), (Φ′𝑙 π‘Ÿ π‘Ÿ 𝑙 π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜏K. The closure properties of (≃) yield that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀 ; snd β†’ 𝑁 }.fst βˆ₯𝑙 πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩. Case 𝛽&2: Ξ“ ⊒ {fst β†’ 𝑀 ; snd β†’ 𝑁 }.snd = 𝑁 : 𝜏 Follows in the same manner as the case immediately above. 159 Case π›½βŠ—: Ξ“ ⊒ case βŸ¨π‘‰ ,π‘Š ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝑃} = 𝑃 [𝑉 /π‘₯,π‘Š /𝑦] : 𝜏 Note that we prove this for the shared computation case where 𝜏 = 𝜏 and 𝑃 = 𝑅, but the proof follows in a similar manner for the computation case since the same transitions exist. Considering arbitrary related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show that ((Φ𝑙 , Σ𝑙 , case βŸ¨π‘‰ ,π‘Š ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝑅}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝑉 /π‘₯,π‘Š /𝑦])) ∈ SharedJ𝜏K. By Proposition 7.8, it is enough to show that the pair is in StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 ), (Φ′𝑙 𝑙 𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K: On the left, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case βŸ¨π‘‰ ,π‘Š ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝑅} βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ , Build (Ξ£ ,𝑉 )/π‘₯, Build (Ξ£ ,π‘Š )/𝑦 βˆ₯ 𝑅 βˆ₯ 𝐾 ⟩⟩ 𝑙 𝑙 𝑉 𝑙 𝑉 𝑙 𝑙 Note that Ξ“ ⊒ βŸ¨π‘‰ ,π‘Š ⟩ : 𝜎 βŠ— 𝜌 and Ξ“, π‘₯ :𝜎,𝑦:𝜌 ⊒ 𝑅 : 𝜏 follows from the equality. By inversion on the former, we know Ξ“ ⊒ 𝑉 : 𝜎 and Ξ“ ⊒ π‘Š : 𝜌 . Applying Corollary 7.1 with our related environments, we know ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯, Build𝑉 (Σ𝑙 ,π‘Š )/𝑦), 𝑅) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝑉 /π‘₯,π‘Š /𝑦])) ∈ SharedJ𝜏K. By Proposition 7.8, the pair is in the set StackJ𝜏Kx. 160 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ , Build (Ξ£ ,𝑉 )/π‘₯,Build (Ξ£ ,π‘Š )/𝑦 βˆ₯ 𝑅 βˆ₯ 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€² 𝑙 𝑙 𝑉 𝑙 𝑉 𝑙 𝑙 π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 [𝑉 /π‘₯,π‘Š /𝑦] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the above related expressions with Ξ¦β€² βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ ,𝑙 and ((Ξ¦β€², 𝐾 ), (Ξ¦β€² , 𝐾 )) ∈ StackJ𝜏K. 𝑙 𝑙 π‘Ÿ π‘Ÿ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case βŸ¨π‘‰ ,π‘Š ⟩ of {⟨π‘₯,π‘¦βŸ© β†’ 𝑅} βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 [𝑉 /π‘₯,π‘Š /𝑦] βˆ₯𝑙 πΎπ‘Ÿ ⟩⟩, by the backwards closure of (≃). Case π›½π‘ˆ : Ξ“ ⊒ {𝜍, force β†’ 𝑀}.force = 𝑀 [𝜍] : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must be able to show that ((Φ𝑙 , Σ𝑙 , {𝜍, force β†’ 𝑀}.force), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏K. By Proposition 7.8, it is enough to show that the pair is in StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦ , 𝐾𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 𝑙 On the left, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {𝜍, force β†’ 𝑀}.force βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍) βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ Note that Ξ“ ⊒ {𝜍, force β†’ 𝑀} : π‘ˆ 𝜏 follows from the equality. By inversion, we know Ξ“ ⊒ 𝜍 : Ξ“β€² and ΓΓ′ ⊒ 𝑀 : 𝜏 . Applying Corollary 7.1 with the assumed related environments, we know ((Φ𝑙 , Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝜍])) ∈ CompJ𝜏K. 161 By Proposition 7.8, this pair is in the set StackJ𝜏Kx. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍) βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝜍] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the related𝑙 computations above with Ξ¦β€² βŠ’ Ξ¦, Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Φ′𝑙 𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {𝜍, force β†’ 𝑀}.force βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝜍] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the𝑙 backwards closure of (≃). Case 𝛽𝐹 : Ξ“ ⊒ (ret 𝑉 ) to π‘₯ in 𝑃 = 𝑃 [𝑉 /π‘₯] : 𝜏 Note that we prove this for the computation case where 𝑃 = 𝑀 and 𝜏 = 𝜏 , but the proof follows in the same manner for shared computations since the same transitions exist. Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show that ((Φ𝑙 , Σ𝑙 , (ret 𝑉 ) to π‘₯ in𝑀) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /π‘₯])) ∈ CompJ𝜏K. By Proposition 7.8, we may just show that the pair is in the set StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ , 𝐾𝑙 )) ∈ StackJ𝜏K:𝑙 𝑙 On the left, there is the transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (ret 𝑉 ) to π‘₯ in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ ret 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in𝑀) Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ Note that Ξ“ ⊒ (ret 𝑉 ) to π‘₯ in𝑀 : 𝜏 follows from the equality. By inversion, we can conclude that Ξ“ ⊒ 𝑉 : 𝜎 and Ξ“, π‘₯ :𝜎 ⊒ 𝑀 : 𝜏 . By Corollary 7.1 with our 162 related environments, we know ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝑀) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /π‘₯])) ∈ CompJ𝜏K. And further, Proposition 7.8 says that the pair is in the set StackJ𝜏Kx. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , Build (Ξ£ ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘‰ 𝑙 𝑙 π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /π‘₯] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the𝑙 property of the related computations above with Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and𝑙 ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (ret 𝑉 ) to π‘₯ in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /π‘₯] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the closure𝑙 properties of (≃). Case 𝛽?Μƒ? : Ξ“ ⊒ case (box 𝑉 ) of {box π‘Ž β†’ 𝑃} = 𝑃 [𝑉 /π‘Ž] : 𝜏 Note that we prove this for the computation case where 𝜏 = 𝜏 and 𝑃 = 𝑀 , but the proof follows in a similar manner for the computation case since the same transitions exist. Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show that ((Φ𝑙 , Σ𝑙 , case (box 𝑉 ) of {box π‘Ž β†’ 𝑀}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /π‘₯])) ∈ CompJ𝜏K. It is enough to show that the pair is in StackJ𝜏Kx by Proposition 7.8. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦ , 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 𝑙 163 On the left, there is the transition: βŸ¨βŸ¨Ξ¦π‘™ βˆ₯ Σ𝑙 βˆ₯ case (box 𝑉 ) of {box π‘₯ β†’ 𝑀} βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦π‘™ βˆ₯ Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© Note that Ξ“ ⊒ box 𝑉 : ?Μƒ? 𝜎 and Ξ“, π‘₯ :𝜎 ⊒ 𝑀 : 𝜏 follows from the equality. By inversion on the former, we know Ξ“ ⊒ 𝑉 : 𝜎 . Applying Corollary 7.1 with the assumed related environment, we know ((Ξ¦β€², (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝑀)𝑙 , (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /π‘₯])) ∈ CompJ𝜏K. By Proposition 7.8, the pair is in the set StackJ𝜏Kx. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /π‘₯] βˆ₯ πΎπ‘Ÿ ⟩⟩ by the above𝑙 related expressions with Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Φ′𝑙 𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case (box 𝑉 ) of {box π‘₯ β†’ 𝑀} βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /π‘₯] βˆ₯ πΎπ‘Ÿ βŸ©βŸ©π‘™ by the backwards closure of (≃). Case 𝛽𝐹 : Ξ“ ⊒ (val 𝑉 ) to π‘₯ in 𝑃 = 𝑃 [𝑉 /π‘₯] : 𝜏 Note that we prove this for the shared computation case where 𝑃 = 𝑅 and 𝜏 = 𝜏 , but the proof follows in the same manner for shared computations since the same transitions exist. Considering arbitrary related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show that ((Φ𝑙 , Σ𝑙 , (val 𝑉 ) to π‘₯ in 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝑉 /π‘₯])) ∈ SharedJ𝜏K. 164 By Proposition 7.8, it is enough to show that the pair is in the set StackJ𝜏Kx. Thus, further consider some Ξ¦β€² βŠ’ Ξ¦ β€² β€² β€² 𝑙 𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦ , 𝐾𝑙 ), (Ξ¦π‘Ÿ , 𝐾𝑙 )) ∈ StackJ𝜏K:𝑙 On the left, there is the transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (val 𝑉 ) to π‘₯ in 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ val 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝑅) Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ 𝑙 𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© Note that Ξ“ ⊒ (val 𝑉 ) to π‘₯ in 𝑅 : 𝜏 follows from the equality. By inversion, we can conclude that Ξ“ ⊒ 𝑉 : 𝜎 and Ξ“, π‘₯ :𝜎 ⊒ 𝑅 : 𝜏 . By Corollary 7.1 with our related environments, we know that ((Φ𝑙 , (Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯), 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝑉 /π‘₯])) ∈ SharedJ𝜏K. And further, Proposition 7.8 says that the pair is in the set StackJ𝜏Kx. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 [𝑉 /π‘₯] βˆ₯ 𝐾𝑙 π‘Ÿ ⟩⟩, by the property of the related computations above with Ξ¦β€² βŠ’ Φ𝑙 , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (val 𝑉 ) to π‘₯ in 𝑅 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 [𝑉 /π‘₯] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the closure𝑙 properties of (≃). Case π›½π‘ˆ : Ξ“ ⊒ {𝜍, enter β†’ 𝑀}.enter = 𝑀 [𝜍] : 𝜏 165 Follows in a similar manner to the π›½π‘ˆ case, except for the fact that there is an evaluation context for β–‘.enter. Thus, we have an extra step on the left side: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {𝜍, enter β†’ 𝑀}.enter βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {𝜍, enter β†’ 𝑀} βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍) βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ The transitivity of (≃) permits this extra step without issue. Case 𝛽𝐹 : Ξ“ ⊒ {eval β†’ 𝑅}.eval = 𝑅 : 𝜏 Follows in a similar manner to the π›½π‘ˆ case and the case above, except that there is no closure to enter as well. The transitions on the left side look like the following: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {eval β†’ 𝑅}.eval βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ 𝑙 𝑙 βˆ₯ {eval β†’ 𝑅} βˆ₯ β–‘.eval Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© Case πœ‚β†’: Ξ“ ⊒ πœ†π‘₯. 𝑀 π‘₯ = 𝑀 : 𝜏 β†’ 𝜎 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must prove ((Φ𝑙 , Σ𝑙 , πœ†π‘₯ . 𝑀 π‘₯), (Φ𝑙 , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏 β†’ 𝜎K. By definition, we must show that the pair is in ElimJ𝜏 β†’ 𝜎Kx. Thus, further consider an arbitrary Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ ,𝑙 and ((Ξ¦β€²,β–‘ V Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘W Β· πΎπ‘Ÿ )) ∈ ElimJ𝜏 β†’ 𝜎K:𝑙 By definition, we know ((Ξ¦β€²,V), (Ξ¦β€²π‘Ÿ ,W)) ∈ ValJ𝜏K and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜎K. 166 Double orthogonal inclusion yields that ((Ξ¦β€²,β–‘ V Β· 𝐾 β€² 𝑙 𝑙 ), (Ξ¦π‘Ÿ ,β–‘W Β· πΎπ‘Ÿ )) ∈ StackJ𝜏 β†’ 𝜎K. The left side has the following transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ πœ†π‘₯ .𝑀 π‘₯ βˆ₯ β–‘ V Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘₯ βˆ₯ 𝑀 π‘₯ βˆ₯ 𝐾𝑙 π‘™βŸ©βŸ© β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ β–‘ V Β· 𝐾𝑙 π‘™βŸ©βŸ© Note that Ξ“ ⊒ 𝑀 : 𝜏 β†’ 𝜎 follows from the equality. By the reflexivity of (β‰ˆ), we know that Ξ“ ⊨ 𝑀 β‰ˆ 𝑀 : 𝜏 β†’ 𝜎 . With ((Ξ¦β€², (Σ𝑙 ,V/π‘₯)), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (which are related by Lemma 7.4 with𝑙 our assumed environments and closure under accessible worlds), we know that ((Ξ¦β€², (Σ𝑙 ,V/π‘₯), 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏 β†’ 𝜎K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V/π‘₯ βˆ₯ 𝑀 βˆ₯ β–‘ V Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ β–‘W Β· πΎπ‘Ÿ ⟩⟩ by the property the𝑙 stacks ((Ξ¦β€²,β–‘ V Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘W Β· πΎπ‘Ÿ )) ∈ StackJ𝜏 β†’ 𝜎K with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² βŠ’ Ξ¦β€²,𝑙 𝑙 𝑙 𝑙 𝑙 and the related expressions above. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ πœ†π‘₯. 𝑀 π‘₯ βˆ₯ β–‘ V Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ β–‘W Β· πΎπ‘Ÿ ⟩⟩ by our closure properties of (≃). Case πœ‚&: Ξ“ ⊒ {fst β†’ 𝑀.fst; snd β†’ 𝑀.snd} = 𝑀 : 𝜏 & 𝜎 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, and then showing that ((Φ𝑙 , Σ𝑙 , {fst β†’ 𝑀.fst; snd β†’ 𝑀.snd}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏 & 𝜎K 167 requires that the pair is in ElimJ𝜏 & 𝜎Kx by definition. Thus, further consider an arbitrary Ξ¦β€² βŠ’ Ξ¦ ′𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and an element in ElimJ𝜏 & 𝜎K, there are two sub-cases𝑙 to consider: case the element is ((Ξ¦β€²,β–‘.fst Β· 𝐾𝑙 ), (Ξ¦β€² β€²π‘Ÿ ,β–‘.fst Β· πΎπ‘Ÿ )) where ((Ξ¦ , 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜏K: By double orthogonal inclusion and the definition of StackJ𝜏 & 𝜎K, we know ((Ξ¦β€²,β–‘.fst Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.fst Β· πΎπ‘Ÿ )) ∈ StackJ𝜏 & 𝜎K and thus the pair is in𝑙 the set CompJ𝜏 & 𝜎Kβ€š. On the left side, we have the following transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀.fst; snd β†’ 𝑀.snd} βˆ₯ β–‘.fst Β· 𝐾𝑙 ⟩⟩ βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀.fst βˆ₯ 𝐾𝑙 ⟩⟩ β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· 𝐾 ⟩⟩ 𝑙 𝑙 𝑙 Note that Ξ“ ⊒ 𝑀 : 𝜏 & 𝜎 follows from the equality. By the reflexivity of (β‰ˆ), we have Ξ“ ⊒ 𝑀 β‰ˆ 𝑀 : 𝜏 & 𝜎 . This in combination with the related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (closure under accessible𝑙 worlds), we can now conclude ((Ξ¦β€², Ξ£ ′𝑙 , 𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏 & 𝜎K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.fstΒ·πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ β–‘.fstΒ·πΎπ‘Ÿ ⟩⟩ by the definition of𝑙 the stacks ((Ξ¦β€²,β–‘.fst Β· 𝐾 ), (Φ′𝑙 π‘Ÿ ,β–‘.fst Β· πΎπ‘Ÿ )) ∈ StackJ𝜏 & 𝜎K with Ξ¦β€² βŠ’ Ξ¦β€²,𝑙 𝑙 𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ , and the related computations above. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {fst β†’ 𝑀.fst; snd β†’ 𝑀.snd} βˆ₯ β–‘.fst Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ β–‘.fst Β· πΎπ‘Ÿ ⟩⟩ by the closure properties of (≃). case the element is ((Ξ¦β€²,β–‘.snd Β· 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.snd Β· πΎπ‘Ÿ )) where ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) βˆˆπ‘™ 𝑙 StackJ𝜎K: This follows in the same manner as the sub-case above. 168 Case πœ‚βŠ—: Ξ“ ⊒ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑃 [⟨π‘₯,π‘¦βŸ©/𝑧]} = 𝑃 [𝑉 /𝑧] : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then showing that ((Φ𝑙 , Σ𝑙 , case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧]}) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀 [𝑉 /𝑧])) ∈ CompJ𝜏K, can be done by proving that the pair is in StackJ𝜏Kx by the Proposition 7.8. We prove this for the case that 𝑃 = 𝑀 and 𝜏 = 𝜏 , but the proof follows similarly for a shared computation in SharedJ𝜏K. Thus, further consider some Ξ¦β€² βŠ’ Ξ¦ β€² 𝑙 𝑙 , Ξ¦π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 ′𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 Note that Ξ“ ⊒ 𝑉 : 𝜎 βŠ— 𝜌 , and Ξ“, π‘₯ :𝜎,𝑦:𝜌 ⊒ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧] : 𝜏 follow from the equality. By the reflexivity of (β‰ˆ), we know that Ξ“ ⊨ 𝑉 β‰ˆ 𝑉 : 𝜎 βŠ— 𝜌 . With environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (note closure under accessible worlds),𝑙 we may conclude ((Ξ¦β€², Build𝑉 (Σ𝑙 ,𝑉 )), (Φ′𝑙 π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝑉 ))) ∈ ValJ𝜎 βŠ— 𝜌K. Furthermore, we know by this definition that Build𝑉 (Σ𝑙 ,𝑉 ) = ⟨V𝑙 ,Wπ‘™βŸ© and Build𝑉 (Ξ£π‘Ÿ ,𝑉 ) = ⟨Vπ‘Ÿ ,Wπ‘Ÿ ⟩. On the left side, we have the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧]} βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ ,V /π‘₯,W /𝑦 βˆ₯ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧] βˆ₯ 𝐾 ⟩⟩ 𝑙 𝑙 𝑙 𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V𝑙/π‘₯,W𝑙/𝑦 βˆ₯ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧] βˆ₯ 𝐾 ′𝑙 π‘™βŸ©βŸ© ≃ ⟨⟨Φ βˆ₯ Σ𝑙 βˆ₯ 𝑀 [⟨V𝑙 𝑙 ,Wπ‘™βŸ©/𝑧] βˆ₯ πΎπ‘™βŸ©βŸ© follows by Corollary 7.1 with the assumed environments then using the reflexively related stack (Ξ¦β€², 𝐾𝑙 ).𝑙 169 We have the following chain of reasoning: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧]} βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 ,V𝑙/π‘₯,W𝑙/𝑦 βˆ₯ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧] βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 [⟨V𝑙 ,Wπ‘™βŸ©/𝑧] βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 , ⟨V𝑙 ,Wπ‘™βŸ©/𝑧 βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ , ⟨Vπ‘Ÿ ,Wπ‘Ÿ ⟩/𝑧 βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝑉 )/𝑧 βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /𝑧] βˆ₯ πΎπ‘Ÿ ⟩⟩ We may conclude by the closure properties of (≃) that βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ 𝑙 𝑙 βˆ₯ case 𝑉 of {⟨π‘₯,π‘¦βŸ© β†’ 𝑀 [⟨π‘₯,π‘¦βŸ©/𝑧]} βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 [𝑉 /𝑧] βˆ₯ πΎπ‘Ÿ ⟩⟩. Case πœ‚π‘ˆ : Ξ“ ⊒ {force β†’ 𝑉.force} = 𝑉 : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“β€²K, we must show that ((Φ𝑙 , Build𝑉 (Σ𝑙 , {force β†’ 𝑉.force})) , (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝑉 ))) ∈ ValJπ‘ˆ 𝜎K. By the reflexivity of (β‰ˆ), we know that Ξ“ ⊨ 𝑉 β‰ˆ 𝑉 : π‘ˆ 𝜎 . By that definition with our related environments, we know ((Φ𝑙 , Build𝑉 (Σ𝑙 ,𝑉 )), (Ξ¦π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,𝑉 ))) ∈ ValJπ‘ˆ 𝜎K. Unfolding the definition further, we have that Build𝑉 (Σ𝑙 ,𝑉 ) = {Ξ£β€², force β†’ 𝑀} and Build𝑉 (Ξ£π‘Ÿ ,𝑉 ) = {Ξ£β€²π‘Ÿ , force β†’ 𝑁 } such that their bodies are𝑙 related computations ((Ξ¦ ′𝑙 , Ξ£ , 𝑀), (Ξ¦π‘Ÿ , Ξ£β€²π‘Ÿ , 𝑁 )) ∈ CompJ𝜎K.𝑙 170 By the definition of building, we know also that Build𝑉 (Σ𝑙 , {force β†’ 𝑉.force}) = {Σ𝑙 , force β†’ 𝑉.force}. We have left to show that ((Φ𝑙 , Σ𝑙 ,𝑉.force), (Ξ¦ , Ξ£β€²π‘Ÿ π‘Ÿ , 𝑁 )) ∈ CompJ𝜎K. By Proposition 7.8, we need only show that the pair is in StackJ𝜎Kx. Thus, consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 𝑙 On the left side, we have the following transition βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉.force βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾 𝑙 𝑙 𝑙 ⟩⟩ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾 β€² β€²π‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ πΎπ‘Ÿ ⟩⟩, by Proposition 7.8 with our𝑙 𝑙 related computations ((Ξ¦β€², Ξ£β€², 𝑀), (Ξ¦β€² β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑁 )) ∈ CompJ𝜏K (note closure under𝑙 𝑙 accessible world) with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² βŠ’ Ξ¦β€², and ((Ξ¦β€², 𝐾 ), (Ξ¦β€² 𝑙 𝑙 𝑙 𝑙 𝑙 𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉.force βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€² β€² β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑁 βˆ₯ 𝐾 ⟩⟩, by the closure properties of𝑙 (≃). Case πœ‚πΉ : Ξ“ ⊒ 𝑀 to π‘₯ in 𝐸 [ret π‘₯] = 𝐸 [𝑀] : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then showing that ((Φ𝑙 , Σ𝑙 , 𝑀 to π‘₯ in 𝐸 [ret π‘₯]) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝐸 [𝑀])) ∈ CompJ𝜏K, it will suffice to show that the pair is in StackJ𝜏Kx by Proposition 7.8. Note that we consider only the computation case here, but the shared computation case 171 follows similarly. Thus, consider further an arbitrary Ξ¦β€² βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and𝑙 ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 On the left side, there is the following transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 to π‘₯ in 𝐸 [ret π‘₯] βˆ₯ πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ (Ξ£,β–‘ to π‘₯ in 𝐸 [ret π‘₯]) Β· πΎπ‘™βŸ©βŸ©π‘™ On the right side, the properties of (≃) give us that βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝐸 [𝑀] βˆ₯ πΎπ‘Ÿ ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€²π‘Ÿ π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎβ€²π‘Ÿ ⟩⟩ where Build (Ξ¦β€² , Ξ£ , 𝐸, 𝐾 ) = (Ξ¦β€²β€², Σ′𝐾 π‘Ÿ π‘Ÿ π‘Ÿ π‘Ÿ π‘Ÿ , πΎβ€²π‘Ÿ ). Note that Ξ£β€²π‘Ÿ is Ξ£π‘Ÿ extended with more bindings. Note that Ξ“ ⊒ 𝑀 : 𝐹 𝜎 follows from the typing derivation. By the reflexivity of (β‰ˆ), we have Ξ“ ⊨ 𝑀 β‰ˆ 𝑀 : 𝐹 𝜎 . With related environments ((Ξ¦β€², Ξ£ ), (Ξ¦β€²β€², Σ′𝑙 π‘Ÿ π‘Ÿ )) ∈ EnvJΞ“K (note closure on accessible worlds), we know that𝑙 ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²β€²π‘Ÿ , Ξ£β€²π‘Ÿ , 𝑀)) ∈ CompJ𝐹 𝜎K.𝑙 Next, we prove that ((Ξ¦β€², (Σ𝑙 ,β–‘ to π‘₯ in 𝐸 [ret π‘₯]) Β· 𝐾𝑙 ), (Ξ¦β€²β€², πΎβ€²π‘Ÿ π‘Ÿ )) ∈ StackJ𝐹 𝜎K,𝑙 by considering Ξ¦β€²β€² βŠ’ Ξ¦β€², Ξ¦β€²β€²β€²π‘Ÿ βŠ’ Ξ¦β€²β€²π‘Ÿ , and ((Ξ¦β€²β€², Ξ£β€², ret 𝑉 ), (Ξ¦β€²β€²β€² ′′𝑙 𝑙 𝑙 𝑙 π‘Ÿ , Ξ£π‘Ÿ , retπ‘Š )) ∈ IntroJ𝐹 𝜎K: ((Ξ¦β€²β€², Build (Ξ£β€²,𝑉 )), (Ξ¦β€²β€²β€², Build (Σ′′𝑉 π‘Ÿ 𝑉 π‘Ÿ ,π‘Š ))) ∈ ValJ𝜎K follows from the𝑙 𝑙 assumption that IntroJ𝐹 𝜎K. From this, we have ((Ξ¦β€²β€², Build𝑉 ((Ξ£β€², Build𝑉 (Ξ£β€²,𝑉 )/π‘₯), π‘₯))𝑙 𝑙 𝑙 , (Ξ¦β€²β€²β€² β€²β€²π‘Ÿ , Build𝑉 (Ξ£π‘Ÿ ,π‘Š ))) ∈ ValJ𝜎K. 172 And it follows by definition that ((Ξ¦β€²β€², (Ξ£β€², Build (Σ′𝑉 ,𝑉 )/π‘₯), ret π‘₯)𝑙 𝑙 𝑙 , (Ξ¦β€²β€²β€², Ξ£β€²β€²π‘Ÿ π‘Ÿ , retπ‘Š )) ∈ IntroJ𝐹 𝜎K. On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€²β€² βˆ₯ ret 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝐸 [ret π‘₯]) Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€², Build𝑉 (Σ𝑙 ,𝑉 )/π‘₯ βˆ₯ 𝐸 [ret π‘₯] βˆ₯ 𝐾𝑙 𝑙 π‘™βŸ©βŸ© And this is observationally equivalent to the following by the closure properties of (≃): βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 , Build(Ξ£β€²,𝑉 )/π‘₯ βˆ₯ 𝐸 [ret π‘₯] βˆ₯𝑙 𝑙 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²β€²β€² βˆ₯ Ξ£β€²β€² βˆ₯ ret π‘₯ βˆ₯ 𝐾′𝑙 ⟩⟩ where building the stack𝑙 𝑙 𝑙 Build𝐾 (Ξ¦β€²β€², (Σ𝑙 , Build(Ξ£β€²,𝑉 )/π‘₯), 𝐸, 𝐾𝑙 ) is equal to (Ξ¦β€²β€²β€², Ξ£β€²β€², 𝐾′).𝑙 𝑙 𝑙 𝑙 𝑙 We know ((Ξ¦β€²β€²β€², 𝐾 ), (Φ′′′𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝐹 𝜎K by Lemma 7.5. This with Ξ¦β€²β€²β€² βŠ’π‘™ 𝑙 Ξ¦β€²β€²β€², Ξ¦β€²β€²β€²π‘Ÿ βŠ’ Ξ¦β€²β€²β€²π‘Ÿ , and the related introductions (note closure over accessible𝑙 heaps) yields βŸ¨βŸ¨Ξ¦β€²β€²β€² βˆ₯ Ξ£β€²β€² βˆ₯ ret π‘₯ βˆ₯ πΎβ€²βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²β€² βˆ₯ Ξ£β€²β€²π‘Ÿ π‘Ÿ βˆ₯ retπ‘Š βˆ₯ πΎβ€²π‘Ÿ ⟩⟩.𝑙 𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€²β€² βˆ₯ ret 𝑉 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝐸 [ret π‘₯]) Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²β€² βˆ₯ Ξ£β€²β€²π‘Ÿ π‘Ÿ βˆ₯ retπ‘Š βˆ₯𝑙 𝑙 πΎβ€²π‘Ÿ ⟩⟩ by the closure properties of (≃). By Proposition 7.8 with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€²β€²π‘Ÿ βŠ’ Ξ¦β€²β€²π‘Ÿ , and the related computations above, we𝑙 𝑙 know βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ (Σ𝑙 ,β–‘ to π‘₯ in 𝐸 [ret π‘₯]) Β· 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€² βˆ₯ 𝑀 βˆ₯ 𝐾′𝑙 𝑙 π‘Ÿ π‘Ÿ π‘Ÿ ⟩⟩. By the closure properties of (≃), we have βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 to π‘₯ in 𝐸 [ret π‘₯] βˆ₯ πΎπ‘™βŸ©βŸ© ≃𝑙 βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝐸 [𝑀] βˆ₯ πΎπ‘Ÿ ⟩⟩. Case πœ‚?Μƒ? : Ξ“ ⊒ case 𝑉 of {box π‘Ž β†’ 𝑃 [box π‘Ž/π‘₯]} = 𝑃 [𝑉 /π‘₯] : 𝜏 Proved in a similar manner to πœ‚βŠ—. 173 Case πœ‚πΉ : Ξ“ ⊒ 𝑅 to π‘₯ in 𝐸 [val π‘₯] = 𝐸 [𝑅] : 𝜏 Proved in a similar manner to πœ‚πΉ . Case πœ‚π‘ˆ : Ξ“ ⊒ {enter β†’ 𝑉.enter} = 𝑉 : π‘ˆ 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show that ((Φ𝑙 , Σ𝑙 , {enter β†’ 𝑉.enter}), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,𝑉 )) ∈ SharedJπ‘ˆ 𝜏K. Note that this equality gives Ξ“ ⊒ 𝑉 : π‘ˆ 𝜏 . By the reflexivity of (β‰ˆ), we have thus Ξ“ ⊨ 𝑉 β‰ˆ 𝑉 : π‘ˆ 𝜏 . We will show ((Φ𝑙 , Σ𝑙 , {enter β†’ 𝑉.enter}), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,𝑉 )) ∈ ValJπ‘ˆ 𝜏K and this concludes the proof in this case because ValJπ‘ˆ 𝜏K βŠ† SharedJπ‘ˆ 𝜏K. By definition, this is to show that the pair is in ElimJπ‘ˆ 𝜏Kx; we already satisfy the requirement that the expressions be shared values. Consider further some Ξ¦β€² βŠ’ Ξ¦ 𝑙 𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€²,β–‘.enter Β· 𝐾𝑙 ), (Ξ¦π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ )) ∈ ElimJπ‘ˆ 𝜏K:𝑙 On the left, there is the transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {enter β†’ 𝑉.enter} βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© βˆ’β†¦ →𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑉.enter βˆ₯ 𝐾 ⟩⟩ β†¦βˆ’β†’ 𝑙 𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉 βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ©π‘™ ((Ξ¦β€², Ξ£ β€² 𝑙 𝑙 ,𝑉 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,𝑉 )) ∈ ValJπ‘ˆ 𝜏K from our initial assumption with the relate environments (closed under future heaps). 174 Since ElimJπ‘ˆ 𝜏K βŠ† VStackJπ‘ˆ 𝜏K, we may conclude that ((Ξ¦β€²,β–‘.enter Β· 𝑙 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.enter Β· πΎπ‘Ÿ )) ∈ VStackJπ‘ˆ 𝜏K. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉 βˆ₯ β–‘.enter Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑉 βˆ₯ β–‘.enter Β· πΎπ‘Ÿ ⟩⟩, by the above𝑙 related value stacks with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and the related environments𝑙 𝑙 above. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {enter β†’ 𝑉 .enter} βˆ₯ β–‘.enter Β·πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑉 βˆ₯ β–‘.enter Β·πΎπ‘Ÿ βŸ©βŸ©π‘™ by the closure properties of (≃). Case πœ‚πΉ : Ξ“ ⊒ {eval β†’ 𝑀.eval} = 𝑀 : 𝐹 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, and then showing that ((Φ𝑙 , Σ𝑙 , {eval β†’ 𝑀.eval}), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝐹 𝜏K requires that the pair is in ElimJ𝐹 𝜏Kx by definition. Thus, further considering an arbitrary Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€²,β–‘.eval Β· 𝐾 ′𝑙 𝑙 𝑙 ), (Ξ¦π‘Ÿ ,β–‘.eval Β· πΎπ‘Ÿ )) ∈ ElimJ𝐹 𝜏K: By double orthogonal inclusion and the definition of StackJ𝐹 𝜏K, we may conclude that ((Ξ¦β€²,β–‘.eval ·𝐾𝑙 ), (Ξ¦β€²π‘Ÿ ,β–‘.eval Β·πΎπ‘Ÿ )) ∈ StackJ𝐹 𝜏K and therefore the pair is𝑙 in the set CompJ𝐹 𝜏Kβ€š by Proposition 7.8. On the left side, we have the following transition sequence: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {eval β†’ 𝑀.eval} βˆ₯ β–‘.eval Β· πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀.eval βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· πΎπ‘™βŸ©βŸ©π‘™ 175 Note that Ξ“ ⊒ 𝑀 : 𝐹 𝜏 follows from the equality. By the reflexivity of (β‰ˆ), we have Ξ“ ⊒ 𝑀 β‰ˆ 𝑀 : 𝐹 𝜏 . With the related environments ((Ξ¦β€², Σ𝑙 ), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K (closure under accessible worlds), we can now𝑙 conclude that ((Ξ¦β€², Σ𝑙 , 𝑀), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝐹 𝜏K.𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· 𝐾 ′𝑙 π‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· πΎπ‘Ÿ ⟩⟩, by the property of our related stacks with Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² βŠ’ Ξ¦β€² , and the related computations 𝑙 𝑙 π‘Ÿ π‘Ÿ immediately above. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ β€² 𝑙 𝑙 βˆ₯ {eval β†’ 𝑀.eval} βˆ₯ β–‘.eval Β· πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ β–‘.eval Β· πΎπ‘Ÿ ⟩⟩, by the closure properties of (≃). Case πœ…: Ξ“ ⊒ 𝐸 [𝑅 memo π‘Ž in 𝑃] = 𝑅 memo π‘Ž in 𝐸 [𝑃] : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then showing that ((Φ𝑙 , Σ𝑙 , 𝐸 [𝑅 memo π‘Ž in𝑀]) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 memo π‘Ž in 𝐸 [𝑀])) ∈ CompJ𝜏K requires that we show the pair is in StackJ𝜏Kx by Proposition 7.8. Note we pick the computation case; the shared case follows similarly except we make use of the definition SharedJ𝜏K = VStackJ𝜏Kx. Thus, further consider an arbitrary Ξ¦β€² βŠ’ Φ𝑙 and𝑙 Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 On the left, βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝐸 [𝑅 memo π‘Ž in𝑀] βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€², βˆ₯𝑙 𝑙 𝑙 𝑅 memo π‘Ž in𝑀 βˆ₯ πΎβ€²βŸ©βŸ© where we know Build β€² β€²β€² β€² β€² 𝑙 𝐾 (Ξ¦ , Ξ£, 𝐸, 𝐾 ) = (Ξ¦ , Ξ£ , 𝐾 ) by 𝑙 𝑙 𝑙 𝑙 𝑙 176 the closure properties of (≃). Thereafter, there is the transition: βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€² βˆ₯ 𝑅 memo π‘Ž in𝑀 βˆ₯ πΎβ€²βŸ©βŸ© β†¦βˆ’β†’ 𝑙 𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²β€², 𝑙 β€² β€²π‘Ž ↦→ {Ξ£ , 𝑅} βˆ₯ Ξ£ , π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎβ€²βŸ©βŸ©π‘™ 𝑙 𝑙 𝑙 On the right side, there is the transition βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 memo π‘Ž in 𝐸 [𝑀] βˆ₯ πΎπ‘Ÿ ⟩⟩) β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , π‘™π‘Ž →↦ {Ξ£π‘Ÿ , 𝑅} βˆ₯ Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž βˆ₯ 𝐸 [𝑀] βˆ₯ πΎπ‘Ÿ ⟩⟩ Additionally, the fourth closure property of (≃) yields βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , π‘™π‘Ž ↦→ {Ξ£π‘Ÿ , 𝑅} βˆ₯ Ξ£ , 𝑙 /π‘Ž βˆ₯ 𝐸 [𝑀] βˆ₯ 𝐾 ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Ξ£β€²π‘Ÿ π‘Ž π‘Ÿ π‘Ÿ π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎβ€²π‘Ÿ ⟩⟩ on the right, where we know that Build ((Ξ¦β€² , 𝑙 ↦→ {Ξ£ , 𝑅}), (Ξ£ , 𝑙 /π‘Ž), 𝐾 ) is equal to (Ξ¦β€²β€² β€² ′𝐾 π‘Ÿ π‘Ž π‘Ÿ π‘Ÿ π‘Ž π‘Ÿ π‘Ÿ , Ξ£π‘Ÿ , πΎπ‘Ÿ ). Note that Ξ“ ⊒ 𝑅 : 𝜎 , Ξ“, π‘Ž:𝜎 ⊒ 𝐸 [𝑀] : 𝜏 , and (Ξ“, π‘Ž:𝜎)Ξ“β€² ⊒ 𝑀 : 𝜌 follows from the equality. Ξ“β€² are extra shared variables that are added to the environment from other memo-expressions. It follows by the reflexivity of (β‰ˆ) that Ξ“ ⊒ 𝑅 β‰ˆ 𝑅 : 𝜎 and (Ξ“, π‘Ž:𝜎)Ξ“β€² ⊒ 𝑀 β‰ˆ 𝑀 : 𝜌 . ((Ξ¦β€², Σ𝑙 , 𝑅), (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑅)) ∈ SharedJ𝜎K follows from the above fact with our related𝑙 environments. (((Ξ¦β€²β€², π‘™π‘Ž ↦→ {Ξ£β€², 𝑅})𝑙 𝑙 , (Ξ£β€², 𝑙 /π‘Ž)), (Ξ¦β€²β€², Ξ£β€²π‘Ž π‘Ÿ π‘Ÿ )) ∈ EnvJ(Ξ“, π‘Ž:𝜎)Ξ“β€²K𝑙 by Lemma 7.1 using empty local environments and that building stacks produces future heaps and environments. (((Ξ¦β€²β€², π‘™π‘Ž →↦ {Ξ£β€², 𝑅})𝑙 𝑙 , (Ξ£β€², π‘™π‘Ž/π‘Ž), 𝑀), (Ξ¦β€²β€²π‘Ÿ , Ξ£β€²π‘Ÿ , 𝑀)) ∈ CompJ𝜌K𝑙 177 follows with the environment above. (((Ξ¦β€²β€², 𝑙 ↦→ {Ξ£β€²π‘Ž , 𝑅}), 𝐾′), (Ξ¦β€²β€², πΎβ€²π‘Ÿ π‘Ÿ )) ∈ StackJ𝜌K by Lemma 7.5.𝑙 𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²β€², π‘™π‘Ž →↦ {Ξ£β€², 𝑅} βˆ₯ Ξ£β€², π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎβ€²βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€² β€² β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩, by our related𝑙 𝑙 𝑙 𝑙 stacks with the same heaps Proposition 7.8 and the above related expressions. Note that for the shared case, we make use of the definition of shared stacks, i.e. SharedJ𝜏K . βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝐸 [𝑅 memo π‘Ž in𝑀] βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 memo π‘Ž in 𝐸 [𝑀] βˆ₯ πΎπ‘Ÿ ⟩⟩ by𝑙 the closure properties of (≃). Case πœ’ : Ξ“ ⊒ (𝑅 memo 𝑏 in 𝑆) memo π‘Ž in 𝑃 = 𝑅 memo 𝑏 in (𝑆 memo π‘Ž in 𝑃) : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K and then showing that ((Φ𝑙 , Σ𝑙 , (𝑅 memo 𝑏 in 𝑆) memo π‘Ž in𝑀) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 memo 𝑏 in (𝑆 memo π‘Ž in𝑀))) ∈ CompJ𝜏K requires that we show the pair is in StackJ𝜏Kx by Proposition 7.8. As before, the proof for the shared case follows similarly but we show the pair is in VStackJ𝜏Kx by the definition of SharedJ𝜏K. Thus, further consider an arbitrary Ξ¦β€² βŠ’ Ξ¦β€²π‘Ÿ , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ ,𝑙 and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (𝑅 memo 𝑏 in 𝑆) memo π‘Ž in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€², 𝑙 𝑙 π‘Ž →↦ {Σ𝑙 , 𝑅 memo 𝑏 in 𝑆} βˆ₯ Σ𝑙 , π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© 178 x On the right side, there is the transition sequence: βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 memo 𝑏 in (𝑆 memo π‘Ž in𝑀) βˆ₯ πΎπ‘Ÿ ⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅} βˆ₯ Ξ£π‘Ÿ , 𝑙𝑏/𝑏 βˆ₯ 𝑆 memo π‘Ž in𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩ βˆ’β†¦ β†’ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}, π‘™π‘Ž →↦ {(Ξ£π‘Ÿ , 𝑙𝑏/𝑏), 𝑆} βˆ₯ Ξ£π‘Ÿ , 𝑙𝑏/𝑏, π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩ From the equality, we know that Ξ“ ⊒ 𝑅 : 𝜎 , Ξ“, 𝑏:𝜎 ⊒ 𝑆 : 𝜌 , and Ξ“, π‘Ž:𝜌 ⊒ 𝑀 : 𝜏 . Thus, the reflexivity of (β‰ˆ) yields Ξ“ ⊨ 𝑅 β‰ˆ 𝑅 : 𝜎 , Ξ“, 𝑏:𝜎 ⊨ 𝑆 β‰ˆ 𝑆 : 𝜌 , and Ξ“, π‘Ž:𝜌 ⊨ 𝑀 β‰ˆ 𝑀 : 𝜏 . We next prove ((Ξ¦β€², Σ𝑙 , 𝑅 memo 𝑏 in 𝑆)𝑙 , ((Ξ¦β€²π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}), (Ξ£π‘Ÿ , 𝑙𝑏/𝑏), 𝑆)) ∈ SharedJ𝜌K by its definition where we show that the pair is in VStackJ𝜎Kx. Thus, consider future worlds Ξ¦β€²β€² βŠ’ Ξ¦β€² and Ξ¦β€²β€²π‘Ÿ βŠ’ (Ξ¦β€²π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}), and some value stack𝑙 𝑙 ((Ξ¦β€²β€²,K ), (Φ′′𝑙 π‘Ÿ ,Kπ‘Ÿ )) ∈ VStackJ𝜌K:𝑙 On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 memo 𝑏 in 𝑆 βˆ₯ Kπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€²β€², 𝑙𝑏 ↦→ {Σ𝑙 , 𝑅} βˆ₯ Σ𝑙 , 𝑙𝑏/𝑏 βˆ₯ 𝑆 βˆ₯ K𝑙 π‘™βŸ©βŸ© ((Ξ¦β€²β€², Ξ£ ), (Φ′′𝑙 π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, by closure over accessible worlds and the𝑙 transitivity of accessibility. ((Φ𝑙 , Σ𝑙 , 𝑅), (Φ𝑙 , Σ𝑙 , 𝑅)) ∈ SharedJ𝜎K by the typing derivation and the reflexivity of (β‰ˆ). And for all future worlds. 179 (((Ξ¦β€²β€², 𝑙𝑏 ↦→ {Σ𝑙 , 𝑅}), (Σ𝑙 , 𝑙𝑙 𝑏/𝑏)) , (Ξ¦β€²β€²π‘Ÿ , (Ξ£π‘Ÿ , 𝑙𝑏/𝑏))) ∈ EnvJΞ“, 𝑏:𝜎K follows from Lemma 7.1 and closure under future worlds. Note that Ξ¦β€²β€²βŠ’(Ξ¦β€²π‘Ÿ π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}) and thus Ξ¦β€²β€²π‘Ÿ will contain the same mapping for 𝑙𝑏 . (((Ξ¦β€²β€², 𝑙𝑏 ↦→ {Σ𝑙 , 𝑅}), (Σ𝑙 , 𝑙𝑏/𝑏), 𝑆)𝑙 , (Ξ¦β€²β€²π‘Ÿ , (Ξ£π‘Ÿ , 𝑙𝑏/𝑏)), 𝑆) ∈ SharedJ𝜌K, follows from Ξ“, 𝑏:𝜎 ⊨ 𝑆 β‰ˆ 𝑆 : 𝜌 with the related environments immediately above. βŸ¨βŸ¨Ξ¦β€²β€², 𝑙𝑏 ↦→ {Σ𝑙 , 𝑅} βˆ₯ Σ𝑙 , 𝑙𝑏/𝑏 βˆ₯ 𝑆 βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²π‘™ π‘Ÿ βˆ₯ Ξ£π‘Ÿ , 𝑙𝑏/𝑏 βˆ₯ 𝑆 βˆ₯ Kπ‘Ÿ ⟩⟩ follows from the above fact with the property of related shared expressions, i.e. SharedJ𝜌K = VStackJ𝜌Kx, with the future worlds (Ξ¦β€²β€², 𝑙𝑏 ↦→ {Σ𝑙 , 𝑅}) βŠ’ Ξ¦β€²β€² and Ξ¦β€²β€² βŠ’ Ξ¦β€²β€²π‘Ÿ π‘Ÿ , and the pair of value stacks𝑙 𝑙 (((Ξ¦β€²β€², 𝑙𝑏 →↦ {Σ𝑙 , 𝑅}),K𝑙 ), (Ξ¦β€²β€²π‘Ÿ ,Kπ‘Ÿ ))∈VStackJ𝜌K. Again note the closure𝑙 over accessible heaps for the value stack. βŸ¨βŸ¨Ξ¦β€²β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 memo 𝑏 in 𝑆 βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ , 𝑙𝑙 𝑏/𝑏 βˆ₯ 𝑆 βˆ₯ Kπ‘Ÿ ⟩⟩, by the closure properties of (≃). Therefore, (((Ξ¦β€², π‘™π‘Ž ↦→ {Σ𝑙 , 𝑅 memo 𝑏 in 𝑆}), (Σ𝑙 , π‘™π‘Ž/π‘Ž))𝑙 , ((Ξ¦β€²π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}, π‘™π‘Ž ↦→ {(Ξ£π‘Ÿ , 𝑙𝑏/𝑏), 𝑆}), (Ξ£π‘Ÿ , 𝑙𝑏/𝑏, π‘™π‘Ž/π‘Ž))) ∈ EnvJΞ“, π‘Ž:𝜌K 180 follows by definition with the previous fact relating the expressions pointed to by π‘Ž and Lemma 7.1. From this, (((Ξ¦β€², π‘™π‘Ž ↦→ {Σ𝑙 , 𝑅 memo 𝑏 in 𝑆}), (Σ𝑙 , π‘™π‘Ž/π‘Ž), 𝑀)𝑙 , ((Ξ¦β€²π‘Ÿ , 𝑙𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}, π‘™π‘Ž ↦→ {(Ξ£π‘Ÿ , 𝑙𝑏/𝑏), 𝑆}), (Ξ£π‘Ÿ , 𝑙𝑏/𝑏, π‘™π‘Ž/π‘Ž), 𝑀)) ∈ CompJ𝜏K follows from the property of Ξ“, 𝑏:𝜎 ⊨ 𝑀 β‰ˆ 𝑀 : 𝜏 . Thus, βŸ¨βŸ¨Ξ¦β€², π‘™π‘Ž →↦ {Σ𝑙 , 𝑅 memo 𝑏 in 𝑆} βˆ₯ Σ𝑙 , π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , 𝑙𝑙 𝑏 ↦→ {Ξ£π‘Ÿ , 𝑅}, π‘™π‘Ž ↦→ {(Ξ£π‘Ÿ , 𝑙𝑏/𝑏), 𝑆} βˆ₯ Ξ£π‘Ÿ , 𝑙𝑏/𝑏, π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩ by our related stacks with Proposition 7.8. Note that our heaps are future heaps of assumed stack heaps. For the case where 𝑃 and 𝑄 are shared expressions, we instead use of the definition of SharedJ𝜏K and that we would have assumed value stacks at the beginning. Finally, βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ (𝑅 memo 𝑏 in 𝑆) memo π‘Ž in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Σ𝑙 π‘Ÿ βˆ₯ 𝑅 memo 𝑏 in (𝑆 memo π‘Ž in𝑀) βˆ₯ πΎπ‘Ÿ ⟩⟩ follows by the closure properties of (≃). Case cl: Ξ“ ⊒ {𝜍, 𝑅} memo π‘Ž in 𝑃 = 𝑅 [𝜍] memo π‘Ž in 𝑃 : 𝜏 Considering related environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must be able to show ((Φ𝑙 , Σ𝑙 , {𝜍, 𝑅} memo π‘Ž in 𝑃) , (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝜍] memo π‘Ž in 𝑃)) ∈ SharedJ𝜏K. By Proposition 7.8, it is enough to show that this pair is in StackJ𝜏Kx. Thus, further consider Ξ¦β€² βŠ’ Ξ¦ , Ξ¦β€² βŠ’ Ξ¦ , and ((Φ′𝑙 π‘Ÿ π‘Ÿ , 𝐾𝑙 ), (Φ′𝑙 𝑙 π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K: 181 On the left, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {𝜍, 𝑅} memo π‘Ž in 𝑆 βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€², 𝑙 →↦ {Ξ£ Build 𝑙 𝑙 𝜍 (Σ𝑙 , 𝜍), 𝑅} βˆ₯ Σ𝑙 , 𝑙/π‘Ž βˆ₯ 𝑆 βˆ₯ πΎπ‘™βŸ©βŸ© On the right, there is the transition: βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 [𝜍] memo π‘Ž in 𝑆 βˆ₯ πΎπ‘Ÿ ⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , 𝑙 ↦→ {Ξ£π‘Ÿ , 𝑅 [𝜍]} βˆ₯ Ξ£π‘Ÿ , 𝑙/π‘Ž βˆ₯ 𝑆 βˆ₯ πΎπ‘Ÿ ⟩⟩ Note that both Ξ“ ⊒ 𝜍 : Ξ“β€², ΓΓ′ ⊒ 𝑅 : 𝜌 , and Ξ“, π‘Ž:𝜌 ⊒ 𝑆 : 𝜏 follow from the equality. By application of Corollary 7.1 with related environments, we are able to conclude that ((Ξ¦β€², Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝑅)𝑙 , (Ξ¦β€²π‘Ÿ , Ξ£π‘Ÿ , 𝑅 [𝜍])) ∈ SharedJ𝜏K. From Ξ“, π‘Ž:𝜌 ⊨ 𝑆 β‰ˆ 𝑆 : 𝜏 , we know (((Ξ¦β€², 𝑙 →↦ {Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝑅}), (Σ𝑙 𝑙 , 𝑙/π‘Ž), 𝑆) , ((Ξ¦β€²π‘Ÿ , 𝑙 ↦→ {Ξ£π‘Ÿ , 𝑅 [𝜍]}), (Ξ£π‘Ÿ , 𝑙/π‘Ž), 𝑆)) ∈ SharedJ𝜏K by applying Lemma 7.1 with the above related expressions. βŸ¨βŸ¨Ξ¦β€², 𝑙 →↦ {Σ𝑙 Build𝜍 (Σ𝑙 , 𝜍), 𝑅} βˆ₯ Σ𝑙 , 𝑙/π‘Ž βˆ₯ 𝑆 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , 𝑙 →↦𝑙 {Ξ£π‘Ÿ , 𝑅 [𝜍]} βˆ₯ Ξ£π‘Ÿ , 𝑙/π‘Ž βˆ₯ 𝑆 βˆ₯ πΎπ‘Ÿ ⟩⟩ by Proposition 7.8 together with the above related expressions and the related stacks in the future worlds (Ξ¦β€², 𝑙 ↦→ 𝑙 {Σ𝑙Build𝜍 (Σ𝑙 , 𝜍), 𝑅}) βŠ’ Ξ¦β€² and (Ξ¦β€²π‘Ÿ , 𝑙 ↦→ {Ξ£π‘Ÿ , 𝑅 [𝜍]}) βŠ’ Ξ¦β€²π‘Ÿ .𝑙 βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ {𝜍, 𝑅} memo π‘Ž in 𝑆 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 [𝜍] memo π‘Ž in 𝑆 βˆ₯ πΎπ‘Ÿ ⟩⟩, by the𝑙 closure properties of (≃). 182 Case deref : Ξ“ ⊒ 𝑉 memo π‘Ž in 𝐢 [π‘Ž] = 𝑉 memo π‘Ž in 𝐢 [𝑉 ] : 𝜏 Note that we take𝐢 [π‘Ž] = 𝐢 [π‘Ž] and𝐢 [𝑉 ] = 𝐢 [𝑉 ] to be computations and 𝜏 = 𝜏 ; the proof will follow similarly for shared computations. From the equality, we know both that Ξ“ ⊒ 𝑉 memo π‘Ž in 𝐢 [π‘Ž] : 𝜏 and Ξ“ ⊒ 𝑉 memo π‘Ž in 𝐢 [𝑉 ] : 𝜏 . By inversion on these, we may conclude further that Ξ“, π‘Ž:𝜎 ⊒ 𝐢 [π‘Ž] : 𝜏 and Ξ“, π‘Ž:𝜎 ⊒ 𝐢 [𝑉 ] : 𝜏 . By further inversion, we know (Ξ“, π‘Ž:𝜎)Ξ“β€² ⊒ π‘Ž : 𝜎 and (Ξ“, π‘Ž:𝜎)Ξ“β€² ⊒ 𝑉 : 𝜎 where 𝐢 binds the extended environment Ξ“β€². Considering some arbitrary ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show ((Φ𝑙 , Σ𝑙 ,𝑉 memo π‘Ž in 𝐢 [π‘Ž]), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ ,𝑉 memo π‘Ž in 𝐢 [𝑉 ])) ∈ CompJ𝜏K. By Proposition 7.8, this is to show that the pair is in StackJ𝜏Kx. Thus, consider some Ξ¦β€² βŠ’ Φ𝑙 , Ξ¦β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾𝑙 ), (Ξ¦β€²π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K:𝑙 𝑙 On the left there is the transition, βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑉 memo π‘Ž in 𝐢 [π‘Ž] βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€², π‘™π‘Ž →↦ Buildπ‘Ž (Σ𝑙 ,𝑉 ) βˆ₯ Σ𝑙 , π‘™π‘Ž/π‘Ž βˆ₯ 𝐢 [π‘Ž] βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ And similarly on the right. (((Ξ¦β€², π‘™π‘Ž →↦ Buildπ‘Ž (Σ𝑙 ,𝑉 )), (Σ𝑙 , π‘™π‘Ž/π‘Ž),𝐢 [π‘Ž])𝑙 , ((Ξ¦β€²π‘Ÿ , π‘™π‘Ž ↦→ Buildπ‘Ž (Ξ£π‘Ÿ ,𝑉 )), (Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž)),𝐢 [𝑉 ]) ∈ CompJ𝜎K, by Lemma 7.3. (((Ξ¦β€², π‘™π‘Ž →↦ Buildπ‘Ž (Σ𝑙 ,𝑉 )), 𝐾𝑙 𝑙 ) , ((Ξ¦β€²π‘Ÿ , π‘™π‘Ž ↦→ Buildπ‘Ž (Ξ£π‘Ÿ ,𝑉 )), πΎπ‘Ÿ )) ∈ StackJ𝜏K, 183 by closure under future heaps. And by Proposition 7.8, we know this pair is in CompJ𝜏K . βŸ¨βŸ¨Ξ¦β€², π‘™π‘Ž →↦ Buildπ‘Ž (Σ𝑙 ,𝑉 ) βˆ₯ Σ𝑙 , π‘™π‘Ž/π‘Ž βˆ₯ 𝐢 [π‘Ž] βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , π‘™π‘Ž ↦→ Buildπ‘Ž (Ξ£π‘Ÿ ,𝑉 ) βˆ₯𝑙 Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž βˆ₯ 𝐢 [𝑉 ] βˆ₯ πΎπ‘Ÿ ⟩⟩, by the combination of the expressions and stacks above from the property of CompJ𝜏K . Case GC: Ξ“ ⊒ 𝑅 memo π‘Ž in 𝑃 = 𝑃 : 𝜏 Note that we take 𝑃 = 𝑀 and 𝜏 = 𝜏 ; the proof will follow similarly for shared computations. From the equality, we know that Ξ“ ⊒ 𝑀 : 𝜏 . Considering some arbitrary environments ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K, we must show that ((Φ𝑙 , Σ𝑙 , 𝑅 memo π‘Ž in𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏K. It is enough to show that the pair is in StackJ𝜏Kx by Proposition 7.8. Thus, further consider some Ξ¦β€² βŠ’ Φ𝑙 , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and ((Ξ¦β€², 𝐾 β€² 𝑙 𝑙 ), (Ξ¦π‘Ÿ , πΎπ‘Ÿ )) ∈ StackJ𝜏K: On the left side, there is the transition: βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 memo π‘Ž in𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© β†¦βˆ’β†’π‘™ βŸ¨βŸ¨Ξ¦β€², π‘™π‘Ž ↦→ Buildπ‘Ž (Σ𝑙 , 𝑅) βˆ₯ Σ𝑙 , π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ©π‘™ (((Ξ¦β€², π‘™π‘Ž →↦ Buildπ‘Ž (Σ𝑙 , 𝑅)), Ξ£ , 𝑙 ′𝑙 π‘Ž/π‘Ž,𝑀), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑀)) ∈ CompJ𝜏K by Lemma 7.4.𝑙 Moreover, it follows by Proposition 7.8, this pair is in StackJ𝜏Kx. βŸ¨βŸ¨Ξ¦β€², π‘™π‘Ž ↦→ Buildπ‘Ž (Σ𝑙 , 𝑅) βˆ₯ Ξ£ ′𝑙 𝑙 , π‘™π‘Ž/π‘Ž βˆ₯ 𝑀 βˆ₯ πΎπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑀 βˆ₯ πΎπ‘Ÿ ⟩⟩, by the property of above related expression in the heaps Ξ¦β€², π‘™π‘Ž →↦ Buildπ‘Ž (Σ𝑙 , 𝑅) βŠ’π‘™ Ξ¦β€² and Ξ¦β€²π‘Ÿ βŠ’ Ξ¦β€²π‘Ÿ with the assumed related stacks (note closure under future𝑙 worlds). 184 x x Case name: Ξ“ ⊒ 𝑅 = 𝑅 memo π‘Ž in π‘Ž : 𝜏 Wemust prove that ((Φ𝑙 , Ξ£π‘Ÿ , 𝑅), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , 𝑅 memo π‘Ž in π‘Ž)) ∈ SharedJ𝜏K for an arbitrary ((Φ𝑙 , Σ𝑙 ), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ )) ∈ EnvJΞ“K. By definition, this is to show that the pair is in the set VStackJ𝜏Kx. Thus, we further consider some Ξ¦β€² βŠ’ Ξ¦ , Φ′𝑙 π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and𝑙 ((Φ𝑙 ,K𝑙 ), (Ξ¦π‘Ÿ ,Kπ‘Ÿ )) ∈ VStackJ𝜏K: On the right side, there is the transition sequence: βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 memo π‘Ž in π‘Ž βˆ₯ Kπ‘Ÿ ⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ , π‘™π‘Ž ↦→ {Ξ£π‘Ÿ , 𝑅} βˆ₯ Ξ£π‘Ÿ , π‘™π‘Ž/π‘Ž βˆ₯ π‘Ž βˆ₯ Kπ‘Ÿ ⟩⟩ β†¦βˆ’β†’ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 βˆ₯ (πœ€, π‘™π‘Ž) Β· Kπ‘Ÿ ⟩⟩ Ξ“ ⊒ 𝑅 : 𝜏 follows from the equality. And thus, Ξ“ ⊨ 𝑅 β‰ˆ 𝑅 : 𝜏 , by the reflexivity of semantic equivalence. ((Ξ¦β€², Ξ£ , 𝑅), (Ξ¦β€² , Ξ£ , 𝑅)) ∈ SharedJ𝜏K, by the above 𝑙 𝑙 π‘Ÿ π‘Ÿ semantic equality with the related environments. ((Ξ¦β€²,K𝑙 ), (Ξ¦β€²π‘Ÿ ,Kπ‘Ÿ )) ∈ StackJ𝜏K, since VStackJ𝜏K is include in StackJ𝜏K and closure𝑙 over accessible heaps. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Σ𝑙 βˆ₯ 𝑅 βˆ₯ Kπ‘™βŸ©βŸ© ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 βˆ₯ Kπ‘Ÿ ⟩⟩, by the property of the related stacks𝑙 with the heaps Ξ¦β€² βŠ’ Ξ¦β€², Ξ¦β€² β€²π‘Ÿ βŠ’ Ξ¦π‘Ÿ , and the related expressions above.𝑙 𝑙 βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 βˆ₯ Kπ‘Ÿ ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 βˆ₯ (πœ€, π‘™π‘Ž) Β· Kπ‘Ÿ ⟩⟩ by the last closure property of (≃) for shared expressions. βŸ¨βŸ¨Ξ¦β€² βˆ₯ Ξ£ βˆ₯ 𝑅 βˆ₯ K ⟩⟩ ≃ βŸ¨βŸ¨Ξ¦β€²π‘™ 𝑙 π‘Ÿ βˆ₯ Ξ£π‘Ÿ βˆ₯ 𝑅 memo π‘Ž in π‘Ž βˆ₯ Kπ‘Ÿ ⟩⟩, by the closure properties𝑙 of (≃). 185 Cases reflexivity, symmetry, transitivity, and compatibility follow by their inductive hypotheses and the properties of (β‰ˆ). β–‘ 7.3 Soundness of CBPVS Theorem 7.1 (Soudness). If Ξ“ ⊒ 𝐴 = 𝐡 : 𝜏 , then 𝐴 ≃ 𝐡. Proof. By Lemma 7.6, we know that Ξ“ ⊨ 𝐴 β‰ˆ 𝐡 : 𝜏 . We know that (β‰ˆ) is compatible; and thus with a closing context 𝐢 , we have ⊨ 𝐢 [𝐴] β‰ˆ 𝐢 [𝐡] : 𝐹 𝐡. With the related empty environments, we have that ((πœ€, πœ€,𝐢 [𝐴]), (πœ€, πœ€,𝐢 [𝐡])) ∈ CompJ𝐹 𝐡K. By Proposition 7.8, we know that βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝐢 [𝑀] βˆ₯ β˜…βŸ©βŸ© ≃ βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝐢 [𝑁 ] βˆ₯ β˜…βŸ©βŸ© if we can show that ((Φ𝑙 ,β˜…), (Ξ¦π‘Ÿ ,β˜…)) ∈ StackJ𝐹 𝐡K for any Φ𝑙 βŠ’ πœ€ and Ξ¦π‘Ÿ βŠ’ πœ€. This is true, since trivial to show termination considering an arbitrary ((Φ𝑙 , Σ𝑙 , ret b), (Ξ¦π‘Ÿ , Ξ£π‘Ÿ , ret b)) ∈ IntroJ𝐹 𝐡K. β–‘ Corollary 7.2. If ⊒ 𝑀 = ret b : 𝐹 𝐡, then EvalS(𝑀) = b. 7.4 Adequacy of Closure Conversions A question left to answer, especially in a language for which closure conversion is novel, is whether or not the transformations we have specified have an effect on the machine. More specifically, are closures still left unspecified at runtime if we have done closure conversion? As mentioned earlier, any rule in the machine that uses the build function to construct machine data may need to build its own closure if it was not specified. For instance: Build𝑉 (Ξ£, {𝜍, force β†’ 𝑀}) = {Ξ£ Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀} The environment Ξ£ is completely captured in the closure; it has only the flat structure that the machine uses for its environment and may contain more variables than needed 186 for evaluating𝑀 later. If our closure conversionwere adequate, then the buildingmachine values ought to be equal to a restricted form of substitution: Buildcl𝑉 (Ξ£, {𝜍, force β†’ 𝑀}) = {Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀} Now building machine values for closures only looks up the variables in the environment specified in the syntax. For the Build𝑉 and Buildπ‘Ž , we can construct similar rules for their closure cases. Since it does not go into the body of the closure (as substitution would), we may generate a fixed code sequence for it. To show that a conversion is adequate, we construct a new abstract machine, denoted (βˆ’β†¦ β†’CC), that uses Buildcl instead of Build. If a program has been closure converted, then it should be able to run on this machine and produce the same result as the larger machine that creates closures dynamically. Definition 7.6 (Closure Converted CBPVS Machine Evaluator). EvalSCC(𝑃) = b where βŸ¨βŸ¨πœ€ βˆ₯ πœ€ βˆ₯ 𝑃 βˆ₯ β˜…βŸ©βŸ© β†¦βˆ’β†’βˆ—CC ⟨⟨Φ βˆ₯ Ξ£ βˆ₯ ret b βˆ₯ β˜…βŸ©βŸ©. Theorem 7.2 (Adequacy). If 𝑃 is a well-typed expression in CC-normal form, then EvalS(𝑃) = EvalSCC(𝑃). Proof. Because of garbage collection (Lemma 7.4), for any closure we build in themachine, we can show that it is related to using the closed builder. For instance, consider some sub- expression of 𝑃 where𝑉 = {𝜍, force β†’ 𝑀} in CC-normal form. We know Build𝑉 (Ξ£,𝑉 ) = {Ξ£ Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀} by definition for an arbitrary Ξ£ covering the free variables of 𝑉 . And by definition, we also have Buildcl𝑉 (Ξ£,𝑉 ) = {Build𝜍 (Ξ£, 𝜍), force β†’ 𝑀} for the closed version. By the definition of CC-normal form, 𝑀 only depends on Build𝜍 (Ξ£, 𝜍). Therefore, by repeated application of the garbage collection lemma, we have ((Ξ¦, Build𝑉 (Ξ£,𝑉 )), (Ξ¦, Buildcl𝑉 (Ξ£,𝑉 ))) ∈ ValJπ‘ˆ 𝜏K. By the compatibility lemmas, we 187 can do this for each closure converted sub-part of 𝑃 . This with the knowledge that our evaluators run 𝑃 in the empty environment and stack (which are trivial related) allows us to conclude. β–‘ There is still a sense in which abstract closures are less adequate than the canonical closure conversion. Whereas our approach keeps the contexts that consume closures (i.e. the application case for call-by-value closure conversion), a full closure conversion in the application case generates code for entering a function. Thus, a machine that accepts our closures need not have special rules for capturing environmentβ€”they are built the same as dataβ€”but will need special rules for closure entry which will instantiate the environment captured. This instantiation amounts to a pattern match followed by a jump; the canonical closure conversion is fine grained enough to detach these two operations, but at the expense of being a global transformation. 188 CHAPTER VIII DISCUSSION 8.1 Related Work Abstract closures have been used in the past for reasoning and optimization. Hannan [21] used abstract closures in an IL to implement the optimizations of Wand and Steckler [56] which reduce the variables in a closure. Minamide et al. [34] used them as an intermediate step in their typed closure conversion. These two works use big-step semantics and global transformations. The work most similar to ours is that of Bowman and Ahmed [11] because they give a language with local rewriting rules instead. For them, abstract closures were necessary for their main goal: proving the correctness of a closure conversion for the Calculus of Construction. Unlike their theory, we did not need to give special πœ‚ laws for abstract closures, only 𝛽 laws. Our work can be seen as promoting abstract closures further by considering their use in an optimizing compiler’s IL. Specifically, we treat the process of closure conversion itself as a rewriting theory capable of being integrated into the optimization passes. Explicit substitution calculi have a similar goal to ours: to close the gap between an equational theory and a practical implementation. Indeed, after adding our abstract closures, we arrived at a calculus that contains explicit substitutions like that of Abadi et al. [1] and that of the later extension to sharing by Seaman and Iyer [47]. A major difference is that we restrict where environmentsβ€”for them substitutionsβ€”can occur in an expression, whereas they allow environments in any expression. For us, they can only occur for computations being delayed to values or shared values and over shared computations bound in a memo-expression; these are directly informed by where closures are constructed in our abstract machines. Moreover, we still make use of a substitution 189 function over the syntax of our language, instead of embedding the entire system in our equational theory. As a result, we can easily specify what it means for a term to be in a closure converted form. The notion of 𝛽 reduction in Abadi et al. and their Krivine machine always construct closure objects. In our system, we can show that a closure converted term does not do this. Like us, McDermott and Mycroft [32] extend CBPV with sharing. Their approach is to use computation variables of type 𝐹 𝜏 for sharing whereas we add another syntactic class for shared objects. In both cases, sharing required the addition of special binders to reference the shared computation as in call-by-need. Theirmotivationwas not specifically focused on using CBPV as a compiler IL and thus their language falls short for us. First, we needed to show the soundness of our theory with respect to an abstract machine because we wanted to use the language for optimization. Second, their approach does not subsume the full equational theory of call-by-need. Since we were interested in these goals, our language takes many ideas from Beyond Polarity (BP) [16] instead. As ANF [18] can be seen as a focalized variant of the πœ†-calculus, our language can be seen as a focalized variant of BP; that is, we must give names to all intermediate computations. We pursued a focalized language because it eliminates syntactic differences between programs; and thus, it is effective in compilation. Our approach to proving the soundness of our equational theories follows from ⊀⊀-closure of [45]. It follows the standard application of the approach, but is extended for environment machines. The correctness of the sharing portion is more novel. We are aware of three other approaches to logical relations for lazy languages [35, 20, 16]. Miquey and Herbelin [35] is only interested in normalization and thus constructs a logical predicate, but makes use of similar multi-level orthogonality operations in order to build up notions of types; their positive characterization of function types will become 190 a problem if they extend their predicate to relation and attempt to prove the soundness of extensional axioms. The relation of Hackett and Hutton [20] is over expressions in the language which imply evaluation in a machine, in a manner similar to us; though it is not clear whether the approach is strong enough to prove the soundness of the extensionality axioms or lifting rules from our equational theories. Their relation does consider two aspects of lazy evaluation that we do not: polymorphism and computational cost. Finally, Downen and Ariola in their BP language [16] prove the soundness of a sharing equational theory with similar axioms including extensionality; it differs in that our operational semantics is an environment machine whereas theirs is a standard reduction theory with substitutions. Our environment machine semantics is why we developed a Kripke logical relation since heaps are part of the related expressions. There is other work by Ahmed [2] on Kripke logical relations for languages with heaps in the operational semantics. The languages that she considers are those with mutable state. Call-by-need heaps are better behaved than those with type-safe mutable references and thus we have a simpler Kripke relationship; hers require step indexing. 8.2 Future Work As future work, we wish to extend our equational theory of CBPVS to a reduction theory. We generalized Levy’s CBPV axioms in order to make the theory more flexible for optimization and we do not know exactly which changes need to be made to the equations to get a reduction theory. Additionally, we want to implement some version of this approach to closure conversion within GHC’s intermediate language, since it is organized around the small, local transformations [44] that inspired this paper. In so doing, we would also need to extend our theory of closures to handle polymorphism and mutual recursion. Both cases have already received special attention with regard to closure conversion by Minamide et al. [34] and Appel [5], respectively. Preliminary 191 work by us with respect to recursion shows that fixpoints out to be added to π‘ˆ 𝜏 types so that they can form a recursive closure; this differs from Levy who adds fixpoints as computations. 8.3 Conclusion This thesis started by examining the abstract machines used to implement different evaluation strategies. We saw that the strictness of a language influenced the closures that were necessary in abstract machines. We first filled a hole in the literature with respect to non-strict closure conversion as an approach to compilation. As a reflection of the machines, we described new closure conversions for these different evaluation strategies. To add flexibility and higher-level reasoning to the transformation, we describe a new approach to compiling closures for these different evaluation strategies that allows us to perform the transformation locally in the intermediate language as well as optimizations thereof. We show how to combine all of these into a single intermediate language based on call-by-push-value that has the strongest 𝛽 and πœ‚ laws for optimization and preserves the equational theories of call-by-name, call-by-value, and call-by-need. To validate our work, we developed a model of types over abstract machines that show that our new approach is both sound and sufficient to remove runtime constructed closures from the machine. 192 REFERENCES CITED [1] M. Abadi, L. Cardelli, P.-L. Curien, and J.-J. Levy. Explicit substitutions. In Proceedings of the 17th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’90, pages 31–46, 1989. [2] Amal Ahmed. Semantics of Types for Mutable State. PhD thesis, Princeton University, 2004. [3] Amal Ahmed and Matthias Blume. Typed closure conversion preserves observational equivalence. In Proceeding of the 13th ACM SIGPLAN international conference on Functional programming, ICFP 2008, Victoria, BC, Canada, September 20-28, 2008, pages 157–168, 2008. [4] Amal Ahmed, Derek Dreyer, and Andreas Rossberg. State-dependent representation independence. In Zhong Shao and Benjamin C. Pierce, editors, Proceedings of the 36th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2009, Savannah, GA, USA, January 21-23, 2009, pages 340–353. ACM, 2009. [5] Andrew W. Appel. Compiling with Continuations. Cambridge University Press, 1992. [6] Andrew W. Appel and Trevor Jim. Continuation-passing, closure-passing style. In Conference Record of the Sixteenth Annual ACM Symposium on Principles of Programming Languages, Austin, Texas, USA, January 11-13, 1989, pages 293–302, 1989. [7] Zena M. Ariola and Matthias Felleisen. The call-by-need lambda calculus. J. Funct. Program., 7(3):265–301, 1997. [8] Zena M. Ariola, Matthias Felleisen, John Maraist, Martin Odersky, and Philip Wadler. The call-by-need lambda calculus. In Conference Record of POPL’95: 22nd ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, San Francisco, California, USA, January 23-25, 1995, pages 233–246, 1995. [9] Zena M. Ariola, John Maraist, Martin Odersky, Matthias Felleisen, and Philip Wadler. A call-by-need lambda calculus. In Proceedings of the 22nd ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’95, pages 233–246, 1995. [10] Lennart Augustsson. Compiling pattern matching. In Proceedings Of a Conference on Functional Programming Languages and Computer Architecture, pages 368–381, 1985. [11] William J. Bowman and Amal Ahmed. Typed closure conversion for the calculus of constructions. In Proceedings of the 39th ACM SIGPLAN Conference on Programming Language Design and Implementation, PLDI 2018, Philadelphia, PA, USA, June 18-22, 2018, pages 797–811, 2018. 193 [12] G. L. Burn, Simon L. Peyton Jones, and J. D. Robson. The spineless g-machine. In Proceedings of the 1988 ACM Conference on LISP and Functional Programming, LFP ’88, pages 244–258, 1988. [13] Alonzo Church. The calculi of πœ†-conversion, volume 6. Princeton University Press, 1941. [14] Nicolaas Govert de Bruijn. Lambda calculus notation with nameless dummies, a tool for automatic formula manipulation, with application to the church-rosser theorem. In Indagationes Mathematicae (Proceedings), volume 75, pages 381–392, 1972. [15] Paul Downen and Zena M. Ariola. The duality of construction. In Programming Languages and Systems - 23rd European Symposium on Programming, ESOP 2014, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2014, Grenoble, France, April 5-13, 2014, Proceedings, pages 249–269, 2014. [16] Paul Downen and Zena M. Ariola. Beyond polarity: Towards a multi-discipline intermediate language with sharing. In 27th EACSL Annual Conference on Computer Science Logic, CSL 2018, September 4-7, 2018, Birmingham, UK, pages 21:1–21:23, 2018. [17] Paul Downen, Philip Johnson-Freyd, and Zena M. Ariola. Abstracting models of strong normalization for classical calculi. J. Log. Algebraic Methods Program., 111:100512, 2020. [18] Cormac Flanagan, Amr Sabry, Bruce F. Duba, and Matthias Felleisen. The essence of compiling with continuations. In Proceedings of the ACM SIGPLAN’93 Conference on Programming Language Design and Implementation (PLDI), Albuquerque, New Mexico, USA, June 23-25, 1993, pages 237–247, 1993. [19] Sebastian Graf and Simon Peyton Jones. Selective lambda lifting. CoRR, abs/1910.11717, 2019. [20] Jennifer Hackett and Graham Hutton. Parametric polymorphism and operational improvement. Proc. ACM Program. Lang., 2(ICFP):68:1–68:24, 2018. [21] John Hannan. Type systems for closure conversions. The Workshop on Types for Program Analysis, pages 64–83, 1995. [22] Richard B. Kieburtz. The g-machine: A fast, graph-reduction evaluator. In Functional Programming Languages and Computer Architecture, FPCA 1985, Nancy, France, September 16-19, 1985, Proceedings, pages 400–413, 1985. [23] Jean-Louis Krivine. A call-by-name lambda-calculus machine. Higher-Order and Symbolic Computation, 20(3):199–207, 2007. 194 [24] Peter J. Landin. The mechanical evaluation of expressions. The Computer Journal, 6(4):308–320, 1964. [25] John Launchbury. A natural semantics for lazy evaluation. In Conference Record of the Twentieth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Charleston, South Carolina, USA, January 1993, pages 144–154, 1993. [26] Xavier Leroy. The ZINC experiment: an economical implementation of the ML language. Technical report 117, INRIA, 1990. [27] Paul Blain Levy. Call-by-push-value. PhD thesis, Queen Mary University of London, UK, 2001. [28] John Maraist, Martin Odersky, and Philip Wadler. The call-by-need lambda calculus. J. Funct. Program., 8(3):275–317, 1998. [29] Simon Marlow and Simon L. Peyton Jones. Making a fast curry: push/enter vs. eval/apply for higher-order languages. In Proceedings of the Ninth ACM SIGPLAN International Conference on Functional Programming, ICFP 2004, Snow Bird, UT, USA, September 19-21, 2004, pages 4–15, 2004. [30] Phillip Mates, Jamie Perconti, and Amal Ahmed. Under control: Compositionally correct closure conversion with mutable state. In Ekaterina Komendantskaya, editor, Proceedings of the 21st International Symposium on Principles and Practice of Programming Languages, PPDP 2019, Porto, Portugal, October 7-9, 2019. ACM, 2019. [31] Luke Maurer, Paul Downen, Zena M. Ariola, and Simon L. Peyton Jones. Compiling without continuations. In Proceedings of the 38th ACM SIGPLAN Conference on Programming Language Design and Implementation, PLDI 2017, Barcelona, Spain, June 18-23, 2017, pages 482–494, 2017. [32] Dylan McDermott and Alan Mycroft. Extended call-by-push-value: Reasoning about effectful programs and evaluation order. In Programming Languages and Systems - 28th European Symposium on Programming, ESOP 2019, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2019, Prague, Czech Republic, April 6-11, 2019, Proceedings, pages 235–262, 2019. [33] Robin Milner, Mads Tofte, and Robert Harper. The Definition of Standard ML. MIT Press, Cambridge, MA, USA, 1990. [34] Yasuhiko Minamide, J. Gregory Morrisett, and Robert Harper. Typed closure conversion. In Conference Record of POPL’96: The 23rd ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Papers Presented at the Symposium, St. Petersburg Beach, Florida, USA, January 21-24, 1996, pages 271–283, 1996. 195 [35] Γ‰tienne Miquey and Hugo Herbelin. Realizability interpretation and normalization of typed call-by-need lambda-calculus with control. In Christel Baier and Ugo Dal Lago, editors, Foundations of Software Science and Computation Structures - 21st International Conference, FOSSACS 2018, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2018, Thessaloniki, Greece, April 14-20, 2018, Proceedings, volume 10803 of Lecture Notes in Computer Science, pages 276–292, 2018. [36] J. Gregory Morrisett, David Walker, Karl Crary, and Neal Glew. From system F to typed assembly language. In POPL ’98, Proceedings of the 25th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, San Diego, CA, USA, January 19-21, 1998, pages 85–97, 1998. [37] Chris Okasaki, Peter Lee, and David Tarditi. Call-by-need and continuation-passing style. LISP Symb. Comput., 7(1):57–82, 1994. [38] Zoe Paraskevopoulou and Andrew W. Appel. Closure conversion is safe for space. Proc. ACM Program. Lang., 3(ICFP):83:1–83:29, 2019. [39] Zoe Paraskevopoulou, John M. Li, and Andrew W. Appel. Compositional optimizations for certicoq. Proc. ACM Program. Lang., 5(ICFP):1–30, 2021. [40] James T. Perconti and Amal Ahmed. Verifying an open compiler using multi-language semantics. In Programming Languages and Systems - 23rd European Symposium on Programming, ESOP 2014, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2014, Grenoble, France, April 5-13, 2014, Proceedings, pages 128–148, 2014. [41] Simon L. Peyton Jones. The Implementation of Functional Programming Languages. Prentice-Hall, 1987. [42] Simon L. Peyton Jones and John Launchbury. Unboxed values as first class citizens in a non-strict functional language. In Functional Programming Languages and Computer Architecture, 5th ACM Conference, Cambridge, MA, USA, August 26-30, 1991, Proceedings, pages 636–666, 1991. [43] Simon L. Peyton Jones and Jon Salkild. The spineless tagless g-machine. In Proceedings of the Fourth International Conference on Functional Programming Languages and Computer Architecture, FPCA ’89, pages 184–201, 1989. [44] Simon L. Peyton Jones and AndrΓ© L. M. Santos. A transformation-based optimiser for haskell. Sci. Comput. Program., 32(1-3):3–47, 1998. [45] Andrew M. Pitts. Parametric polymorphism and operational equivalence. Math. Struct. Comput. Sci., 10(3):321–359, 2000. 196 [46] Gordon D. Plotkin. Call-by-name, call-by-value and the lambda-calculus. Theor. Comput. Sci., 1(2):125–159, 1975. [47] Jill Seaman and S. Purushothaman Iyer. An operational semantics of sharing in lazy evaluation. Sci. Comput. Program., 27(3):289–322, 1996. [48] Peter Sestoft. Deriving a lazy abstract machine. J. Funct. Program., 7(3):231–264, 1997. [49] Zhong Shao and Andrew W. Appel. Space-efficient closure representations. In Proceedings of the 1994 ACM Conference on LISP and Functional Programming, Orlando, Florida, USA, 27-29 June 1994, pages 150–161, 1994. [50] Zhong Shao and Andrew W. Appel. Efficient and safe-for-space closure conversion. ACM Trans. Program. Lang. Syst., 22(1):129–161, 2000. [51] Guy L. Steele. Rabbit: A compiler for scheme. Master’s thesis, Massachusetts Institute of Technology, 1978. [52] Zachary J. Sullivan, Paul Downen, and Zena M. Ariola. Strictly capturing non-strict closures. In Proceedings of the 2021 ACM SIGPLAN Workshop on Partial Evaluation and Program Manipulation, PEPM@POPL 2021, Virtual Event, Denmark, January 18-19, 2021, pages 74–89. ACM, 2021. [53] Zachary J. Sullivan, Paul Downen, and Zena M. Ariola. Closure conversion in little pieces. In Santiago Escobar and Vasco T. Vasconcelos, editors, International Symposium on Principles and Practice of Declarative Programming, PPDP 2023, Lisboa, Portugal, October 22-23, 2023, pages 10:1–10:13. ACM, 2023. [54] D. A. Turner. A new implementation technique for applicative languages. Softw., Pract. Exper., 9(1):31–49, 1979. [55] Philip Wadler. Call-by-value is dual to call-by-name. In Proceedings of the Eighth ACM SIGPLAN International Conference on Functional Programming, ICFP 2003, Uppsala, Sweden, August 25-29, 2003, pages 189–201, 2003. [56] Mitchell Wand and Paul Steckler. Selective and lightweight closure conversion. In Proceedings of the 21st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’94, pages 435–445, 1994. 197