Science, Faculty of
Computer Science, Department of
DSpace
UBCV
Eremondi, Joseph S.
Doctor of Philosophy - PhD
University of British Columbia
Dependently typed programming languages provide a way to write programs, specifications, and correctness proofs using a single language. If a dependent type checker accepts a program, the programmer can be assured that it behaves according to the specification given in its types. However, dependently typed programming languages can be hard to use. Gradual types provide a way to mix dynamically and statically typed code in a single language. Under this paradigm, programs may have imprecise types, causing certain type checks to be deferred to run time. We build the theoretical foundations for combining gradual and dependent types in a programming language, with the aim of making dependent types easier to use. The differences between these two paradigms lead to inherent tensions when choosing the properties such a language should satisfy. Gradual typing's effectful nature conflicts with the compile-time reductions of dependent type checking. Gradual run-time type comparisons clash with dependent types containing terms that bind variables. This dissertation identifies such tensions and proposes a design that finds balance between the conflicting goals. Our contribution has three parts: First, we present a foundational calculus for gradual dependent types, with functions, function types and universes. To ensure that type checking terminates, we reduce compile-time terms with approximate normalization, producing imprecise results when the available type information cannot guarantee termination. We use hereditary substitution to show that approximate normalization always terminates. Second, we present a notion of propositional equality for gradual dependent types. We devise a method of tracking run-time consistency information between imprecise equated terms, and introduce a composition operator in the language itself. Third, we show that the first and second contributions can be combined, giving a language with approximate normalization that supports inductive types and propositional equality with dynamic consistency tracking. Since hereditary substitution does not scale to inductive types, we use a syntactic model to establish termination. The same technique is used to model non-terminating run-time semantics using guarded type theory, paving the road for mechanizing the metatheory of gradual dependent types.
One Design of a Gradual Dependently TypedLanguage for ProgrammingbyJoseph S. EremondiBSc. Honours Computer Science, University of Saskatchewan, 2014BSc. Mathematics, University of Saskatchewan, 2014MSc. Computing Science, Universiteit Utrecht, 2016a thesis submitted in partial fulfillmentof the reqirements for the degree ofDoctor of Philosophyinthe faculty of graduate and postdoctoral studies(Computer Science)e University of British Columbia(Vancouver)March 2023© Joseph S. Eremondi, 2023e following individuals certify that they have read, and recommend to theFaculty of Graduate and Postdoctoral Studies for acceptance, the thesis entitled:On eDesign of aGradualDependentlyTypedLanguage for Programmingsubmi ed by Joseph S. Eremondi in partial ful llment of the requirements forthe degree of Doctor of Philosophy in Computer Science.Examining Committee:Ronald Garcia, Associate Professor, Computer Science, UBCSupervisorWilliam Bowman, Assistant Professor, Computer Science, UBCSupervisory Commi ee MemberE´ric Tanter, Professor, Computer Science Department, University of ChileSupervisory Commi ee MemberIvan Beschastnikh, Associate Professor, Computer Science, UBCUniversity ExaminerSathish Gopalakrishnan, Associate Professor, Electrical and Computer Eng., UBCUniversity ExaminerDaniel Licata, Associate Professor, Computer Science, Wesleyan UniversityExternal ExamineriiAbstractDependently typed programming languages provide a way to write programs,specications, and correctness proofs using a single language. If a dependenttype checker accepts a program, the programmer can be assured that it behavesaccording to the speci cation given in its types. However, dependently typedprogramming languages can be hard to use.Gradual types provide a way to mix dynamically and statically typed codein a single language. Under this paradigm, programs may have imprecise types,causing certain type checks to be deferred to run time.We build the theoretical foundations for combining gradual and dependenttypes in a programming language, with the aim of making dependent types eas-ier to use. e di erences between these two paradigms lead to inherent tensionswhen choosing the properties such a language should satisfy. Gradual typing’s ef-fectful nature con icts with the compile-time reductions of dependent type check-ing. Gradual run-time type comparisons clash with dependent types containingterms that bind variables. is dissertation identi es such tensions and proposesa design that nds balance between the con icting goals.Our contribution has three parts:First, we present a foundational calculus for gradual dependent types, withfunctions, function types and universes. To ensure that type checking terminates,we reduce compile-time terms with approximate normalization, producing impre-cise results when the available type information cannot guarantee termination.We use hereditary substitution to show that approximate normalization alwaysterminates.Second, we present a notion of propositional equality for gradual dependentiiitypes. We devise a method of tracking run-time consistency information betweenimprecise equated terms, and introduce a composition operator in the languageitself.ird, we show that the rst and second contributions can be combined, giv-ing a language with approximate normalization that supports inductive types andpropositional equality with dynamic consistency tracking. Since hereditary sub-stitution does not scale to inductive types, we use a syntactic model to establishtermination. e same technique is used to model non-terminating run-time se-mantics using guarded type theory, paving the road for mechanizing the metathe-ory of gradual dependent types.ivLay SummaryProgramming is hard, and soware with mistakes is frequently released. Depen-dently typed programming languages give a way for programmers to specify howprograms should behave, and to write mathematical proofs that programs meetthose speci cations.However, programming with dependently typed languages is hard. If a pro-gram passes a dependent type checker, the programmer can be con dent it is cor-rect, but to satisfy the type checker, they must accurately specify the behaviourof their program and mathematically prove that it ful lls the desired properties.As such, the barrier to entry is high for dependent types.is dissertation develops the theory of gradual dependent types, a system thatlets the programmer gradually introduce speci cations and choose whether thosespeci cations should be proved before the program runs or checked while it runs.Our work provides a balance between safety and exibility, laying a foundationthat makes dependent types easier to use.vPrefacee text of Chapter 1 draws from Eremondi, Tanter, and Garcia (2019) [58] ofwhich I was the lead author. In particular, the motivating example with quicksortand length-indexed vectors is drawn from that work.A version of Chapter 3 is published [J. Eremondi, E. Tanter, and R. Garcia. Approx-imate normalization for gradual dependent types. Proc. ACM Program. Lang., 3(ICFP):88:1–88:30, July 2019. ISSN 2475-1421]. e use of compile-time evidenceis novel to this dissertation, and corrects an error in the published work. I wasthe lead author, conceiving of the idea, developing the calculus, and constructingthe proofs. R. Garcia and E´. Tanter were supervisory authors and were involvedthroughout the research and manuscript preparation. E´. Tanter was responsiblefor the normalization gradual guarantee.e text of Chapter 4 draws from Eremondi, Garcia, and Tanter (2022) [60], andpresents material originally published by Lennon-Bertrand, Maillard, Tabareau,and Tanter (2022) [87] under a license that permits abstracting with credit.A version of Chapter 5 is published [J. Eremondi, R. Garcia, and E. Tanter. Proposi-tional equality for gradual dependently typed programming. Proc. ACM Program.Lang., 6(ICFP), August 2022]. I was the lead author, inventing equality witnessesand constructing the language. R. Garcia and E´. Tanter were supervisory authorsand were involved throughout the research and manuscript preparation.e remaining chapters are the original, unpublished work of J. Eremondi.viTable of ContentsAbstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiiLay Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vPreface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viTable of Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viiList of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiiiList Of Abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvGlossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xviiAcknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiDedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xxiv1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1 Why Gradual Dependent Types? . . . . . . . . . . . . . . . . . . . 11.1.1 e Best of Both Worlds: Gradual Types . . . . . . . . . . 21.1.2 Extreme Static Typing: Dependent Types . . . . . . . . . . 31.1.3 e Need for Gradual Dependent Types . . . . . . . . . . 41.2 A Note on Typography . . . . . . . . . . . . . . . . . . . . . . . . 61.3 A Motivating Example . . . . . . . . . . . . . . . . . . . . . . . . 71.3.1 e Pain and Promise of Dependent Types . . . . . . . . . 7vii1.3.2 Challenges and Solutions with Gradual Dependent Types 111.4 esis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Background and Related Work . . . . . . . . . . . . . . . . . . . . . 172.1 Gradual Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.1.1 Imprecise Types . . . . . . . . . . . . . . . . . . . . . . . . 172.1.2 Gradual Metatheory . . . . . . . . . . . . . . . . . . . . . 192.1.3 Abstracting Gradual Typing . . . . . . . . . . . . . . . . . 232.2 Dependent Types . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.2.1 Essential Dependent Types . . . . . . . . . . . . . . . . . 282.2.2 Inductive Families and Pa ern Matching . . . . . . . . . . 322.2.3 Generic Representations of Inductive Types . . . . . . . . 412.2.4 Dependent Types: Implementation and Practical Details . 462.2.5 Syntactic Models of Dependently Typed Languages . . . . 502.3 Prior Work on Gradual Dependent Types . . . . . . . . . . . . . . 512.3.1 Contracts and Dynamic Checking . . . . . . . . . . . . . . 522.3.2 Gradual Type eories . . . . . . . . . . . . . . . . . . . . 532.3.3 Dependently Typed Non-termination . . . . . . . . . . . . 543 Foundations of Gradual Dependent Types . . . . . . . . . . . . . . 563.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573.2 Goals and Challenges . . . . . . . . . . . . . . . . . . . . . . . . . 593.2.1 e unknown as a type index . . . . . . . . . . . . . . . . 603.2.2 e unknown as a term at run time . . . . . . . . . . . . 603.2.3 Managing e ects from gradual typing . . . . . . . . . . . 613.2.4 Gradual Guarantees for gdtl . . . . . . . . . . . . . . . . 633.2.5 Summary of Design Decisions . . . . . . . . . . . . . . . . 643.3 sdtl: A Static Dependently Typed Language . . . . . . . . . . . . 653.3.1 Syntax and Dynamic Semantics . . . . . . . . . . . . . . . 653.3.2 Comparing Types: Normal Forms . . . . . . . . . . . . . . 663.3.3 Type checking and Normalization . . . . . . . . . . . . . . 673.3.4 Hereditary Substitution . . . . . . . . . . . . . . . . . . . 703.3.5 Properties of sdtl . . . . . . . . . . . . . . . . . . . . . . 74viii3.4 gdtl: Abstracting the Static Language . . . . . . . . . . . . . . . 743.4.1 Terms and Normal Forms . . . . . . . . . . . . . . . . . . 753.4.2 Concretization and Predicates . . . . . . . . . . . . . . . . 773.4.3 Functions and Abstraction . . . . . . . . . . . . . . . . . . 773.4.4 Soundness and Optimality . . . . . . . . . . . . . . . . . . 793.4.5 Typing Rules . . . . . . . . . . . . . . . . . . . . . . . . . 813.4.6 Example: Type checking the head of an empty vector . . . 843.5 Approximate Normalization . . . . . . . . . . . . . . . . . . . . . 863.5.1 Dierences from the Published Version . . . . . . . . . . . 873.5.2 Approximate Substitution . . . . . . . . . . . . . . . . . . 873.5.3 Normalization and Compile-Time Evidence . . . . . . . . 923.5.4 Properties of Approximate Normalization . . . . . . . . . 1003.6 gdtl: Run-time Semantics . . . . . . . . . . . . . . . . . . . . . . 1013.6.1 e Run-time Language . . . . . . . . . . . . . . . . . . . 1013.6.2 Typing and Evidence . . . . . . . . . . . . . . . . . . . . . 1033.6.3 Developing a Safe Semantics . . . . . . . . . . . . . . . . . 1043.6.4 Example: Computing the head of the empty vector . . . . 1063.7 Properties of gdtl . . . . . . . . . . . . . . . . . . . . . . . . . . . 1063.7.1 Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1073.7.2 Conservative Extension of sdtl . . . . . . . . . . . . . . . 1073.7.3 Embedding of Untyped Lambda Calculus . . . . . . . . . . 1083.7.4 Gradual Guarantees . . . . . . . . . . . . . . . . . . . . . 1083.8 Related Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1103.8.1 Static Dependent Types . . . . . . . . . . . . . . . . . . . 1103.8.2 Mixing Dependent Types and Non-termination . . . . . . 1103.8.3 Mixing Dependent Types and Simple Types . . . . . . . . 1113.8.4 Programming with Holes . . . . . . . . . . . . . . . . . . 1113.9 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1124 Interlude: e Gradual Calculus of Inductive Constructions . . . 1134.1 Overview: gdtl vs. gcic . . . . . . . . . . . . . . . . . . . . . . . 1144.1.1 Similarities . . . . . . . . . . . . . . . . . . . . . . . . . . 1144.1.2 Di erences . . . . . . . . . . . . . . . . . . . . . . . . . . 114ix4.2 e Bidirectional CIC . . . . . . . . . . . . . . . . . . . . . . . . . 1174.2.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1174.2.2 Typing and Semantics . . . . . . . . . . . . . . . . . . . . 1184.3 gcic: e Surface Language . . . . . . . . . . . . . . . . . . . . . 1214.4 CastCIC: e Cast Calculus . . . . . . . . . . . . . . . . . . . . . 1224.4.1 Syntax, Typing and Reductions . . . . . . . . . . . . . . . 1224.4.2 Elaboration . . . . . . . . . . . . . . . . . . . . . . . . . . 1245 Propositional Equality and Dynamic Consistency Tracking . . . . 1295.1 Gradual Propositional Equality . . . . . . . . . . . . . . . . . . . . 1305.2 Se ing e Stage . . . . . . . . . . . . . . . . . . . . . . . . . . . 1325.2.1 Programming vs. Proving and the Gradual Guarantees . . 1325.2.2 Relationship to Existing Languages . . . . . . . . . . . . . 1335.2.3 A Motivating Example: Eagerly Enforcing Speci cations . 1345.2.4 Lazily Enforcing Specs: Function Equalities and Exten-sionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1395.3 Propositional Equality . . . . . . . . . . . . . . . . . . . . . . . . . 1435.3.1 GEq Syntax and Typing . . . . . . . . . . . . . . . . . . . 1455.3.2 CastEq Syntax and Typing . . . . . . . . . . . . . . . . . 1455.3.3 Cast Semantics . . . . . . . . . . . . . . . . . . . . . . . . 1465.3.4 Semantics of Composition . . . . . . . . . . . . . . . . . . 1495.4 Parameterized Metatheory: Criteria for Precision and Consistency 1535.4.1 Stating the Gradual Guarantees . . . . . . . . . . . . . . . 1535.4.2 Necessary Properties of Precision and Consistency . . . . 1545.4.3 Metatheory: Proving Safety and the Gradual Guarantees . 1575.5 Consistency and Precision . . . . . . . . . . . . . . . . . . . . . . 1595.5.1 Precision and Consistency in gcic . . . . . . . . . . . . . 1605.5.2 Precision and Consistency for GEq . . . . . . . . . . . . . 1615.5.3 Ful lling e Criteria . . . . . . . . . . . . . . . . . . . . . 1655.6 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1675.6.1 Extensions Enabled by Equality . . . . . . . . . . . . . . . 1675.6.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . 1705.6.3 Related Work . . . . . . . . . . . . . . . . . . . . . . . . . 172x6 A Syntactic Model of Approximate and Exact Gradual Semantics 1746.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1756.1.1 ree Problems, One Solution . . . . . . . . . . . . . . . . 1766.2 A Birds Eye View of the Syntactic Model . . . . . . . . . . . . . . 1786.2.1 e Source Language . . . . . . . . . . . . . . . . . . . . . 1786.2.2 What’s In a Model? . . . . . . . . . . . . . . . . . . . . . . 1846.2.3 e Target Language . . . . . . . . . . . . . . . . . . . . . 1856.2.4 Mode Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . 1886.2.5 Modelling Values and Expressions . . . . . . . . . . . . . 1886.2.6 Elimination Operations . . . . . . . . . . . . . . . . . . . 1926.3 Modelling e Unknown, Exactly and Approximately . . . . . . . 1936.3.1 Heads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1936.3.2 An Inductive Representation of the Unknown Type . . . . 1936.3.3 e Germ for Inductive Types . . . . . . . . . . . . . . . . 1966.4 Modelling Types: A Gradual Universe of Codes . . . . . . . . . . 2016.4.1 Gradual W-Types . . . . . . . . . . . . . . . . . . . . . . . 2016.4.2 Codes for inductive types . . . . . . . . . . . . . . . . . . 2026.4.3 Tying the Knot . . . . . . . . . . . . . . . . . . . . . . . . 2106.5 Elimination Operations on Values . . . . . . . . . . . . . . . . . . 2116.5.1 Operations for Inductives . . . . . . . . . . . . . . . . . . 2116.5.2 Dynamic Errors . . . . . . . . . . . . . . . . . . . . . . . . 2116.5.3 Well-Founded Recursion on Codes and Values . . . . . . . 2126.5.4 De ning the Operations . . . . . . . . . . . . . . . . . . . 2176.5.5 Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2206.6 Inductives in the Model . . . . . . . . . . . . . . . . . . . . . . . . 2296.6.1 Inductive Constructors and Eliminators . . . . . . . . . . 2296.7 Bringing it All Together . . . . . . . . . . . . . . . . . . . . . . . . 2306.7.1 e Translation . . . . . . . . . . . . . . . . . . . . . . . . 2306.7.2 Key Properties . . . . . . . . . . . . . . . . . . . . . . . . 2306.7.3 A Final Example . . . . . . . . . . . . . . . . . . . . . . . 2327 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2367.1 Does Approximate Normalization Ma er? . . . . . . . . . . . . . 236xi7.1.1 Approximate Witnesses . . . . . . . . . . . . . . . . . . . 2377.2 Limitations and Future Work . . . . . . . . . . . . . . . . . . . . . 2387.2.1 Adequacy . . . . . . . . . . . . . . . . . . . . . . . . . . . 2387.2.2 Approximating Inductive Types . . . . . . . . . . . . . . . 2387.2.3 Mechanized Metatheory . . . . . . . . . . . . . . . . . . . 2397.2.4 Symbolic Gradual Dependent Types . . . . . . . . . . . . 2407.2.5 Broader Applications of Approximate Normalization . . . 2437.2.6 Implementation . . . . . . . . . . . . . . . . . . . . . . . . 2437.3 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245A Full Proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263xiiList of FiguresFigure 3.1 sdtl: Syntax and Semantics . . . . . . . . . . . . . . . . . . . 66Figure 3.2 sdtl: Normal and Neutral Forms . . . . . . . . . . . . . . . . 68Figure 3.3 sdtl: Type Synthesis and Checking . . . . . . . . . . . . . . . 69Figure 3.4 sdtl: Normalization . . . . . . . . . . . . . . . . . . . . . . . 71Figure 3.5 sdtl: Auxiliary Judgments for Normal Forms . . . . . . . . . 72Figure 3.6 sdtl: Hereditary Substitution . . . . . . . . . . . . . . . . . . 73Figure 3.7 gdtl: Terms and Normal Forms . . . . . . . . . . . . . . . . . 76Figure 3.8 gdtl: Concretization and Consistency . . . . . . . . . . . . . 78Figure 3.9 gdtl: Abstraction and Lied Functions . . . . . . . . . . . . . 80Figure 3.10 gdtl: Type Checking and Synthesis . . . . . . . . . . . . . . . 82Figure 3.11 gdtl: Well-Formedness Rules . . . . . . . . . . . . . . . . . . 83Figure 3.12 Type Derivation for head of nil . . . . . . . . . . . . . . . . . 85Figure 3.13 Approximate Neutral Substitution, Key Rules . . . . . . . . . 89Figure 3.14 gdtl: Approximate Normal Substitution . . . . . . . . . . . . 90Figure 3.15 gdtl: 𝜂-expansion . . . . . . . . . . . . . . . . . . . . . . . . 92Figure 3.16 gdtl: Approximate Normalization . . . . . . . . . . . . . . . 95Figure 3.17 gdtl: Meta-level Casting . . . . . . . . . . . . . . . . . . . . . 97Figure 3.18 gdtl: Meta-level Casting to the unknown type . . . . . . . . 98Figure 3.19 gdtl: Meta-level Casting from the unknown type . . . . . . . 99Figure 3.20 gdtl: Composing Normal Forms . . . . . . . . . . . . . . . . 99Figure 3.21 Evidence Term Syntax and Typing . . . . . . . . . . . . . . . 102Figure 3.22 gdtl: Dynamic Semantics . . . . . . . . . . . . . . . . . . . . 105Figure 3.23 Gradual Precision of Normals, Neutrals and Environments . . 109xiiiFigure 4.1 bcic: Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117Figure 4.2 bcic: Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . 119Figure 4.3 Bidirectional cic: Syntax, Typing and Semantics . . . . . . . . 120Figure 4.4 gcic: Syntax and Typing Lemmas . . . . . . . . . . . . . . . . 121Figure 4.5 CastCIC: Typing and New Syntax . . . . . . . . . . . . . . . 123Figure 4.6 CastCIC: Propagation Reduction Rules . . . . . . . . . . . . 124Figure 4.7 CastCIC: Cast Reduction Rules . . . . . . . . . . . . . . . . . 125Figure 4.8 Elaboration from gcic to CastCIC . . . . . . . . . . . . . . . 126Figure 4.9 Elaboration from gcic to CastCIC (ctd.) . . . . . . . . . . . . 127Figure 4.10 CastCIC Consistency and Consistent Convertibility . . . . . 128Figure 5.1 Sorting Fixed-Length Lists . . . . . . . . . . . . . . . . . . . . 136Figure 5.2 GEq: Syntax and Typing Lemmas . . . . . . . . . . . . . . . . 146Figure 5.3 CastEq: Syntax, Typing and Elaboration Rules . . . . . . . . 147Figure 5.4 CastEq: Reductions for Casts and Equality . . . . . . . . . . 148Figure 5.5 CastEq: Semantics for Composition . . . . . . . . . . . . . . 150Figure 5.6 Positive Types . . . . . . . . . . . . . . . . . . . . . . . . . . . 151Figure 5.7 Telescope Composition . . . . . . . . . . . . . . . . . . . . . . 152Figure 5.8 Structural Precision: Generating and Cast Rules . . . . . . . . 161Figure 5.9 Precision: Diagonal Rules for gcic forms . . . . . . . . . . . . 162Figure 5.10 Denitional Precision . . . . . . . . . . . . . . . . . . . . . . . 163Figure 5.11 Precision for Propositional Equality and Composition . . . . . 164Figure 5.12 Precision Modulo Conversion . . . . . . . . . . . . . . . . . . 164Figure 5.13 Consistency for Propositional Equality and Composition . . . 164Figure 6.1 Ordering on Sizes . . . . . . . . . . . . . . . . . . . . . . . . . 218Figure 6.2 Model of Composition . . . . . . . . . . . . . . . . . . . . . . 221Figure 6.3 Model of Composition for Codes . . . . . . . . . . . . . . . . 222Figure 6.4 Model of Casting . . . . . . . . . . . . . . . . . . . . . . . . . 224Figure 6.5 Model of Casting (ctd.) . . . . . . . . . . . . . . . . . . . . . . 225Figure 6.6 Casting Functions To and From the Germ . . . . . . . . . . . 226Figure 6.7 e Unknown Term for Codes . . . . . . . . . . . . . . . . . . 228Figure 6.8 Syntactic Model of ⊲GEq: Summary . . . . . . . . . . . . . . . 231xivList Of Abbreviationsagt Abstracting Gradual Typing.bcic the Bidirectional Calculus of Inductive Constructions.CastCIC Cast calculus for the Gradual Calculus of Inductive Constructions.CastEq Cast calculus with propositional Equality.cc𝜔 the Calculus of Constructions with a predicative universe hierarchy.cic the Calculus of Inductive Constructions.EP-pair embedding-projection pair.ffi Foreign function interface.gcic the Gradual Calculus of Inductive Constructions.gdtl Gradual Dependently Typed Language.GEq Gradual language with propositional Equality.⊲GEq Guarded Gradual language with propositional Equality and decidable typechecking.grip a “reasonably gradual” type theory.gtt Guarded Type eory.xvmltt Martin-Lo¨f Type eory.ott Observational Type eory.repl Read Eval Print Loop.sdtl Static Dependently Typed Language.stlc the Simply Typed Lambda Calculus.tctt Ticked Cubical Type eory.uip Uniqueness of Identity Proofs..xviGlossaryapproximate normalization Amethod of reducing programs to a normal formfor gradual types. Whenever type information is not precise enough toguarantee that a term can halt, an imprecise term is produced as a result.Approximate normalization ensures that type checking terminates.axiom K e principle that re exivity is the only proof that a term is equal toitself. Equivalent to uip.canonicity e property that, for every type 𝑇 , every closed term of type 𝑇 caneither be reduced, or is constructed with a type former for 𝑇 .cast calculus An intermediate language for gradual typing, where imprecise typesare allowed, but all conversions between types are explicitly marked by acasting operation.closed type theory A type theory with a xed set of type formers, where newinductive types cannot be declared.consistent transitivity For a given relation, the operation in Abstracting Grad-ual Typing where, given evidence that 𝑇1 and 𝑇2 are related, and evidencethat𝑇2 and𝑇3 are related, the two pieces of evidence are composed to deter-mine if 𝑇1 and 𝑇3 are known to be related. Collapses to the precision-meetwhen the relation is the gradual li ing of equality.container See W-type.cumulativity e principle that a term with type Typeℓ can also be typed atTypeℓ+1.xviiCurry-Howard correspondence A correspondence between constructive logicand programming languages, where propositions correspond to types, pro-grams correspond to proofs, and inhabited types correspond to theorems.denitional equality e notion of equality used to compare terms during de-pendent type checking. O en it is de ned as syntactic 𝛼-equivalence ofnormal forms.dependent pair A dependent type whose elements contain two values, wherethe type of the second may refer to the value of the rst.dynamic gradual guarantee e property that reducing a program’s precisioncauses no new dynamic type errors, and that other than errors, changing aprogram’s precision does not alter its behaviour.function extensionality e principle (or axiom) that two functions are propo-sitionally equal if they produce the equal outputs for all inputs.functor In this dissertation: the function from Type to Type of which an induc-tive type is a xed-point..gradual guarantees See static gradual guarantee and dynamic gradual guaran-tee.graduality e semantic notion of the gradual guarantee given by New andAhmed [105], stating that precision-related terms produce precision-relatedresults under any context. Used by Lennon-Bertrand et al. [87] to meanembedding-projection pair, since they are typically how graduality is es-tablished..inductive type A type𝑇 de ned in terms of some number of constructors, eachof which contains elds, some of which may be of type 𝑇 .motive A function producing a type, given as an argument to the eliminator foran inductive data type. If the motive is 𝑃 , eliminating 𝑡 produces a value oftype 𝑃 𝑡 .xviiinormalization gradual guarantee e property that all normalizations duringtype checking obey the dynamic gradual guarantee..observational equivalence Two programs are observationally equivalent if, un-der any observable context, they produce the same results. Common no-tions of observation include whether two programs have the same haltingbehavior under all contexts, or whether two programs produce the sameresult in all boolean-typed contexts.open type theory A type theorywhich does not have a xed set of type formers,but allows for the declaration of new inductive types and their constructors.proof terms A term in a dependently typed program whose purpose is not tospecify behavior, but to establish that another piece of code ful lls someproperty.propositional equality e internalization of de nitional equality as a type in adependently typed programming language. For any two terms of some type,the propositional equality type contains all proofs that those two terms areequal, if any such proofs exist.static gradual guarantee e property that reducing a program’s precision causesno new static type errors.strictly positive A function from types to types is called strictly positive if itsparameter never occurs to the le of a function arrow. An inductive de ni-tion is strictly positive if it is the xed-point of a strictly positive function,that is, it has no self-reference to the le of an arrow..syntactic model A method of de ning semantics for a language by giving atranslation to another language, usually a logically-consistent dependentlytyped language.transport A function that converts between two types, given a proof that thosetypes are equal.xixunknown type e least precise type in gradual typing. A term of the unknowntype can be used in a context expecting a value of any type.W-type Agenericmethod of de ning inductive types, given by specifying a com-mand type 𝐶 that speci es the constructor and values for non-recursiveelds, and a response type 𝑅 for each command value, roughly denoting“how many” recursive references should accompany that command. ecommand and response together are called a container. e elements of𝑊 𝐶 𝑅 consist of a command value 𝑐 :𝐶 and a function from 𝑅 𝑐 to𝑊 𝐶 𝑅.xxAcknowledgmentsI am grateful to NSERC for their nancial support through the CGS-D scholarship.I am thankful to everyone who has helped me on this journey. In particular, Iwish to thank:• Ron Garcia: When I arrived at UBC, I thought studying programming lan-guages meant using Haskell, that writing was about using big words toshow how smart you were, and that I could treat conference talks like de-bate speeches, speaking quickly and angrily. In my time as your student,you have taught me so much, and you have done so with a gentleness andexibility, without which I would have buckled under the stresses of a PhD.You have gone out of your way to ensure my studies were compatible withbeing a parent, and for some reason you put up with my last-minute dead-line pushes and typo-ridden dra s. ank you for being my mentor andguide.• E´ric Tanter: from the time Ron gave you my half-cooked error-ridden draof our ICFP19 paper, you have been instrumental in helping me re ne myideas into something worth sharing, guiding me through existing literatureand nding the interesting questions in my research.• William Bowman: Whether as a senior student introducing me to Cur inNara at the beginning of my PhD, or as a professor teaching me compilertheory, you have been a friend and guide throughout this process. One day,we will bring Ron to the light of dependent types.• Daniel Licata, Mieszko Lis, Ivan Beschastnikh, and Sathish Gopalakrishnan:xxiank you for agreeing to be on my examination commi ee, for reviewingmy dissertation, for your helpful suggestions and ideas for future work, andfor keepingme onmy toes with tough but fair questions duringmy defence.• Wouter Swierstra: for your exibility in helping me complete my Master’sthesis, and for teaching me how to collaborate remotely, a skill that provedvery useful in 2020. Without you, I would not have begunmy PhD, let alonenished it.• Dominic Orchard: In 2012 I a ended the SPLASH to compete in the under-graduate student research competition. I had never a ended a conferencebefore, and I was scared, shy and lonely. You talked to me and invited meout with your labmates, and visited with me throughout the conference.Your kindness was my introduction to the warmth found in throughoutthe programming languages community, and was part of why I ultimatelywanted to be part of that community.• Jana Dun eld and Alex Summers: through reading group and the SPL, youhave both been valuable mentors. ank you for all the programming lan-guage ideas, old and new, that you have introduced me to.• Felipe, Nico, Rui, Paule e, Jonathan, Adam, and all my other SPLabmates,classmates, reading group members and UBC friends: From helping eachother with our research, to keeping the mood light in the lab, to su er-ing through impenetrable category theory papers together, I am thankfulfor the fellowship we shared at UBC.• Andrej Bauer, Andra´s Kova´cs, Conor McBride, Daniel Gratzer, Jonathan Ster-ling, Ame´lia Liao, Paolo Giarrusso, Guillaume Allais, Jesper Cockx, Neel Kr-ishnaswami, Andrea Vezzosi, and everyone else who answered my questionsonline: you have providedmewith somuch knowledge, and you helped cre-ate a sense of community when I was stuck at home during the pandemic.ank you.• MyDalmeny family: You have supported me andmy family throughout thisentire process, nancially, emotionally, and with your time. From drivingxxiito Vancouver to help us move to the vast amount of child care you gavein my last year, I absolutely could not have nished my PhD without yoursupport.• My Nanaimo family: I am so grateful to have had family with me in BritishColumbia. From game nights, to baby si ing, to saving us during two familyemergencies, you have been true friends to us. I love you, and I am so proudof how you have grown and what your family has become.• My parents: You have encouraged my learning throughout my whole life,from reading to me about dinosaurs, to learning the world capitals with me,to proofreading high-school essays, to listening to whatever I was ramblingon about at a given time. You have taught me, supported me, and believedin me, and loved me unconditionally. ank you.• My wife, Joanne: You have supported me unwaveringly through this longprocess, in somanyways. You have endured somuchwithme and sacri cedso much for us to reach this point. I cannot imagine what my life would beif I did not have you in it. I love you, and I could not have done this withoutyou.xxiiiDedicationFor B and K, my reasons to go on.xxivChapter 1Introduction1.1 Why Gradual Dependent Types?Writing correct soware is hard. As so ware becomes ubiquitous in society, thecosts of incorrect so ware increase. e harms caused by programmer error in-clude the loss of millions of dollars in currency exchanges [45], widespread cor-ruption of analysis in genomics research [10], and even airplane crashes [148].Many tools have been developed to prevent errors in programs, but the pro-grammer’s rst line of defence against bugs is the programming language. Whengiven tools for abstraction, the programmer can design large scale programswith-out needing to reason about the byte-level behaviour of their program. Likewise,repeated behaviour can be separated into a function or method, le ing the pro-grammer reason about the behaviour of parts of the code without having to men-tally model the entire program at once.Two main paradigms have arisen in programming languages. Statically typedprogramming languages require each expression in a language to have a type,which can describe properties such as the possible forms that data can take, infor-mation ow, exceptions that can be raised, etc. Likewise, operations are assignedtypes to determine what expressions constitute valid arguments. ese types maybe speci ed by the programmer, or they may be inferred by a type checker, butthey must be known before the program runs. A type checker veri es that code iswell typed, and hence describes a valid program, before running or compiling it.1Dynamically typed languages impose no such restriction that types must be stat-ically known, and programs that provide invalid operands to an operation maycrash with a run-time error.Static and dynamic checking have their own tradeos. Static checking canprevent a large class of bugs, and provide guidance to the programmer about whatvalues are valid arguments to a function or operation. However, when writing afunction, the programmer must know the types of its inputs and outputs beforeit can be tested. On the other hand, dynamic checking leave the possibility ofrun-time errors, but allow for easy code re-use and rapid prototyping.1.1.1 The Best of Both Worlds: Gradual TypesStatic and dynamic checking each have unique advantages, but their bene ts arenot mutually exclusive. Gradual typing [132] provides a principled approach tomixing statically and dynamically typed code. In a gradual language, the pro-grammer can annotate some expressions with the unknown type ?. Terms of type? can be used in any context and built from values of any type. e key featureof (sound) gradual typing is that when typing information is not known stati-cally, dynamic checks are automatically inserted into a program, ensuring thatany run-time type errors lead to immediate program termination, rather than un-safe memory access or other undesired behaviour that might be exploitable by ana acker, or might inadvertently cause data loss or other damage.Moreover, fully gradual languages support migration from dynamic enforce-ment of type invariants to static enforcement. e gradual guarantees of Siek et al.[136] state that decreasing the precision of a program never introduces new staticor dynamic type errors. ese guarantees ensure that, when an error is encoun-tered, the problem is never too few types, but that some statics types ascribed toparts of the program are fundamentally incompatible. With the gradual guaran-tees, if a program is statically typeable, then that program is gradually typeableat every step between fully dynamic and fully static.21.1.2 Extreme Static Typing: Dependent TypesConventional static and dynamic typing are not capable of eliminating all bugsfrom code. Static checks can prevent dynamic type errors, and dynamic checkscan ensure such errors never cause unsafe behaviour. However, correctness bugscan still cause problems in programs. Even if a program runs successfully, it mightnot behave in the way the programmer expects. Testing is not sucient to guar-antee correctness: if a program has in nitely many possible inputs, then it is im-possible for testing alone to ensure that the program produces the desired outputfor each input.However, dependently typed languages can guarantee the correctness of a pro-gram, at least up to the speci cation given in its type. Types may refer to (dependon) terms, which makes them expressive enough to write complete program spec-i cations. For instance, the type of vectors is indexed by a number denoting itslength. e terms occurring within types need not be values: types can dependon yet-to-be-evaluated expressions. Moreover, dependent types are rst-class lan-guage constructs: in addition to containing computation, types can be the inputto computation or the result of computation.Dependent types are deeply connected to logic: rough a connection knownas the Curry-Howard correspondence, each type corresponds to a logical propo-sition, and a term of that type denotes a proof that said proposition holds. iscorrespondence allows for programmers to write their programs, the correctnessspeci cations for their programs, and the proof that the programs meet thosespeci cations, using a single, uni ed language.Dependent types can express invariants that are more ne-grained than non-dependent static type systems, such asML orHaskell-style types, whichwe hence-forth describe as simply-typed. Dependent type checkers can reject some pro-grams accepted by simply-typed languages, such as those that call a function butviolate said function’s precondition. Conversely, the ability of a function’s returntype to depend on an argument’s value means that some idioms from dynami-cally typed languages can be expressed with static dependent types. ere areprograms that have no type in simply-typed languages, that can be assigned atype in a dependently typed language. Hence, with dependent types, developers3can write highly exible, reliable code.1.1.3 The Need for Gradual Dependent Typesough dependently typed languages give the power to ensure that so ware iscorrect, they can be di cult to use. One can be con dent that a program acceptedby a dependent type checker meets the speci cation given by its types, but ac-tually producing such a program and speci cation is hard. When verifying a Ccompiler using dependent types, Leroy [88] notes that the veri cation code is ap-proximately six times larger than the program being veri ed. Ringer et al. [126]observe that most dependently typed developments are completed by small teamsof experts, and that these experts o en work closely with, or are themselves, de-velopers of dependently typed languages.e high barrier to entry for dependent types leads to a vicious cycle. e rigidtype discipline and the need to manually write proofs means that dependentlytyped languages are di cult to learn, so few people use them for programming.Because few people use dependent types, the libraries and tooling for dependentlytyped languages are lacking. e dearth of libraries leads to a negative feedbackloop: few libraries have been wri en, meaning that few people use dependenttypes, meaning that few people write libraries, etc.Lowering the barrier to entry for dependent types disrupts this vicious cycle:if dependent types are easier to use, more people will use them, so more peoplewill write tools and libraries for them, which in turn makes them easier to use, etc.Several e orts to improve the usability of dependent types are ongoing, includ-ing improved error messages [57], proof reusability [127], and metaprogrammingtools to automate the construction of proof terms [28, 32].However, among the remaining barriers is the di culty of migrating codefrom non-dependent to dependent types, and the di culty of constructing theproofs necessary for programs to type check. Migrating code from languages likeScheme, Haskell or ML is o en not straightforward, and while these languagescan be accessed via a Foreign function interface ( ffi ), doing so o en violates thesafety guarantees provided by dependent types. For instance, passing an emptylist from OCaml to the dependently typed language Coq can lead to a null-pointer4dereference [42].To alleviate these diculties, we propose integrating gradual types with de-pendent types. is would provide multiple advantages.1.1.3.1 MigrationGradual types provide a smooth path for migrating from dynamically typed lan-guages to those with static types. At each stage of the migration, the whole pro-gram can be run, even when static type information is missing, with dynamicchecks performed to ensure safety. Gradual typing is particularly helpful withmigrating to dependent types: in many places, standard dependently typed func-tions contain terms (called indices), or demand construction of a proof that someproperty holds. By expanding the notion of the unknown type to also includeterms, gradual dependent types let programs run even when parts of type indicesor proofs are missing.1.1.3.2 InteroperabilityAnother use of gradual dependent types is to ensure a safe interface betweendependently typed and non dependently typed code (as opposed to, say, an ffithat does not perform dynamic type checks). In such a system, typing guaranteesare still ensured dynamically, and gradual dependent types enable enforcementof both basic types and sophisticated function preconditions across the boundarybetween languages.1.1.3.3 Aiding DevelopmentSeveral dependently typed languages are oriented around typed holes: while build-ing a proof, the user may omit parts, and the editor informs them of type theomi ed part (called the goal) should have, along with what premises (i.e. in-scopevariables) they can use to construct a value of the goal type. However, terms withholes cannot be safely compiled, and while tools to evaluate terms with holes ex-ist, they usually get stuck when a hole is reached, causing static type checks to beomi ed without dynamic checks to replace them.5Gradual dependent types allow for hole-based development where evalua-tion does not get stuck on holes. Static checks are not omied but are insteadconverted to dynamic checks. is provides be er support for dynamic develop-ment tools, such as a Read Eval Print Loop ( repl ) or a test suite. We conjecturethat information from dynamic runs of a program could even be useful in theautomated construction of correctness proofs. Moreover, structure editors likeHazel [110, 111] allow for user-friendly editing in which every reachable editorstate is a runnable program. e theory of such editors is based on gradual types,so gradual dependent types could facilitate the development of structured editorsfor dependently typed languages.is dissertation lays the foundation for these goals. Our vision for gradualdependent types is to have a type system that provides a uni ed interface for spec-ifying program properties, whether they are to be checked statically or dynam-ically. Every programmer has wri en code like error(’TODO write later’),and we seek to provide foundations for language-level support to dynamicallytrack the safety of such code. We do not envision gradual dependently typedcode being widely used in production, but see it as a stepping stone on the path toreleasing fully static dependently typed so ware, with the hope that it can helpsurpass some of the roadblocks that prevent dependently typed languages frombeing used at all. We do not yet have empirical evidence for the usefulness ofour techniques, but we cannot test usefulness without an implementation, andwe cannot implement gradual dependent types without adequate foundations.1.2 A Note on Typographyroughout this dissertation, we routinely discuss terms in a static language,along with their counterparts in a gradual language. For clarity, we write staticdependently typed terms using red sans-serif font, and gradual surface terms us-ing green, italic serif font. Terms from intermediate languages, such as a gradualcast calculus or evidence language, are wri en using blue, bold serif font.ough this thesis can be read on paper, the digital version contains severalenhancements that aid with reading. In particular, uses of acronyms and the rst6uses of glossary terms link to their respective denitions. Likewise, references tosections are linked to section headers, inference rules are linked to their de ni-tions, and citations are linked to their bibliography entries. Clicking these linkscan be used to navigate from a use to a de nition, and in a su ciently modernPDF viewer, such as Evince, hovering over such a link displays the respectivede nition in a pop-up frame.1.3 A Motivating ExampleIn this section, we give a preview of our vision for gradual dependent types, alongwith an example of why we might want them. e example is adapted from ourprevious work [58].1.3.1 The Pain and Promise of Dependent Types1.3.1.1 Length-indexed VectorsWe begin with a classic example of dependently typed code: length-indexed vec-tors. We use vectors in examples throughout this dissertation, as they provide aminimal example of how dependent types can add safety to the typically unsafeoperation of accessing the 𝑛th component of a list of unknown length.Consider the type of vectors:Vec : Type→ N→ TypeFor any type T and natural number n, Vec T n is the type of vectors containingexactly n elements of type T. Vec describes a family of types, and for each typeT and number n, Vec T n is a distinct type. e type Vec is generic not only overT : Type (its element type), but over n taken fromN, the type of natural numbers.e type depends on a value, thus the name dependent type.e Vec type has two constructors:Nil : Vec X 0Cons : X→ Vec X n→ Vec X (n+1)7e constructor Nil creates a vector with length 0, while Cons takes a vector oflength n and adds an element to produce one of length n+1. In both cases, theselength constraints are re ected in the constructor types: each has a return type ofthe form Vec T m, but the precise value ofm di ers between the two constructors,and in the case ofCons,m actually depends on the value of a previous argument’slength. We say that m is a type index, since the choice of m constrains whichvectors can inhabit Vec T m.Including the length of the vector in the type ensures that operations thatare typically partial can only receive values for which they produce results. Forinstance, one can write a well typed function that yields the rst element of avector, using the type:head : (X : Type)→ (n : N)→ Vec X (n+1)→ XSince head takes a vector of non-zero length, in a static dependently typed lan-guage, it can never receive an empty vector. If the type checker accepts a call tohead, then the programmer knows such a call will not raise an error. e downsideof this strong guarantee is that head can only be called with vectors whose lengthis statically known to be non-zero, or the programmer must manually prove thatthe length cannot be zero. is burden makes it di cult to migrate code fromlanguages with simpler types, and di cult for newcomers to rapidly prototypetheir algorithms.1.3.1.2 Migrating icksortTo see the di culty of using vectors, consider the task of migrating a simple sort-ing algorithm into a dependently typed language. Consider the non-dependentlytyped quicksort, wri en in pseudo-Haskell:sort : List N→ List Nsort Nil = Nilsort (Cons h t) = (sort (filter (< h) t)) + (singleton h) + (sort (filter(≥ h) t))Now consider the task of migrating this de nition to a dependently typed lan-8guage. One benet of using dependent types is that we can capture the invariantthat sort preserves the size of the list by giving it the type:sort : Vec N n→ Vec N ne helper concatenation function can be assigned the type++ : Vec N m→ Vec N n→ Vec N (m+n)However, assigning filter a type ismore tricky, aswe explain below, as ismigratingthe rest of the function:sort Nil = Nilsort (Cons h t) = transport ????((sort (filter (< h) t))++(singleton h)++(sort (filter(≥ h) t)))In order for this to be well typed, in the Cons case, the lengths of(sort (filter (< h) t)), singleton h and (sort (filter (≥ h) t)) must sum to the lengthof Cons h t. However, 1+ length (sort (filter (< h) t)) + length (sort (filter (≥ h) t))is not syntactically identical to 1+ length t. Instead, we must use a transport func-tion, which consumes a proof that the two types are equal and converts from onetype to the other. We use ???? to denote the hole that the programmer must llwith such a proof.A bigger issue for the migration is determining what the type of filter shouldbe for vectors. It consumes a vector of type Vec T n and a predicate of type T→ B(where B is the type of booleans), but what should its return type be? It shouldhave the form Vec T ???? , but we cannot statically know the length withoutknowing exactly how many elements of the vector satisfy the predicate.A nal problem is that sort calls itself recursively on the result of filter. Toensure decidable type checking, most dependently typed languages require thatrecursive calls be made on structurally smaller arguments, or that the program-mer manually provide some metric which is strictly decreasing for each recursive9call.1 Because the recursive calls are made on the results of filter, they are notstructurally smaller than the original list, and for the type checker to accept sort,the programmer must provide proof that each recursive call is made on a strictlyshorter list.It should be clear now that migrating a simple function is not necessarily asimple process. All of the above diculties can be overcome: it is certainly possi-ble to write a proof that the result has the same length as the input, though doingso involves lemmas about the length of concatenating lists and the associativityof addition. Likewise, filter can be rewri en to return a dependent pair contain-ing the number of elements satisfying the predicate and a vector of that length,and one can write a proof that ltering a list with a predicate and that predicate’snegation produces two lists whose lengths sum to that of the original list.e issue is not that the above tasks are impossible, but that they are di cult.If a newcomer to dependent types tries to migrate some of their code, they are im-mediately faced with tasks that are not beginner-friendly. Even if they use holesto skip the parts they get stuck on, they cannot compile their code until thoseholes are lled. Alternately, one could use simply-typed lists in the dependentlytyped language, but this would require duplicating every vector function for lists.Existing solutions, like ornaments [41], require the standard libraries of depen-dently typed languages to be redesigned under a totally di erent programmingparadigm.1.3.1.3 Envisioning A Gradual SolutionGradual dependent types can ease the migration of the sort function. For lter ,instead of using dependent pairs, one can write a lter function that returns avalue of type:Vec T ?at is, it returns a vector with an imprecise type. Likewise, the programmer canwrite ? to give an imprecise proof to transport that the two lists have the samelength, and similarly use an imprecise proof to show that recursive calls to sortare made on smaller lists. Unlike with holes, the programmer is free to run their1 is requirement will cause us much grief in Chapter 6.10program or move on to developing dierent modules that use sort.e nal gradual sort is as follows:sort Nil = Nilsort (Cons h t) = transport ?((sort ( lter (< h) t))++(singleton h)++(sort ( lter(≥ h) t)))is dissertation is devoted to designing safe, principled language mecha-nisms that support the above techniques for migrating code. In the followingsection, we outline the major design decisions and challenges that come with de-signing such a language.1.3.2 Challenges and Solutions with Gradual Dependent TypesIntegrating gradual and dependent types is non-trivial. ough techniques existfor systematically introducing gradual types into a static language [33, 67], theycannot handle types that depend on terms. We identify the primary challenges ofintegrating gradual and dependent types, and summarize the solutions presentedin the rest of this dissertation.1.3.2.1 The Unknown Type Is Not EnoughOn its own, the unknown type ? from non-dependent gradual types is not expres-sive enough for dependent types. One could write a lter function that returnstype ?, but that return type is too permissive: we know that lter should returna vector, and that the vector’s element type should be the same as the input tolter . e program might perform unnecessary run-time checks to ensure thatthe result is a list, and if the programmer were to edit the de nition of lter , theycould accidentally modify it to return a non-list value.e solution is to introduce imprecision more judiciously, as in Vec N ?: thetype of vectors of numbers with unknown length. But the length is a term (anatural number), not a type. So to be su ciently expressive, gradual dependenttypes need a notion of imprecise term, which does not exist for non-dependentgradual types.111.3.2.2 Proofs Can Persist at Run TimeDependently typed programs oen require proof terms, which establish that twoexpressions are equal or that some other precondition holds. Holes can be usedto defer the construction of proofs, but programs containing these holes typi-cally cannot be fully compiled or run, presenting a serious barrier to development.ese proof terms are parts of the program, and may contain data or a ect therun-time behaviour of the program in any number of ways.To seamlessly blend untyped and dependently typed code, programmers shouldbe able to omit proofs, yet still have their code type check and run. Moreover,whatever invariants the omi ed proofs were supposed to be establishing shouldbe checked at run time, to the extent that doing so is decidable, so that the pro-grammer is alerted when a program violates its speci cation.Our proposed solution is to let ? be used as an expression at run time, andto give semantics for how computing with it should behave. Giving ? dynamicsemantics is an extension of the previous goal, since such a semantics lets ? beused in place of any term, not just type indices. en, the user can omit proofsand still run their programs.For the sort example, transport ???? could be replacedwith transport ?, whichwould result in a complete but imprecise program. When executed, the proofimprecision should induce a run-time check that the return vector actually hasthe same length as the input.1.3.2.3 Gradual Typing Introduces E ectsAdding ? to types introduces two computational e ects. e ability to type self-applications enables the construction ofwell typed xed-point combinators. us,programs may run forever. Likewise, the ability to write imprecise types intro-duces the possibility of type errors that may be encountered while evaluatingexpressions.ese e ects are troubling because, to compare types, dependent type check-ing must o en evaluate code, sometimes under binders. Since the return type ofa dependently typed function may depend on the value given, we must evaluatecode at compile time to compute these return types. So both e ects can manifest12during type checking.For non-termination, our solution is to devise a separate notion of compile-time and run-time evaluation, ensuring that type checking terminates and prop-erly handle errors. e compile-time notion approximates terms to ? whenever itcannot guarantee their termination, while run-time evaluation is precise but mayrun forever. A large portion of this dissertation is dedicated to establishing thatcompile-time normalization is decidable, since proving termination is non-trivial,particularly for a language supporting inductive types and propositional equality.To account for dynamic type errors during type checking, we present two ap-proaches. e rst approach is to produce ?whenever a type error is encountered.is technique bene ts from simplicity, but violates the static gradual guarantee,since adding type information can trigger an approximation that prevents a run-time type error. To avoid this issue, an alternate approach is presented wheredynamic type errors are represented explicitly as terms in gradual programs.1.3.2.4 Gradual Typing A ects EqualityTo ensure type safety, gradual programs must perform run-time checks in pro-grams with imprecise types. For non-dependent gradual typing, these checks in-volve comparing types at run time. However, with dependent types, such a com-parison needs to compare type indices, since these may occur within types. Independent types, any term can serve as a type index, including functions, proofs,and other higher-order structures for whom equality is not decidable.For static type checking, dependently typed languages typically use di er-ent notions of equality in di erent places: de nitional equality compares termssyntactically at compile time, while propositional equality denotes the rst-classequalities that can be produced or consumed by dependently typed functions.ese notions may or may not agree with observational equivalence, whether twoterms produce the same result in all contexts.e re ection of compile-time equality into run-time checks means that, todesign a gradual dependently typed language, one must specify precisely howthe di erent notions of equality interact. is dissertation explores two di erentpoints in this design space, giving one language where run-time checks use syn-13tactic equality, and another that uses observational equivalence. e former ismuch simpler, but has the unfortunate property that observationally-equivalentstatic terms may behave di erently when used in the gradual language. e la eris more complex, but preserves static equivalences, and supports a rich notion ofgradual equality proofs that can be checked either statically or at run time.1.3.2.5 Compilation Is Non-TrivialFor a gradual the language to be usable in practice, it should be possible to com-pile it to (relatively) e cient machine code, and to type check it relatively quickly.Both of these goals are complicated by gradual dependent types, since a term’sactual type might not be known until run time, and type checking involves nor-malizing and comparing arbitrary terms. Since writing an e cient dependentlytyped compiler is a monumental task, our solution is to translate gradual depen-dent types into an existing static dependently typed language. In addition to pig-gybacking o of another language’s compiler and type checker, such a transla-tion establishes a model of the gradual language and enables mechanization ofits metatheory in the static target language. is model provides a path towarda denotational semantics: if the core theory of the target language has a denota-tional semantics, then a denotational semantics for the gradual language can beobtained via the translation.1.4 ThesisOur thesis is that the design of a gradual dependently typed language isfeasible and useful2. In this dissertation, we address the challenges and goalsof Section 1.3.2, developing a fully gradual language for dependently typed pro-gramming as follows:• Chapter 2 discusses the background knowledge and related work to sup-port the subsequent chapters, discussing gradual types (Section 2.1), depen-dent types (Section 2.2), and existing e orts to integrate dynamic or gradualideas into dependently typed languages (Section 2.3);2 is formulation of a thesis statement is borrowed from [99]14• Chapter 3 gives a foundational calculus for gradual dependent types, in-troducing the unknown term ? along with its static and dynamic semantics.We address the problem of decidable type checking using a novel techniquecalled approximate normalization, where separate semantics are used forcompile-time and run-time normalization of terms. Run-time checks basedon denitional equality ensure the safe execution of programs.• Chapter 4 reviews the the Gradual Calculus of Inductive Constructions( gcic ), a gradual cast calculus originally presented by Lennon-Bertrandet al. [87]. ough the contents of this chapter are not a contribution of thisdissertation, it contains the calculus upon which later chapters are built.gcic uses features an unknown term with similar semantics to the calculusfrom Chapter 3, but additionally supports inductive data types. e gcicauthors show that no gradual language can simultaneously embed the staticthe Calculus of Inductive Constructions ( cic ), have strong normalization,and a strengthening of the gradual guarantees. Accordingly, gcic comes inthree variants, each sacri cing one of the above properties while ful llingthe other two.• Chapter 5 extends the gcic variant lacking strong normalization with agradual notion of propositional equality. at is, we present a type con-taining gradual proofs that two given terms are equal. ese equality proofsdynamically track consistency information about the equated terms, so thatwhen a program violates the speci cation given by its types, a run-time er-ror can be agged. is chapter departs from the approach of Chapter 3,ensuring that run-time checks preserve static observational equivalencesby deferring checking of functions, instead of using syntactic comparison.Because it is based on a gcic variant without strong normalization, thischapter does not address the issue of decidable type checking.• Chapter 6 presents a syntactic model of a gradual language, that is, asemantics-respecting translation into a static dependent language [17]. Itcombines the work of Chapters 3 and 5 to give a language that has decidabletype checking, inductive types, and gradual propositional equality. ough15we cannot get around the impossibility result of Chapter 4, we show a wayto regain decidable type checking without needing the restrictions used bythe various gcic variants.e syntactic model serves three purposes.1. e model lets us mechanize the metatheory of our gradual calculus,since proofs can be wri en in the static target. To capture exact run-time semantics, we use Guarded Type eory ( gtt ) [14, 15, 140] tosoundly model unbounded recursion and potentially non-terminatingterms.2. e model lets us prove strong normalization for approximate normal-ization, by showing that the static target, in which all terms terminate,can simulate approximate normalization of any term. We overcomeseveral limitations from Chapter 3. In particular, we can prove nor-malization even for code involving inductive types and large elimina-tion.3. e gradual-to-static translation serves as an implementation strat-egy. Gradual terms can be compiled by translating to an existing staticdependently typed language, then using its compiler to generate ma-chine code. Likewise, the conversion check for gradual terms can rsttranslate those terms to the static target and check if the results areconvertible.• Chapter 7 concludes the dissertation, describing limitations of the research,along with possible directions for future work.16Chapter 2Background and Related Worke research in this dissertation involves combining gradual types and depen-dent types, both of which have a large body of work behind them. As such, webuild on the work that has developed these two concepts separately, as well as themuch smaller body of work that has gone into introducing type dynamism intodependently typed languages.2.1 Gradual Typingough a variety of systems for optional and exible type systems have beendeveloped, this thesis focuses on a notion of gradual typing based around an un-known type ? and a notion of type imprecision.2.1.1 Imprecise TypesDynamically typed parts of programs can be represented through imprecise types.Speci cally, gradual languages feature a type ? called the unknown type. A termwith type ? can be used in any context, so dynamically typed computations canbe embedded into gradual programs using ? in type ascriptions. Because a term oftype ? can be used at any type, ? can express di erent levels of imprecision. Termsof type ?→ N are functions returning numbers, but can take arguments of anytype. Likewise, N→ ? is the type for functions that take a number but produce adynamically typed result.172.1.1.1 The Gradual Consistency RelationIn a statically typed language, checking whether a program is well typed relies ona notion of type equality. For example, given a functiondouble : N→ N, the type checker veries that double 2 is well typed by comparingthe domain of double to the type of 2. In this case, both are N, so the call is welltyped.However, equality is too restrictive when checking gradual types. Considersome dynamically typed function f of type ?→N. en f 2 should be well typed.But, if we compare the domain type to the argument type, ? and N are not equal.e solution is to replace checks of type equality with a new relation, consis-tency, wri en T1  T21. Consistency between types represents whether any statictype exists that could plausibly be used in place of both types. e unknown type? is consistent with any type T , since the actual type of the result of a ? typed com-putation may be T . Composite types are consistent with one another if their partsare. For example, S1 → S2  T1 → T2 if and only if S1  T1 and S2  T2. e equal-ity checks in a static type system correspond directly to the consistency checksof a gradual one. e gradual consistency relation is symmetric and re exive,but notably, it is not transitive. Since ? is consistent with every type, transitiv-ity would imply that all types were consistent to one another, and no types werestatically checked.2.1.1.2 Gradual Precision and CompositionConsistency is related to precision, a partial ordering v on gradual types. Forany T , T v ? holds, and T1 v T2 holds for composite types T1 and T2 wheneverthe parts of T1 are each more precise than the corresponding parts of T2. Forexample, Nat v ? and Bool→ ? v ?→ ?. Unlike a subtyping relation, precision isnot contravariant on the le of a function arrow: S1 → S2 v T1 → T2 holds if andonly if S1 v T1 and S2 v T2.A related concept is the precision meet of two types, which provides a way ofcomposing the information of two imprecise types: T1uT2 is the least precise type1While  is typically used to refer to isomorphism, in this dissertation we follow Garcia et al.[67] and use  to refer to consistency, following the intutition that it is the gradual li ing of equality.18that is as precise as both T1 and T2, if such a type exists. For example, Boolu ? isBool, and Nat → ?u?→ Bool is Nat → Bool. Typically, the composition T1uT2 isdened if and only if T1  T2. e meet is useful for composing type information:a term should check against both T1 and T2 if and only if it checks against T1uT2.e precision relation on types gives away to compare programs for precision.Term precision, t1 v t2, is de ned using the precision of their type annotations (as-criptions on function arguments, or general term ascriptions, which we write as::). So (𝜆x : Int .x) v (𝜆x : ?.x) holds. Term precision lets us reason about changesin program behaviour in terms of changes in program precision, which is key forde ning the gradual guarantees in Section 2.1.2.2.e composition of two types is sometimes wri en as T1&T2. We use theampersand to refer to composition as an operation, and reserve u for semanticcomposition in the model in Chapter 6.2.1.2 Gradual MetatheoryAdding ? to a language is not enough to make it a good gradual language. In-stead, we want our language to ful ll certain metatheoretic properties, to ensurethat it behaves safely and predictably, and that changes in precision do not causeunexpected behaviour.2.1.2.1 Gradual Type SafetyConsistency lets us type check programs with imprecision, but this necessarilymeans assigning types to some programs where a term’s type assignment is in-compatible with its context. Hence, type checking is only half of the gradualtyping story. For a gradual language to be safe, dynamic checks must ensure thatno type-unsafe operations are performed [136]. is safety is a key concept ofgradual typing: type checks are always performed, but they may be performed atcompile time or at run time, depending on howmuch type information is staticallyavailable.Many presentations of gradual typing ensure run-time safety using a cast cal-culus. Under the cast calculus approach, gradual programs are elaborated into alanguage with type annotations and explicit casts. e semantics of a cast calcu-19lus specify the result of casting between any pair of types, and whether that resultis a run-time type error. We use a cast calculus to dene the semantics of gradualdependent types from Chapter 4 onward.An alternate approach to ensuring safety is the evidence-based approach ofthe Abstracting Gradual Typing ( agt ) [67] framework, which we explain in Sec-tion 2.1.3.3.2.1.2.2 The Gradual GuaranteesMany languages and systems claim to have some form of optional or mixed static-dynamic typing, but they vary widely in how safe they are and how smoothlyterms can be moved from dynamic to static or vice-versa. Greenman and Felleisen[70] describe a generalized spectrum of type soundness, ranging from fully safegradual types to erasable types with no run-time checks. Siek et al. [136] identifyre ned criteria for what makes a language, in their eyes, truly gradual. We followthese la er criteria.In addition to gradual type safety (which they call soundness), the key prop-erty of a gradual language is:• If a term t : T , and t v t ′, then t ′ : T ′ for some T ′ where T v T ′.• If a term t : T runs successfully with result v , and t v t ′, then t ′ runs suc-cessfully with result v ′ where v v v ′. If t ′′ v t where t ′′ : T ′′ and T ′′ v T ,then either t ′′ runs to some v ′′ where v ′′ v v , or t ′′ raises a dynamic typeerror.ese guarantees, referred to as the static gradual guarantee and dynamicgradual guarantee respectively, have critical implications for the process of incre-mentally increasing the precision of annotations in a program. e static guar-antee is useful because of the contrapositive: if a program does not type check,then it is because some types are fundamentally incompatible, not because an as-cription is missing. Likewise, the dynamic guarantee captures the property that,modulo precision, type ascriptions do not change the behaviour of a program.Static or dynamic type errors are always caused by incompatible types, never byimprecise type information. e static guarantee goes in one-direction, but the20dynamic guarantee is bidirectional: since increasing the precision of type infor-mation may result in an ill typed program, the static guarantee does not addressthis case.An interesting property is that, in a language satisfying the dynamic grad-ual guarantee, run-time type errors must not be caught. ough this may seemundesirable, the ability to catch dynamic type errors could mean that changing atype annotation of a program could result in completely di erent behaviour. Withthe gradual guarantee, a programmer can add or remove type signatures with theknowledge that the program’s behaviour does not change (modulo uncatchabletype errors), so migrating from dynamic to static types is easy.2.1.2.3 Embedding-Projection PairsRelated to the gradual guarantees is the embedding-projection pairs (EP-pairs)property. e EP-pairs property relates type precision to casts. If T1 v T2, thenthe casts 〈T2 ⇐ T1〉 and 〈T1 ⇐ T2〉 form an EP-pair if:• Casting t from T1 to T2, then casting that back to T1, yields a term that isobservationally equivalent to t. at is, for all contexts C : T1 → Bool,𝐶 [t]evaluates to a boolean equal to 𝐶 [〈T1 ⇐ T2〉〈T2 ⇐ T1〉t];• Casting t′ from T2 to T1, then casting that back to T2, yields a term t′′ suchthat, for every context C : T2 → Bool, either C[t′′] raises an error, or C[t′]and C[t′] evaluate to equal booleans.at is, reducing then increasing precision produces the original term, andincreasing then reducing precision produces a term that behaves like the origi-nal, except that it might be an error, or raise an error in strictly more contexts.For non-dependent gradual types, the intuition is that reducing precision lets aterm be used at a less precise type, but that the result of that cast is in somesense the “same” term as the original. Likewise, increasing the precision of a termshould not change its behaviour, but it might increase the precision of run-timetype information, and hence “remember” what type it was cast to, causing futureoperations to trigger an error.21New and Ahmed [105] dene graduality as the semantic version of the grad-ual guarantee: two precision-related terms produce precision-related results inany context. e existence of EP-pairs between any two precision-related typesimplies graduality2. Just as parametricity strengthens type safety, and proves itas a corollary, graduality strengthens the gradual guarantees and, as the authorsshow using a logical-relations argument, graduality proves the guarantees as acorollary.For gradual dependent types, EP-pairs are even more important than withsimply-typed languages: since ? is a term aswell as a type, EP-pairs guarantee thatcasts don’t needlessly produce ?. However, Lennon-Bertrand et al. [87] showedthat no conservative extension of the Calculus of Inductive Constructions canhave both EP-pairs and strong normalization. In Chapter 7, we describe a weakerversion of EP-pairs that captures the idea that run-time casts do not needlesslylose information in gradual dependently typed languages, and conjecture thatthey can be adapted to the model we give in Chapter 6.2.1.2.4 Gradual Full AbstractionJacobs et al. [81] describe another property that is important for gradual lan-guages: a fully abstract embedding between a static language and its gradualcounterpart. Full abstraction means that two static terms are observationally-equivalent if and only if the embeddings of those terms are equivalent in the grad-ual language. Full abstraction enables the programmer to fearlessly refactor staticcode: since terms that are statically equivalent are also gradually equivalent, theyknow that if a refactoring is safe statically, it is also safe in the gradual language.Full abstraction has a subtle interaction with gradual dependent types: be-cause types may be indexed by functions, any two functions that are extension-ally equal (agree on all inputs) must be observationally equivalent in the graduallanguage. Speci cally, two extensionally equal functions must raise type errorsin exactly the same contexts, a goal which is incompatible with re ecting checksof de nitional equality to run time. We discuss an approach to preserving equiv-alences in Chapter 5, and a potential approach to prove a weaker version of full2Lennon-Bertrand et al. [87] refer to the existence of EP-pairs as graduality, since for depen-dently typed languages it is a stronger statement than the gradual guarantee.22abstraction in Chapter 7.2.1.3 Abstracting Gradual Typingus far, we have not presented a general way to make a static language grad-ual. Ad hoc notions of gradual typing enabled the integration of gradual typesand many programming language features, including mutable state [137], unionand intersection types [24, 145], ownership types [128], e ects [9], parametricpolymorphism [4, 147], security types [64, 146], and session types [80]. However,without a uni ed technique for converting a static type system into a gradual one,proofs of safety and the gradual guarantees are lengthy and ad hoc. Garcia et al.[67] seeks to remedy this by introducing the framework of Abstracting GradualTyping (agt).We use agt to devise our foundational gradual dependently typed languagein Chapter 3.2.1.3.1 Concretization: The Meaning of Gradual Typese agt framework is based around the idea that the meaning of a gradual typeshould be speci ed in terms of the set of static types that it could plausibly repre-sent. Consider a statically typed language whose types come from the set SType.We want to extend this language into a gradual language, whose types come fromGType ⊇ SType. To specify the meaning of the new gradual types, we de nea function 𝛾 : GType→ P(SType). is function is known as the concretizationfunction. Intuitively, 𝛾 (T ) represents the set of static types that a value of type Tcould represent.Concretization gives a systematic way of deriving relations in gradual typing.Before agt, consistency and precision were de ned ad-hoc, with a number ofcases for each type introduction form. With agt, we de ne the concretizationonce by cases, and then say that t1  t2 if and only if 𝛾 (T1)∩𝛾 (T2) ≠ ∅. Likewise,T1 v T2 can be de ned as 𝛾 (T1) ⊆ 𝛾 (T2).Once gradual relations have been de ned from a concretization function, manystatic typing rules can be systematically turned into gradual ones. When rulescontain repeatedmetavariables, this repetition induces implicit equality constraints23on the sub-terms of the judgment. ese so-called “pa ern matches” can be elim-inated by instead using distinct metavariables in each premise, and introducingexplicit equality side-conditions these metavariables corresponding to the repeti-tions in the original rule. To convert such rules from static to gradual, the equalityside-condition is replaced with a consistency check. In general, a binary predicate𝑃 can be converted to a gradual form ˜ by taking:˜(t1, t2) ⇐⇒ ∃S1 ∈ 𝛾 (t1),S2 ∈ 𝛾 (𝑇2). 𝑃 (S1,S2)is easily generalizes to 𝑛-ary predicates.To see the transformation in action, consider a typing rule for addition:Γ ` t1 : N Γ ` t2 : NΓ ` t1 + t2 : Natis rule is equivalent to the following rule:Γ ` t1 : T1 Γ ` t2 : T2 T1 = Nat T2 = NatΓ ` t1 + t2 : NatTo convert this to a gradual rule, we replace the equality checks with consistencychecks:Γ ` t1 : t1 Γ ` t2 : t2 t1  Nat t2  NatΓ ` t1 + t2 : Natis change allows addition for values of type ? or type Nat to be well typed.2.1.3.2 Abstraction and Partial FunctionsConcretization lets us deal with equalities and other static predicates, but it is notsu cient to convert rules that require types to have a certain shape. Consider thetyping rule for function application:Γ ` t1 : T1 → T2 Γ ` t2 : T1Γ ` t1 t2 : T2To avoid repeated metavariables, the rule could require that t1 : T′, and have T′ =T1 → T2 as a side-condition. However, when we relax equality to consistency for24the gradual language, the rule is no longer syntax directed, since any number ofarrow types may be consistent with the type of t1.To derive gradual versions of static rules like these, the key is to avoid paernmatching by de ning partial functions for decomposing a type. For example, wede ne a partial domain function as follows:dom(T1 → T2) =T1dom(T) unde ned otherwisee codomain function cod can be de ned similarly. en, the static applicationrule can be rephrased as follows:Γ ` t1 : T1 Γ ` t2 : T2 dom(T1) = T2Γ ` t1 t2 : cod(T1)e gradual language can use a partial function d˜omwhere d˜om (T1 → T2) = T1and d˜om ? = ?, but is unde ned otherwise. e codomain c˜od can be de ned sim-ilarly. Given these functions, we replace dom and cod with their gradual counter-parts to obtain a gradual rule for application.To derive these li ed partial functions in general, we need an abstraction func-tion𝛼 :P(SType)→GType, which serves as the converse of concretization, takingsets of static types to a single representative gradual type. e function 𝛼 shouldbe sound, where X ⊆ 𝛾 (𝛼(X)) for any non-empty X ∈ P(SType), as well as optimal:𝛼(X) v t whenever X ⊆ 𝛾 (t ) for non-empty X. ese conditions ensure that theabstraction returns a type capturing all possibilities of the input set, but that itrespects the subset ordering of the concretization sets.e abstraction 𝛼 gives a way to li arbitrary partial functions from static togradual. If 𝐹 : SType⇀ SType, then we de ne its li ing ˜ : GType⇀ GType as˜(t ) = 𝛼(𝐹 (𝛾 (t ))): that is, we apply 𝐹 element-wise on each element of 𝛾 (t ), thenabstract back to a single gradual type. is can be generalized to functions withany number of arguments.252.1.3.3 Evidence for Dynamic Semanticsough concretization and abstraction give us the tools to systematically derivethe typing rules for a gradual language from its underlying static language, wewould also like to execute gradual programs, and ensure that they either succeedor fail with a run-time type error. We do so with an intermediate language whererun-time terms may be ascribed evidence,3 wri en using blue, bold serif font.For two types T1,T2, the consistency judgment T1  T2 holds if and only if thereexists some type in the overlap of their concretizations. If 𝛼 is sound and optimal,then there exists some T3 v T1 u T2. We call such a witness evidence of theirconsistency, and write 〈T3〉 ` T1  T2. ( e angle brackets 〈〉 denote that we aretreating their contents not as a type, but as information that is carried around atrun-time).e key feature of gradual consistency, and the reason that run-time typeerrors may still happen with gradual types, is that consistency is not transitive.We may accept a boolean where a number is expected, provided we rst ascribethat boolean the type ?, which is consistent with both Int and Bool. However,Int 6 Bool. agt generates a gradual type system by replacing static equality withconsistency. But the transitivity of equality is a key property needed to establishthe safety of a static language. agt accounts for this using consistent transitivity:if 〈S1〉 ` T1  T2 and 〈S2〉 ` T2  T3, then 〈S1u S2〉 ` T1  T3, if S1u S2 is de ned.at is, given evidence that T1  T2 and T2  T3, consistent transitivity informsus how we can compose that evidence to determine whether T1  T3. If the meetis unde ned, then we cannot conclude that the transitive composition of the twoconsistency relations holds, given the available evidence.Evidence is useful for preserving the well-typedness of terms under reduc-tion. Where surface syntax allows t : T2 whenever t : T1 and T1  T2, the evidencelanguage instead only allows this for terms of the form 𝜀t, where 𝜀 v T1uT2. atis, all applications of consistency in the evidence language are explicitly repre-sented in the syntax, and are relevant to reductions. In places that the static proofof type preservation uses the transitivity of equality, the gradual proof uses con-3Here we describe evidence for consistency, the gradual li ing of equality. If a language usesa more complex comparison relation in place of equality, such as subtyping, the approach can beextended, as described by Garcia et al. [67].26sistent transitivity, ensuring that either typing is preserved or the reduction fails.At any point, the evidence ascription on a term represents the most precise in-formation we know about its type, and this information increases monotonically.is approach signi cantly simpli es the proof of gradual type safety: evidence iscomposed speci cally to preserve typing, making subject reduction easy to show.Because consistent transitivity is a monotone operation, the gradual guaranteecan be shown to hold using a straightforward simulation argument.2.2 Dependent TypesIn this section, we provide relevant background knowledge on dependently typedlanguages. Speci cally, we focus on full-spectrum dependent types, in the styleof the Calculus of Inductive Constructions ( cic ) and Martin-Lo¨f Type eory( mltt ), where types and terms inhabit a single syntactic category:4 types maycontain expressions, and expressions can produce types as a result. Systems usingthis style of dependent types include Coq [12], Agda [109], Lean [46], DependentHaskell [55], Cur [28] and Idris [19]. Types in these languages di er from thelightweight dependent types of Dependent ML [157] and its successor ATS [156],or the re nement types of Liquid Haskell [150], where the interaction betweentypes and terms is restricted. F★ [142] mixes the two styles, using SMT to dis-charge proof obligations when possible, but falling back to full dependent typeswith manual proofs when a solution cannot be automatically found.ough cic [116] and mltt [93, 94] are widely known formalizations of de-pendent types, we avoid commi ing to either, since ideas from both are usefulto us. Various presentations of cic and mltt disagree on precisely what distin-guishes them: for example, Lennon-Bertrand [86] present a bidirectional versionof cic without indexed types, and homotopy type theory uses a variant of mlttwith cumulative universes [149], both of which di er from the “standard” presen-tations. For our purposes, the main distinction between the two is that cic uses4Some variations of type theory use a Universe a` la Tarski, where types and terms inhabit sep-arate categories, but a class of terms known as codes re ects types to the term level. We de neour own Universe a` la Tarski in Chapter 6, but assume that our underlying type theories have aUniverse a` la Russell where types and terms are uni ed.27an untyped rewrite relation to dene when two terms are convertible, whereasmltt uses a typed judgmental equality to compare terms for convertibility5.2.2.1 Essential Dependent TypesWe begin by introducing dependent functions and pairs, which are the key typeformers that enable value dependency.2.2.1.1 The Dependent Function Spacee central feature of a dependently typed language is the dependent functiontype. e simple function type T1 → T2 denotes the type of functions that take anargument of type T1 and return a value of type T2. e dependent function type iswri en as (x : T1)→ T2, where critically, x may be free in T2. e meaning of thedependent function type is perhaps best seen with (a version of) the typing rulesfor functions and applications.Γ,x : T1 ` t : T2Γ ` (𝜆x. t) : (x : T1)→ T2Γ ` t1 : (x : T1)→ T2 Γ ` t1 : T1Γ ` t0 t1 : [t1/x]T2A function is well typed if its body has the stated return type when the parame-ter is added to the typing environment (which is why the parameter may occurin codomain). If we apply a function to an argument, the return type of that ap-plication may depend on the value of the argument, thus the name “dependentfunction.”e dependent function type is sometimes wri en as Π(x : T1).T2, though weprefer the arrow notation to re ect the textual notation of programming lan-guages, particularly Agda and Idris. It is sometimes called a dependent prod-uct type, because it is the generalization of product types to in nite index sets,though we prefer “function type” to avoid confusion with dependent pairs. esimple product type T1×T2 is equivalent to (x : B)→ (if x T1 T2), where B is thetype of booleans.5Arguably the greatest distinction between cic and mltt is an impredicative sort, but Lennon-Bertrand et al. [87] call gcic a variant of cic without an impredicative sort, so we avoid this dis-tinction.282.2.1.2 Dependent Pair Typesedual of the dependent function type is the dependent pair type, which wewrite(x : T1)×T2, where xmay be free in T2. Just as the dependent function type lets thereturn type depend on the value given for the argument, dependent pairs allowthe type of the second element to depend on the value of the rst. We can see thisin the typing rules for dependent pair accessors:Γ ` t : (x : T1)×T2Γ ` 𝜋1 t : T1Γ ` t : (x : T1)×T2Γ ` 𝜋2 t : [𝜋1 t/x]T2e dependent pair type is sometimes wri en as Σ(x : T1).T2, and is sometimescalled the dependent sum type, since it generalizes sum types to an in nite indexset. We prefer the term “pair”, since dependent pairs can model both simple sumsand simple products: (x : T1)×T2 where x is not free in T2 gives the simple producttype, and (x : B)× (if x T1 T2) gives the simple sum type. is dual nature of thedependent pair as both product and sum makes it ideally suited for genericallyrepresenting inductive data types [29]: though inductive types are traditionallysums-of-products, dependent languages can represent them as sigmas-of-sigmas.Several features of dependent types can be desugared into dependent pairs.Record types, with named elds whose types can depend on the values of previouselds, can typically be desugared into nested dependent pairs. We use recordsextensively in Chapter 6. Similarly, simple sums can be expressed as dependentpair. We write T1 +T2 for the non-dependent sum type given by (x : B)× if x T1 T2,with injections inj1 and inj2 and a non-dependent eliminator sumCase.2.2.1.3 Type-Term OverlapWhat does it mean for a value to occur in a type? For functions, variables de-noting the value of a function’s argument can occur free in the codomain of afunction type. In a full-spectrum language, types and terms inhabit a single syn-tactic category, or there is a special type of codes that re ects types to the termlevel. So using function applications or other expressions within a type is permit-ted syntactically. Since types are terms, they are also assigned types: if t : T then29T : Type (explained more fully in Section 2.2.1.5) Likewise, expressions may taketypes as arguments, and produce types as a result. For instance, Nat→ Type is avalid type. In Section 1.3.1.1, we saw that Vec had a type of Type→ N→ Type:Vec takes a type and a number, and produces another type as a result. In general,if F : Nat→ Type, then (x : Nat)→ F x is a well-formed type. We say that x is theindex of F in this case. Such functions may be formed using 𝜆-abstraction, or theymay be declared with inductive types or families (Section 2.2.2).2.2.1.4 The Curry-Howard Correspondencee true power of dependent types lies not only in the ability to write programswith them, but also the ability to write proofs about those programs. e Curry-Howard correspondence [40, 76] is a view of type theory where types correspondto propositions, and terms correspond to proofs. Inhabited types correspond totheorems. Function, product and sum types correspond to implication, conjunc-tion and disjunction respectively.e dependent product and pair types t nicely into the Curry-Howard inter-pretation, acting as quanti ers. e type (x : T1)→ T2 corresponds to the propo-sition ∀(𝑥 ∈ 𝑇1).𝑇2: given a function producing a proof of T2 for each possibleargument x in T1, we can conclude the proposition holds universally. Similarly,(x : T1)×T2 corresponds to ∃𝑥 ∈ 𝑇1.𝑇2. at is, if a pair containing t : T1 and aproof that T2 holds for t, then t serves as the existential witness for the proposi-tion ∃𝑥 .𝑇2. Consider (3, refl) : (x : Nat)× (x+1 ≡ 4). Here 3 serves as a witness thatthere exists a number one less than 4, and refl is the re exive proof that 3+1 ≡ 4.Dependent types use types to precisely specify function behaviour. Precon-ditions of functions can be speci ed by adding arguments that specify certainpredicates on the inputs that must hold. Likewise, postconditions can be speci-ed by returning dependent pairs containing values along with proofs that thosevalues satisfy the desired property. Conversely, dependent types allow for exi-bility when de ning functions: di erent inputs may produce outputs of di erenttypes, as long as some expression can describe the output type in terms of theinput value.With dependent types, the programmer canworkwithin the rigidity of precise30specications, constructing proofs programmatically to convince the type checkerthe preconditions of a given call hold. us, dependent types provide a sound andcomplete form of veri cation: if there exists a proof that a property holds, thenour types can use that fact, so long as the programmer can construct such a proof.is manual construction is in contrast to automated veri cation techniques, likesymbolic execution or model checking, where the user need not provide proofs,but as a result all analyses produce false positives or false negatives. e cost ofthis power, however, is that the typing discipline is rigid, and that programmersmust construct proof terms whenever a function requires them.2.2.1.5 Universes and PredicativityAbove, we saw the type Type, which is the type of types. What should the type ofType be? Allowing Type : Type enables Girard’s Paradox [37], the type-theoreticanalog to Russell’s paradox that provides a closed inhabitant of any type. Compu-tationally, some proofs in the language corresponds to non-terminating compu-tations, which causes two problems. First, because values may occur in our types,we must compare terms during type checking, usually by conversion to somenormal form. Having non-termination makes type checking undecidable, sincedetermining equivalence of terms can be used to determine whether a given Tur-ing Machine halts. Second, proofs under the Curry-Howard correspondence areno longer meaningful: the corresponding logic would be inconsistent since wecould write a (possibly non-terminating) proof for every proposition.e standard way to avoid Girard’s Paradox is to introduce a universe hierar-chy. For a term t : T, where t is not a type (or something as “large” as a type),T : Type0. en Type0 : Type1, Type1 : Type2, etc. roughout, we write Typeto mean Type0.We focus on languages in which quanti cation is predicative: if T1,T2 : Typeℓ ,then (x : T1)→ T2 : Typeℓ and (x : T1)×T2 : Typeℓ . So T1 and T2 may only refer toTypeℓ′ for ℓ ′ < ℓ . Impredicative dependently typed systems do exist, such as theCalculus of Constructions [39]. Such systems still disallow Typeℓ : Typeℓ , but let(X : Typeℓ )→ T2 have type Typeℓ . However, great care must be taken to ensurethat the formulation of inductive types or the use of postulated axioms does not31introduce inconsistency due to impredicativity.A related concept to universe levels is cumulativity. We say a language iscumulative where, whenever t : Typeℓ , we also have t : Typeℓ+ℓ′ for any ℓ , ℓ ′.2.2.2 Inductive Families and Paern Matchingough dependent functions and pairs give us universal and existential quanti -cation, we lack a key tool from logic: induction. Here, we describe how users ofdependently typed languages can de ne their own types, and how they can provefacts about them using induction.2.2.2.1 Inductive TypesMany dependently typed languages allow for the de nition of inductive types,which combine aspects of recursive types from simple type theory [22], sumtypes, and dependent pairs. Like algebraic data types in Haskell or ML, induc-tive types are declared by specifying a name for the type, along with zero or moreconstructors. For example, the type of natural numbers can be declared as follows,using Agda style notation:data Nat : Type whereZ : NatS : Nat→ NatHere, Nat is a type, with two data constructors, Z and S. Data constructors maytake any arguments, but must return the declared type. Self reference is allowed:Nat can occur as a type for S. However, such self reference must be strictly positive(never in the domain of a function-typed eld) to maintain logical consistency.Without strict positivity, one can de ne T that is isomorphic to T→ T, embeddingthe untyped lambda calculus and enabling non-termination.An inductive type may have one or more type parameters over which it is32generic. For example, the classic list type can be declared as follows:data List (X : Type) : Type whereNil : List XCons : X→ List X→ List XHere, List is a type constructor with type Type→ Type. e parameter is declaredand named at the start of the declaration, and the parameter is used in the returntype of each constructor.Inductive types and algebraic data types di er in two main ways. First, con-structors are assigned dependent function types, enabling existential constraintsto be encoded in constructor types. For example, the dependent pair type fromSection 2.2.1.2 may be rephrased as an equivalent inductive type:data Ex (X : Type) (P : X→ Type) : Type wherePack : (x : X)→ P x→ Ex X Pe second di erence is that, unlike in Haskell or ML, inductive types cannot beconsumed using unrestricted pa ern matching or general recursion. To ensurelogical consistency, inductive types must either be consumed using eliminators,which correspond to induction principles from logic, or using dependent pa ernmatching and structural recursion. We explain both of these in Section 2.2.2.4.2.2.2.2 Indexed Inductive FamiliesIndexed inductive families, commonly called inductive families, further extend thepower of inductive types. Parameters for inductive types must occur uniformlyin the return types of all constructors. Inductive families relax this restriction byle ing the type constructor additionally take a di erent kind of type argument:indices. For inductive families, indices are like parameters, but each data con-structor may specify values for the indices of its return type. We call these typefamilies because one de nition declares an entire family of types, one for eachdi erent combination of indices. Unlike a parameterized type, the value of theindex constrains which constructors could have been used to construct a value33from a type in the family.Recall the length-indexed vectors of Section 1.3.1.1:data Vec (X : Type) : (n : Nat)→ Type whereNil : Vec 0 XCons : (m : Nat)→ X→ Vec X m→ Vec X (1+ m)e type constructor Vec has type Type→ Nat→ Type. Here, X is a parameter,but n is an index, which we show using Agda’s convention of keeping parametersto the le of the colon. Nil only produces vectors of length zero, and Cons onlyproduces vectors with length one more than their tail. So Vec T n is a distinct typefor each n, which is only ever inhabited by vectors with exactly n elements. Typeindices let us reason about the concrete values of a vector. Given a value of typeVec T (n+1), we know that it cannot possibly be Nil if it is well typed, since theNil constructor does not return a value of this type.2.2.2.3 Propositional EqualityWhere inductive types give the Curry-Howard equivalent of inductively de nedsets, inductive families provide a version of the inductive relations commonly usedto de ne judgments in the theory of programming languages. Constructors mayuse their arguments in multiple indices, allowing for the same kinds of constraintsas inference rules.A key relation is propositional equality, since, as we explain in Section 2.2.2.6,all other inductive families can be built from inductive types and propositionalequality. e type for propositional equality can be expressed as an inductivefamily:data Eq (X : Type) : X→ X→ Type whererefl : (y : X)→ Eq X y yWe usually write the type Eq T t1 t2 as t1 =T t2, omi ing T when it is clear fromcontext. For any two values of type T, the type t1 =T t2 is well-formed, expressingthe proposition that t1 and t2 are equal. Since refl is the only constructor for this34type, the type is only inhabited when t1 and t2 are actually equal. Specically, t1and t2 must have syntactically equal normal forms, modulo other equality proofsthat are in scope.Propositional equality is very useful when programmingwith dependent types,because we can express equality not only between concrete values, but also be-tween terms containing variables. Dependent functions that can take argumentswhose types are equalities, used to express the precondition that an argument isequal to some value. Likewise, an equality proof can be provided alongside theresult of computation, giving a certi cate that a certain property holds for theresult of a function call.Chapter 5 is largely concerned with how to integrate propositional equalityinto a gradually typed language, and how to track and store dynamic consistencyinformation in equality proofs.2.2.2.4 Deconstructing Inductive TypesUnder Curry-Howard, deconstructing a value of an inductive type correspondsto a proof by cases. By inspecting which constructor was used to construct avalue, we gain more re ned information about the type, that can either be usedto prove invariants or to derive a contradiction, e ectively showing that a branchis unreachable. Likewise, recursion involving inductive types gives the Curry-Howard analogue to induction.e two main strategies for deconstructing inductively de ned data are elim-inators and dependent pa ern matching.Eliminators An eliminator is a function built into a type theory that recursivelydecomposes a value of a recursive data type. For example, the eliminator for thenatural number type from Section 2.2.2.1 has the following type, and satis es the35following equalities:natElim : (P : Nat→ Typeℓ )→ (P Z)→((n : Nat)→ (P n)→ P(S n))→ (x : Nat)→ P xnatElim m z s 0 = znatElim m z s (S n) = s n (natElim m z s n)e eliminator has a few components:• It begins by taking amotive P, which is a type family (i.e. function producinga type) that takes the value being eliminated and returns the type of whatwe are trying to produce. For any scrutinee t (i.e., the term whose form weare branching on), elimination produces a value of type P t: the Z branchproduces P Z and the S n branch produces P (S n). Because the motive takesthe scrutinee as an argument, the result type of elimination may di er foreach potential argument;• We require a value of our motive applied to the base case 0;• We also require a function that produces a value of ourmotive type for n+1,given one for n;• Given the above arguments, the eliminator takes the scrutinee, and pro-duces a value of the motive at that number.is eliminator corresponds to the principle of mathematical induction onnatural numbers. It also provides a programming construct for both branchingand recursion: given a handling function for each constructor of an inductivetype, the eliminator checks which constructor the given value uses and proceedsaccordingly.In general, an eliminator for a type gives a fold function over that type, and canbe de ned for any inductive type, indexed or not. For example, the eliminator forvectors resembles a conventional list fold, except that the return type can depend36on the value of the given vector:vecElim : (X : Type)→ (P : (n : Nat)→ Vec X n→ Typeℓ )→ (P (Nil X))→ ((n : Nat)→ (h : X)→ (t : Vec X n)→ (P n t)→ P (Suc n) (Cons X n h t)))→ (n : Nat)→ (v : Vec X n)→ P n ve result is a function which produces P n v for any n : Nat and v : Vec X n. eeliminator for a type family lets us prove not only properties for all values of atype, but for all values of each type in the family.Dependently typed eliminators are useful because they guarantee termina-tion: recursion is built into the theory, and is always on strictly smaller values.However, they are cumbersome to program with, since motives must be speci edexplicitly. Dybjer [50] describe the general form of an eliminator for an inductivefamily.Dependent Pa ernMatching Dependent pa ernmatching provides the samefunctionality as eliminators, but with less syntactic overhead. When a function isde ned, the programmer may specify multiple clauses with the possible pa ernsthat the arguments may take, akin to the case expressions of Haskell or match inML.Unlike in Haskell andML, inductive families may have type indices, so match-ing a value to a speci c constructor may provide more re ned knowledge of theargument type. In the branch for a constructor, the index values of a match’sscrutinee are uni ed with the concrete index values for said constructor, whereprogram variables are treated as uni cation variables. e substitution producedby this uni cation is applied to all variables free in the clause’s result, as well asto the type of said result. In cases where no uni er exists, we know that no welltyped input to the function can reach that branch, so those cases may be safelyelided.Unlike eliminators, recursion is not built into the structure of pa ern match-ing. To alleviate this, a named function may be allowed to call itself. However,not all pa ern matches de ned this way are terminating. Because of this, matchesare usually fed to an external termination checker [108]. Such a checker ensures37that each recursive function is made on a strictly-smaller argument. e termina-tion check is necessarily conservative: since we cannot solve the halting problem,programs exist that halt but cannot be proved to halt.Pa ern matches are as expressive as eliminators, and can be strictly moreexpressive depending on the formulation. Goguen et al. [69] give a language withdependent pa ernmatching that is equivalent to a combination of eliminators andStreicher’s K axiom [141], which asserts that any proof of x =T x is refl. While thisprinciple seems obvious from refl being equality’s only constructor, it cannot bederived using the eliminator for equality. Axiom K is equivalent to UIP , whichasserts that any two proofs of equality are themselves equal. Recent work hasshown how to formulate dependent pa ern matching without implying axiom K[34, 35], allowing pa ern matching to be used in more theoretical se ings.2.2.2.5 Eliminating Equality ProofsWhen propositional equality is de ned as an inductive type, several useful prin-ciples about equalities can be derived from its eliminator. e eliminator itselfcorresponds to the J-rule from mltt [94]:J : (X : Type)→ (P : (z1 : X)→ (z2 : X)→ z1 =X z2 → Type)→ ((y : X)→ P y y (refl X y))→ (z1 : X)→ (z2 : X)→ (x : z1 =X z2)→ P z1 z2 xat is, for a motive P that is parameterized over two values z1,z2 : X, and a proofpf : z1 =X z2, if we are given a way for any y to build a motive instance for y anditself with refl, then we can produce an instance of the motive for z1, z2 and pfwhenever pf : x =T y.e J principle can be used to implement amore familiar substitution principle,which allows any type involving y to be transformed into one involving z wheny = z:subst : (X : Type)→ (P : X→ Type)→ (y : X)→ (z : X)→ y =X z→ P y→ P z38When X is Type and P is set to the identity, the result is the transport principle6 :transport : (X1 : Type)→ (X2 : Type)→ X1 =Type X2 → X1 → X2at is, we can convert a value of one type to some other type, given a proof thatthe two types are equal.Other useful functions that can be derived from J include proofs that propo-sitional equality is symmetric and transitive, as well as a congruence function es-tablishing that applying a function to equal values produces equal results:cong : (X : Type)→ (Y : Type)→ (f : X→ Y)→(z1 : X)→ (z2 : X)→ z1 =X z2 → f z1 =Y f z22.2.2.6 Equality and Type FamiliesIf we take the equality type as built into our theory, rather than de ned as aninductive family, then the di erent return types of each constructor can be sim-ulated by requiring each constructor to take as arguments proofs that the returnparameters are equal to the desired values for that constructor [95].7 For example,we could formulate vectors as follows:data Vec′ (X : Type) (n : Nat) : Type whereNil′ : (y : Nat)→ (y =N 0)→ Vec′ X yCons′ : (y : Nat)→ (n : Nat)→ X→ Vec′ X n→ (y =N Suc n)→ Vec′ X yIn both constructors, the return type isVec′ X n, and the equality proof argumentsensure that we can only provide 0 as the n value forNil′, with a similar constraintfor Cons′. So long as the eliminator for Vec′ is allowed to vary in the values of nwhich the eliminator can access recursively, this type is equivalent to the normalindexed de nition of Vec. Programming in this style is cumbersome, but because6In some presentations of type theory, transport behaves like our subst and a coercion functioncoe converts between equal types. Our naming convention is chosen to align with the Agda cubicallibrary, as well as to avoid confusion between gradual casts and dependently typed coercions.7In Programming Languages folklore, this practice is known as “Fording”, in reference to theHenry Ford quip that customers could have cars in any colour, so long as it was black.39using it in a core language nicely separates reasoning about sum types (via paernmatching) and constraints on indices (by eliminating equality proofs).2.2.2.7 Empty and UnitBy de ning an inductive type with no constructors, we obtain an empty type, theCurry-Howard analogue to falsehood:data Empty : Type where (no data constructors)emptyElim : (P : Empty→ Typeℓ )→ (z : Empty)→ P zBecause the type has no constructors, the eliminator takes no input other than themotive and the value itself, le ing us produce a value for any motive type froma value of Empty. From this eliminator, we obtain the principle of “reduction toabsurdity” in logic: we can derive an inhabitant of any type (i.e. a proof of anystatement) from falsehood.No closed inhabitants Empty exist, so any contexts where a proof of Emptyis in scope are unreachable. e eliminator for Empty lets us construct explicitproofs that a particular branch of code is dead, and to use falseElim to avoid pro-viding a result in those branches.e dual of the empty type is the unit type, with a single inhabitant, and aneliminator establishing the uniqueness of that inhabitant:data Unit : Type whereunit : UnitunitElim : (P : Unit→ Typeℓ )→ P unit→ (z : Unit)→ P zWe sometimes refer to the empty type as 0 and the unit type as 1, since theyhave zero and one elements respectively.2.2.2.8 Intensional vs. Extensional EqualityDe nitional equality is inherently an intensional equality: although it comparesterms a er normalizing, it still relies on the syntactic equality of these normal40forms. is reliance on syntax means that functions that have di erent imple-mentations are not de nitionally equal, even if they produce the same outputsfor every input. Propositional equality is essentially the internalization of de ni-tional equalities as rst-class values in the language. refl can only be used to provethat two de nitionally equal terms are propositionally equal, but when equalityproofs are in scope, they can be used with the J rule to derive equalities for termsthat are not necessarily de nitionally equal. For example, two distinct variablesx and z are not de nitionally equal, but if proofs of type x =T y and y =T z are inscope then one can form a term of type x =T z.e most common deviation from intensionality is function extensionality, theprinciple that, when two functions produce equal output for each input, they arepropositionally equal. Function extensionality cannot be proved in cic or mlttwithout additional axioms, but it is known to be consistent to add it as an axiomto these languages. Alternately, function extensionality can be proved directly byextending the language with various features. For example, observational equal-ity [105, 124] de nes propositional equality by cases for each type, and equalityre ection [74] expands de nitional equality to include any two terms for which apropositional equality can be proven in the given scope. Both of these additionsimply function extensionality.2.2.3 Generic Representations of Inductive TypesInductive types as described above t into an open type theory: instead of havinga xed set of type constructors, the user can de ne their own. Open type theoriesare useful for the programmer, but proving facts about such a system is di cult,since we must reason about every possible combination of type de nitions.Here, we present ways that inductive de nitions can be de ned in a closedtype theory, using a xed set of type formers. A closed type theory is particularlyuseful for Chapter 6, where we prove that approximate normalization terminates,even with inductive types.412.2.3.1 Functors and Fixed Pointse key property of inductive types is their recursive structure. Each inductivetype T corresponds to a function F : Type→ Type such that T is isomorphic toF T. at is, T is a xed-point of F.8 is function F is called a functor, and eachinductive type is the least xed-point of some functor, which can generally beobtained by replacing self-reference in the de nition of T with the bound vari-able X of F. e strict-positivity condition for inductive types is a syntactic over-approximation ensuring that the functor for each inductive type is a functor in thecategory-theory sense, that is, for all types S1,S2 one can de ne a well-behavedfunction map : (S1 → S2)→ F S1 → F S2.Unfortunately, most type theories are not strong enough to construct thexed-point of an arbitrary functor, even given proof that it is strictly positive.Instead, we must use syntactic descriptions from which functors and their xed-points can be computed. e following sections describe two techniques for do-ing this. We use both of these techniques in Chapter 6 when devising a syntacticmodel of a gradual language with inductive types.2.2.3.2 Containers and W-typesContainers provide a syntactic way to describe functors [1]. A container is a pair(S,P) with type (X : Type)× (X→ Type), where S and P are called the shape andposition respectively. e functor È(S,P)É described by (S,P) : Type→ Type isgiven by 𝜆X. ((x : S)× (P x→ X)).Well-founded trees, commonly calledW-types, are the xed-points of functorsdescribed by containers. W-types are o en added as primitives to a base typetheory, like mltt, but for clarity, we write them using the notation of inductive8Technically these are not true xed-points, since they are only up to isomorphism, but in univa-lent type theories [149] these isomorphisms can be made into equalities to obtain true xed-points.42types:dataW (S : Type) (P : S→ Type) whereWsup : (x : S)→ (P x→W S P)→W S PwElim : (X :W S P→ Type)→ ((s : S)→ (f : (P s)→W S P)→ ((p : P s)→ X (f p))→ X (sup s f))→ (x :W S P)→ X xe constructor Wsup takes a (curried) argument of type È(S,P)É(W S P), andsinceWsup is the only way to construct an element ofW S P, thenW S P is equiv-alent to È(S,P)É(W S P), that is, it is a xed point of the functor for a container.e eliminator provides a generalization of induction: we can derive somethingfor each value of a W-type if, for each shape and position function, given an in-stance of the motive for each recursive value at each position (i.e. each “smaller”value), we can nd an instance of the motive forWsup of that shape and positionfunction.W can be used to create a type equivalent to some inductive type. e intu-ition is that the shape S should be a dependent pair, where the rst element is atag corresponding to a constructor of the inductive type, and the second elementcontains the arguments to that constructor, except for any recursive references tothe type itself. e position then encodes how many recursive references to thetype occur, or more generally, for which types Y the given constructor has a eldY→ T.e trick to devising the position is to think “logarithmically”, under the intu-ition that a function type A→ B can be wri en as BA, and will obey the standardproperties of exponents in arithmetic in relation to sums and products. If a con-structor for T has type (a : A)→ B(T,a)→ T, then A is the shape type for thisconstructor, and nding the position for that constructor amounts to nding Psuch that T(P a) is equivalent to B(T,a). Products in a constructor’s elds becomesums in the position, 1 becomes 0, etc.To make this idea concrete, consider the task of nding a W-type representa-43tion of List A. We need to nd Pnil such that (List A)Pnil is equivalent to 1 (since nilhas no list arguments), and Pcons(a) such that (List A)Pcons(a) is equivalent to List A.inking logarithmically, (List A)0 is 1 and (List A)1 is (List A). e result is:W (1+A) (sumCase (𝜆x.0) (𝜆x.1))In the nil case, the shape argument is inj1 unit, so the remaining data has type is0→ List A, which is equivalent to 1, that is, the constructor takes no argumentsof type List A. In the cons case, the shape argument is inj2 a for some a : A, sothe remaining data has type 1→ List A, which is equivalent to List A. e typeof binary trees with data at each node can be obtained by replacing 1 with B inthe position, since non-leaf nodes contain two subtrees.Without function extensionality, the straightforward encoding of an induc-tive type as a W-type is generally not as powerful as the original inductive type.However, Hugunin [79] recently discovered an alternate formulation of inductivetypes as W-types which does not require extensionality to produce equivalenttypes.An indexed version of containers and W-types also exists. e basic idea isthat the shape-type S should be parameterized over whatever type I indexes theinductive type, and the position provides a type for each i : I and s : S i. Indexedcontainers contain an additional “next” eld which describes, for each recursivereference in the codomain of the position, what the value of the index should befor that reference.2.2.3.3 DescriptionsDescriptions give a less compact but more direct alternative to containers andW-types for encoding functors and inductive types. Many presentations of de-scriptions exist [29, 52, 97], but for this dissertation, we follow the presentation44of Diehl and Sheard [48]:data Desc : Type1 whereEnd : DescArg : (A : Type)→ (A→ Desc)→ DescRec : (A : Type)→ Desc→ DescDescriptions have a tree-like structure: each node either describes a recursive(Rec) or non-recursive (Arg) part of an inductive type, where branches are termi-nated with End. e Arg constructor serves two purposes. First, it can be used toencode a description for each constructor of a type, for example, by se ing A to besome nite type of tags. It also encodes non-recursive elds of constructors, en-abling dependent products by giving a description of what data should be presentfor each possible argument of type A. Rec describes what elds of the form A→ Tare contained in constructors for T.e functor described by a description is given by the El function:El : Desc→ Type→ TypeEl End X = 1El (Arg A D) X = (a : A)×El (D a) XEl (Rec A D) X = (A→ X)×El D Xat is, End takes no data, Rec takes a function from A to the input type X pluswhatever is encoded in the rest of the description, and Arg takes a dependent pairof a : A plus data speci ed for whatever description D gives for a.e xed point of a description can then be given as an inductive type, whichcloses the loop and turns each use of X in El into a recursive reference:data 𝜇 (D : Desc) : Type whereinit : El D (𝜇 D)→ 𝜇 D45For example, the description-encoding for List A would be:𝜇(Arg B(𝜆b. if b End (Arg A (𝜆x.Rec 1 End))))Here, B denotes the type of booleans. e rst piece of data in a List is a booleandescribing whether it is a nil or a cons. In the nil case, we take no more data,marked by End. In the cons case, we take a head value of type A, followed by atail value of type 1→ List A, which is equivalent to List A.Descriptions do not rely on extensionality for encoding datatypes directly.Moreover, they are easier to inspect thanW-types. Containers are function-oriented,making it di cult to introspect on the structure of an inductive type from itsequivalent container. Descriptions, on the other hand, are more data-orientedthan function-oriented, so it is generally easier to inspect the structure of a de-scription and recover the structure of the original inductive data type.Like W-types, descriptions have an indexed variant. With an index type I, Elhas type (I → Type)→I→ Type. e idea is that the End constructor takes anargument specifying an index value, and El for End takes a propositional equalityproof that the given index matches the one speci ed in the description. Likewise,Rec has an additional argument specifying an index value for each recursive ref-erence.2.2.4 Dependent Types: Implementation and Practical DetailsBecause of the type-term overlap, implementing a dependently typed languagebrings with it unique challenges. Here, we highlight those that are particularlyrelevant when mixing gradual and dependent types, along with standard tech-niques for dealing with them in non-gradual se ings.2.2.4.1 Local Inference and Bidirectional Type CheckingIn lambda calculi, the desired type of an expression is not always clear. Even inthe simply-typed lambda calculus, a term such as 𝜆x.xmay be assigned in nitelymany types. e situation is more complex with dependent types: even if weknow the type family a term should belong to, we may not be able to infer the46parameters or indices of that family from the term alone.One particularly elegant solution to this problem is bidirectional typing [123].Instead of a single typing judgment Γ ` t : T, a bidirectional system has two judg-ments. e checking judgment, Γ ` t ⇐ T, treats the type of an expression asinput, while the synthesis judgment, Γ ` t⇒ T, treats the type as output. Bidirec-tional typing does not remove the need for type ascriptions, but it allows typinginformation from top-level ascriptions to be propagated into sub-terms, meaningthat in most cases, only top-level function de nitions need annotations.In most bidirectional systems, the switching between checking and synthesisis mediated by two generic rules. First, a type-ascribed expression synthesizes thetype in its annotation, and checks its body against that type.AscrΓ ` t⇐ TΓ ` (t :: T)⇒ TIn the other direction, we let any term check against the type it synthesizes:CheckSynthΓ ` t⇒ T′ T′ = TΓ ` t⇐ Te equality between T and T′ can be replaced by amore permissive relation, suchas subtyping or, as we do in this thesis, gradual consistency.Bidirectional typing helps pinpoint where type ascriptions are needed to en-able checking. In particular, function de nitions do not synthesize types, so theymust either be annotated, or used in contexts where their desired type is known.By using a bidirectional system, the implementation of a type checker may closelymatch the typing rules, since it removes the need for the rules to nondeterministi-cally “guess” the desired type for an expression. Lo¨h et al. [89] provide a referenceimplementation of a simple dependently typed language using bidirectional typ-ing.Lennon-Bertrand [86] presents the Bidirectional Calculus of Inductive Con-structions ( bcic ), which uses an alternate style of bidirectional typing. In bcic,functions are still ascribed with their argument types, and all terms are synthe-sizing terms. Some typing rules have premises that are checking rules, in caseswhere the desired type of an expression is known. For example, when synthesiz-47ing a type for a function application, the argument is checked against the functiondomain type, since it is already known from synthesizing the function’s type. bcichas a single checking rule, which says that a term checks against any type that isdenitionally equal to the type it synthesizes.bcic is equivalent to cic, but the proof relies on the transitivity of de nitionalequality. e reliance on transitivity provides insight into why bidirectional typ-ing is preferable to, or at least, not equivalent to, unidirectional typing for graduallanguages, where the consistency relation used in place of de nitional equality isnot transitive. We use bcic as the starting static language for Chapters 5 and 6.2.2.4.2 Compile-time NormalizationIn the CheckSynth rule above, the type-term overlap complicates the issue ofwhat it means for two dependent types to be equal. For example, are Vec Nat 2and Vec Nat (1+1) the same type? If we compare them syntactically, they aredi erent, but they are computations resulting in the same type.To account for this, instead of simple syntactic equality, dependent types use anotion of de nitional equality [93], which we write as =𝛼𝛽𝜂 . Two terms are de ni-tionally equal if they are 𝛼-equivalent a er being fully 𝛽-reduced and 𝜂-expanded.So our CheckSynth rule would become:CheckSynthΓ ` t⇒ T′ T′ =𝛼𝛽𝜂 TΓ ` t⇐ Te main way to implement this rule to normalize the terms involved: two termsare de nitionally equal if and only if we can reduce them to the same normalform.Normalization is similar to, but not identical to, run-time evaluation. Typi-cally, run-time evaluation is only de ned for closed terms, and evaluation nevertakes place under binders. e body of a function is not evaluated until that func-tion is applied. When comparing types, we want to consider 𝜆x.x− (1+1) and𝜆x.x−2 to be the same. So we need to normalize under binders (𝜆 , → and ×),meaning that we need to know how to normalize terms with free variables.Normalization under binders is achieved by de ning normal forms as mutu-ally inductive with neutral terms. A neutral term is one of the form x · −→p : it has a48variable, called the head, and a spine [26], which is a list of eliminators −→p appliedto the head. An eliminator could be an argument (for function application), a pairprojection, or the eliminator for an inductive type. is convention lets us excludeterms like (𝜆x.x) y from our normal forms, since it can be further reduced, whileallowing 𝜆x. (x y), which cannot be further reduced. A term is then in normal formif it is neutral, it is a constructor applied to normal forms, or it is a function witha normal body.A variant of this approach is to use canonical forms [72, 121]. Instead of nor-malizing at each application of CheckSynth, the canonical-forms approach onlyconsiders normal form types in checking and synthesis, and allows any term tocheck against the type it synthesizes. Since judgments only refer to normal formsof types, a notion of hereditary substitution [154] is required for function appli-cation and other forms with types depending on values. In hereditary substitu-tion, substitutions performed on normal forms are further reduced to producenormal forms as a result. Neutral forms in hereditary substitution are also calledatomic forms. Hereditary substitution is particularly elegant, because in a calculuswithout inductive types, normalization can be wri en as a structurally-recursiveprocedure. We use this in Chapter 3 to prove the termination of approximatenormalization for gradual types.2.2.4.3 Implicits, Unification, and Type InferenceDependent types as we have presented them are incredibly cumbersome to use.For example, the eliminator for vectors takes several arguments, and requires thatthe motive be manually speci ed. Likewise, refl requires one to explicitly providethe t for which t = t is being proved, along with the type of t.In practice, dependently typed languages alleviate this verbosity through asystem of program metavariables and implicit arguments. A program metavari-able, usually wri en as an underscore , is a special syntactic construct that in-forms the compiler to infer what value must replace the metavariable for the pro-gram to be type correct. For example, in refl 3, Nat is the only valid type value,since 3 has a known type. Implicit arguments in a function declaration, wri enusing curly-braces {x : X}, form a shorthand that instructs the compiler to insert a49program metavariable for that function argument unless it is explicitly provided.ough dependent types do not have a separate construct for type polymor-phism, the fact that we can pass types as arguments lets us use the normal 𝜆construct similarly to the Λ binder of System-F [125]. For example, we can write(𝜆X x.x) : (X : Type0)→ X→ X for an explicitly polymorphic identity function.With implicit arguments, we can eliminate the need for explicitly instantiatingpolymorphic functions. If instead we write id = (𝜆{X} x.x) : {X : Type0} → X→ X,we can call id t for any term t : T, and let the compiler determine that T shouldbe provided for the parameter Xm le ing us write polymorphic code in a stylereminiscent of Haskell or ML.Program metavariables must be resolved using uni cation [109]. Unlike theinference system of Damas and Milner [44], however, this inference cannot becomplete. e type-term overlap, and the fact that dependent functions and pairshave binding structure, means that we must use higher order uni cation [77] tosolve our metavariables. Higher order uni cation is undecidable in the generalcase [78], although it has a decidable subproblem called the pa ern fragment [100].is fragment is large enough that it can be used to solve most uni cation prob-lems that arise with dependent types [3, 71].Type inference has an interesting relationship with gradual typing becauseof the subtle di erence between a type with a single static value that is not yetknown and a gradual type that can potentially represent many static types. econsistency relation between types resembles uni cation, with each ? occurrenceacting as a distinct metavariable. Siek and Vachharajani [134] provide an accountof mixing type inference and gradual typing without dependent types, as do Gar-cia and Cimini [66]. We discuss possible future work on gradual higher orderuni cation in Chapter 7.2.2.5 Syntactic Models of Dependently Typed LanguagesProving termination is one of the main strategies for proving consistency of alanguage: the usual argument combines the fact that the empty type containsno normal form terms with the fact that all terms eventually reduce to a normalform. Conventional decreasing-metric arguments are typically di cult, if not im-50possible, to use when showing that all terms in a dependently typed languageterminate.e common approach for showing termination of a system is to construct amodel of the language: devise some mathematical structure for each type, whereeach term of that type can be mapped to an instance of that structure called adenotation, and that the denotation of a term is invariant under reduction. en, ifthe empty type has an empty denotation, there can be no closed terms of that type.Models of dependently typed languages are o en based on partial equivalencerelations or category theory [51].A simpler form of model is a syntactic model [11, 17], where instead of hav-ing an abstract mathematical denotation, each term’s denotation is a term froma dependent type theory. Syntactic models let us “piggyback” o of a model foran existing type theory, such as mltt or cic. Depending on how the model isconstructed, we can then use properties of the target type theory to prove factsabout the source type theory. For example, if we give a language a syntacticmodel in a strongly normalizing type theory, and each source redex has a denota-tion containing a target-language redex, then strong normalization for the sourcelanguage follows from a straightforward simulation argument. Likewise, consis-tency can be shown by ensuring that empty source types translate to empty typesin the syntactic model.Syntactic models are well suited to showing weaker forms of consistency fordependently typed languages that lack full consistency. For example, if Empty hasa denotation that is a target singleton type, then there is a unique characterizationof what source terms can inhabit Empty. is technique is used, for example, tomodel that errors are the only inhabitants of empty types in a type theory withexceptions [118, 120], and to show that errors and ? are the only inhabitants ofempty types in a gradual type theory [87, 90].2.3 Prior Work on Gradual Dependent TypesHere, we describe existing work in the space of mixing dynamic and dependentlytyped code. To our knowledge, our work [58], on which Chapter 3 is based, isthe rst to address fully gradual dependent types, where any type or term can be51replaced by ?.2.3.1 Contracts and Dynamic CheckingFindler and Felleisen [65] introduced higher order contracts, which provide a wayfor programmers to specify properties of functional programs. Among their con-tributions are dependent contracts, which allow the contract on a function’s re-turn value to depend on the value of the argument. ough dependent contractsprovide a form of dynamic dependent typing, they are purely dynamic, o eringno static guarantees on code.Ou et al. [114] provide a system in which static dependent types are mixedwith dynamic checks, in one of the earliest a empts to bring gradual typing con-cepts to dependent types. However, their language is oriented around subsettypes, which constrain a simple type to only those values satisfying some booleanpredicate. e reliance on boolean predicates makes it easy to move compile-timechecks to run time. Boolean predicates are strictly less expressive than full depen-dent types, and are not compatible with much of the existing dependently typedcode. Any proofs of theorems that are not of the form p(x) ≡ true cannot be omit-ted by the user.Tanter and Tabareau [144] modify Coq, a dependently typed theorem prover,to have dynamic enforcement of type constraints. Using a combination of un-sound axioms and Coq’s typeclass and implicit coercion mechanisms, they allowfor a value t : T to be automatically converted into the type (t : T)× (p(t) ≡ true),with the check that p holds dynamically performed. is work also relies onboolean predicates and subset types, and doesn’t allow for arbitrary proofs tobe omi ed.Gradual re nement types provide a limited form of term-dependence in types.Lehmann andTanter [84] provide a system for gradual re nement types, lightweightdependent types providing predicates over numbers. is work provides many ofthe same properties as our proposed language, such as the ability to smoothlymove between more or less precise types. However, the techniques used for re-nement types do not scale to full dependent types. Zalewski et al. [158] presenta blame-safe system for gradual re nement types with dependent functions, but52achieve decidable type checking through a strict distinction between terms andtypes.2.3.2 Gradual Type TheoriesSeveral aempts have been made to incorporate concepts from gradual typinginto formal type theories, with various levels of compromise on consistency, con-venience, and the gradual guarantees.Osera et al. [113] present dependent interoperability, a system for interfacingbetween a (simple) static and dependently typed language. e approach relies ona one-to-one correspondence between constructors of types in the static and de-pendent languages, and requires users to provide their own functions for convert-ing between the two. is technique was extended by Dagand et al. [42, 43] to usepartial equivalences, a loosening of equivalences from type theory. ese equiva-lences take a way to map a simple type, such as List T into a dependent type, likeVec T n and back, with the former having the possibility of failure. Given such anequivalence, functions operating on one type can be automatically li ed to workwith the other. Type failure is expressed using an error monad. e partial equiv-alence approach works with any types that can be rewri en to be expressed as asubset type.Dependent interoperability is related to gradual typing. However, its focusis on interactions between simply-typed and dependently typed code, where weseek to support the whole spectrum between dynamic and dependently typed.Exceptional type theory provides a formalization of dependently typed lan-guages with catchable run-time exceptions [118, 120]. ese languages do notsupport gradual typing. Moreover, gradual type errors are traditionally not catch-able, as catching errors violates the gradual guarantees. However, the ability toformally model terms that may fail provides valuable insights that can be usedwhen describing the behaviour of approximate normalization. Pe´drot and Tabareau[119] show that dependent elimination and substitution must be restricted in thepresence of observable e ects, but the non-catchable run-time type errors of grad-ual typing do not fall into this category.Lennon-Bertrand et al. [87] combine aspects of gradual typing and exceptional53type theory to provide a fully gradual Calculus of Inductive Constructions (CIC).ey identify three properties which cannot possibly co-exist in a gradual depen-dently typed language: conservatively extending the static sub-language (CIC intheir case), strong normalization, and the embedding-projection (EP) property. eEP property, rst used in gradual typing by New and Ahmed [105], is the prop-erty that losing and re-gaining precision on a term produces the original term,and gaining then losing precision on a term produces the same term, or an error.the Gradual Calculus of Inductive Constructions ( gcic ) is presented as three lan-guage variants, based on a common framework, that ful ll each combination ofthe above properties. e work on gcic was published a er our initial publica-tion [58], and inherits some features from that work, such as the use of ? as botha term and a type.gcic was extended to a “reasonably gradual” type theory ( grip ) by Maillardet al. [90]. grip sacri ces the full gradual guarantees, but identi es the fragmentof their language that satis es the gradual guarantees. e type theory is dividedinto two layers, a gradual layer in which all terms may fail or produce ?, and apropositional layer which can be used to reason about terms in the gradual layer.Notably, gradual precision is re ected into the propositional layer, so the precisionrelation between terms can be established in the type theory itself.2.3.3 Dependently Typed Non-termination2.3.3.1 Allowing Non-terminating FunctionsWe are not the rst to encounter the problem of running possibly non-terminatingduring dependent type checking. e Zombie language [23, 138] featured two dis-tinct sub-languages. One was logically consistent and could be used for theoremproving, while the other featured general recursion and was used for program-ming. ough no false theorems can be proved in such a language, the terminationof type checking is not guaranteed. In many ways, their language is the converseof what we present in Chapter 3: they have two separate sub-languages with iden-tical semantics but limited interactions, while we want a single language that hasdi erent behaviour depending on whether it is run at compile time or run time.Other approaches to non-termination include that of Dependent Haskell [55],54where no termination checks are performed at compile time and logical consis-tency is lost, or Idris [19], where the user must declare which functions are totaland may be executed at compile time.92.3.3.2 Modelling Non-terminationA separate line of research involves using dependently typed languages to modelnon-terminating computations. Such systems have the ability to describe possiblyinnite computation, while keeping all functions in the core language terminat-ing. e advantage of this approach is that minimal changes are required to thetype theory itself, and the programmer can rest assured that functions they writein said type theory always terminate, as does type checking. e disadvantage isthat fewer de nitional equalities are present: since non-terminating proceduresare de ned as objects describing functions, rather than functions themselves, thenormal 𝛽-equalities are not automatically applied during type checking.Most approaches to modelling non-termination use some sort of modality,possibly a monad. Capre a [21] uses a coinductive type, commonly called thedelay monad, to model general recursion. McBride [98] generalizes this techniqueusing a free monad, where a generic interface is provided for de ning general-recursive functions. Semantics may then be given to this interface using one ofseveral methods, such as a fuel-based semantics, or using a delay monad (in anapproach adapted from Abel and Chapman [2]).Guarded recursion [103] is particularly useful for gradual types, since it can de-scribe non-terminating computation and non-positive xed points using a latermodality, where data under the modality is only available at some time in thefuture. e later modality can be used to express many coinductive computa-tions [7]. Guarded type theory can be given a model using the topos of trees [14],and provides a type-theoretical analogue to step-indexing in logical relations. Sev-eral dependent type theories have been developed based on guardedness [13, 16],along with various computational interpretations [15, 140]. In Chapter 6, we useguarded recursion to model the non-terminating parts of gradual run-time com-putations.9At the time of writing, current implementation of Idris 2 allows non-termination at compiletime, but adding the check from Idris 1 is planned to eventually be added back to Idris 2.55Chapter 3Foundations of GradualDependent Typesis chapter presents a Gradual Dependently Typed Language ( gdtl ), whichoriginally appeared in [58]. gdtl is a foundational gradual dependently typedlanguage: at the time of publication, to our knowledge, it was the only calculusin the literature that enabled ? to be used as both a type and a term.Our aims for this chapter are twofold. First, we make a rst foray into the de-sign space for gradual dependent types. With gdtl, we identify the key ways thatgradual dependent types should di er from gradual simple types. Speci cally, thedependence of types on terms means that ? should be allowed to be used as botha term and a type, so that the programmer can express types with a known typeconstructor but imprecise indices. Likewise, proof terms in dependently typedlanguages can persist at run time and even a ect program behaviour, so ? shouldbe allowed to replace proof terms, and should have de ned run-time semantics.We adopt the approach of Abstracting Gradual Typing ( agt ) to ensure that grad-ual capabilities are added to dependent types in a safe, principled way.e second task for this chapter is to make precise the relationship betweengradual types, dependent types, and computational e ects. Speci cally, gradualtypes introduce both non-termination and dynamic type errors, which are in ten-sion with the need to normalize terms at compile time when checking depen-dent types. To account for non-termination and failure, we distinguish between56compile-time normalization and run-time execution: compile-time normalizationis approximate but terminating, while run-time execution is exact, but may di-verge. We prove that gdtl has decidable type checking and satises all the ex-pected properties of gradual languages. In particular, gdtl satis es the gradualguarantees: reducing type precision preserves typedness, and altering type pre-cision does not change program behaviour outside of dynamic type failures. Toprove these properties, we establish a novel normalization gradual guarantee thatcaptures the monotonicity of approximate normalization with respect to impre-cision.e original publication of gdtl claimed that it satis ed the gradual guaran-tee, but unfortunately, there was an error in the proof. As such, we have modi edthe presentation of gdtl to ensure that it does satisfy the static gradual guaran-tees. Speci cally, we include a notion of evidence on neutral terms when normal-izing during type checking, storing the most precise information available aboutwhat their actual types should be. is approach lets us monotonically handletype errors.In general, the approaches taken to proving the static guarantee in Chapters 5and 6 are preferable to this one: the cast calculus paradigm greatly simpli es theissue of normalizing types and comparing them during type checking. Moreover,in contrast to gdtl, the languages of those chapters respect static equivalences:extensionally-equal static programs cannot be distinguished gradually. Unlikethis chapter, Chapters 5 and 6 do not use a systematic approach to derive thegradual type system, but we discuss possible future work to re-systematize ourapproach in Chapter 7.3.1 IntroductionA major barrier to the integration of gradual dependent types is the tension be-tween the purity of dependently typed code and the impurity of gradually typedcode. A dependent type checker must evaluate some program terms as part oftype checking, but gradual types complicate this in two ways. First, if a graduallanguage fully embeds an untyped language, then some programs diverge: in-deed, self application (𝜆x : ?.x x) is typeable in such a language. Second, gradual57languages introduce the possibility of type errors that are uncovered as a termis evaluated: applying the function (𝜆x : ?.x +1) may or may not fail, dependingon whether its argument can actually be used as a number. For example, usingtrue : ? as an argument fails, but 0 : ? succeeds. So a gradual dependently typedlanguage must account for the potential of non-termination and failure duringtype checking.is chapter a empts to rectify the pure-impure tension between dependentand gradual types. We present a Gradual Dependently Typed Language ( gdtl )that supports the whole spectrum between an untyped functional language and adependently typed one. As such, gdtl adopts a uni ed term and type language,meaning that the unknown type ? is also a valid term. Having ? as a term letsprogrammers specify types with imprecise indices and replace proof terms with? (Section 3.2).gdtl is a gradual version of the the Calculus of Constructions with a pred-icative universe hierarchy ( cc𝜔 ) (Section 3.3), similar to the core language ofIdris [19]. We gradualize this language following the Abstracting Gradual Typing( agt ) methodology [67] in Section 3.4. Because gdtl is a conservative extensionof this dependently typed calculus, it is both strongly normalizing and logicallyconsistent for fully static code. However, these strong properties are lost as soonas imprecise types and/or terms are introduced. On the dynamic side, gdtl canfully embed the untyped lambda calculus. When writing purely untyped code,static type errors are never encountered. In between, gdtl satis es the static anddynamic gradual guarantees of Siek et al. [136], meaning that evaluation is mono-tone with respect to type imprecision. ese guarantees enable the programmerto move between imprecise and precise types in small, incremental steps, with theprogram type checking and behaving identically (modulo dynamic type errors) ateach step.e key technical insight on which gdtl is built is to exploit two distinctnotions of evaluation: one for normalization during type checking, and one forexecution at run time. Speci cally, we present a novel semantics, called approx-imate normalization. Approximate normalization is not used to de ne the run-time behavior of programs, but rather, as a means of de ning an approximatenotion of de nitional equality that determines whether two types are equivalent58in the eyes of the type checker. Approximate normalization allows decidable typechecking (Section 3.5): applying a function of unknown type, which may trig-ger non-termination, normalizes to the unknown value ?. Consequently, someterms that would be distinct at run time become indistinguishable as type indices.Compile-time tracking of type information during normalization safely handles“dynamic” type errors occurring during static normalization. In this sense, gdtlis closer to the styles of Idris, Agda, Coq, etc. than Dependent Haskell [55], whichdoes admit reduction errors and non-termination during type checking. At runtime, gdtl uses the standard, precise run-time strategy of existing gradual lan-guages, which may fail due to dynamic type errors, and may diverge as well (Sec-tion 3.6). In that respect, gdtl is closer to Dependent Haskell and Zombie [23, 138]than to Idris, which features a termination checker and a static eect system. Weprove that gdtl has decidable type checking and satis es several desirable prop-erties of gradual languages [136]: type safety, conservative extension of the staticlanguage, embedding of the untyped language, and the gradual guarantees (Sec-tion 3.7). Section 3.8 discusses related work, and Section 3.9 discusses limitationsand perspectives for future work.3.2 Goals and ChallengesIn this section, we revisit the example of Section 1.3, introducing gdtl by showinghow the vector head operation behaves when given various inputs. To propagateimprecision to type indices, and soundly allow omission of proof terms, gdtl ad-mits ? both as a type and a term. To manage e ects due to gradual typing, we useseparate notions of evaluation for compile time and run time. Introducing impre-cision in the compile-time normalization of types avoids both non-terminationand failures during type checking.is section uses both vectors and propositional equality for the sake of expo-sition, so that the examples are actually comprehensible by a human. Neither ofthese features is directly supported by gdtl, since gdtl is a foundational calcu-lus, and does not support inductive types. Analogous types can be de ned usingChurch encoding, although the predicative nature of gdtl weakens how thesecan be used. However, we emphasize that the purpose of this chapter is to ex-59plore decidable type checking for gradual dependent type. Features necessary forpractical programming are discussed in Chapter 5.3.2.1 The unknown as a type indexRecall that the type of vectors has constructors Nil : Vec A 0 andCons : A→ Vec A n→ Vec A (n+1), and a function head : Vec A (1+n)→ A.Since full-spectrum dependently typed languages conate types and terms,gdtl lets ? be used as either a term or a type. Just as any term can have type ?,the term ? can have any type, allowing imprecision in indices to be speci ed. Forexample, we can de ne vectors staticNil, dynNil and dynCons as follows:staticNil : Vec Nat 0 dynNil : Vec Nat ? dynCons : Vec Nat ?staticNil = Nil dynNil = Nil dynCons = Cons 0 (Nil)en:• head staticNil does not type check,• head dynNil type checks but fails at run time,• head dynCons type checks and succeeds at run timee programmer can choose between compile time or run time, but safety is main-tained either way, and in the fully-static case, the unsafe code is still rejected.3.2.2 The unknown as a term at run timeHaving ? as a termmeans that programmers can use it to optimistically omit proofterms. Indeed, terms can be used not only as type indices, but also as proofs ofpropositions. For example, we can use propositional equality to write a (slightlycontrived) formulation of the head function:head ′ : (n : Nat)→ (m : Nat)→ n =Nat m+1→ Vec A n→ Ais variant accepts vectors of any length, provided the user also supplies a proofthat its length n is not zero by explicitly providing the predecessor m and the60equality proof of type n =N (m+1). gdtl lets ? be used in place of a proof, whilestill ensuring that a run-time exception is thrown if head ′ is ever given an emptylist. For instance, suppose we dene a singleton vector and a proof that 0 =N 0:staticCons : Vec Nat 1 staticProof : 0 =N 0staticCons = Cons Nat 0 (Nil Nat) staticProof = Re Nat 0en:• head ′ Nat 0 0 staticProof staticNil does not type check• head ′ Nat 0 ? ? staticNil type checks but fails at run time• head ′ Nat 1 ? ? staticCons type checks and succeeds at run timeWe defer discussion of the speci cs of gradual propositional equality to Chapter 5,where we develop a more sophisticated method of tracking run-time equality in-formation. e important point is that, because dependent types use proofs thatcan persist at run time, ? should be treated as a term with properly de ned dy-namic semantics.3.2.3 Managing e ects from gradual typingTo illustrate how the e ects of gradual typing can show up in type checking,suppose a programmer uses ? to write a gradually typed Z-combinator, the call-by-value counterpart of the Y-combinator:Z = 𝜆(f : ?). ((𝜆(x : ?). f (𝜆(v : ?).x x v)) (𝜆(x : ?). f (𝜆(v : ?).x x v)))ey may then use this combinator to accidentally write a non-terminating func-tion badFact.badFact = 𝜆 m .Z (𝜆 f . ifzero m (f 1)(m ∗ f (m)) -- never terminates61Many languages allow non-termination, but the issue is that computing the returntype of a function application may diverge. For example:repeat : (A : Type )→ (n : Nat)→ A→ (Vec A n)factList = repeat Nat (badFact 1) 0 -- has type Vec Nat (badFact 1)It turns out that any diverging code necessarily applies a function of type ?.ough badFact does not have type ?, its de nition uses Z , which contains as-criptions of type ?.Similarly, a naı¨ve approach to gradual dependent types encounters failureswhen normalizing some terms. Let :: denote a type ascription in the surface lan-guage, which can induce an implicit type conversion. How should we a empt totype check the following term?failList = repeat Nat (false :: ?) 0e return type of this call is Vec Nat (false :: ?), that is, a vector with length false.It is fairly clear that such a nonsensical example should not type check, since nor-malizing false :: ? at type Nat should produce an error. However, not all dynamicerrors are this straightforward. Consider a function that gives repeat a length ofunknown type:failFun = 𝜆(x : ?). repeat Nat x 0Just because a function raises a type error on some inputs does not mean thatnormalizing it should fail. So we need a notion of compile-time normalizationthat can raise a type error for failList, but is lazy enough to let failFun be calledon ?-typed inputs that normalize to numbers.gdtl avoids both problems by using di erent notions of running programs forthe compile time and run time. We distinguish compile-time normalization, whichis approximate but terminating, from run-time execution, which is exact but maydiverge. When non-termination is possible, compile-time normalization uses ?as an approximate but pure result. To account for possible failure under binders,neutral terms are ascribed with compile-time evidence, a novel version of run-timeevidence from agt, that stores type information under binders to potentially raise62an error if an invalid input is provided. So factList can be dened and used in runtime, but are assigned type Vec Nat ?. Conversely, failList is rejected due to theerror when normalizing at compile time.gdtl normalization is based around hereditary substitution [154], which is atotal operation from canonical forms to canonical forms. With hereditary sub-stitution, we can de ne a decreasing measure in terms of the type of the valuebeing substituted, so a static termination proof is easily adapted to gdtl. is de-creasing measure lets us pinpoint exactly where gradual types introduce possiblenon-termination, approximating in those cases. Similarly, our use of bidirectionaltyping means that a single check needs to be added to prevent failures in normal-ization.3.2.4 Gradual Guarantees for gdtlTo ensure a smooth transition between precise and imprecise typing, gdtl satis-es the gradual guarantee of Section 2.1.2.2. One novel insight of gdtl’s designis that the interplay between dependent type checking and program evaluationcarries over to the gradual guarantees. Speci cally, the static gradual guaranteefundamentally depends on a restricted variant of the dynamic gradual guaran-tee. We show that approximate normalization maps terms related by precisionto canonical forms related by precision, thereby ensuring that reducing a term’sprecision always preserves well typedness.By satisfying the gradual typing criteria, and embedding both a fully staticand a fully dynamic fragment, gdtl gives programmers freedom to move withinthe entire spectrum of typedness, from the safety of higher-order logic to theexibility of dynamic languages. Furthermore, admi ing ? as a term means thatwe can easily combine code with dependent and non-dependent types, the mid-point between dynamic and dependent types. For example, the simple list typecould be wri en as List A = Vec A ?, so lists could be given to vector-expectingcode and vice-versa. e programmer knows that as long as vectors are used invector-expecting code, no crashes can happen, and safety ensures that using a listin a vector operation always fails gracefully or run successfully. is approachis signi cantly di erent from work on casts to subset types [144] and dependent63interoperability [43], where the user must explicitly provide decidable propertiesor (partial) equivalences.3.2.5 Summary of Design Decisionsgdtl embodies several important design decisions, each with trade-os related toease of reasoning and usability of the language.By embracing full-spectrum dependent types, gdtl lets types be rst-classcitizens: arbitrary terms can appear in types and expressions can produce typesas a result. e programmer does not need to learn a separate index language,and does not need to recreate term-level operations at the type level.Sticking to clearly separated phases lets us adopt di erent reduction strate-gies for type checking and for execution. Crucially, by using approximate normal-ization, we ensure that type checking in gdtl always terminates: compile-timenormalization is a total (though imprecise) operation. At type ?, some type infor-mation is statically lost, with checks deferred to run time.gdtl features an unknown term ?, which resembles term holes in Agda andIdris, and existential variables in Coq; the notable di erence is that programscontaining ? can be run without evaluation ge ing stuck. Every type in gdtl istherefore inhabited at least by the unknown term ?, so the language is inconsistentas a logic, except for fully-precise programs.In a gradual language that can embed arbitrary untyped terms, programs maynot terminate at run time. Every type in gdtl contains expressions that can failor diverge at run time, due to imprecision. Fully-precise programs are guaranteedto terminate.Finally, like Coq, Agda, and Idris, gdtl is based on an intensional type theory,meaning that it automatically decides de nitional equality—i.e. syntactic equalityup to normalization—and not propositional equality; explicit rewriting is neces-sary to exploit propositional equalities. Consequently, this check is re ected torun time: dynamic checks in gdtl also rely on de nitional equality. us, equalityis decidable, but a run-time error can be triggered even though two (syntacticallydi erent) terms are propositionally equal. e limitations of this approach, andalternatives to it, are described in Chapter 5.643.3 sdtl: A Static Dependently Typed LanguageWe now present our Static Dependently Typed Language ( sdtl ), which is essen-tially a bidirectional, call-by-value, variant of the predicative fragment of cc𝜔 (i.e.the calculus of constructions with a universe hierarchy [39]). sdtl is the startingpoint of our gradualization eort.3.3.1 Syntax and Dynamic Semanticse syntax of sdtl is shown in Fig. 3.1, with metavariables for the static variantsof terms, values, etc. wri en in red sans-serif font. Types and terms share a syn-tactic category. e syntax has functions and applications in their usual form, butfunction types are dependent: a variable name is given to the argument, and thecodomain may refer to this variable. e form Typeℓ denotes a universe at level ℓ ,i.e. a type of types. Universes have a hierarchical structure: the lowest types havethe type Type0 and each Typeℓ has type Typeℓ+1. In this chapter, we write Typeto mean Type0. Finally, an explicit type ascription form t :: T lets the programmermanually specify what the type of an expression should be, which is crucial forthis style of bidirectional typing.We use metavariables v,V to range over values, the subset of terms consistingonly of functions, function types and universes. For evaluation, we use a call-by-value reduction semantics (Fig. 3.1). Ascriptions are dropped when evaluating,and function applications result in (syntactic) substitution. We refer to the valuesand semantics as simple rather than static, since they apply equally well to anuntyped calculus, albeit without the same soundness guarantees. Aswe see below,the semantics used to compare terms during type checking is based on hereditarysubstitution, and is extremely strict, even normalizing under binders. However,for the most part this is irrelevant to gradual typing: call-by-name and call-by-value cause the same static and dynamic checks to be performed, di ering onlyin when the types involved in those checks are normalized.65t,T F 𝜆x. t | t1 t2 | x | (x : T1)→ T2 | Typeℓ | t :: T (Static Terms)v,V F 𝜆x. t | (x : V)→ T | Typeℓ (Simple Values)C F  t | v | (x :  )→ T |  :: T (Simple Contexts)(Simple Small-Step Semantics)SimpleStepAnn(v :: T) −→ vSimpleStepApp(𝜆x. t) v −→ [x ⇒ v]tSimpleStepContextt1 −→ t2C[t1] −→ C[t2]Figure 3.1: sdtl: Syntax and Semantics3.3.2 Comparing Types: Normal Formssdtl compares types using normal forms. Since dependent types can contain ex-pressions, it is possible that types may contain redexes. Most dependent type sys-tems have a conversion rule that assigns an expression type T1 if it has type T2, andT2 is convertible to T1 through some sequence of 𝛽-conversions, 𝜂-conversions,and 𝛼-renamings. Instead, we treat types as 𝛼𝛽𝜂-equivalence classes. To compareequivalence classes, we represent them using normal forms [154], denoted withmetavariables u and U. Normal forms are 𝛽-reduced, 𝜂-long canonical membersof an equivalence class. We compare terms for 𝛼𝛽𝜂-equivalence by normalizingand syntactically comparing their normal forms.Figure 3.2 denes the syntax and well-formedness (typing) for normal forms.Normal forms are either universes, functions, function types, or neutral termstagged with their type, which must itself be either neutral or Typeℓ . For example,〈X z〉(y z) and 〈Type2〉(x Type1) are both well-formed tagged neutrals. e typetag for neutrals is not necessary for the static language, since we can synthesizetheir types without annotations. However, the tag simpli es the de nition of themeaning of gradual types in Section 3.4. e angle-bracket notation is taken fromthe agt notation for evidence, since when we gradualize sdtl, that is preciselywhat is a xed to neutral terms.e de nition of neutral forms is also given in Fig. 3.2. A neutral form is avariable applied to some number of normal-form arguments. Neutrals are de ned66as a list-like structure, but for hereditary substitution it is convenient to alwaysknowwhat variable is at the end of the chain of applications. So we dene neutralterms as a variable x called the head, applied to a list of arguments, which we referto as its spine [26].e separation of neutrals and normals is key to ensuring that normal arenot reducible. By only allowing applications in neutral form, we ensure thatall heads are variables, and thus no redexes are present, even under binders.Well-formedness is de ned bidirectionally: neutrals synthesize and normal formscheck. We defer discussion of thewell-formedness rules to Section 3.3.3, wherewegive the more general typing rules for terms. In addition to the usual type restric-tions, the well-formedness rules ensure 𝜂-longness: the types of neutral forms areeither neutral or Typeℓ for some ℓ , so they cannot have type (y : U1)→ U2.3.3.3 Type checking and NormalizationWith normal forms de ned, we can present the typing rules for sdtl (Fig. 3.3),where terms are assigned types in normal form. To ensure syntax directedness,we again use bidirectional typing.e typing rules use the typical synthesis and checking judgments for bidi-rectional typing. e type synthesis judgment Γ ` t⇒ U says that t has type Uunder context Γ, where the type is treated as an output of the judgment. atis, from examining the term, we can determine its type. e checking judgmentΓ ` t⇐ U says that, given a type U, we can con rm that t has that type. eserules propagate the information from ascriptions inwards, so that only top-levelterms and redexes need ascriptions.e rule SSynthApp displays several important concepts that are key to thedesign of sdtl. Since functions are dependently typed, the rule computes theresult of applying a particular term by substituting that term into the returntype. First, the judgment Γ ` u {t2 ⇐ U1 computes the normal form of t2 attype U1. en the return type is computed using hereditary substitution, whichtakes normals as inputs and produces the normal form result of replacing thevariable x with the argument’s normal form. Hereditary substitution, which wewrite [u1/x]Uu2 = u3, is distinct from syntactic substitution, which in this chapter67Snf 3 u, U F Typeℓ | 𝜆x.u | 〈N〉N| 〈Typeℓ〉N | (x : U1)→U2 (Static Normal Forms)Sne 3 N F x p (Static Neutral Forms)SSpine 3 p F · | p u (Static Normal Spines)Γ ` N⇒ U (Static Well Formed Neutrals)SWFVar(x : U) ∈ ΓΓ ` x · ⇒ USWFAppΓ ` x p⇒ (y : U1)→ U2Γ ` u⇐ U1 [u/y]U1U2 = U3Γ ` x p u⇒ U3Γ ` u⇐ U (Static Well Formed Normal Forms)SWFTypeΓ ` Typeℓ ⇐ Typeℓ+1SWFNeutralΓ ` N⇒ N′Γ ` N′⇒ TypeℓΓ ` 〈N′〉N⇐ 〈Typeℓ〉N′SWFNeutralTypeΓ ` N⇒ TypeℓΓ ` 〈Typeℓ〉N⇐ TypeℓSWFLam(x : U1)Γ ` u⇐ U2Γ ` 𝜆x.u⇐ (x : U1)→ U2SWFPiΓ ` U1 ⇐ Typeℓ (x : U1)Γ ` U2 ⇐ TypeℓΓ ` (x : U1)→ U2 ⇐ TypeℓFigure 3.2: sdtl: Normal and Neutral Formswe write as [x ⇒ t1]t2 = t3. We explain hereditary substitution further in Sec-tion 3.3.4.e remaining rules in the system are standard. Each universe Typeℓ synthe-sizes Typeℓ+1 (SSynthType), and variables synthesize their type from the contextΓ (SSynthVar). e switch from checking to synthesis is mediated by the ruleSSynthAnn, where t :: T checks against U so long as t synthesizes U and U is thenormal form of type T. We do not care what level the type T has, only that it hasa normal form U at some level. e SCheckSynth is the bidirectional version ofa conversion check: t checks against U so long as it synthesizes a type with thesame normal formU. Functions are checked in the usual way: 𝜆x. t checks against68Γ ` t⇒ U (Static Synthesis)SSynthTypeℓ > 0Γ ` Typeℓ ⇒ Typeℓ+1SSynthVar(x : U) ∈ ΓΓ ` x⇒ USSynthAnnΓ ` U {T : Type⇒ℓΓ ` t⇐ UΓ ` t::T⇒ USSynthAppΓ ` t1 ⇒ (x : U1)→ U2 Γ ` u {t2 ⇐ U1 [u/x]U1U2 = U3Γ ` t1 t2 ⇒ U3Γ ` t⇐ U (Static Checking)SCheckSynthΓ ` t⇒ UΓ ` t⇐ USCheckLam` (x : U1)Γ (x : U1)Γ ` t⇐ U2Γ ` 𝜆x. t⇐ (x : U1)→ U2SCheckPiΓ ` U {T1 ⇐ Typeℓ ` (x : U)Γ (x : U)Γ ` T2 ⇐ TypeℓΓ ` (x : T1)→ T2 ⇐ TypeℓFigure 3.3: sdtl: Type Synthesis and Checkinga function type if its body checks against the return type, under the assumptionthat its argument has the domain type. e rule SCheckPi encodes predicativequanti cation: we can check function types against Typeℓ , provided the domainand codomain check against Typeℓ .e normalization judgment used in SSynthApp is de ned in Fig. 3.4, withrules directly mirroring those of well typed terms. In particular, the rule SNorm-SynthVar𝜂-expands any variables with function types, which lets us assume thatthe function in an application always normalizes to a 𝜆-term. We use this assump-tion in SNormSynthApp, where the normal form of an application is computedusing hereditary substitution.Auxiliary judgments supporting normalization, are de ned in Fig. 3.5. ejudgment Γ ` T {U : Type⇒ℓ works like checking against Typeℓ , but producesthe level ℓ of the type as an output rather than taking it as an input. Synthesiz-ing forms normalize using the normalization-synthesis judgment, discarding the69synthesized Typeℓ . Function types are the only types that are checking forms,and their level-unaware normal forms are computed by computing the normalforms for the domain and codomain at unknown level and synthesizing the max-imum. e 𝜂-expansion judgment expands neutral terms into normal forms in atype-directed manner. In EtaNeut, a neutral term with a neutral type expandsby adding the type as a tag, and in EtaType a neutral type expands by adding theType tag. Finally, a neutral term with a function type expands in EtaPi by ab-stracting over a fresh variable y that is added to the spine. We recursively expandboth the freshly generated variable and the resulting spine, noting that these ex-pansions happen at structurally smaller types. Our 𝜂-expansion assumes that theterms in the spine of a neutral are already 𝜂-long: it wraps the neutral in functionabstractions, but does not traverse into it.3.3.4 Hereditary SubstitutionHereditary substitution (Fig. 3.6) de nes substitution in a way that preserves nor-mal forms, and is used to compute the return types of dependent function ap-plications. At rst glance, many of the rules look like a traditional substitutionde nition. ey traverse the expression looking for variables, and replace themwith the corresponding term. However, the di erence is in how the actual re-placement of variables is handled.ough the majority of the rules traverse terms looking for variables to re-place, the key computation for hereditary substitution takes place in the ruleSHsubRSpine. When replacing x with u1 in xp u2, we nd the substituted formsof u2 and xp, which we call u3 and 𝜆y.u′1 respectively. If the inputs are well typedand 𝜂-long, the substitution of the spine always returns a 𝜆-term, meaning that itsapplication to u3 is not a normal form. To produce a normal form in such a case,we continue substituting, recursively replacing y with u3 in u′1. A similar substi-tution in the codomain of U gives our result type. us, if this process terminates,it always produces a normal form.To ensure that the process does terminate for well typed inputs, we de nehereditary substitution in terms of the type of the variable being replaced. Sincewe are replacing a di erent variable in the premise SHsubRSpine, we must track70Γ ` t{ u⇒ U Γ ` t {u⇐ U (Static Normalization Synthesis and Checking)SNormSynthAnnΓ ` U {T : Type⇒ℓΓ ` u {t⇐ UΓ ` (t :: T){ u⇒ USNormSynthTypeℓ > 0Γ ` Typeℓ { Typeℓ ⇒ Typeℓ+1SNormSynthVar(x : U) ∈ Γx{𝜂 u : UΓ ` x{ u⇒ USNormSynthAppΓ ` t1 { 𝜆x.u1 ⇒ (x : U1)→ U2 Γ ` u2 {t2 ⇐ U1[u2/x]U1u1 = u3 [u2/x]U1U2 = U3Γ ` t1 t2 { u3 ⇒ U3SNormCheckSynthΓ ` t{ u⇒ UΓ ` u {t⇐ USNormCheckLam(x : U1)Γ ` u {t⇐ U2Γ ` 𝜆x.u {𝜆x. t⇐ (x : U1)→ U2SNormCheckPiΓ ` U1 {T1 ⇐ Typeℓ (x : U1)Γ ` U2 {T2 ⇐ TypeℓΓ ` (x : U1)→ U2 {(x : T1)→ T2 ⇐ TypeℓFigure 3.4: sdtl: Normalizationthe type of the resultant expression when substituting in spines, which is whysubstitution on neutral forms is a separate relation. Termination is shown byordering types according to the multiset of universes of all arrow types that aresubterms of the type, similar to techniques used for Predicative System F [54, 91].We can use the well-founded multiset ordering given by Dershowitz and Manna[47]: if a type U has maximum arrow type universe ℓ , we say that it is greaterthan all other types containing fewer arrows at universe ℓ whose maximum isnot greater than ℓ . Predicativity ensures that, relative to this ordering, the returntype of a function application is always less than the type of the function itself.Likewise, the order is preserved under substitution, because predicativity ensuresthe size of any terms replacing variables is dominated by the size of the type of thereplaced variable. In all premises but the last two of SHsubRSpine, we recursivelyinvoke substitution on strict subterms, while keeping the type of the variable thesame. In the remaining cases, we perform substitution at a type that is smaller by71Γ ` T {U : Type⇒ℓ (Type Normalization at Unknown Level)STypeNormSynthΓ ` T{ U⇒ TypeℓΓ ` U {T : Type⇒ℓSTypeNormPiΓ ` U1 {T1 : Type⇒ℓ1(x : U1)Γ ` U2 {T2 : Type⇒ℓ2Γ ` (x : U1)→ U2 {(x : T1)→ T2 : Type⇒max ℓ1 ℓ2Γ ` T : Type (Well Formed Type at Unknown Level)StaticTypeWFΓ ` T {U : Type⇒ℓΓ ` T : Type⇒ℓN{𝜂 u : U (Neutral 𝜂-Expansion)EtaNeutN{𝜂 〈N′〉N : 〈Typeℓ〉N′EtaTypeN{𝜂 〈Typeℓ〉N : TypeℓEtaPiy{𝜂 u′ : U1 x p u′{𝜂 u : U2x p{𝜂 𝜆y.u : (y : U1)→ U2` Γ (Well Formed Environment)SEnvNil` ·SEnvCons` Γ Γ ` U : Type⇒ℓ x ∉ Γ` (x : U)ΓFigure 3.5: sdtl: Auxiliary Judgments for Normal Forms72[u/x]Uu′ = u′′ (Static Hereditary Substitution)SHsubPi[u/x]UU1 = U′1 [u/x]UU2 = U′2[u/x]U(y : U1)→ U2 = (y : U′1)→ U′2SHsubType[u/x]UTypeℓ = TypeℓSHsubNeutx ≠ y [u/x]U〈Typeℓ〉N = U2[u/x]Up1 = p2 y p2 {𝜂 u2 : U2[u/x]U〈N〉y p1 = u2SHsubNeutTypex ≠ y [u/x]Up1 = p2[u/x]U〈Typeℓ〉y p1 = 〈Typeℓ〉y p2SHsubLam[u/x]Uu2 = u3[u/x]U(𝜆y.u2) = (𝜆y.u3)SHsubSpine[u1/x]Ux p = u2 : U′′[u1/x]U〈U′〉x p = u2[u/x]Up = p (Substitution Spine Traversal)SHsubDiffNil[u/x]U· = ·SHsubDiffCons[u/x]Up = p′ [u/x]Uu2 = u3[u/x]Upu2 = p′ u3[u/x]Uxp = u′ : U′ (Static Neutral Substitution)SHsubRHead[u/x]Ux· = u : USHsubRSpine[u1/x]Ux p = (𝜆y.u′1) : (y : U′1)→ U′2 [u1/x]Uu2 = u3[u3/y]U′1u′1 = u′2 [u3/y]U′1U′2 = U′3[u1/x]Ux pu2 = u′2 : U′3Figure 3.6: sdtl: Hereditary Substitution73our multiset order.3.3.5 Properties of sdtlSince sdtl is mostly standard, it enjoys the standard properties of dependentlytyped languages. Subject reduction is easily proved, and the termination of hered-itary substitutionmeans that the language is strongly normalizing, and hence log-ically consistent. Since the type rules, hereditary substitution, and normalizationare syntax-directed and terminating, type checking is decidable. Finally, becauseall well typed terms have normal forms, sdtl is type safe.3.4 gdtl: Abstracting the Static LanguageWe now present gdtl, a gradual counterpart to sdtl derived by extending theagt methodology [67] to the seing of dependent types. e key idea behindagt is that gradual type systems can be designed by rst specifying the meaningof gradual types in terms of sets of static types. is meaning is given as a con-cretization function 𝛾 that maps a gradual type to the set of static types that itrepresents, and an abstraction function 𝛼 that recovers the most precise gradualtype that represents a given set of static types. Formally, 𝛾 and 𝛼 form a Galoisconnection, an important concept from abstract interpretation (hence the nameAbstracting Gradual Typing). is property lets the gradual guarantee be easilyproven. We explain more in Section 3.4.4.Once the meaning of gradual types is speci ed using 𝛾 and 𝛼 , the typing rulesand dynamic semantics for the gradual language can be derived systematically.First, 𝛾 and 𝛼 let us li the type predicates and type functions used in the statictype system (such as equality, subtyping, join, etc.) to obtain their gradual coun-terparts. From these de nitions, algorithmic characterizations can then be val-idated and implemented. Second, the gradual type system is obtained from thestatic type system by using these li ed type predicates and functions. Finally,the run-time semantics are de ned by proof reduction of the typing derivation,mirroring the type safety argument at run time.In gdtl, typing derivations are augmented with pieces of evidence for consis-74tent judgments, whose combination during reduction may be undened, henceresulting in a run-time error. is ascription is evidence for plausible equality(consistency) in the agt sense (Section 2.1.3.3), but our use of bidirectional typingfor normal forms means we need only ascribe neutral terms. Also, because theevidence is a dependent type, we can perform hereditary substitution on it likeany other term. Normally evidence is not present for compile-time type check-ing, but here it is needed because dependent type checking normalizes types, andgradual typing means those normalizations can fail.In this chapter we follow the agt methodology, specifying 𝛾 and 𝛼 , then de-scribing how the typing rules are li ed to gradual types. We uncover severalpoints for which the standard agt approach lacks the exibility to accommodatefull-spectrum dependent types with ? as a term. We describe our extensions to(and deviations from) the agt methodology, and how they let us fully supportgradual dependent types.roughout this section, we refer to not-yet-de ned gradual versions of hered-itary substitution and normalization. We leave the detailed development of thesenotions to Section 3.5, as they are non-trivial if one wants to preserve both decid-able type checking and the gradual guarantees. e dynamic semantics of gdtlare presented in Section 3.6, and its metatheory in Section 3.7.3.4.1 Terms and Normal Formse syntax of the gdtl surface language (Fig. 3.7) is an extension of sdtl’s syntax.We use green, italic serif font for metavariables denoting gradual surface terms. Inaddition to constructs from sdtl, gdtl’s syntax includes ?, the unknown term/-type, which represents a type or term that is unknown to the programmer. Byannotating a term with type ? or leaving a term as ?, they can let their programtype check with only partial typing information or an incomplete proof.e syntax for normal forms in gdtl is similar to sdtl, but has some technicalsubtleties, since we use normal forms to de ne abstraction, concretization, andhereditary substitution. As with terms, ? is now a valid normal form. Neutralnormals are ascribed with evidence, a type that is more precise than both the typeof the neutral and the type at which it is used, which witnesses the consistency of75t, T F 𝜆x . t | t1 t2 | x | Typeℓ| (x : T1)→ T2 | t :: T | ? (Gradual Terms)Gnf 3 u, U F ? | Typeℓ | 𝜆x .u| 〈N 〉N | 〈Typeℓ〉N| 〈?〉N | (x : U1) ℓ−→ U2 (Gradual Normal Forms)Gne 3 N F xp (Gradual Neutral Forms)p F · | p u (Gradual Normal Spines)Figure 3.7: gdtl: Terms and Normal Formsthose two types. We formalize precision in Section 3.4.2, but for now, it suces tothink of a term being less precise than another if some number of ? occurrencesin the rst can be replaced to obtain the second. Since 𝜂-longness ensures thatneutrals do not have function types, this evidence is either neutral, Typeℓ , or thecompletely unknown ?. Function types are annotated with a level ℓ . e type(x : u1)ℓ−→ u2 is well-formed at type Typeℓ . Additionally, arrows may be annotatedwith the special maximum level 𝜔 where (x : u1)𝜔−→ u2 is well-formed at type ?,which is used in places where ?makes it impossible to determine amaximum levelfor a function type. ese annotations are necessary to ensure the terminationof hereditary substitution, but are inferred during normalization, and are neverpresent in source programs. We o en omit these annotations, as they clu er thepresentation.Normal forms do not contain ascriptions. ough statically typed languagesuse ascriptions only to guide type checking, the potential for dynamic type fail-ure means that ascriptions have computational content in gradual typing. No-tably, only variables or neutral applications can synthesize ? as a type, though anytyped expression can be checked against ?. Omi ing ascriptions gives us a formof canonicity: the type of a normal form conveys what possible forms it can take.For example, we can layer ascriptions on top of terms, such as (true :: ?) :: ?→ ?,but the only normal forms with function types are lambdas and ?.763.4.2 Concretization and Predicatese main idea of agt is that gradual types abstract sets of static types, and thateach gradual type can be made concrete as a set of static types given by a con-cretization function 𝛾 . For dependent types, we extend this to say that gradualterms represent sets of static terms. In a simply-typed language, a static type em-bedded in the gradual language concretizes to the singleton set containing itself.However, for terms, we wish to consider the entire 𝛼𝛽𝜂-equivalence class of thestatic term. As with type checking, this process is facilitated by considering onlynormal forms. e gdtl concretization function 𝛾 : Gnf→P(Snf)\ ∅, de ned inFig. 3.8, de nes a non-empty set of static normal forms for each gradual term. Itrecurs over sub-terms, with ?mapping to Snf, the set of all static normal forms (asde ned in Fig. 3.2). It is de ned mutually with 𝛾𝑁 , which maps the set of gradualneutrals to sets of static neutrals from Sne.Given the concretization, we can li a predicate from the static system to thegradual system. A predicate holds for a gradual type if it holds for some type in itsconcretization. e gradual li ing of equality is consistency, U  U ′, which holdsif and only if 𝛾 (U )∩𝛾 (U ′) ≠ ∅. Figure 3.8 gives an equivalent syntactic de nition.Concretization also gives us a notion of precision on gradual types. We say thatU v U ′ if 𝛾 (U ) ⊆ 𝛾 (U ′): that is, U is more precise because its concretization hasfewer terms it could plausibly represent. We can similarly de ne the compositionof two types U uU ′ as the most general term that is as precise as both U and U ′.In this chapter, U uU ′ is de ned if and only if U  U ′ i.e. if 𝛾 (U )∩𝛾 (U ′) ≠ ∅,and like the consistency relation, it can be computed syntactically. In Chapter 5,we de ne a way of composing types that does not have this property, but be erre ects the dynamic behaviour of terms.3.4.3 Functions and AbstractionConcretization is not enough to de ne all typing rules, since some rules match onthe syntactic forms of their inputs. For example, when type checking a functionapplication, we must handle the case where the function has type ?. Recall thestatic rule SSynthApp, which had a premise that the applied function synthesizedan arrow type. Since ? is not an arrow type, the static rule would fail in all such77𝛾 : Gnf→P(Snf) \ ∅𝛾𝑁 : Gne→P(Sne) \ ∅𝛾 (?) = Snf𝛾 (Typeℓ ) = {Typeℓ }𝛾 (𝜆x .u) = {𝜆x.u′ | u′ ∈ 𝛾 (u)}𝛾 ((x : U1)ℓ−→ U2) = {(x : U′1)→ U′2 | U′1 ∈ 𝛾 (U1),U′2 ∈ 𝛾 (U2)}𝛾 (〈Typeℓ〉N ) = {〈Typeℓ〉N | N ∈ 𝛾𝑁 (N )}𝛾 (〈?〉N ) = {〈u〉N | u ∈ {Typeℓ | ℓ ∈ N} ∪Sne,N ∈ 𝛾𝑁 (N )}𝛾 (〈N ′〉N ) = {〈N′〉N | N′ ∈ 𝛾𝑁 (N ′),N ∈ 𝛾𝑁 (N )}𝛾𝑁 (x) = {x}𝛾𝑁 (x pu) = {x p′u′ | x p′ ∈ 𝛾𝑁 (xp),u′ ∈ 𝛾 (u)}u  u′ N 𝑁 N ′ (Consistency of Gradual Normal and Neutral Forms)ConsistentEqu  uConsistentPiU1  U ′1 U2  U′2(x : U1)→ U2  (x : U ′1 )→ U ′2ConsistentLamu  u′𝜆x .u  𝜆x .u′ConsistentDynL?  uConsistentDynRu  ?ConsistentNeutU1  U2 N1 𝑁 N2〈U1〉N1  〈U2〉N2ConsistentNeutNeutL〈?〉N ′  U N1  N2〈N ′〉N1  〈U 〉N2ConsistentNeutNeutR〈?〉N ′  U N1 𝑁 N2〈U 〉N1  〈N ′〉N2ConsistentVarx 𝑁 xConsistentAppx p 𝑁 x p′ u  u′x pu 𝑁 x p′u′Figure 3.8: gdtl: Concretization and Consistency78cases. Instead, we extract the domain and codomain from the type using partialfunctions. Statically, dom (x : U )→ U ′ = U , and is undened otherwise. But whatshould the domain of ? be?agt gives a recipe for li ing such partial functions to gradual types using thecounterpart to concretization: abstraction. e abstraction function 𝛼 is de nedin Fig. 3.9. It takes a set of static terms, and nds the most precise gradual termthat is consistent with the entire set.With concretization and abstraction, we are able to take gradual terms to setsof static terms, perform operations on those sets, then transform the result setback into a gradual term. We can then de ne gradual partial functions in termsof their static counterparts: we concretize the inputs, apply the static functionelement-wise on all values of the concretization for which the function is de ned,then abstract the output to obtain a gradual term as a result.We use concretization and abstraction to de ne partial functions to decom-pose types and terms. For example, the domain of a gradual term U is:𝛼({dom U′ | U′ ∈ 𝛾 (U )}),which can be expressed algorithmically using the rules in Fig. 3.9. We de nefunction-type codomains and lambda-term bodies similarly, though we pair theseoperations with substitution because a er extracting the codomain from a func-tion type or the body of a lambda, we typically want to substitute some term in, forexample, when checking or normalizing an application. us, we avoid creatinga “dummy” bound variable name for ?.3.4.4 Soundness and OptimalityTaken together, 𝛼 and 𝛾 form a Galois connection, meaning it is sound and opti-mal. Soundness ensures that 𝛼 does not spuriously add information: for any set𝑆 , 𝛼𝑆 represents at least as many types as 𝑆 . Optimality expresses that 𝛼 does notlose precision unnecessarily: of the gradual types available, it chooses the mostprecise one that denotes the given set.eorem 3.4.1 (Soundness). For all ∅ * 𝑆 ⊆ Snf, 𝑆 ⊆ 𝛾 (𝛼(𝑆)).79𝛼 : P(Snf) \ ∅ → Gnf𝛼𝑁 : P(Sne) \ ∅⇀ Gne𝛼({(x : U1)→ U2 | U1 ∈ 𝐴,U2 ∈ 𝐵}) = (x : U ′1 )→ U ′2 where 𝛼(𝐴) = U ′1 , 𝛼(𝐵) = U ′2𝛼({𝜆x.u | u ∈ 𝐴}) = 𝜆x .u′ where 𝛼(𝐴) = u′𝛼({Typeℓ }) = Typeℓ𝛼{〈yp′〉xp | p′ ∈ {𝐴},p ∈ {𝐵}} = 〈yp′〉xp where 𝛼𝑁 ({yp′ | p′ ∈ 𝐴}) = yp′,𝛼𝑁 ({xp | p ∈ 𝐵}) = xp𝛼{〈Typeℓ〉xp | p ∈ {𝐴}} = 〈Typeℓ〉xp where 𝛼𝑁 ({xp | p ∈ 𝐴}) = xp𝛼{〈u〉xp | p ∈ {𝐴}} = 〈?〉𝛼𝑁 (𝑆) otherwisewhere 𝑆 = {xp | p ∈ 𝐴}𝛼(𝐴) = ? otherwise𝛼𝑁 ({x}) = x𝛼𝑁 ({xp u | xp ∈ 𝐴,u ∈ 𝐵}) = x p′u′ where 𝛼(𝐴) = x p′, 𝛼(𝐵) = u′dom : Gnf⇀ Gnf (Gradual Domain)DomainPidom (x : U1)→ U2 = U1DomainDyndom ? = ? undened otherwise[/ ] cod : Gnf3 ⇀ Gnf (Gradual Codomain Substitution)CodSubPi[u/x]U1U2 = U ′2[u/ ]cod (x : U1)→ U2 = U ′2CodSubDyn[u/ ]cod ? = ? unde ned otherwise(Gradual Function Body Substitution)BodySubPi[u/x]Uu2 = u′2[u/ ]Ubody 𝜆x .u2 = u′2BodySubDyn[u/ ]Ubody ? = ? unde ned otherwiseFigure 3.9: gdtl: Abstraction and Li ed Functions80See proof in Appendix A .eorem 3.4.2 (Optimality). For ∅ * 𝑆 ⊆ Snf and U ∈ Gnf, if 𝑆 ⊆ 𝛾 (U ) then𝛼(𝑆) v U. at is, 𝛾 (𝛼(𝑆)) ⊆ 𝛾 (U ).See proof in Appendix A .3.4.5 Typing RulesGiven concretization and abstraction, agt gives a recipe to convert a static typesystem into a gradual one, and we follow it closely. Figure 3.10 gives the rulesfor typing. Equalities implied by repeated metavariables have been replaced byconsistency checks, such as in GCheckSynth. Similarly, in GCheckPi we usethe judgment U  Type to ensure that the given type is consistent to, rather thanequal to, some Typeℓ when ℓ is unknown. Rules that matched on the form ofa synthesized type instead use partial functions, as we can see in GSynthApp.We split the checking of functions into GCheckLamPi and GCCheckLamDyn forclarity, but the rules are equivalent to a single rule using a partial function.e last thing we must decide is how to type the unknown term ?. We wishto let ? replace any term in a program. But what should its type be? By the agtphilosophy, ? represents all terms, so it should synthesize the abstraction of allinhabited types, which is ?. We encode this in the rule GSynthDyn. So we canuse the unknown term in any context.e consistency relation used in the gdtl typing rules corresponds to thegradual li ing of de nitional equality: u1  u2 if and only if some u′1 ∈ 𝛾 (u1) andu′2 ∈ 𝛾 (u2) where u′1 =𝛼𝛽𝜂 u′2. Because 𝛾 (x ) = {x} for any variable 𝑥 , consistency,precision and meet are all well-de ned on open terms, and two variables are con-sistent if and only if they are equal. is correspondence re ects our intensionalapproach: functions are compared according to their bodies, rather than their ex-tensional behaviour. Chapter 5 explains the problems this intensional approachraises for run-time checks, but it is su cient for the foundational calculus of thischapter. ough 𝛾 and 𝛼 are crucial for deriving the de nitions of gradual opera-tions, the operations can be implemented algorithmically as syntactic checks: animplementation does not need to compute 𝛾 or 𝛼 .81Γ ` t ⇒ U (Gradual Synthesis)GSynthDynΓ ` ?⇒ ?GSynthAnnΓ ` U {T : Type Γ ` t ⇐ UΓ ` (t :: T )⇒ UGSynthTypeℓ > 0Γ ` Typeℓ ⇒ Typeℓ+1GSynthVar(x : U ) ∈ ΓΓ ` x ⇒ UGSynthAppΓ ` t1 ⇒ U Γ ` u {t2 ⇐ dom U [u/ ]cod U = U2Γ ` t1 t2 ⇒ U2Γ ` t ⇐ U (Gradual Checking)GCheckSynthΓ ` t ⇒ U ′U ′  UΓ ` t ⇐ UGCheckLamPi(x : U1)Γ ` t ⇐ U2Γ ` 𝜆x . t ⇐ (x : U1)→ U2GCheckLamUnk(x : ?)Γ ` t ⇐ ?Γ ` 𝜆x . t ⇐ ?GCheckPiΓ ` U  Typeℓ Γ ` U ′ {T1 ⇐ U (x : U ′)Γ ` T2 ⇐ UΓ ` (x : T1)→ T2 ⇐ UFigure 3.10: gdtl: Type Checking and SynthesisAs with the static system, we represent types in normal form, which makesconsistency checking easy. Well-formedness rules (Fig. 3.11) are derived fromthe static system in the same way as the gradual type rules. e changes areGWFUnk, which lets ? check against any type as a normal form, and GWFNeutreplacing SWFNeut and SWFNeutType, which lets a neutral be used as a normalform so long as it is tagged with valid evidence that its type is consistent withthe target type. is evidence is some normal-form type that is as precise as thetwo consistent types. We also allow edvidence to be neutral: neutrals are embed-ded into normal forms by tagging them with evidence, so allowing non-normalneutral evidence means that we avoid stacks of evidence-within-evidence. Evi-dence tracking is necessary for safe normalization of gradual terms. We explaincompile-time evidence more, along with the full gradual normalization judgmentsΓ ` t { u⇒ U and Γ ` u {t ⇐ U , in Section 3.5.3.82𝜀 F U | N (Compile-time evidence)Γ ` u ⇒ U (Gradual Well Formed Neutrals)GWFVar(x : U ) ∈ ΓΓ ` x ⇒ UGWFAppΓ ` xp⇒ (y : U1)→ U2Γ ` u⇐ U1 [u/y]U1U2 = U3Γ ` x pu ⇒ U3Γ ` u⇐ U (Gradual Well Formed Normals)GWFUnkΓ ` U : TypeΓ ` ?⇐ UGWFNeutΓ ` N ⇒ U ′ 𝜀 ` U  U ′Γ ` 〈𝜀〉N ⇐ UGWFLam(x : U1)Γ ` u ⇐ U2Γ ` 𝜆x .u⇐ (x : U1)→ U2GWFLamUnk(x : ?)Γ ` u⇐ ?Γ ` 𝜆x .u⇐ ?GWFPiΓ ` U1 ⇐ Typeℓ(x : U1)Γ ` U2 ⇐ TypeℓΓ ` (x : U1) ℓ−→ U2 ⇐ TypeℓGWFPiUnkΓ ` U1 ⇐ ?(x : U1) ` U2 ⇐ ?Γ ` (x : U1) 𝜔−→ U2 ⇐ ?GWFTypeΓ ` Typeℓ ⇐ Typeℓ+1GWFTypeUnkΓ ` Typeℓ ⇐ ?𝜀 ` U  U ′ (Gradual Well Formed Compile-time Evidence)GEvNormU ′′ v U U ′′ v U ′Γ ` U ′′ ` U  U ′GEvNeutNeutN ′′ v N N ′′ v N ′Γ ` N ′′ ` 〈Typeℓ〉N  〈Typeℓ〉N ′GEvNeutLN ′′ v NΓ ` N ′′ ` 〈Typeℓ〉N  ?GEvNeutRN ′′ v NΓ ` N ′′ ` ?  〈Typeℓ〉NGEvNeutUnkΓ ` N ′′ ` ?  ?Figure 3.11: gdtl: Well-Formedness Rules833.4.6 Example: Type checking the head of an empty vectorTo illustrate how the gdtl type system works, we explain the type checking ofone example from the introduction. Suppose we have postulated types for naturalnumbers and vectors, and a derivation for:Γ ` head ⇒ (A : Type0)→ (n : Nat)→ Vec A (n+1)→ A.In Fig. 3.12, we show the (partial) derivation of:Γ ` head Nat 0 (Nil :: Vec Nat ?)⇒ Nate key detail here is that the compile-time consistency check lets us compare0 to ?, and then ? to 1, which lets the example type check. Notice how we onlycheck consistency when we switch from checking to synthesis. ough this codetype checks, it fails at run time. Once we have de ned semantics for gdtl, weexplain the execution of this term in Section 3.6.4.84...Γ ` headNat 0⇒VecNat 1→NatGSynthAnnGCheckSynth...Γ ` Nil⇒ VecNat 0...VecNat 0  VecNat ?Γ ` Nil⇐ VecNat ? ...Γ ` Nil::VecNat ?⇒VecNat ?...VecNat ?VecNat 1Γ ` Nil::VecNat ?⇐ VecNat 1 GCheckSynthΓ ` headNat 0(Nil::VecNat ?)⇒ Nat GSynthAppFigure 3.12: Type Derivation for head of nil853.5 Approximate NormalizationNot all type checking computations are simple substitutions like we saw in theprevious example. As we saw in Section 3.2.3, the type-term overlap in gdtlmeans that code that is run during type checking may fail or diverge. But what isthe meaning of such errors inside of a type?One option is to declare types ill-formed if they contain imprecisely typedterms. However, this approach breaks the criteria for a gradually typed language,since dependent functions could never take imprecise terms as arguments. Inparticular, it would result in a language that violates the static gradual guarantee(Section 3.2.4). e static guarantee implies that if a program does not type check,the programmer knows that the problem is not the absence of type precision, butthat the types present are fundamentally wrong. Increasing precision in multipleplaces never causes a program to type check if doing so in one place fails.is section gives the de nitions of normalization and substitution that weremissing from the previous chapter. We describe approximate hereditary substitu-tion, which regains decidability while preserving the gradual guarantee, by pro-ducing compile-time normal forms that are potentially less precise than their run-time counterparts. us, we trade precision for a termination guarantee.Approximate substitution is used to build approximate normalization. In ad-dition to avoiding non-termination, approximate normalization handles dynamictype failures by tracking type information of neutrals. A key insight of this chap-ter is that we need separate notions of compile-time normalization and run-timeexecution. at is, we use approximate normalization only in our types. Executingour programs at run time does not lose information, but may diverge or fail.For type checking, the e ect of approximate normalization is that non-equalterms of the unknown type may be indistinguishable at compile time. Returningto the example from Section 3.2.3, the user’s faulty factorial-length vector typechecks, but at type Vec Nat ?. Using it never raises a static error due to its length,but it may raise a run-time error. e failList example from Section 3.2.3 raises atype error, but failFun only raises a type error when called on an invalid input.863.5.1 Dierences from the Published VersionIn this section, we present a novel notion of compile-time evidence for gdtl. eprevious version of this work [58] erroneously claimed that its version of gdtlsatis ed the static gradual guarantee, but previous approach of normalizing errorsto ? was awed. We develop compile-time evidence as a way to handle errorswithout producing ? as the result of dynamic errors in types.e published version of this work contained a notion that this chapter lacks:ideal substitution, which was de ned in terms of equivalence classes of the con-cretization of gradual terms. Ideal substitution provided theoretical justi cationfor the de nition of approximate substitution. Because that version approximatedtype errors to ?, the ideal normal form of a term was always as precise as the ap-proximate normal form. However, error approximation meant that said versionof gdtl did not satisfy the static gradual guarantee, a mistake not caught untila er publication.To handle errors in this chapter, we use a system of compile-time evidencethat ensures we satisfy the static guarantee. Such a version does not approximateideal substitution, because there are cases where a term could execute safely butraises an error. For example, 𝜆(x : Typeℓ ).x can be safely applied to any term, de-spite the type ascription, so its 𝛼𝛽𝜂-equivalence class is unrestricted. However,its approximate normalization ascribes the argument with evidence that preventsit from being in contexts incompatible with Typeℓ . We feel the loss of the rela-tionship to ideal substitution is justi ed by gaining the static gradual guarantees.3.5.2 Approximate SubstitutionWe now turn to the problem of how to recover decidable comparison for normalforms without losing the gradual guarantees. We again turn to (gradual) normalforms as representatives of 𝛼𝛽𝜂-equivalence classes. What happens when we tryto construct a hereditary substitution function syntactically, as in sdtl?3.5.2.1 Ensuring Terminatione issuewith gradualizing hereditary substitution is in adapting the rule SHsubR-Spine. Suppose we are substituting u for x in xp u2, and the result of substituting87in xp is 𝜆y.u′ : ?. Following the agt approach, we can use the dom function tocalculate the domain of ?, which is the type at which we substitute y. But sucha substitution violates the well-foundedness condition we imposed in the staticcase! e type ? contains zero arrow-types, so a recursive substitution that is alsoat type ? is not strictly smaller. Since the domain of ? is ?, eliminating redexesmay in nitely apply substitutions without decreasing the size of the type. eremaining cases have no termination issues, since the term we are substitutinginto is structurally decreasing.Hereditary substitution informs us as to the cases we must approximate topreserve decidability. To guarantee termination, we must not perform recursivesubstitutions in spines with ? typed heads. We are le with two options for howto proceed without making recursive calls: we either fail when we try to applya ? typed function, or we return ?. e former preserves termination, but it doesnot preserve the static gradual guarantee. Reducing the precision of a well typedprogram’s ascriptions should never yield ill typed code. If applying a dynami-cally typed function caused failure, then changing an ascription to ? could causea previously successful program to be ill-typed, violating the guarantee.Our solution is to produce ?when applying a function of type ?. We highlightthe changes to neutral hereditary substitution in Fig. 3.13. GHsubRDynType ac-counts for ? typed functions, and GHsubRDynSpine accounts for ? applied as afunction.We must give gradual hereditary substitution one more check to guaranteetermination, because ? : ? could be used to circumvent the universe hierarchy.For instance, we can assign (x : ?)→ (x Type99) the type Type0, and we can evenwrite a version of Girard’s paradox [38, 68] by using ? in place of Type .To avoid Girard’s paradox, normal form arrow types are ascribed with a level,and GHsubRLamSpine checks whether this value is decreasing according to ourmetric. We extend the natural number order with a maximum element 𝜔 , where𝑖 ≺ 𝜔 for every 𝑖 . e level 𝜔 denotes a function type of unknown level. enU ≺ U ′ when the multiset of annotations on arrow types in U is less than that ofU ′ by the well-founded multiset ordering given by Dershowitz and Manna [47].In the static case, the type of substitution is always decreasing for this metric.In the presence of ?, we must check if the order is violated and return ? if it is,88[u/x]U x p = u2 : U2 (Approximate Neutral Hereditary Substitution, Key Rules)GHsubRHead[u/x]Ux· = u : UGHsubRDynSpine[u/x]Uxp = ? : (y : U1)→ U2[u2/y]U1U2 = U3[u/x]Uxp u2 = ? : U3GHsubRDynType[u1/x]Uxp = u2 : ?[u1/x]Uxp u2 = ? : ?GHsubRLamSpine[u/x]Uxp = 𝜆y.u2 : (y : U1)→ U2[u/x]Uu1 = u3 U1 ≺ U[u3/y]U1u2 = u4 [u3/y]U1U2 = U3[u/x]Uxp u1 = u4 : U3GHsubRLamSpineOrd[u/x]Uxp = 𝜆y.u2 : (y : U1)→ U2U1 ⊀ U[u/x]Uxp u1 = ? : ?Figure 3.13: Approximate Neutral Substitution, Key Rulesas seen in the rule GHsubRLamSpineOrd. Unlike applying a function of type ?,we believe that this case is unlikely to arise in practice unless programmers aredeliberately using ? to circumvent the universe hierarchy.3.5.2.2 Handling Type ImprecisionOn top of substituting in neutral forms, hereditary substitution must handle termand type imprecision in normal forms, which we do in Fig. 3.14. For term impreci-sion, substituting in ? produces ? (GHsubUnk). For type imprecision, because ofthe normal typing rule GWFCheckSynth, hereditary substitution must accountfor how the actual type of an evidence-ascribed neutral term may dier from thetype at which it is used. Moreover, the result should incorporate a substitutedversion of the type information contained within the evidence. ese rules endup being a mess of cases, which is part of why we ultimately abandon hereditarysubstitution in later chapters.If a neutral term is ascribed neutral evidence, then the evidence head maybe the variable we are replacing. Rule GHSubNeutTySame handles this case bynding the substituted form of the evidence, substituting in the spine of the term,then 𝜂-expanding the term at the evidence type (Fig. 3.15). Since 𝜂-expansiontakes neutrals to normals, the result is ascribed evidence based on the given type.89[u/x]U u1 = u2 (Approximate Normal Hereditary Substitution, Key Rules)GHsubUnk[u/x ]U ? = ?GHsubNeutTySamex ≠ y [u/x ]Uxp′1 = U2 : U3U3  Type [u/x ]Up1 = p2yp2 {𝜂 u2 : U2[u/x ]U 〈xp′1〉yp1 = u2GHsubNeutTyDiffx ≠ y x ≠ z[u/x ]Up′1 = p′2[u/x ]Up1 = p2[u/x ]U 〈zp′1〉yp1 = zp′2GHsubNeutTypex ≠ y [u/x ]Up1 = p2[u/x ]U 〈Typeℓ〉yp1 = 〈Typeℓ〉yp2GHsubNeutUnkx ≠ y [u/x ]Up1 = p2[u/x ]U 〈?〉yp1 = 〈?〉yp2GHsubSpineUnk[u1/x ]Uxp = u2 : U ′′[u1/x ]U 〈?〉xp = u2GHsubSpineTypeType[u1/x ]Uxp = Typeℓ′ : U ′′ ℓ = ℓ ′+1[u1/x ]U 〈Typeℓ〉xp = Typeℓ′GHsubSpineTypeUnk[u1/x ]Uxp = ? : U ′′[u1/x ]U 〈Typeℓ〉xp = ?GHsubSpineTypePi[u1/x ]Uxp = (x : U1)→ U2 : U ′′[u1/x ]U 〈Typeℓ〉xp = (x : U1)→ U2GHsubSpineTypeNeut[u1/x ]Uxp = 〈𝜀〉N : U ′′ U ′′  Typeℓ[u1/x ]U 〈Typeℓ〉xp = 〈Typeℓ u 𝜀〉NGHsubSpineNeutUnk[u1/x ]Uxp = ? : U ′′[u1/x ]U 〈N 〉xp = ?GHsubSpineNeutNeut[u1/x ]Uxp′1 = p′3 [u1/x ]Uxp1 = 〈𝜀〉zp2 : U2x ≠ y z ≠ y[u1/x ]U 〈yp′1〉xp1 = 〈yp′3u 𝜀〉zp2Figure 3.14: gdtl: Approximate Normal Substitution90By expanding at the type given by the substituted evidence, its type information isretained in the ascriptions on the result, while still accounting for the fact that thenew type may be a function type. If the head is a dierent variable, we substitutein both spines (GHsubNeutTyDiff), and if the evidence is not neutral, then wesubstitute in the spine of the neutral term (GHsubNeutType,GHsubNeutUnk).e nal case to handle is when replacing x in an evidence-ascribed neutralwhose head is x . Since the result may not be neutral, we cannot simply tackon a substituted version of the old evidence. However, we take advantage of animportant fact about the typing of normals in gdtl: only neutral terms and ? canhave neutral types. We handle the cases separately:• If a neutral has evidence ?, then the evidence carries no information, andwe can disregard it (GHsubSpineUnk)• If a neutral has evidence Typeℓ , then the result must be a type. If it is ?,a universe, or a function type, then we need not propagate the evidence(GHsubSpineTypeType, GHsubSpineTypePi). If the result is neutral, thenwe use composition to ensure that the evidence on that neutral is consistentwith Typeℓ (GhsubSpineTypeNeut).• If a neutral term has neutral evidence with head y, then it must synthesizeeither ? or another neutral with head y. Predicativity ensures that y cannotbe equal to x, so replacing x in the evidence produces another y-headed neu-tral. If the result of substituting on the neutral term is ?, then the nal resultis ?, and we need not propagate evidence (GHsubSpineNeutUnk). Other-wise, substituting produces a non-? term, whose type needs to be consistentwith y-headed neutral evidence, meaning that the substitution should failunless the result is neutral. When the result is neutral, we compute newy-headed evidence by substituting, and compose with the evidence on theresult of substituting in the neutral term (GHsubSpineNeutNeut). So weproduce a neutral that re ects the type information of the substituted initialevidence.91N {𝜂 u : U (Gradual 𝜂-Expansion)GEtaNeutN {𝜂 〈N ′〉N : 〈Typeℓ〉N ′GEtaTypeN {𝜂 〈Typeℓ〉N : TypeℓGEtaUnkN {𝜂 〈?〉N : ?GEtaPiy{𝜂 u′ : U1 xp u′{𝜂 u : U2xp{𝜂 𝜆y.u : (y : U1)→ U2Figure 3.15: gdtl: 𝜂-expansion3.5.3 Normalization and Compile-Time EvidenceApproximate hereditary substitution eliminates non-termination, but we muststill account for dynamic failures when adapting the normalization relation ofsdtl (Fig. 3.4) to gdtl. We do this by augmenting neutral terms with evidence,and by introducing a partial casting meta-operation to convert a normal formfrom one type to another. We explain the theory behind evidence more in Sec-tion 3.6. e main idea is that, when a neutral synthesizes a type and is checkedat a consistent type, that consistency implies that there exists some type as pre-cise as both the synthesized and checked-against types. We a ach one such typeto a neutral term, to represent all the collected run-time type information aboutthe neutral, and whenever that neutral is used at a di erent type, we composethe evidence with the new type, so that it monotonically evolves. is monotonicevolution is central to the simplicity of the agt approach to proving the gradualguarantees.e possibility for errors arises at the boundary between checking and syn-thesis, i.e. the normalization analogue of SCheckSynth. e critical propertyof normalization, around which we design the relation, is type preservation: ifΓ ` u {t ⇐ U , then we should have both Γ ` t ⇐ U and Γ ` u ⇐ U . For thechecking-synthesis boundary, if Γ ` t{ u′⇒ U ′, and Γ ` U ′  U , then normaliz-ing t while checking against U should produce a term u such that Γ ` u⇐ U . edi culty is that normalization does not preserve type synthesis, only type check-92ing. For example, applications always synthesize, but if the applied expression is a𝜆-term, then the result could normalize to another 𝜆-term, which does not synthe-size a type. Likewise, t could be some ascribed term t ′ :: T , where t ′ synthesizesa type consistent with T but not with U , since consistency is not transitive. Sou′ is not guaranteed to check against type U , since we cannot necessarily applyGWFCheckSynth.Because of dynamic type errors during normalization, not all well typed termsare guaranteed to have a normal form. For gdtl, this design choice has the unfor-tunate eect that, when typing an application t0 t1, if t1 contains a run-time typeerror then the application does not type check. To type t0 t1, the rule GSynthAppnormalizes t1 to substitute into the return type. For example, if tyId is de nedas 𝜆x .x : Type0 → Type0, then tyId (Type99 :: ? :: Type0) is ill typed, even thoughType99 :: ? :: Type0 is well typed, because it does not have a normal form.By tagging neutrals with evidence, we are able to normalize terms with vari-ables without necessarily raising an error, even if some values for those variablesthat would raise an error. When variables are replaced with concrete terms, thetype information is checked against the type information in the term. For ex-ample, 𝜆(x : ?). tyId(x :: Type0) is well typed, even though x :: Type0 might fail forsome inputs. e key is that x normalizes to 〈?〉x at type ?. To normalize to a resultof type Type0, the evidence is updated to produce 〈Type0〉x, which checks againstType0 because it synthesizes the consistent type ?. So until a concrete value forx is given, no error is raised. e variable x has a normal form at type Type0 thatcaptures the known type information without needing to ensure that all possiblex values match Type0. If, for example, Type99 is supplied for x , the hereditarysubstitution GHsubSpineTypeType rule can not be applied because 0 ≠ 99+1. Inlater chapters, we can further defer errors by treating casts and composition asoperations in the language, rather than meta-operations. Eremondi et al. [58] in-correctly claimed that allowing dynamic type errors during normalization wouldprevent t0 t1 from being well typed if t1 encountered an error for any possiblevalues of its free variables. However, the incarnation of gdtl presented in thisdissertation does not su er from this issue. For example, if t1 is 1+ (true :: N),then t0 t1 will not type check, but if t is 1+x, it does type check, even thoughthere are values for x which would cause failure (namely true :: N).933.5.3.1 The Top Level Judgment: Approximate Normalizatione de nition of approximate normalization is given in Fig. 3.16, de ned in termsof casting and composition operationswhose de nitionwe leave for Section 3.5.3.2.e context and term are inputs, with the normal form as an output. e typeis an output for synthesis rules, but an input for the checking rules. e rulesprimarily mirror the static rules, with a few major departures. Initial evidencefor variables is generated during 𝜂-expansion (Fig. 3.15) in GNormSynthVar.GNormCheckSynth normalizes a term checking against U by nding the syn-thesizing normal form for that term, and then casting the result to type U . ecast uses identical contexts to start, but functions or function types may causethese to di er during casting. Rule GNCheckPiUnk and CNCheckLamDyn mir-ror GCheckPiUnk and GCheckLamDyn: since functions and function types arechecking forms, they cannot check against ? with GNSynthCheck, so they needspecial rules to check against ?.e possibility of ? being applied as a function is handled in GNSynthApp:instead of matching on the normal form of the function and checking if it is alambda, the body metafunction (Fig. 3.9), de ned in terms of abstraction 𝛼 , pro-duces ? if the applied function is ?, and uses hereditary substitution to reduce thefunction application otherwise.Normalization is also where we generate the annotations necessary to en-sure the decreasing metric of hereditary substitution. As we see in the rulesGNCheckPiType and GNCheckPiUnk, we annotate arrows either with the levelagainst which they are checked, or with 𝜔 when checking against ?. e remain-ing rules for normalization directly mirror the rules from Fig. 3.10. Typei, ?, andvariables all normalize to themselves, and all other rules construct normal formsfrom the normal forms of their subterms.3.5.3.2 Casting and CompositionFigures 3.17 to 3.19 de ne the key relation for handling type imprecision duringnormalization: a casting meta-operation Γ1 |Γ2 ` 〈U2 ⇐ U1〉u1 { u2, which takesas input two contexts Γ1 and Γ2, two types U1 and U2, and a term u1 such thatΓ1 ` u1 ⇐ U1, and (if successful) outputs a term such that Γ2 ` u2 ⇐ U2. e two94Γ ` t { u ⇒ U (Approximate Normalization Synthesis)GNSynthAnnΓ ` U {T : Type⇒iΓ ` u {t ⇐ UΓ ` (t :: T ){ u⇒ UGNSynthAppΓ ` t1 { u1 ⇒ U dom U = U1Γ ` u2 {t2 ⇐ U1 [u2/ ]cod U = U2[u2/ ]U1body u′1 = u3Γ ` t1 t2 { u′3 ⇒ U2GNSynthTypei > 0Γ ` Typei { Typei ⇒ Typei+1GNSynthVar(x : U ) ∈ Γx {𝜂 u : UΓ ` x { u⇒ UGNSynthDynΓ ` ?{ ?⇒ ?Γ ` u {t ⇐ U (Approximate Normalization Checking)GNCheckSynthΓ ` t { u′⇒ U ′U  U ′Γ |Γ ` 〈U ⇐ U ′〉u′{ uΓ ` u {t ⇐ UGNCheckPiTypeΓ ` U1 {T1 ⇐ Typei` (x : U1)Γ(x : U1)Γ ` U2 {T2 ⇐ TypeiΓ ` (x : U1) i−→U2 {(x : T1)→ T2 ⇐ TypeiGNCheckPiUnkΓ ` U1 {T1 ⇐ ? (x : U1)Γ ` U2 {T2 ⇐ ?Γ ` (x : U1) 𝜔−→U2 {(x : T1)→ T2 ⇐ ?GNCheckLamPi` (x : U1)Γ (x : U1)Γ ` u {t ⇐ U2Γ ` 𝜆x .u {𝜆x . t ⇐ (x : U1)→ U2GNCheckLamDyn` (x : ?)Γ (x : ?)Γ ` u {t ⇐ ?Γ ` 𝜆x .u {𝜆x . t ⇐ ?Figure 3.16: gdtl: Approximate Normalization95contexts are necessary because when a cast changes the domain of a dependentfunction type, it changes the context in which the result codomain is typed. Weemphasize that casting is not a gdtl operation, but a relation between gdtl terms,which is in contrast to later chapters, in which we use cast calculi to dene seman-tics for gradual languages. ough agt is typically able to avoid casting by usingevidence, the dependence of types on terms and the possibility of free variablesin types means that we need a casting operation to ensure that evidence ascribedto terms is itself well typed.To support the combination of di erent evidence, we use the compositionoperator (Fig. 3.20), which computes the precision meet of two terms. at is, ityields the most general term that is as precise as both inputs. Here compositionis a metafunction, but in Chapter 5 we see a version of the meet that is built intothe gradual language itself.e main idea behind casting is to propagate type constraints deeper intoterms until we hit a neutral term, at which point we can incorporate the newtype into the evidence stored at that term. Neutrals are retyped with an auxiliaryrelation Γ1 |Γ2 ` (N1 : U1){ (N2 : U2), which takes a neutral that is typed under Γ1and casts terms in its spine to be well typed under Γ2. Along with the producedneutral term, the types of both input and output neutrals are outputs, since theycan be determined by synthesis. In MCastNeutToNeut, this relation is used tocreate a well typed version of the neutral and its evidence under the new context.Finally, the result neutral is produced, with evidence formed by composing the(retyped) original evidence, the type that the result neutral synthesizes, and thetype to which it is being cast. Composing with the retyped version of the oldevidence makes it easy to establish that the monotonicity of casting follows fromthe monotonicity of composing. is in turn simpli es the proof of the staticgradual guarantee. Most rules work similarly, or are simpler. For example, inrules MCastNeutFromUnkToUnk and MCastNeutEvTypeUnk, the evidenceon the neutral is either ? or Typeℓ , avoiding the need for composition.e remaining cases primarily propagate casts. MCastUnk casts ? to itself atany type. e function type and function casting rules require having separatecontexts for the input and output. In MCastType, casting Typeℓ to type Typeℓ+1produces Typeℓ . e rule MCastPi pushes a cast from Typeℓ to Typeℓ deeper96Γ1 |Γ2 ` 〈U2 ⇐ U1〉u1 { u2 (Meta-level Casting of Normal Forms)MCastUnkΓ |Γ′ ` 〈U2 ⇐ U1〉?{ ?MCastNeutToNeutΓ |Γ′ ` (Nval : 〈Typeℓ〉Nsynth){ (N ′val : 〈Typeℓ〉N ′synth)Nev ` U  〈Typeℓ〉Nsynth Γ |Γ′ ` (Nev : U ){ (N ′ev : U ′)Γ |Γ′ ` 〈〈Typeℓ〉N ′chk ⇐ U 〉〈Nev〉Nval { 〈N ′chk uN ′ev uN ′synth〉N ′valMCastNeutFromUnkToUnkΓ |Γ′ ` (N : ?){ (N ′ : ?)Γ |Γ′ ` 〈?⇐ ?〉〈?〉N { 〈?〉N ′MCastNeutEvTypeΓ |Γ′ ` (N : U1){ (N ′ : U ′1 ) U ′  TypeℓΓ |Γ′ ` 〈U ′⇐ U 〉〈Typeℓ〉N { 〈Typeℓ〉N ′MCastTypeΓ |Γ′ ` 〈Typeℓ+1 ⇐ Typeℓ+1〉Typeℓ { TypeℓMCastPiΓ |Γ′ ` 〈Typeℓ ⇐ Typeℓ〉U1 { U ′1(x : U )Γ |(x : U ′1 )Γ′ ` 〈Typeℓ ⇐ Typeℓ〉U2 { U ′2Γ |Γ′ ` 〈Typeℓ ⇐ Typeℓ〉(x : U1)→ U2 { (x : U ′1 )→ U ′2MCastLam(x : U1)Γ |(x : U ′1 ) ` 〈U ′2 ⇐ U2〉u{ u′Γ ` 〈(x : U ′1 )→ U ′2 ⇐ (x : U1)→ U2〉𝜆x .u{ 𝜆x .u′Γ |Γ′ ` (N : U ){ (N ′ : U ′) (Neutral Re-typing)NeRetypeVar(x : U ) ∈ Γ (x : U ′) ∈ Γ′Γ |Γ′ ` (x : U ){ (x : U ′)NeRetypeAppΓ |Γ′ ` (xp : U ){ (xp′ : U ′) Γ |Γ′ ` 〈dom U ′⇐ dom U 〉𝑢 { 𝑢 ′[u/ ]codU = U2 [u ′/ ]codU ′ = U ′2Γ |Γ′ ` (xp u : U2){ (xp′ u′ : U ′2 )Figure 3.17: gdtl: Meta-level Casting97Γ1 |Γ2 ` 〈U2 ⇐ U1〉u1 { u2 (Meta-level Casting of Normal Forms, ctd.)MCastLamFromUnkToUnk(x : ?)Γ |(x : ?)Γ′ ` 〈?⇐ ?〉u { u′Γ |Γ′ ` 〈?⇐ ?〉𝜆x .u{ 𝜆x .u′MCastTypeFromUnkToUnkΓ |Γ′ ` 〈?⇐ ?〉Typeℓ { TypeℓMCastPiFromUnkToUnkΓ |Γ′ ` 〈?⇐ ?〉U1 { U ′1 (x : U1)Γ |(x : U ′1 )Γ′ ` 〈?⇐ ?〉U2 { U ′2Γ |Γ′ ` 〈?⇐ ?〉(x : U1)→ U2 { (x : U ′1 )→ U ′2MCastNeutToUnkTagNeutΓ |Γ′ ` (Nval : 〈Typeℓ〉Nsynth){ (N ′val : 〈Typeℓ〉N ′synth)Nev ` U  〈Typeℓ〉Nsynth Γ |Γ′ ` (Nev : U ){ (N ′ev : U ′)Γ |Γ′ ` 〈?⇐ U 〉〈Nev〉Nval { 〈N ′ev uN ′synth〉N ′valMCastTypeToUnkΓ |Γ′ ` 〈?⇐ Typeℓ+1〉Typeℓ { TypeℓMCastPiToUnkΓ |Γ′ ` 〈?⇐ Typeℓ〉U1 { U ′1 (x : U )Γ |(x : ?)Γ′ ` 〈?⇐ Typeℓ〉U2 { U ′2Γ |Γ′ ` 〈?⇐ Typeℓ〉(x : U1)→ U2 { (x : U ′1 )→ U ′2MCastLamToUnk(x : U1)Γ |(x : ?)Γ′ ` 〈?⇐ U2〉u{ u′Γ |Γ′ ` 〈?⇐ (x : U1)→ U2〉𝜆x .u{ 𝜆x .u′Figure 3.18: gdtl: Meta-level Casting to the unknown typeinto the type, which is necessary because the result may need to be typed in adierent context from the input. Likewise, because function types bind a variablex, the result of casting the codomain must be typed in a context where the type ofx is the result of casting the domain. Similarly, in MCastLam functions are castby casting their bodies, but the resulting body must be typed with the bound xhaving the result domain type.Each type former has a rule for how to cast from a type using that former to? (Fig. 3.18). Functions, function types, and universes are cast by pushing castsdeeper into the term (MCastLamToUnk, MCastPiToUnk, MCastTypeToUnk).98Γ1 |Γ2 ` 〈U2 ⇐ U1〉u1 { u2 (Meta-level Casting of Normal Forms, ctd.)MCastTypeFromUnkΓ |Γ′ ` 〈Typeℓ+1 ⇐ ?〉Typeℓ { TypeℓMCastPiFromUnkΓ |Γ′ ` 〈Typeℓ ⇐ ?〉U1 { U ′1 (x : ?)Γ |(x : U )Γ′ ` 〈Typeℓ ⇐ ?〉U2 { U ′2Γ |Γ′ ` 〈Typeℓ ⇐ ?〉(x : U1)→ U2 { (x : U ′1 )→ U ′2MCastNeutTagUnkFromUnkToTypeΓ |Γ′ ` (N : ?){ (N ′ : U ′) U ′  TypeℓΓ |Γ′ ` 〈Typeℓ ⇐ ?〉〈?〉N { 〈Typeℓ〉N ′MCastLamFromUnk(x : ?)Γ |(x : U1) ` 〈U2 ⇐ ?〉u{ u′Γ |Γ′ ` 〈(x : U1)→ U2 ⇐ ?〉𝜆x .u{ 𝜆x .u′MCastNeutFromUnkToPiΓ |Γ′ ` (N : ?){ (y p : U ′) x {𝜂 u : U1 (x : U1)→ U2  U ′Γ |Γ′ ` 〈(x : U1)→ U2 ⇐ ?〉〈?〉N { 𝜆x .y p uFigure 3.19: gdtl: Meta-level Casting from the unknown typeu : (Gnf∪Gne)2 ⇀ Gnf∪Gne (Composition of Normals and Neutrals)? u u = uu u ? = ux u x = xxp1u1 u xp2u2 = (xp1uxp2)(u1uu2)〈𝜀1〉N1 u 〈𝜀2〉N2 = 〈𝜀1u 𝜀2〉(N1uN2)Typeℓ u Typeℓ = Typeℓ(x : U1)ℓ−→ U2 u (x : U ′1 )ℓ−→ U ′2 = (x : U1uU ′1 )ℓ−→ U2uU ′2𝜆x .u1 u 𝜆x .u2 = 𝜆x .u1uu2u1 u u2 undened otherwiseFigure 3.20: gdtl: Composing Normal Forms99For neutrals with neutral types (MCastNeutToUnkTagNeut) we must re-typethem to account for possible dierences between the two contexts. (Neutralswith non-neutral types are handled byMCastNeutFromUnkToUnk andMCast-NeutEvType). Even when casting from ? to ? we must recursively cast subtermsbecause of the possible di erences in contexts (MCastLamFromUnkToUnk,MCast-TypeFromUnkToUnk,MCastPiFromUnkToUnk,MCastNeutFromUnkToUnk).Likewise, each type former has rules to cast from ? (Fig. 3.19). Functions,function types, and universes are again cast by pushing casts to deeper subterms(MCastLamFromUnk, MCastPiFromUnk, MCastTypeFromUnk). For castingneutrals, if their type is ?, then their tag may also be ?, so we have two rules han-dling ?-tagged neutrals. e rule MCastNeutTagUnkFromUnkToType casts aneutral with tag ? to Typeℓ , since this case is not handled by MCastNeutEv-Type. In this case, the evidence 〈Typeℓ〉 captures (lack of) information from thetype ? and the information from the new type Typeℓ , and succeeds as long asthe neutral can be re-typed to a type consistent with Typeℓ in the new context.e ruleMCastNeutFromUnkToPi handles the special case of casting a neutralfrom ? to a function type: since it is 𝜂-long at type ? but not at a function type, were-type the neutral in the new context, then 𝜂-expand it applied to an 𝜂-expandedargument. Casting ?-typed neutrals with non-? tags is handled by MCastNeut-ToNeut andMCastNeutEvType.3.5.4 Properties of Approximate Normalization3.5.4.1 Preservation of TypingTo prove type safety for gdtl, a key property of normalization is that it preservestyping. is property relies on the fact that hereditary substitution preserves typ-ing, which can be shown using a technique similar to that of Pfenning [121].eorem3.5.1 (Normalization preserves typing). If Γ ` u {t ⇐ U, then Γ ` u⇐ U.See proof in Appendix A .1003.5.4.2 Normalization Is DecidableSince we have dened substitution and normalization using inference rules, theyare technically relations rather than functions. e rules are syntax directed interms of their inputs, so it is easy to show that there exists at most one result forevery set of inputs. Since substitution and normalization are syntax directed andonly have self-reference on strictly smaller sub-terms, we can decide whether agiven term has a normal form when checked against some type.eorem 3.5.2 (Normalization is Decidable). If Γ ` t ⇐ U, then Γ ` u {t ⇐ Ufor at most one u. Determining whether such a u exists is decidable, as is computingit.3.6 gdtl: Run-time SemanticsWith the type system for gdtl realized, we turn to its dynamic semantics. Follow-ing the approaches of Garcia et al. [67] and Toro et al. [147], we let the syntactictype-safety proof for the static sdtl drive its design. In place of a cast calculus,gradual terms carry evidence matching their type, and computation steps evolvethat evidence incrementally. When evidence no longer supports the well typed-ness of a term, execution fails with a run-time type error.3.6.1 The Run-time LanguageFigure 3.21 gives the syntax for the gdtl run-time language, which we call the ev-idence language. It mirrors the syntax for gradual terms, with two main changes.In place of type ascriptions is a special form for terms augmented with evidence,following Toro et al. [147]. As with compile-time evidence, run-time evidence iseither a normal or neutral form. Notably, run-time terms are ascribed surface-normals as evidence, and evidence is normalized using approximate normaliza-tion, so all evidence computations terminate. We also havef, an explicit term forrun-time type errors.ere is a straightforward elaboration from the surface language to the evi-dence languagewhich augments the bidirectional typing rules to output the trans-lated term. Type ascriptions are dropped in the GSynthAnn rule, and initial ev-101t, T F 𝜆x. t | t1 t2 | x | (x : T1)→ T2 | Typei | ? | 〈𝜀〉 t | f (Evidence Terms)v, V F 〈𝜀〉rv | rv (Evidence Values)rv, rV F 𝜆x.e | (x : rV1)→ rV2 | Typei | ? (Raw Values)C F  t | v | (x : )→ T | 〈𝜀〉 (Evidence Contexts)(Evidence Term Typing)EvTypeVar(x : U ) ∈ ΓΓ ` x : UEvTypeAppΓ ` t1 : (x : U1)→ U2 Γ ` t2 : U1Γ ` u2 {t2 ⇐ U1 [u2/x]U1U2 = U3Γ ` t1 t2 : U3EvTypePiU  Type Γ ` U ′ {T1 ⇐ U(x : U ′)Γ ` T2 : UΓ ` (x : T1)→ T2 : UEvTypeType𝑖 > 0Γ ` Typei : Typei+1EvTypeEvΓ ` t : U ′ 𝜀 ` U ′  UΓ ` 〈𝜀〉 t : UEvTypeLevelΓ ` T : Typei 0 < 𝑖 < 𝑗Γ ` T : TypejEvTypeLam` (x : U1)Γ (x : U1)Γ ` t : U2Γ ` 〈(x : U1)→ U2〉𝜆x. t : (x : U1)→ U2EvTypeDynΓ ` U : Typeℓ 𝜀 ` U  UΓ ` 〈𝜀〉 ? : UFigure 3.21: Evidence Term Syntax and Typingidence of consistency is added in GCheckSynth. Section 3.6.2 describes how toderive this initial evidence. In the GSynthDyn rule, we annotate ? with evidence?, so ? is always accompanied by some evidence of its type. Similarly, functionsof type ? are ascribed 〈?→ ?〉.In Fig. 3.21 we also dene the class of syntactic values, which determinesthose terms that are done evaluating. We wish to let values be augmented withevidence, but not to have multiple evidence objects stacked on a value. To expressthis, we separate the class of values from the class of raw values, which are neverascribed with evidence at the top level.102Values are similar to, but not the same, as normal forms. In particular, normalterms contain no redexes, even beneath a 𝜆, whereas values may contain redexeswithin abstractions.3.6.2 Typing and EvidenceTo establish progress and preservation, we need typing rules for evidence terms,whose rules we give in Fig. 3.21. ese rules are essentially the same as for grad-ual terms, with two major changes. First, we no longer use bidirectional typing,since our type system need not be syntax-directed to prove safety. e importantproperties are that each well typed surface term elaborates to a well typed evi-dence term, and that each reduction step preserves typedness for evidence terms.Second, whereas gradual terms could be given any type that is consistent withtheir actual type, we only allow this for dynamic terms directly ascribed withevidence, as seen in the rule EvTypeEv. us, all applications of consistencyare made explicit in the syntax of evidence terms, and for a term (〈𝜀〉t), the evi-dence 𝜀 serves as a concrete witness between the actual type of t and the type atwhich it is used. Unlike with normal forms, any evidence term can be ascribedwith evidence. is di erence re ects the di erent purposes for the two syntaxes.Normal forms are the target of normalization, where all possible reductions areperformed, even under binders, so only neutrals need be ascribed with evidence,as the casting operation can traverse deep into terms. Evidence terms, model therun-time behaviour of gradual programs, where we do not reduce under binders,and reductions are performed sequentially, not all at once.Because evidence ascriptions are normal forms, not evidence terms, we mayneed to substitute an evidence term into evidence, for example, when applying afunction. To facilitate this, we extend the term normalization relation to operateon evidence terms by erasing evidence ascriptions. Using normal forms for ev-idence ensures that evidence computations terminate. We discuss the trade-o sof having terminating evidence more extensively in Chapters 6 and 7. We canthen de ne hereditary substitutions of evidence terms into types, which is crucialwhen updating evidence a er function applications.103Evidence has two key operations. First, we need initial evidence to elaborategradual terms to evidence terms. If a term synthesizes some U and is checkedagainstU ′, then during elaborationwe can ascribe to it the evidence 〈U uU ′〉. Sec-ondly, we need a way to combine two pieces of evidence at run time, an operationreferred to as consistent transitivity in agt: if 〈U 〉 ` U1  U2, and 〈U ′〉 ` U2  U3,then 〈U uU ′〉 ` U1  U3, provided that the meet is dened. So we can also use theprecision meet to dynamically combine di erent pieces of evidence.Second, evidence is combined using the composition (meet) operation fromFig. 3.20, which is based on de nitional (intensional) equality. If we haveA : (Nat→ Nat)→ Type , then A(𝜆x.x+x−x) and A(𝜆x.x) are not consistent atrun time, despite being extensionally equivalent. ere is a delicate balance be-tween the decidability of consistency checking and dynamically respecting termsthat are statically equivalent, which we examine in depth in Chapter 5.3.6.3 Developing a Safe SemanticsAs a driving force behind the design of our semantics, we imagine a hypotheticalproof of progress and preservation. Progress tells us which expressions we needreduction rules for, and preservation tells us how to step while remaining welltyped. We explain the rules here, but the full listing is given in Fig. 3.22.3.6.3.1 Double EvidenceSince values do not contain terms of the form 〈𝜀2〉 (〈𝜀1〉rv), progress dictates thatwe need a reduction rule for such a case. If · ` rv : U , then 𝜀1 ` U  U ′ and 𝜀2 `U ′  U ′′, then 𝜀1u𝜀2 `U  U ′′, so we step to 〈𝜀1u𝜀2〉rv. If the meet is not de ned,then a run-time error occurs.3.6.3.2 Functions with EvidenceTwo complications arise when reducing applications with evidence. e rst isthat in 𝜆x. t, the variable xmay be free in evidence ascriptions within t. When per-forming a substitution, we need the type and normal form of the term replacingthe variable. We use the notation [x ⇒ t1]u:U t2 to denote the syntactic replace-ment of x by t1 in t2, where free occurrences of x in evidence within t2 are replaced104t1 −→ t2 (Evidence-based Small-Step Semantics)StepAscr𝜀1u 𝜀2 = 𝜀3𝜀1 (𝜀2 rv) −→ 𝜀3 rvStepAscrFail𝜀1u 𝜀2undened𝜀1 (𝜀2 rv) −→fStepAppDyn· ` u {v⇐ dom U [u/ ]cod U = U2(〈U 〉 ?) v −→ 〈U2〉 ?StepAppEvdom U uU ′ = U1 · ` u {rv⇐ U1 [u/ ]cod U = U2(〈U 〉𝜆x. t) (〈U ′〉 rv) −→ 〈U2〉 ([x ⇒ 〈U1〉 rv]u:U1t)StepAppEvRaw· ` u {rv⇐ dom U [u/ ]cod U = U2(〈U 〉𝜆x. t) rv −→ 〈U2〉 ([x ⇒ (〈U1〉 rv)]u:U1t)StepAppFailTransdom U uU ′unde ned(〈U 〉𝜆x. t) (〈U ′〉 rv) −→fStepContextt1 −→ t2 t1, t2 ≠ fC[t1] −→ C[t2]StepContextErrt −→fC[t] −→fFigure 3.22: gdtl: Dynamic Semanticsby u (the normal form of t2) using hereditary substitution at type U . We use thisoperation to reduce applications.A second issue is that, while the simple rules dictate how to evaluate a 𝜆-term applied to a value, they do not determine how to proceed for applicationsof the form (〈U 〉𝜆x. t) (〈U ′〉 rv). In such a case, we know that · ` (〈U 〉𝜆x. t) : U1and that 〈U 〉 ` U1  U2 for some U2. Computing dom U uU ′ either fails or yieldsevidence that the type of rv is consistent with the domain of U1, so we ascribethis evidence during substitution to preserve well typedness. e evidence-typingrules say that the type of an application is found by normalizing the argumentvalue and substituting into the codomain of the function type. To produce a resultat this type, we can normalize rv and substitute it into cod 〈U 〉, thereby producing105evidence that the actual result is consistent with the return type. In the case whererv is not ascribed with evidence, we can behave as if it were ascribed 〈?〉 andproceed using the above process.3.6.3.3 Applying The Unknown Terme syntax for values only admits application under binders, so wemust somehowreduce terms of the form (〈𝜀〉?) v. If the function is unknown, so is its output. Sincethe unknown term is always accompanied by evidence at run time, we calculatethe result type by substituting the argument into the codomain of the evidenceassociated with ?.3.6.3.4 Remaining CasesAll other well typed terms are either values, or contain a redex as a subterm, eitherof the simple variety or of the varieties described above. Using contextual rulesto account for these remaining cases, the agt approach yields a semantics wheretype conversions satisfy progress and preservation by construction.3.6.4 Example: Computing the head of the empty vectorWe return to the example from Section 3.4.6, this time explaining its run-timebehaviour. Because of consistency, the term Nil :: (Vec Nat ?) is given the evi-dence 〈Vec Nat ?〉, obtained by computing Vec Nat 0uVec Nat ?. Applying con-sistency to use this as an argument adds the evidence 〈𝑉𝑒𝑐 𝑁𝑎𝑡 1〉, since we checkNil :: (Vec Nat ?) against dom (Vec Nat 1→ Nat). e rule StepContext dictatesthat we must evaluate the argument to a function before evaluating the applica-tion itself. Our argument is 〈Vec Nat 1〉〈Vec Nat 0〉Nil, and since the meet of theevidence types is unde ned, we step to f with StepAscrFail.3.7 Properties of gdtlgdtl satis es all the criteria for gradual languages set forth by Siek et al. [136].1063.7.1 SafetyFirst, gdtl is type safe by construction: it inherits safety for static operations fromsdtl, and the evidence operations are specically cra ed tomaintain progress andpreservation. We can then obtain the standard safety result for gradual languages,namely that well typed terms do not get stuck.eorem 3.7.1 (Type safety). If · ` t : U, then either t −→∗ v for some v, t −→∗ f,or t diverges.See proof in Appendix A .So gradually well typed programs in gdtlmay fail with run-time type errors,but they never get stuck. Among the three main approaches to deal with grad-ual types in the literature, gdtl follows the original approach of Siek and Taha[132] and Siek et al. [136], which enforces types eagerly at boundaries, includingat higher-order types. is choice is in contrast with rst-order enforcement (i.e.transient semantics [152]), or simple type erasure (also known as optional typ-ing).1 In particular, while the transient semantics supports open world soundness[152] when implemented on top of a (safe) dynamic language, it is unclear if andhow this approach, which is restricted to checking type constructors, can scaleto full-spectrum dependent types. gdtl is a sound gradually typed language thatrequires elaboration of the complete program to insert the pieces of evidence thatsupport run-time checking.3.7.2 Conservative Extension of sdtlIt is easy to show that gdtl is a conservative extension of sdtl, so any fully-precise gdtl programs enjoy the soundness and logical consistency propertiesthat sdtl guarantees. Any statically typed term is well typed in gdtl by construc-tion, thanks to agt: on fully precise gradual types, 𝛼 ◦𝛾 is the identity. Moreover,the only additions are those pertaining to ?, meaning that if we restrict ourselvesto the static subset of terms (and types) without ?, thenwe obtain all the propertiesof the static system. We formalize the statement as follows:1Greenman and Felleisen [70] present a detailed comparative semantic account of these threeapproaches.107eorem 3.7.2. If Γ𝐺 , tG ,UG are the embeddings of some Γ𝑆 , tS,US into gdtl, andΓ𝐺 ` tG ⇐ UG , then Γ𝑆 ` tS ⇐ US. Moreover, if tS −→∗ vS and tG elaborates to tE,then there exists some vE where tE −→∗ vE, where removing evidence from vE yieldsvS.3.7.3 Embedding of Untyped Lambda CalculusA signi cant property of gdtl is that it can fully embed the untyped lambda cal-culus, including non-terminating terms. Given an untyped embedding functiond𝑡e that (in essence) annotates all terms with ? we can show that any untypedterm can be embedded in our system. Since no type information is present, allevidence objects are formed using ? or→, and the meet operator never fails. Sountyped programs behave normally in gdtl.eorem 3.7.3. For any untyped 𝜆-term 𝑡 and closing environment Γ that mapsall variables to type ?, then Γ ` d𝑡e ⇒ ?. Moreover, if 𝑡 is closed, then 𝑡 −→∗ 𝑣 impliesthat d𝑡e elaborates to t where t −→∗ v and stripping evidence from v yields 𝑣 .See proof in Appendix A .3.7.4 Gradual GuaranteesTo state the gradual guarantees, we need a precision relation on contexts, whichwe give in Fig. 3.23, along with a syntactic formulation of precision that is equiv-alent to, but less opaque than u1 v u2 := 𝛾 (u1) ⊆ 𝛾 (u2). Precision on surface andevidence terms is de ned in the exact same way: everything is at least as preciseas the unknown term, and composite terms are precision-related if their parts are.gdtl supports the gradual guarantees, with a smooth transition between de-pendent and untyped programming.eorem 3.7.4 (Gradual Guarantee).(Static Guarantee) Suppose Γ ` t ⇐ U and U v U ′. If Γ v Γ′ and t v t ′, thenΓ′ ` t ′⇐ U ′.(Dynamic Guarantee) Suppose that · ` t1 : U, · ` t1 : U ′, t1 v t1, and U v U ′. Ift1 −→∗ t2, then t1 −→∗ t2 where t2 v t2.108u v u′ N v N ′ (Syntactic Presentation of Precision)PrecUnku v ?PreTypeTypeℓ v TypeℓPrecLamu1 v u2𝜆x .u1 v 𝜆x .u2PrecNeutN1 v N2 𝜀1 v 𝜀2〈𝜀1〉N1 v 〈𝜀2〉N2PrecPiU1 v U ′1 U2 v U ′2(x : U1)→ U2 v (x : U ′1 )→ U ′2PrecVarx v xPrecAppxp1 v xp2u1 v u2xp1u1 v xp2u2Γ v Γ′ (Environment Precision)PrecEnvNil· v ·PrecEnvConsΓ1 v Γ2 U1 v U2(x : U1)Γ1 v (x : U2)Γ2Figure 3.23: Gradual Precision of Normals, Neutrals and EnvironmentsSee proof in Appendix A .agt ensures that the gradual guarantee holds by construction. Specically,because approximate normalization and consistent transitivity aremonotonewithrespect to precision, we can establish a weak bisimulation between the steps ofthe more and less precise versions [67].A novel insight that arises from our work is that we need a restricted formof the dynamic gradual guarantee for normalization to prove the static gradualguarantee. To di erentiate it from the standard one, we call it the normalizationgradual guarantee. Because an 𝜂-long termmight be longer at a more precise type,we phrase the guarantee modulo 𝜂-equivalence: we say that U1 v𝜂 U2 if U1 =𝜂 U ′1 ,U2 =𝜂 U ′2 and U ′1 v U ′2 .With these de ned, we can state the normalization gradual guarantee. Weemphasize that while this theoremwas claimed in [58], devising a version of gdtlthat actually satis es it is novel to this thesis.Lemma 3.7.5 (Normalization Gradual Guarantee). Suppose Γ1 ` u1 {t1 ⇐ U1. IfΓ1 v𝜂 Γ2, t1 v t2, and U1 v𝜂 U2, then Γ2 ` u2 {t2 ⇐ U2 where u1 v𝜂 u2.109See proof in Appendix A .3.8 Related Work3.8.1 Static Dependent Typese static dependently typed language sdtl, fromwhich gdtl is derived, incorpo-rates many features and techniques from the literature. e core of the language isvery similar to that of cc𝜔 [39], albeit without an impredicative Prop sort, and thetyped normalization judgment more closely resembles Martin-Lo¨f Type eory (mltt ). e core language of Idris [19], TT, also features cumulative universeswith a single syntactic category for terms and types. Our use of canonical formsdraws heavily from work on the Logical Framework (LF) [72, 73]. e bidirec-tional type system we adopt is inspired by the tutorial of Lo¨h et al. [89]. Ourformulation of hereditary substitution [121, 154] in sdtl is largely drawn fromthat of Harper and Licata [72], particularly the type-outpu ing judgment for sub-stitution on neutral forms, and the treatment of the variable type as an extrinsicargument.3.8.2 Mixing Dependent Types and Non-terminationDependently typed languages that admit non-termination either give up on log-ical consistency altogether (Ωmega [129], Haskell), or isolate a sublanguage ofpure terminating expressions. is separation can be either enforced throughthe type system and/or a termination checker (Aura [82], F★ [142], Idris [19]), orthrough a strict syntactic separation (Dependent ML [157], ATS [30]). e designspace is large, re ecting a variety of sensible trade-o s between expressiveness,guarantees, and exibility.e Zombie language [23, 138] implements a exible combination of program-ming and proving. e language is de ned in two separate, but interacting, frag-ments: the programmatic fragment ensures type safety but not termination, andthe logical fragment (a syntactic subset of the programmatic one) guarantees log-ical consistency. Programmers must declare in which fragment a given de nitionlives, but mobile types and cross-fragment case expressions allow interactions be-110tween the fragments. Zombie embodies a dierent trade-o from gdtl: while thelogical fragment is consistent as a logic, type checking may diverge due to nor-malization of terms from the programmatic fragment. In contrast, gdtl eschewslogical consistency as soon as imprecision is introduced (with ?), but approximatenormalization ensures that type checking terminates.3.8.3 Mixing Dependent Types and Simple TypesSeveral approaches [114, 144] for mixing dynamic and dependent typing havebeen proposed around the idea of subset types. is idea is extended by dependentinteroperability [42, 43, 113], which allows the automatic li ing of subset-typebased conversions to higher-order programs. ese subset-type based approachesrely on the connection between pre-existing types, such as Vec and List, imposingthe overhead of data structure conversions. e fact that List is a less precisestructure than Vec is therefore de ned a posteriori. In contrast, in gdtl, one cande ne List A as an alias for Vec A ?, thereby avoiding the need for deep structuralconversions.e work of Lehmann and Tanter [84] on gradual re nement types includessome form of dependency in types. Re nement types separate types from termsmore cleanly, and hence do not need approximate normalization. However, theyare less expressive than the dependent type system considered here. Furthermore,gdtl is the rst gradual language to let ? be used in both term and type position,and to fully embed the untyped lambda calculus.3.8.4 Programming with HolesFinally, we observe that using ? in place of proof terms in gdtl is related to theconcept of holes in dependently typed languages. Idris [19] and Agda [109] bothallow type checking of programs with typed holes. e main di erence between? and holes in these languages is that applying a hole to a value results in a stuckterm, while in gdtl, applying ? to a value produces another ?. us, when pro-gramming with holes, either undesired type errors occur, or type checks are ig-nored due to unsolved constraints.Recently, Omar et al. [112] describe Hazelnut, a language and programming111system with typed holes that fully supports evaluation in presence of holes, in-cluding reduction around holes. e approach is based on Contextual Modal Typeeory [104]. It would be interesting to studywhether the dependently typed ver-sion of CMTT [122] could be combined with the evaluation approach of Hazelnut,and the IDE support, to provide a rich programming experience with gradual de-pendent types.3.9 Conclusiongdtl represents a glimpse of the challenging and potentially large design space in-duced by combining dependent types and gradual typing. Speci cally, this chap-ter proposes approximate normalization as a novel technique for designing grad-ual dependently typed languages, in a way that ensures decidable type checkingand naturally satis es the gradual guarantees.Currently, gdtl lacks a number of features required of a practical dependentlytyped programming language. It might also be interesting to consider pa ernmatching as the primitive notion for eliminating inductives, as in Agda, insteadof elimination principles as in Coq; the equalities implied by dependent matchescould be turned into run-time checks for gradually typed values.Future work includes supporting implicit arguments and higher-order uni-cation, blame tracking [153], and e cient run-time semantics with erasure ofcomputationally-irrelevant arguments [20]. Approximate normalization might bemade more precise by exploiting termination contracts [107].112Chapter 4Interlude: The GradualCalculus of InductiveConstructionsIn this chapter, we describe the the Gradual Calculus of Inductive Constructions( gcic ). We emphasize that gcic is not a contribution of this thesis: it wascreated by Lennon-Bertrand, Maillard, Tabareau, and Tanter [87]. In Section 4.1,we discuss the dierences between the gcic and gdtl approaches. e remainingtext of this chapter is based on a section from the paper version of Chapter 5 [60],which presented gcic as important background knowledge. We include it here,rather than in Chapter 2 or Chapter 5, for three reasons:• Separating gcic into its own chapter ensures that the distinction betweenprevious work and novel contributions in Chapter 5 is clear;• Chronologically, the paper presenting gcic was published a er the paperon which Chapter 3 is based [58], but before the paper on which Chapter 5is based. So to understand the evolution of ideas surrounding gradual de-pendent types, familiarity with gdtl helps clarify the context under whichgcic was devised.• Chapters 5 and 6 present extensions of gcic, so it is not merely related to113our work, but is a critical piece of understanding our work.To present gcic, we rst describe the the Bidirectional Calculus of InductiveConstructions ( bcic ), a modi cation of the Calculus of Inductive Constructions( cic ) whose bidirectional types are convenient for gradual typing [86]. We thendescribe the gradual surface language gcic, along with Cast calculus for the Grad-ual Calculus of Inductive Constructions ( CastCIC ), and a translation from gcicto CastCIC [87]. Speci cally, we use GCICG , the variant that satis es the grad-ual guarantees and embeds cic, but sacri ces strong normalization. Chapter 6 isdedicated to regaining decidable type checking for an extension of gcic.4.1 Overview: gdtl vs. gcicIn this section, we give a birds-eye view of the di erences between the GradualDependently Typed Language ( gdtl ) and gcic, with the aim of providing contextthat helps the reader understand the details provided from Section 4.2 onward.4.1.1 Similaritiesgdtl and gcic are built on a similar foundation. ey are both fully gradual, fullspectrum dependently typed languages. Types and terms inhabit a single syn-tactic category, and ? can be used to replace a term of any type. Both languagesimplement sound gradual typing: deep run-time type information is kept to per-form dynamic checks, as opposed to the shallow run-time type information oftransient typing or the non-existent run-time type information of optional typ-ing [70]. Neither language directly supports indexed families or propositionalequality, though we extend gcic with these in Chapter 5.4.1.2 Di erences4.1.2.1 Static Languagegdtl is variant of the Calculus of Constructions with a predicative universe hier-archy ( cc𝜔 ), whereas gcic is based on cic. at is, in gdtl the only static values114are functions, function types, and universes. gcic has inductive types (but not in-dexed families), so users can dene their own types as recursive sums of products.As such, gcic is much closer to a model of a usable programming language withconditional branching and pa ern matching.gcic also uses a very di erent avour of bidirectional typing than the oneused in gdtl. In gdtl, normal forms are checking, and neutral forms synthesize.Normal forms are typed using a relation similar to, but separate from, term typing.In gcic, there is no separate judgment for typing of normal forms, which are astrict subset of terms. All syntactic forms are synthesizing, and the only checkingrule is for conversion. Because of this, functions in gcic must be ascribed withtheir argument types so that their typing rule can synthesize but still be syntax-directed.e style of conversion check di ers between gdtl and gcic. In gdtl, con-version checking is done using type-directed judgmental equality, much like inMartin-Lo¨f Type eory (mltt ). However, unlike cic ormltt, judgmental equal-ity compares terms by rst normalizing them with hereditary substitution. Ingcic, convertibility of terms is de ned using an untyped rewrite relation that canbe applied to any subterm. is small-step style lends itself well to simulationarguments. Terms are judgmentally equal if there is some common term to whichthey both reduce.4.1.2.2 The Unknown TermIn gdtl, the unknown term is never ascribed with its type: any program compo-nent can be replaced with ?. In contrast, gcic requires that ? have a level ascrip-tion: if ? : T and T : Typeℓ , then ? is ascribed level ℓ . ese ascriptions avoid thegradual versions of Girard’s paradox which can be expressed in gdtl.4.1.2.3 Dynamic Type Checksgdtl is based on Abstracting Gradual Typing ( agt ), whereas gcic uses thecast calculus approach. In gdtl’s run-time language, all terms (including values)may be ascribed with evidence of the consistency between their actual type andthe type at which they are used. Run-time checks are performed by composing115stacked evidence, and failures happen when the composition of such evidence isnot dened. In gcic, type imprecision is expressed computationally: the run–timelanguage has an explicit form for casts. Values can only contain casts if they areneutral, or if the casts are on ?1. Type information is not explicitly composed, butcasts are pushed inward in terms, and they fail if the source and destination haveinconsistent top-level constructors.e two languages also di er in their handling of errors and function types. Ingdtl, function type information is eagerly composed, so using a function of typeInt → Int in a context expecting Bool→ Bool fails. In gcic, casts are lazily appliedto function types: casting from Int → Int to Bool→ Bool succeeds but produces afunction that always raises an error when called. is is ing for gcic, however,as the error f at type (x : A)→ B is 𝜂-expanded to 𝜆(x : A).f.4.1.2.4 Normalization and the Gradual GuaranteesDecidable type checking is the driving force behind gdtl: its syntax, typing, andsemantics are all designed around the goal of ensuring all type computations ter-minate. As such, di erent semantics are used for normalizing during type check-ing and executing at run time. e core calculus is limited to ensure that heredi-tary substitution can be de ned using well founded recursion.gcic is instead designed around the aim of providing a fully gradual type the-ory. Compile-time and run-time computations use the exact same reduction rules,and the mechanism for prevent non-termination is to reject such terms, ratherthan to approximate them. e original presentation of gcic explores the inherenttradeo s with strong normalization. e authors present three variants of gcic.gcicG behaves much like the run-time language of gdtl, satisfying the gradualguarantees and allowing non-termination, at the expense of strong normalizationand decidable type checking. gcic𝑁 contains an extra universe restriction that al-lows terms to raise errors instead of diverging, enabling strong normalization at1Casts on ? are really an abuse of notation. We would prefer to separate the computation ofconverting from ? of one type to another from the act of tagging ? with the type of values it couldplausibly represent, and have casts on ? reduce to tagged versions of ? by composing the cast typewith the information in the tag. But we follow the original presentation of gcic in this case, whichdoes help reduce the notational overhead.116the cost of the gradual guarantees. Finally, gcic↑ obtains both strong normaliza-tion and the gradual guarantees by statically restricting the universes over whichfunction types can quantify. However, this restriction means there are static cicprograms that cannot be typed in gcic↑.Lennon-Bertrand et al. [87] show that no language can conservatively extendthe Simply Typed Lambda Calculus ( stlc ), have all terms strongly normalizing,and have the embedding-projection pairs (EP-pairs) property (Section 2.1.2.3). ethree gcic variants each sacri ce one property to obtain the other two. However,gdtl is able to conservatively extend stlc while satisfying decidable type check-ing and the gradual guarantees (but not EP-pairs), something no variant of gcicis able to do. Chapter 6 shows how to extend approximate normalization to alanguage that includes inductive types.4.2 The Bidirectional CIC4.2.1 SyntaxFigure 4.1 gives the bidirectional calculus of inductive constructions (bcic), whichwas created by Lennon-Bertrand [86], though we modify their notation to t withthe rest of this thesis. bcic terms are denoted by metavariables t and T, looselyfollowing the convention that T be reserved for types. Variables are denoted byx,y,z. e notation −→𝑉 denotes a sequence of objects matching metavariable V.bcic has variables, a predicative hierarchy of universes, function types, func-tions, and applications. Technically, bcic extends the predicative, non-cumulativefragment of cic: each function type is in a higher universe than its domain andcodomain, and there is no subtyping between universe levels. We assume a pre-t,TF x | Typei | (x : T1)→ T2 | 𝜆(x : T). t | t1 t2| C@{i}(−→t ) | DC@{i}(−→t ,−→t′ ) | indC(t1,z.T,x.−→𝑦.𝑡2)hF C | Type | ΠFigure 4.1: bcic: Syntax117existing set of inductive type constructors, denoted by the metavariable C, eachof which has a xed set of data constructors DC. Type and data constructors areannotated with the universe level of their type, though we omit these annotationswhen they are not relevant.To eliminate members of inductive types, a combined form indC(t1,z.T,x.−→𝑦.𝑡2)replaces cic’s fix and match. is form branches on the scrutinee t1 and has aparameterized result type T, called the motive [96], that binds a variable z of thescrutinee’s type, giving the result type of elimination for a particular input z. ebranches −→t2 correspond to the constructors−→𝐷𝐶 of C. In each branch, the variables−→y are bound to the arguments toDC, and x is bound to the whole indC expression,to facilitate recursion. e indC form expresses an induction principle: if eachbranch produces a result of type T where z is bound to DC applied to −→y , theelimination has type T where z is bound to the scrutinee t1. In essence, indC saysthat if we can build a T for each constructor DC of C with the given parameters,then we can build one for any value of C with those parameters. Normally, aseparate check ensures that recursive calls are only made on structurally smallerarguments, but we omit this check, since it is orthogonal to gradual typing andGCICG would not be strongly normalizing even with it.bcic also uses head tags, denoted by h, which act as symbols to specify a typeconstructor without specifying its arguments. We use these in typing, e.g. forexpressing that an applied function must synthesize a function type, even thoughwe do not know what the domain and codomain should be. Head tags (or tags forshort) are also useful in gcic for de ning the least precise type with a given head.4.2.2 Typing and Semanticse semantics of bcic (Fig. 4.2) is standard, and is given with primitive notions ofreduction {, contextual stepping −→ where any sub-term reduces (even underbinders), and multi-step contextual reduction −→∗, which allows zero or moresteps with −→.e typing (Fig. 4.3) for bcic resembles the typical presentation of cic, buttyping is divided into synthesis, which produces a type, and checking, whichconsumes a type. Because function types bind their parameter in the codomain,118t{ t′ (Notions of Reduction) t −→ t′ (Contextual reduction)Red𝛽(𝜆(x : T). t) t′{ [t′/x]t t{ t′ 𝐶 an arbitrary context𝐶 [t] −→𝐶 [t′]RedMatchindC(Dk(−−→𝑡𝑝𝑎𝑟 ,−→𝑡𝑎𝑟𝑔),z.TP,xrec.−−−→𝑦.𝑡𝑟ℎ𝑠 ){[𝜆(x : C(−−→𝑡𝑝𝑎𝑟 )). indC(x,z.T,xrec.−−−→𝑦.𝑡𝑟ℎ𝑠 )/xrec] [−→𝑡𝑎𝑟𝑔/−→y ]trhskFigure 4.2: bcic: Semanticsapplications synthesize a type depending on the value of the argument, since itis substituted for x in the codomain type. A term checks against any type thatreduces to the same type as its synthesized type, since an application may haveproduced a type that must be reduced before comparing. Constrained-synthesis,Γ ` t⇒hT, generalizes the paern of synthesizing a type for a term a er reducingit to a point that it has the desired head h. Separating synthesis from constrainedsynthesis will be useful once gradual types are introduced. Function applicationhas the standard 𝛽-reduction rule.For inductive types, the typing rule establishes that, if TP is a type parameter-ized over a value x from the inductive type C, and we can (recursively) build a TPfor each constructor of C, then we can build a TP for any member or C. Hence,indC() form gives an induction principle for C, hence the notation indC( . . . ). In-ductive types may be parameterized, but each constructor has the same returntype. e reduction rule says that an indC( . . . ) form given a value DC(. . .) reducesto the branch corresponding to DC.119Γ ` t⇒ T (Synthesis) Γ ` t⇐ T (Checking) Γ ` t⇒hT (Constrained Synthesis)SCheckΓ ` t⇒ T′T −→∗ T′′ T′ −→∗ T′′Γ ` t⇐ TSVar(x : T) ∈ ΓΓ ` x⇒ TSTypeΓ ` Typei ⇒ Typei+1SFunΓ ` T1⇒Type TypeiΓ,x : T1 ` T2⇒Type TypejΓ ` (x : T1)→ T2 ⇒ Typemax(i,j)SAppΓ ` t0⇒Π (x : T1)→T2Γ ` t1 ⇐ T1Γ ` t0 t1 ⇒ [t1/x]T2SAbsΓ ` T1⇒Type TypeiΓ,x : T1 ` t⇒ T2Γ ` 𝜆(x : T1). t⇒ (x : T1)→ T2SInd−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` tk ⇐ Paramsk(C, i)[−→t ]𝑘Γ ` C@{i}(−→t k)⇒ TypeiSCtor−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` tk ⇐ Paramsk(C, i)[−→t ]𝑘−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` t′𝑚 ⇐ Args𝑚(C, i,D)[−→t ,−→t′ ]𝑚Γ ` DC@{i}(−→t k ,−→t′m)⇒ C@{i}(−→𝑡 k)SMatchΓ ` tscrut⇒CC@{i}(−−→𝑡𝑝𝑎𝑟 )Γ,z : C(−−→𝑡𝑝𝑎𝑟 ) ` TP⇒Type Typej©­­«−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→Γ,xrec :𝑋 ,−→y :Args(C, i,Dk)[−→tpar,−→y ] ` trhsk ⇐[DCk @{i}(−−→𝑡𝑝𝑎𝑟 ,−→y )/z]TP𝑘where 𝑋 := (z : C@{i}(−→tpar))→ TPª®®¬Γ ` indC(tscrut,z.TP,xrec.−−−−→−→𝑦 .𝑡𝑟ℎ𝑠k)⇒ [tscrut/z]TPSConstrSynthTypeΓ ` t⇒ TT −→∗ TypeiΓ ` t⇒Type TypeiSConstrSynthFunΓ ` t⇒ TT −→∗ (x : T1)→ T2Γ ` t⇒Π (x : T1)→ T2SConstrSynthIndΓ ` t⇒ TT −→∗ C@{i}(−→tp )Γ ` t⇒CC@{i}(−→tp )Figure 4.3: Bidirectional cic: Syntax, Typing and Semantics1204.3 gcic: The Surface LanguageFigure 4.4 extends bcic into gcic, the Gradual CIC, by adding the imprecise term?@i, which can be used at any type in universe level i, along with type ascriptions,which were not in bcic because all forms synthesized types. We use ?T as sugarfor ?@i when T : Typei.Dependent types complicate the typing of gcic. Because the dynamic seman-tics of gcic are dened using a cast calculus, and typing refers to reduction ofterms, Lennon-Bertrand et al. [87] de ne gcic typing with cast calculus types.Nevertheless, we can establish lemmas (Fig. 4.4), phrased like rules, which pro-vide intuition for how gcic terms are typed against gcic types, helping gcic beunderstood without diving into the details of the cast calculus.e unknown term ?@i synthesizes ?@i+1 i.e. its type is unknown, one levelup in the universe hierarchy. A term checks against any type consistent with itssynthesized type, where the relation −→ is understood to mean convertibilityup to well typed occurrences of ?. An ascribed term synthesizes the given typeif it checks against it, relaxing or tightening the types of gradual terms. In thecase where a term synthesizes ?Typei , constrained synthesis produces the germ2.e type germ𝑖 (h) is the least precise type with a given head in universe 𝑖 . Forfunction types, the germ is ?@i → ?@i, and Typei is its own germ. For inductives,the germ is C(−→?@i) where the i’s are the parameters’ levels.2called the ground type in non-dependently typed literaturet,T +F ?@i | t :: TΓ ` ?@i ⇒ ?@i+1Γ ` t ⇐ TΓ ` t :: T ⇒ TΓ ` t ⇒ T ′ T ′−→TΓ ` t ⇐ TΓ ` t ⇒ T T −→∗ ?@iΓ ` t⇒Π ?@i→?@iΓ ` t ⇒ T T −→∗ ?@iΓ ` t⇒C C(−−−−−−−−→?Params(C,i))Γ ` t ⇒ T T −→∗ ?@i+1Γ ` t⇒Type TypeiFigure 4.4: gcic: Syntax and Typing Lemmas1214.4 CastCIC: The Cast Calculus4.4.1 Syntax, Typing and ReductionsFigure 4.5 presents the added syntax and typing for CastCIC, the cast calculusfor gcic. CastCIC extends bcic with the unknown term ?, an error f, and a cast〈T2 ⇐ T1〉t from type T1 to T2. Forms ?T and fT are ascribed with their typeT, which aect the dynamic semantics of CastCIC. In the new rules, terms ?Tand fT synthesize their ascribed type T (CastUnk, CastErr), while casts syn-thesize the destination type, given that the term being cast checks against thesource type, and that both types are well-formed (CastCast). Because casts areexplicit, the rule CastCheck uses de nitional equality, rather than consistency,when switching from synthesis to checking.e CastCIC semantics includes all bcic reductions, plus cast rules (Fig. 4.7)and propagation rules (Fig. 4.6). e propagation rules handle ? and f. At type(x : T1)→ T2, ? andf expand to 𝜆(x : T1).?T2 inRedPropFunUnk and 𝜆(x : T1).fT2in RedPropFunErr. In the remaining RedProp rules, eliminating or casting ? orf produces ? or f.Cast rules either convert between types with the same head, cast to ?Typeℓ ,or produce an error. A cast from Typei to itself reduces away (RedCastType).For inductives, casts from C(−→𝑡1 ) to C(−→𝑡2 ) reduce by casting elds to the new typegiven by the di erent parameter values (RedCastInd). Note that tpar and tpar′′need not match, but typing guarantees that they are convertible. Casts betweentypes with mismatched heads produce an error (RedCastHeadErr), as do caststo or fromfTypei (RedCastDomErr, RedCastCodomErr). A cast from the germfor a given head does not reduce: 〈?Typei ⇐ germ(T)〉 acts as a tag, injecting into?Typei . Casts from non-germ types to ?Typei decompose into casts through thegerm that are then tagged with their injection into ?Typei (RedCastFunGerm,RedCastIndGerm). In RedCastUpDown, a cast from ?Typei to T reduces whenthe value being cast originates from a type with a matching head, and was ac-cordingly tagged with a cast from head(T) to ?Typei .122t,T +F ?T | fT | 〈T2 ⇐ T1〉tCastCheckΓ ` t⇒ T′T −→∗ T′′ T′ −→∗ T′′Γ ` t⇐ TCastVar(x : T) ∈ ΓΓ ` x⇒ TCastTypeΓ ` Typei ⇒ Typei+1CastFunΓ ` T1⇒Type TypeiΓ,x : T1 ` T2⇒Type TypejΓ ` (x : T1)→ T2 ⇒ Typemax(i,j)CastAppΓ ` t⇒Π (x : T1)→ T2Γ ` t⇐ TΓ ` t0 t1 ⇒ [t1/x]T2CastAbsΓ ` T1⇒Type TypeiΓ,x : T1 ` t⇒ T2Γ ` 𝜆(x : T1). t⇒ (x : T1)→ T2CastInd−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` tk ⇐ Paramsk(C, i)[−→t ]kΓ ` C@{i}(−→t k)⇒ TypeiCastCtor−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` tk ⇐ Paramsk(C, i)[−→t ]k−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` t′𝑚 ⇐ Args𝑚(C, i,D)[−→t ,−→t′ ]mΓ ` DC@{i}(−→t k ,−→t′m)⇒ C@{i}(−→𝑡 k)CastMatchΓ ` tscrut⇒CC@{i}(−−→𝑡𝑝𝑎𝑟 ) Γ,z : C(−−→𝑡𝑝𝑎𝑟 ) ` TP⇒Type Typej©­­«−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→Γ,xrec : 𝑋𝑟𝑒𝑐 ,−→y : Args(C, i,Dk)[−→tpar,−→y ] ` trhsk ⇐ [DCk@{i}(−−→𝑡𝑝𝑎𝑟 ,−→y )/z]TP𝑘where 𝑋𝑟𝑒𝑐 := ((z : C@{i}(−→tpar))→ TP)ª®®¬Γ ` indC(tscrut,z.TP,xrec.−−−−→−→𝑦 .𝑡𝑟ℎ𝑠k)⇒ [tscrut/z]TPCastUnkΓ ` T⇒Type TypeiΓ ` ?T ⇒ TCastErrΓ ` T⇒Type TypeiΓ `fT ⇒ TCastCastΓ ` T𝑗⇒Type Typei for 𝑗 ∈ {1,2}Γ ` t⇐ T1Γ ` 〈T2 ⇐ T1〉t⇒ T2CastConstrSynthTypeΓ ` t⇒ TT −→∗ TypeiΓ ` 𝑡⇒Type TypeiCastConstrSynthFunΓ ` t⇒ TT −→∗ (x : T1)→ T2Γ ` t⇒Π (x : T1)→ T2CastConstrSynthIndΓ ` t⇒ TT −→∗ C@{i}(−→tp )Γ ` t⇒CC@{i}(−→tp )Figure 4.5: CastCIC: Typing and New Syntax123Propogation ReductionsRedPropCastInd(Unk,Err)〈C(−→𝑡2 )⇐ C(−→𝑡1 )〉?T1 { ?C(−→𝑡2 )〈C(−→𝑡2 )⇐ C(−→𝑡1 )〉fT1 { fC(−→𝑡2 )RedPropCastDown(Unk,Err)〈T⇐ ?Typei〉??Typei { ?T〈T⇐ ?Typei〉f?Typei { fTRedPropFun(Unk,Err)?(x:T1)→T2 { 𝜆(x : T1).?T2f(x:T1)→T2 { 𝜆(x : T1).fT2RedPropMatch(Unk,Err)indC(?C(−−→tpar),z.TP,xf .−→y .−→t ){ ?[?C(−−→tpar)/z ]TPindC(fC(−−→tpar),z.TP,xf .−→y .−→t ){ f[fC(−−→tpar)/z ]TPFigure 4.6: CastCIC: Propagation Reduction Rules4.4.2 ElaborationFinally, elaboration (Figs. 4.8 and 4.9) denes the relationship between gcic andCastCIC, which in turn de nes which gcic terms are well typed. Like CastCIC,elaboration has synthesis, checking, and constrained synthesis, but each addi-tionally produces the elaboration of the subject term as output, so it can be usedto compute the return types of dependent functions and eliminations. e ruleElabUnk synthesizes the unknown type for the unknown term at the given uni-verse level. ElabApp works like a normal dependent function application, butuses the elaboration of the argument to replace the parameter in the return type.ElabCst checks a term against a type consistent with its synthesized type, insert-ing the cast between these types into the elaboration. Figure 4.8 also de nes newconstrained synthesis rules. Rule ElabUnkFun produces an elaboration wherethe applied value of type ?Typeℓ is cast to a function type, so it can be safely ap-plied. Rules ElabUnkInd and ElabUnkUniv work similarly. We omit the elabo-ration rules corresponding to the remaining bcic rules, which homomorphicallyelaborate the sub-terms of a given term, but refer the curious reader to the originalpresentation [87].Consistency in gcic is checked modulo conversion, with a relation de nedin Fig. 4.10. Two terms are consistently convertible if they step to terms that are𝛼-consistent. e 𝛼-consistency relation (Fig. 4.10) is very similar to consistencyin gdtl: every term is consistent with ?, and terms with the same head are con-124Cast Reductions:RedCastUpDown〈T⇐ ?Typei〉〈?Typei⇐germ𝑖 (h)〉t{ 〈T⇐germ𝑖 (h)〉tRedCastInd〈C(−−→𝑡 ′𝑝𝑎𝑟 )⇐ C(−−→𝑡𝑝𝑎𝑟 )〉DC(−−−→𝑡𝑝𝑎𝑟 ′′ ,−→𝑡𝑎𝑟𝑔){ DC(−−→𝑡 ′𝑝𝑎𝑟 ,−→𝑡 ′𝑎𝑟𝑔)where t′argi := 〈Argsi(C, i,D)[−−→𝑡 ′𝑝𝑎𝑟 ,−−→𝑡 ′𝑎𝑟𝑔𝑠] ⇐ Argsi(C, i,D)[−−→𝑡𝑝𝑎𝑟 ,−−→𝑡𝑎𝑟𝑔𝑠]〉targiRedCastType〈Typei ⇐ Typei〉T{ TRedCastDomErr〈T⇐fTypei〉t{ fTRedCastCodomErr〈fTypei ⇐ T〉t{ ffTypeiRedCastHeadErrhead(T) ≠ head(T′)〈T′⇐ T〉t{ fT′RedCastFun〈(x : T′1)→ T′2 ⇐ (x : T1)→ T2〉t{ 𝜆y. 〈T′2⇐[〈T1 ⇐ T′1〉y/x]T2〉(t 〈T1 ⇐ T′1〉y)RedCastFunGerm(x : T1)→ T2 ≠ germ𝑗 (Π) for 𝑗 ≥ 𝑖〈?Typei ⇐ (x : T1)→ T2〉t{ 〈?Typei ⇐ ?Typei → ?Typei〉〈?Typei → ?Typei ⇐ (x : T1)→ T2〉tRedCastIndGermC(−−→𝑡𝑝𝑎𝑟 ) ≠ germ𝑗 (C) for 𝑗 ≥ 𝑖〈?Typei ⇐ C(−−→𝑡𝑝𝑎𝑟 )〉t{ 〈?Typei ⇐ C(−−−−−−−→?Params(C))〉〈C(−−−−−−−→?Params(C))⇐ C(−−→𝑡𝑝𝑎𝑟 )〉tRedCastSizeErrmin { 𝑗 | ∃h.germ𝑗 (h) = T} > 𝑖〈?Typei ⇐ T〉t{ fTypeiFigure 4.7: CastCIC: Cast Reduction Rulessistent if their parts are. Additionally, terms with casts are consistent are checkedfor consistency by ignoring the casts. e name 𝛼-consistency comes from thefact that it only considers consistency up to (implicit) 𝛼-equivalence, not moduloconversion.Elaboration de nes gcic typing for surface terms and types: we say t : T when· ` T _ T⇒Type Typei and · ` t _ t⇐ T.125Γ ` t_ t⇒ T Γ ` t _ t⇐ T Γ ` t _ t⇒h T (Elaboration)ElabUnkΓ ` ?@i_ ??Typei ⇒ ?TypeiElabCstΓ ` t _ t⇒ T′T′−→TΓ ` t _ 〈T⇐ T′〉t⇐ TElabUnkFunΓ ` t_ t⇒ ?TypeiΓ ` t_ 〈?Typei→?Typei ⇐ ?Typei〉t⇒Π ?Typei→?TypeiElabAppΓ ` t0_ t0 ⇒Π (x : T1)→ T2Γ ` t1_ t1 ⇐ T1Γ ` t0 t1_ t0 t1 ⇒ [t1/x]T2ElabTypeΓ ` Typei_ Typei ⇒ Typei+1ElabUnkIndΓ ` t_ t⇒ ?iΓ ` t_ 〈C(−−−−−−−−→?Params(C,i))⇐ ?i〉t⇒C C(−−−−−−−−→?Params(C,i))ElabUnkUnivΓ ` t_ t⇒ ?Typei+1Γ ` t_ 〈Typei ⇐ ?Typei+1〉t⇒Type TypeiElabVar(x : T) ∈ ΓΓ ` x _ x⇒ TElabFunΓ ` T1_ T1 ⇒Type TypeiΓ,x : T1 ` T2_ T2 ⇒Type TypejΓ ` (x : T1)→ T2_ (x : T1)→ T2 ⇒ Typemax(i,j)ElabAbsΓ ` T1_ T1 ⇒Type TypeiΓ,x : T1 ` t _ t⇒ T2Γ ` 𝜆(x : T1). t_ 𝜆(x : T1). t⇒ (x : T1)→ T2Figure 4.8: Elaboration from gcic to CastCIC126ElabIndΓ ` tk_ tk ⇐ Paramsk(C, i)[−→t ]Γ ` C@{i}(−→t )_ C@{i}(−→t )⇒ TypeiElabCtorΓ ` tk_ tk ⇐ Paramsk(C, i)[−→t ]Γ ` t ′𝑚_ t′𝑚 ⇐ Args𝑚(C, i,D)[−→t ,−→t′ ]Γ ` DC@{i}(−→t ,−→t ′ )_ DC@{i}(−→t ,−→t′ )⇒ C@{i}(−→𝑡 )⇒ElabMatchΓ ` tscrut _ tscrut ⇒C C@{i}(−−→𝑡𝑝𝑎𝑟 )Γ,z : C(−−→𝑡𝑝𝑎𝑟 ) ` TP _ TP ⇒Type Typej−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→Γ,xrec : ((z : C@{i}(−→tpar))→ TP),−→y : Args(C, i,Dk)[−→tpar,−→y ] `−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→trhsk _ trhsk ⇐ [DCk@{i}(−−→𝑡𝑝𝑎𝑟 ,−→y )/z]TPΓ ` indC(tscrut ,z .TP ,xrec .−−−−→−→𝑦 .𝑡𝑟ℎ𝑠 )_ indC(tscrut,z.TP,xrec.−−−−→−→𝑦 .𝑡𝑟ℎ𝑠 )⇒ [tscrut/z]TPElabConstrSynthTypeΓ ` t _ t⇒ TT −→∗ TypeiΓ ` t _ t⇒Type TypeiElabConstrSynthFunΓ ` t _ t⇒ TT −→∗ (x : T1)→ T2Γ ` t _ t⇒Π (x : T1)→ T2ElabConstrSynthIndΓ ` t _ t⇒ TT −→∗ C@{i}(−→tp )Γ ` t _ t⇒C C@{i}(−→tp )Figure 4.9: Elaboration from gcic to CastCIC (ctd.)127Consistent Convertibility:ConvCstT1 −→∗ T′1 T2 −→∗ T′2 T′1𝛼T′2T1−→T2𝛼-Consistency:CstVarx𝛼xCstUnkL?T𝛼 tCstUnkRt𝛼?TCstCastLt𝛼 t′〈T2 ⇐ T1〉t𝛼 t′CstCastRt𝛼 t′t𝛼 〈T2 ⇐ T1〉t′CstAbsT1𝛼T2t1𝛼 t2𝜆(x : T1). t1𝛼𝜆(x : T2). t2CstCastT1𝛼T2 T′1𝛼T′2t1𝛼 t2〈T′1 ⇐ T1〉t1𝛼 〈T′2 ⇐ T2〉t2CstInd−−−−→t1𝛼 t2C@{i}−→t1𝛼C@{i}−→t2CstCons−−−−→t1𝛼 t2−−−−→t′1𝛼 t′2DC( −→t1 ,−→t′1 )𝛼DC(−→t2 ,−→t′2 )CstAppt1𝛼 t2t′1𝛼 t′2t1 t′1𝛼 t2 t′2CstUnivTypeℓ𝛼TypeℓCstProdT1𝛼T2T′1𝛼T′2(x : T1)→ T′1𝛼 (x : T2)→ T′2CstFix −−−→t𝛼 t′indC(−→t )𝛼 indC(−→t′ )Figure 4.10: CastCIC Consistency and Consistent Convertibility4.4.2.1 A Note on PrecisionWe defer the presentation of gcic’s denition of precision to Chapter 5. Precisionis not needed to de ne gcic itself, only to state the gradual guarantees for gcic.Moreover, we make a small but pervasive change to the de nition of precisionin Chapter 5, so we present it there instead of presenting two nearly-identicalde nitions separately.128Chapter 5Propositional Equality andDynamic Consistency TrackingIn this chapter, we add propositional equality to a gradual dependently typedlanguage. In the previous chapters, we saw how gradual dependent types canpotentially help with the incremental adoption of dependently typed code. egiven theories, however, lack propositional equality, which is a central feature oftype theory.e static equality type cannot be added to a gradual language without sign -cant changes. Lennon-Bertrand et al. [87] show that, when the re exive proof reis the only closed value of an equality type, any gradual extension of the Calculusof Inductive Constructions (CIC) with propositional equality violates static obser-vational equivalences. Extensionally-equal functions should be indistinguishableat run time, but they can be dynamically distinguished using a combination ofequality and type imprecision. Violating static equivalence is problematic, be-cause optimizations, program transformations, or reasoning principles that werestatically valid may not be gradually valid.Here, we present a notion of gradual propositional equalitywhere static equiv-alences are respected. We do so by devising an equality type of which re is notthe only closed inhabitant. Instead, each equality proof is accompanied by a termthat is at least as precise as the equated terms, acting as a witness of their plau-sible equality. ese witnesses track partial type information as a program runs,129raising errors when that information shows that two equated terms are undeni-ably inconsistent. Composition of type information is internalized as a constructof the language, and is deferred for function bodies whose evaluation is blockedby variables. We thus ensure that extensionally-equal functions compose with-out error, thereby preventing contexts from distinguishing them. We describe thechallenges of designing consistency and precision relations for this system, alongwith solutions to these challenges. Finally, we prove important metatheory: typesafety, conservative embedding of the Calculus of Inductive Constructions ( cic ),weak canonicity, and the gradual guarantees, which ensure that reducing a pro-gram’s precision introduces no new static or dynamic errors.5.1 Gradual Propositional Equalitye propositional equality [94] type, wri en t1 =T t2 expresses that t1 and t2 areequal inhabitants of type T. Its only constructor is reflt : t =T t, the proof thatevery term is equal to itself. Equality is useful for practical dependently typedprogramming, since it lets a function express pre- and postconditions by takingor returning equality proofs. Likewise, a programmer can use an equality proof torewrite the type of the expression they are trying to produce. Propositional equal-ity even lays a path to support GADT-style inductive families, since constructorswith di erent return types can be encoded with non-indexed inductive types andpropositional equality [95].Propositional equality is immensely useful for programming, but it has beenlargely omi ed from gradual languages, where only limited means of represent-ing and reasoning about equality have been available. In the Gradual Calculusof Inductive Constructions ( gcic ) [87], decidable equality is supported (see Sec-tion 5.2.2), where a type is computed by pa ern-matching on the equated terms.Gradual Re nement Types [84] support rst-order constraints in linear integerarithmetic. In contrast, propositional equality is more general than re nementtypes and more lightweight than decidable equality: it works for every type, pro-vides its own construction and elimination principles, and can be used with quan-ti ers or higher order functions.One challengewith gradual equality has been propagating and enforcing equal-130ity constraints at run time. e problem is that equated terms may contain func-tions or dependent function types, both of which bind variables. For example,(𝜆x.x+0) =N (𝜆x.x) and ((x : N)→ Vec N (x+0)) =Type ((x : N)→ Vec N x) arewell-formed types. Extensional equality of functions, even up to partial information,is undecidable. Comparing functions syntactically, by directly comparing boundvariables, is decidable. Such a notion works for compile-time consistency checks,but would be problematic during run-time checks, since it destroys static reason-ing principles. Observationally equivalent terms in the static language could bedistinguishable in the gradual language, because a dynamic type check can agthem as being syntactically di erent e.g., replacing 𝜆x .x +x with 𝜆x .2∗x cancause new dynamic errors. A language that dynamically compares terms withbound variables is impractical: it cannot be easily compiled to e cient code, sinceevery function now needs a syntactic representation that persists at run time.Even worse, Lennon-Bertrand et al. [87] show that when re is the only staticconstructor for propositional equality, it is not possible to include said equalitytype in a gradual language while respecting static equivalences.Our key insight is to represent an equality proof using a witness that capturesequality constraints discovered at run time. We do so with a Gradual languagewith propositional Equality (GEq ), pronounced “geek”, which adds propositionalequality to gcic, allowing =, re and J to be used like in the Calculus of InductiveConstructions (CIC), but with a dynamic semantics that is meaningful for gradualtypes. Taking inspiration from evidence in Abstracting Gradual Typing ( agt) [67] and middle-types in threesomes [135], we represent witnesses with a termthat is as precise as both equated terms. As a consequence, re and ? are not theonly inhabitants of the equality type, avoiding the above impossibility result.is chapter is structured as follows:• We demonstrate how equality proofs between imprecise terms are useful fordiscovering bugs in programs and for guiding the development of static proofs(Section 5.2);• We extend gcic with propositional equality (Section 5.3) by typing equality us-ing consistency witnesses between terms (Section 5.3.2). We give operationalsemantics via a cast calculus, where the eliminator for equality uses casts go-131ing through the result type given by the witness (Section 5.3.3). To combinewitnesses when casting between equality types, we add witness compositiondirectly as a construct in GEq (Section 5.3.4). is operator delays the compar-ison of neutral terms until their variables are bound to values, so composingstatically equivalent functions does not raise an error;• We prove type safety, conservative extension of cic, weak canonicity, and thegradual guarantees for GEq (Section 5.4), so imprecision never causes stuckstates or new (static or dynamic) errors, and GEq rejects ill typed cic programs.Like Siek and Chen [131], our proofs are parameterized over de nitions of con-sistency and precision, revealing su cient properties to prove the theorems;• We de ne precision and consistency for the cast calculus (Section 5.5), showingthat they ful ll the previously identi ed properties. We separate static consis-tency, whether a term of some type can be used in a given context, from dynamicconsistency, whether two terms compose without error. ese coincide for non-dependent gradual languages, but in GEq they must be separated to respectstatic equivalences while still rejecting ill typed static programs.• Section 5.6 discusses extensions enabled by GEq’s features, along with relatedand future work.5.2 Se ing The Stage5.2.1 Programming vs. Proving and the Gradual Guaranteesough programming and proving are connected by the Curry-Howard corre-spondence, the pragmatics of proving and programming are somewhat di erent.Our focus is dependently typed programming: we consider GEq as a model of aprogramming language rather than as a type theory for mechanizing mathemat-ics. Nevertheless, we prove important metatheory about GEq that may aid in thedevelopment of future gradual type theories.One goal withGEq is proving the gradual guarantees of Siek et al. [136], whichstate that a reduction in precision introduces no new static or dynamic errors.ese guarantees are useful for programming because of the contrapositive: if a132program has a type error, adding more type information does not remove the er-ror. e types are fundamentally inconsistent and must be changed. By contrast,current implementations of holes either block reduction, causing errors, or blocktype checking, hiding errors that would otherwise be statically detectable.5.2.2 Relationship to Existing LanguagesGEq builds o the languages of Chapters 3 and 4, gdtl [58] and gcic [87]. Sec-tion 5.6.3 gives a broader discussion of related work.From Gradual Dependently Typed Language ( gdtl ), GEq inherits ? and thegeneral model of imprecise terms and types. Since it is based on agt [8, 67],gdtl features ideas similar to GEq’s witnesses. However, the original presenta-tion only discuss equality and inductive types as an extension, omi ing it fromtheir metatheory. Also, gdtl uses naive syntactic composition, and su ers fromthe issues we discuss in the introduction: fully static terms that are observation-ally equivalent in the static language may have di erent run-time behaviour inthe gradual language.Unlike gdtl, gcic uses a cast calculus approach, extending a restricted ver-sion of CIC with inductive types but no indexed inductive families or proposi-tional equality. GEq is a direct extension of gcic. e gcic authors prove that nogradual language can simultaneously conservatively extend cic, have strong nor-malization, and have graduality, a strengthening of the gradual guarantees wheredecreasing then increasing precision produces an equivalent term. e authorsgive three variants of gcic, called gcicG , gcicN and gcic↑, which respectivelysacri ce one of strong normalization, graduality, and conservative extension ofcic, while keeping the other two properties. We extend gcicG because, of thethree options, we feel that sacri cing strong normalization is most palatable forprogramming. gcicN violates the gradual guarantees, and gcic↑ is too restrictivefor practical programming, so we avoid them both. Logical inconsistency andpossibly-diverging proofs are not as detrimental in programming as in mecha-nized mathematics: type safety is still guaranteed, and errors due to divergingproofs are likely to be discovered when a program is run.gcic has no dedicated equality type, but we should be clear that reasoning133about equality is not totally unsupported. Programmers can write their owndecidable equality: a function that takes two elements of a type, and produces atype that is inhabited if and only if they are equal. e programmer must con-struct, either manually or with tactics, an equality function for each type whoseterms they wish to equate, along with the corresponding elimination principle.Most function types have undecidable equality, and hence are unsupported by thismethod. Also, common functions on equalities cannot be expressed in their mostgeneral form with this method, such as cong : (f : T→ S)→ a =T b→ f a =S f b.Full propositional equality is more convenient for the programmer.5.2.3 A Motivating Example: Eagerly Enforcing SpecificationsIn this section, we motivate our development with examples of how gradual de-pendent types can catch errors related to the lengths of lists. A guiding principle ofthis chapter is that, to the extent possible, the types the programmer writes shouldbe treated as speci cations to be checked, either statically or dynamically. esechecks should happen regardless of whether their enforcement is required forsafety. We revisit the quicksort example of Section 1.3.1.1, but instead of vectors,use the equivalent type of xed-length lists. ough the notation is more cumber-some, the advantage is that, unlike Section 3.2, we no longer need to hand-waveover the lack of support for indexed families. e terms in the following examplescan actually be wri en using the features of GEq.5.2.3.1 A Buggy icksortOnce again we start with quicksort, but this time, we begin with code containing amistake, to show how gradual dependent types can possibly help the programmernd bugs:sort : List Float→ List Floatsort Nil = Nilsort (Cons h t) =(sort (filter (< h) t)) + [h] + (sort (filter (> h) t))134Since < is used instead of ≤, duplicates are erroneously removed from the list. eprogrammer may have a suspicion that they have made a mistake in their code, ormay have observed incorrect behaviour while testing. eir dependent type en-thusiast friends have repeatedly assured them that dependently typed languagescan help eliminate bugs, so they try migrating their code to a dependently typedlanguage with propositional equality.Just like we used vectors in Section 1.3.1.1, an approach to producing a bug-free quicksort is to use Fixed-length Lists, which we call FLists. Dependent pairsand propositional equality allow for a type of lists indexed by their length. Fixedlength lists are the dependent-pair version of vectors from Section 1.3.1.1, whichwe avoid in order to stay strictlywithin the features ofGEq. Full inductive familiesare discussed in Section 5.6.1.Figure 5.1 shows the de nition of FList, and how it can be used to expressthat sort should preserve the length of the produced list. Here, refl is the re exiveproof that t is equal to itself. at sort function behaves like the non-dependentversion, except it must extract the Lists from the FLists produced by the recursivecalls, and produce an FList with proof that the length is the same as the input.At this stage, the programmer must ll the hole ? by constructing a proofof type:length (Cons h t) =N length (sortLt+ [h] + sortGt).e programmer must prove that length t =N (length lt) + (length gt), but such aproof is impossible, due to the bug. Even if they had such a proof, they would needto then use the proofs from the recursive calls, plt and pgt, to relate the lengthsof lt and gt to the lengths of sortLt and sortGt.Development has now stopped: the programmer cannot run or test their codewithout the missing proof, and they are now cursing their type-theorist friend.For a non-buggy quicksort, one could construct the necessary proof, but doing sois di cult, particularly for a newcomer. e type checker does not detect the bug,so it does not inform the programmer that hole cannot be lled, and it cannot saywhich aspect of the proof is impossible.135FList : Type→ N→ TypeFList A n = ((x : List A)× length x =N n)sort : (n : N)→ FList Float n→ FList Float nsort 0 (Nil,p) = (Nil,p)sort (1+n) (Cons h t,p) =let lt = (filter (< h) t)(sortLt,plt) = sort (length lt) (lt, refl)gt = (filter (> h) t)(sortGt,pgt) = sort (length gt) (gt, refl)in (sortLt+ [h] + sortGt, ? )Figure 5.1: Sorting Fixed-Length Lists5.2.3.2 Gradual Types to the RescueGEq lets the programmer run and test sort before writing the missing proof,checking (within the limits of decidability) whether any static values could possi-bly replace imprecise types and proofs. In Fig. 5.1, replacing the hole with ?, theimprecise term,1 yields a complete, well typed GEq function that can be called,tested, or used in other modules.e bug- nding potential of gradual propositional equality is shownwhen weactually run the code. Like gcic, the run-time semantics of GEq are de ned viatype-directed elaboration to a Cast calculus with propositional Equality ( CastEq), in which all implicit conversions are replaced by explicit casts. During typechecking, ? is elaborated into the CastEq term:?n=Nlength (sortLt++ [h]++ sortGt)i.e., the least precise term of type n =N length (sortLt+ [h] + sortGt), which is1Each ? is actually ?@0, i.e., annotated with its type’s universe level. Our exposition omits levels;we explain them in Section 4.4.136not a value in CastEq. Instead, it reduces to the consistency witnessn&N length (sortLt+ [h] + sortGt)e operator & is the gradual composition operator, a rst-class version ofcomposition u from gdtl, which combines information statically known aboutits operands. Because types depend on terms, composition is not limited to types,but can combine terms of any type. e & operator is a syntactic construct ofCastEq, not a meta-operation like it is in existing literature [130, 135]. Reifying& into the object language is critical for composing functions (Section 5.2.4). Sincen is a variable, this composition expression does not reduce further.We can identify the bug once sort is applied to a concrete list. Consider theinput [2.2,1.1,3.3,2.2], which elaborates to [2.2,1.1,3.3,2.2] in CastEq. Applyingsort binds lt := [1.1] and gt := [3.3], giving a result list of [1.1,2.2,3.3]. en nis 4 and length (sortLt+ [h] + sortGt) is 3, so the witness for the result is thecomposition 4&N 3, which reduces to a run-time error.In a language without dependent types, this bug could be caught with testingor assertions. In GEq, however, dependent types provide a uni ed means of spec-ifying properties to be checked statically or dynamically. During development,types serve as assertions to be checked dynamically (or statically, if enough in-formation is present). When a program is completed and all uses of ? have beenremoved, those same types establish properties that have been statically veri ed.5.2.3.3 Witness Compositione key to nding the error above was tracking information with witnesses, andcombining those witnesses using the composition operator. While that composi-tion was a simple equality check, in general the composed values may be impre-cise, and the result is some value that is as precise as both inputs. e informationfrom the witness is used when eliminating an equality proof: when using a wit-ness tw of t1 =T t2 to rewrite a term of type P(t1) into P(t2), we rst cast to P(tw),then to P(t2). For a program with imprecise types or values, the witness retainsthe information gained by running the program, preventing unsafe execution, andinforming the programmer when a counter-example to an imprecise equality is137found.Here we present an example of a bug that is found, not because of safety, butbecause a remembered constraint was violated. Consider the following functions:zip : (n : N)→ FList A n→ FList A n→ FList (A×A) ntake : (n : N)→ (m : N)→ FList B (n+m)→ FList B nHere, zip takes two lists of exactly the same length, and produces a list of pairsof their elements, while take takes a list with at least n elements, and returns therst n elements of that list. Each function constrains the size of its input, so bytracking equality witnesses, we can also track these constraints and detect wherethey are incompatible. Now consider lists with imprecise types:list1 := ([1.1,2.2], re ?) : FList Float ?list2 := (Cons 1.1 ?, re ?) : FList Float ?For list1, we are converting a list of length 2 to a xed-length list of unknownlength, since 2 is consistent with ?. For list2, however, the length is truly imprecise,since its tail is the unknown term. We can zip these lists together aszip ? list1 list2 : FList Float ?producing another list of unknown length, since recursively applying zip to theunknown tail ? produces an unknown result. Applying take 3 to the result of zipis well typed, since the length ? is consistent with 3+ ?, i.e.,take 3 ? (zip ? list1 list2) : FList Float 3However, computing the witness ags an error.is error represents something deeper than a simple safety check: it detectsfundamental inconsistencies in statically-determined propositional equalities. Inthe absence of equality proofs, the call could run safely: Cons (1.1,3.3) ? would bea sensible result, having length consistent with 3. e witness composition is notjust checking if a list is empty before taking the head, or counting the elements138in the list before running take. Rather, the information added by zip, that thelist should have length 2, has been propagated using the list1 witness and com-posed with the conicting information. GEq uses witnesses to enforce impreciseequality constraints at run time.To understand how GEq detects this mismatch, we look at the result of elabo-rating to CastEq. Initially, list2 has 1+ ?N as the witness that ?N is equal to 1+ ?N.e result of zip has 2 as the witness of equality between ?N and ?N, since thatis the length of list1. is new witness was determined by composition: since1+ ?N is consistent with 2, this composition succeeds. (Using a Peano representa-tion of naturals, S(?) is consistent with S(S(0))) en, even though zip’s result hasa type that is consistent with what take expects, the run-time type informationremembers that zip constrained the list to have length 2. e result of zip is castto FList Float (3+ ?N), the type expected by take 3. e zip result has an equalityproof of type 1+ ?N =N ?N, which is cast to type 1+ ?N =N 3+ ?N. During this cast,the target value 3+ ?N is composed with the witness 2. Despite the imprecision,these values are not consistent, and composition produces an error: no value canreplace ? to make S(S(S(?))) equal to S(S(0)). We detail the semantics enabling thisin Section 5.3.With equality witnesses, we achieve more than type safety. From the gradualguarantees, we know the above code cannot possibly be made static by replacingthe ? uses with static terms. When a witness reduces to an error, the program isequating two terms that are fundamentally not-equal. So the gradual guaranteesnow inform about equality constraints, in addition to type constraints. eseconstraints are expressed through types, rather than some external language ofassertions.5.2.4 Lazily Enforcing Specs: Function Equalities and Extension-alityPropositional equality is not restricted to rst-order values like numbers or totypes with decidable equality. In particular, we can form equalities between func-tions, for which equality is not in general decidable. e following summarizeshow GEq handles propositional equality for functions without encountering the139impossibility result of Lennon-Bertrand et al. [87]. Consider the example they useto show the incompatibility between gradual typing and re-based equality:idN := (𝜆x .x) : N→ Nadd0 := (𝜆x .x +0) : N→ Ntest := 𝜆f . J ( .B) idN true f (re idN :: ? :: (idN =N→N f )) : (N→ N)→ BHere J is the eliminator for equality: we explain it fully in Section 5.3.2, but itsu ces to know that in this case, it uses a proof of type idN =N→N f to rewrite(𝜆 .B) idN to (𝜆 .B) f . e form :: denotes surface type ascriptions, which areelaborated to casts in the cast calculus. Both types reduce to B, but J only reducesif the equality proof reduces without error, which causes problems with test.Lennon-Bertrand et al. [87] show that test distinguishes idN and add0. WhenidN is given as an argument, casting re idN to ? then back to idN =N→N idN shouldproduce re idN . However, when add0 is given for f , the cast must fail, since recannot have type idN =N→N add0.is example captures the subtle way that gradual typing can observe infor-mation that is transparent to static programs. Since idN and add0 agree on all in-puts, they should be observationally equivalent, producing the same result in anycontext in which we use them. Violating this would mean that the embedding ofcic into gcic orGEq does not respect function extensionality, i.e., some statically-equivalent terms are distinguishable in the gradual language. Even though thereare dependent type theories in which extensionally equal functions are not prov-ably equivalent, the problem is that the gradual language has destroyed the abilityto mentally reason about equivalent pieces of code using principles from the staticlanguage.e rst key to ensuring such terms remain equivalent is the witness-basedrepresentation of equality. InCastEq, re is the only constructor for equality, butit takes an argument: the consistency witness for the equated terms. Moreover, itdoes not require the equated terms to be syntactically identical, only that the wit-ness be at least as precise as both of them. So re can have type idN =N→N add0.But what witness should be a ached to the proof of idN =N→N add0?e second key feature is the composition operator of CastEq, which is used140to build equality witnesses. Elaborating reidN creates witness idN. e cast toidN =N→N f composes that witness with the destination endpoints, idN and f ,yielding idN&N→N idN&N→N f . e semantics of & reduce this composition to𝜆x. (x&N x&N (f x)), similar to how a higher-order contract applied to a functionproduces a new function that checks the input and result [65]. Since & is an oper-ator in the language, the composition does not need to reduce further, but whenthe function is applied, it continues to reduce. e same holds when we replacef with idN or add0. Section 5.5 de nes precision such that x&N x&N f x is moreprecise than both x and f x, so the above composition is a valid witness. We de nesemantics for J so that when it is given the equality proof with the above witness,it reduces, so test reduces to true for both idN and add0.How can equating non-identical functions be safe, since deferring composi-tion means that we can prove an equality between unequal functions? As we sawwith sort above, J casts through the witness, so when functions are extension-ally non-equal, trying to prove equality between their results dynamically fails.Consider instead subadd1 := (𝜆(x : N).x−1+1). Since 0− t = 0 inN, subadd1 0 = 1.We can use the witness 𝜆x. (x&N x&N (subadd1 x)) to inhabit idN =N→N subadd1.However, if we try to use J to prove that idN 0 =N subadd1 0, the result substitutes0 for x in the witness, giving 0&N 0&N 1, which reduces to an error.e consequence of our approach is that GEq supports a limited form of ex-tensionality. Neutral terms, i.e., variables or terms for which reduction is blockedby one or more variables, always compose to a non-error, so we can build a wit-ness capturing the plausibility of equality between them, given partial informa-tion. at witness makes an equality proof constructible. Furthermore, any twofunctions with neutral bodies compose to a non-error. If the functions agree onall inputs, eliminating their equality never fails and the proof of equality can befreely used. If the functions disagree on some input, an error is raised when build-ing a term that relies on the functions producing the same value for said input.Since it is undecidable whether two functions agree on every input, this approachnds a balance between decidability and exibility.1415.2.4.1 Static vs. Dynamic Consistencye relationship between consistency and composition is complicated by depen-dent types. For non-dependent gradual types, the successful composition of twotypes usually implies that they are consistent. However, for GEq, two neutrals al-ways compose to a more-precise term. To conservatively extend cic, all ill typed(fully-static) cic programs must be ill typed in GEq, and an uninhabited cic typemust not be inhabited by any fully-static GEq terms. So GEq cannot have all neu-trals consistent: thiswould yield a fully-static proof of (𝜆x𝜆y.x) =T→T→T (𝜆x𝜆y.y).We resolve this tension with separate static and dynamic notions of consis-tency (Section 5.5). Terms are statically consistent if they are syntactically equalup to 𝛼-equivalence, reduction, casts, and occurrences of ?T. Terms are dynam-ically consistent if they compose without error, or equivalently, if there existsa non-error term as precise as both terms. Essentially, terms are dynamically-consistent if they are statically consistent in the non-neutral parts. e type rulesfor GEq use static consistency. Some pairs of terms are not statically consistent,yet still compose to a non-error term.To compare static and dynamic consistency, consider the ill typed cic termrefl : x =N y. When embedded into GEq, re : x =N y is still ill typed: the expectedtype of x =N y and the actual type of x =N x are not statically consistent, becausethe variables x and y are not identical. In CastEq, x and y are neutral, and hencedynamically consistent, meaning x&N y witnesses x =N y.Le ing neutrals be dynamically consistent does not interfere with conser-vatively extending cic. For conservative extension, every ill typed cic programshould be ill typed in GEq. In the absence of ?, pairs of de nitionally-unequalcic terms are statically inconsistent. While GEq gives re the same type as cic,CastEq lets re prove equality for dynamically consistent terms. However, dy-namic consistency does not let CastEq type any ill typed cic terms, because cicprograms are elaborated into a subset of CastEq where t only witnesses t =T tand all casts have the form 〈T⇐ T〉. e type (x : N)→ (y : N)→ (x =N y) is un-inhabited in cic, and while this type is inhabited in CastEq using witness x&N y,the use of &N puts the witness outside the static fragment of CastEq. e termx&N y does not correspond to any typed or ill typed cic program.142Static and dynamic consistency let us balance conicting goals. If all stati-cally inconsistent functions composed to an error, then statically-equivalent termswould not be gradually equivalent, making it harder to reason about programequivalence. Using dynamic consistency during type checking would not conser-vatively extend cic. By separating these, we obtain conservative extension, whiledynamically respecting all extensional equalities.5.3 Propositional Equalitye main contribution of this chapter is GEq: an extension of gcic with propo-sitional equality, where the information about an imprecise value accumulates atrun time to detect inconsistencies. We de ne GEq’s semantics using a cast cal-culus CastEq, which extends Cast calculus for the Gradual Calculus of InductiveConstructions ( CastCIC ) with equality.e core idea is that a surface-language proof of type t1 =T t2 is elaborated intoa witness for the consistency of t1 and t2. Much like evidence2 from agt [67] orthe middle-type from threesomes [135], the consistency witness between termsis a term that is at least as precise as either term. e standard equality proof,re t : t =T t, witnesses that t is consistent with itself, while the imprecise proof?t1=T t2 is witnessed by the least precise term that is dynamically consistent witht1 and t2. As a program runs, equality witnesses may take values between theseextremes, whichmay bemore precise than thewitness for re when t is imprecise.e technical challenge with adding propositional equality is determininghow to combine information represented by the equality witnesses. When cast-ing between types t1 =T t2 to t′1 =T t′2, both of which may be imprecise, we musttransform a witness tw for 𝑡1 =𝑇 𝑡2 into one for 𝑡 ′1 =𝑇 𝑡 ′2, but even though tw is asprecise as t1 and t2, it may not be as precise as t′1 and t′2. So we need a compo-sition operator that can take t′1, t′2 and tw and produce a term that is as preciseas all three. However, to respect static observational equivalences and avoid theproblems of Section 5.2.4, composition cannot be a syntactic meta-operation. eissue is with neutral terms, i.e., variables, or terms whose reduction is blocked by2Evidence is more complex in agt, since it can witness subtyping. Evidence for plausible equal-ity between types collapses to a single term as precise as the equated terms.143applying or eliminating a variable. Syntactic composition would require distinctneutral terms to compose to an error, but that would violate static equivalences.Along with composition, wemust dene a notion of precision that determinesvalid witnesses of consistency. For the evolution of type information to be mono-tone, the operator & should compute a lower bound with respect to this notionof precision. Computing the greatest lower bound prevents premature errors, al-though the proof that composition is the greatest lower bound is le to futurework. With non-dependent gradual types, precision can be de ned syntactically,by adding structural rules to t v ?T, but structural rules are not exible enough tohandle composition.e solutions to these two challenges are interdependent. We avoid the is-sues with syntactic composition by adding it as a separate syntactic construct toCastEq, so that composition of neutral terms is itself a neutral term. However, ifcomposition is a construct in CastEq, then precision must be de ned to accom-modate terms that feature composition, so composing two neutral terms producessomething that is actually as precise as those two terms. Precision must be de-ned to respect composition without losing its other important properties, suchas transitivity.is section gives typing and semantics for gradual propositional equality,where proofs of equality are represented by consistency witnesses, but at thispoint we leave the exact de nitions of consistency and precision unspeci ed. InSection 5.4, we describe the properties that consistency and precision should ful-ll to ensure that GEq satis es type safety and the gradual guarantees. Finally,Section 5.5 instantiates GEq with notions of precision and consistency that ful llour goals while ensuring decidable consistency-checking. We separate our pre-sentation in this way to motivate the choices we make in the design of precision,and to avoid monolithic proofs when developing GEq’s metatheory.Wewrite precision as Γ1 |Γ2 ` t1 v←−−→ t2 and consistency as t1 −→ t2, highlight-ing the operators in grey to indicate that their de nitions are not yet speci ed.e subscript−→ on −→ indicates that it is de nitional consistency, whose nameis chosen by analogy to de nitional equality, since the operands can be reducedbefore being compared structurally [92]. Precision is precision modulo conversion,meaning it is closed under the equivalence relation given by convertibility. Unlike144consistency, precision modulo conversion can look backwards in time, relatingterms that are the results of reducing syntactically-related terms, in addition torelating terms that are syntactically-related aer reducing. ankfully, this time-travelling relation is only needed for the theory, not to type check or elaborategcic programs. We discuss the need for this in Section 5.3.2. Precision takes twocontexts, as its operands must be typed in di erent contexts.5.3.1 GEq Syntax and TypingFigure 5.2 extends gcic to GEq by adding the equality type, introduction form,and eliminator. eir types are identical to what is expected in the static se ing.Again, because surface typing is de ned by elaboration, the given rules are actu-ally admissible lemmas. An equality type t1 =T t2 denotes equality between anytwo values of consistent types (because each endpoint is checked against T ). ere exive proof re t synthesizes type t =T t, so long as t is well typed at type T .e eliminator J takes a type TP parameterized over a value of type T 3, along withtwo values of type T . en, given a value of type [t1/x ]TP , and a proof teq thatt1 and t2 are equal, the elimination has type [t2/x ]TP . at is, if two values areequal, we can take any term whose type refers to the rst, and transform it into aterm whose type refers to the second. For the remainder of this dissertation, weuse the notation [𝑡/𝑥]𝑢 to denote the usual capture-avoiding substitution, not thehereditary substitution of Chapter 3.5.3.2 CastEq Syntax and TypingFigure 5.3 extends the CastCIC to CastEq by adding propositional equality andthe gradual composition operator. We extend the syntax for a static head h toinclude value constructors, not just types, which is useful when de ning the se-mantics of composition. A proof of re exivity is wri en as re (tw)`t1t2 , where t1and t2 are the equated terms, and tw is a witness of the (dynamic) consistency ofthose endpoints. We borrow the notation (tw)`t1t2 from agt to indicate that twcontains information supporting the (dynamic) consistency of t1 and t2. Compo-3 e full J in type theory parameterizes TP over the equality proof. Section 5.6.1.2 shows whythis is not needed for GEq.145t +F t =T t | ret | J(x.T , t1, t2, t3, t4)h +F =Γ ` teq⇒= t1 =T t2 Γ,x : T ` TP⇒Type TypeiΓ ` t1 ⇐ T Γ ` t2 ⇐ T Γ ` tP1 ⇐ [t1/x ]TPΓ ` J(x.TP , t1, t2, tP1, teq)⇒ [t2/x ]TPΓ ` t1 ⇐ T Γ ` t2 ⇐ T Γ ` T⇒Type TypeiΓ ` t1 =T t2 ⇒ TypeiΓ ` t ⇒ TΓ ` re t ⇒ t =T tFigure 5.2: GEq: Syntax and Typing Lemmassition is ascribed with the type of its arguments so that we can ascribe the properT when the composition of two terms steps to fT.Each new form also has an associated typing rule. CastComp synthesizes acomposition’s ascribed type when both arguments check against that type. InCastRefl, re (tw)`t1t2 synthesizes t1 =T t2 if the witness tw is as precise as botht1 and t2. In ElabRefl, re t is elaborated into re (t)`tt, i.e., a term serves as theinitial witness that it is equal to itself. If t is imprecise, casts applied to the equalityproof may produce more precise witnesses, but the programmer never constructsa witness directly.e typing rule for CastRefl induces constraints on our precision relation,which we note here so we can address them when fully de ning precision. Preci-sion must be closed under convertibility because, as Lennon-Bertrand et al. [87]note, syntactic precision is not preserved by stepping the less precise term. Since?T is less precise than x, the less precise term may reduce in a way that is blockedfor the other term. So for contextual steps to preserve CastRefl, the results ofstepping related terms must be related.5.3.3 Cast SemanticsMuch of the challenge with gradual equality is designing its dynamic semantics.In a fully static language, refl always equates identical values, so J performs nocomputation other than pa ernmatching on the proof of equality. In the presence146t +F t1 =T t2 | re(t)`t1t2 | J(x.T, t1, t2, t3, t4) | t1&T t2h +F 𝜆 | CD | re | =ElabReflΓ ` t _ t⇒ TΓ ` re t _ re (t)`tt ⇒ t =T tCastReflΓ ` tw ⇒ T Γ ` t1 ⇐ T Γ ` t2 ⇐ TΓ |Γ ` tw v←−−→ t1 Γ |Γ ` tw v←−−→ t2Γ ` re (tw)`t1t2 ⇒ t1 =T t2CastCompΓ ` t1 ⇐ TΓ ` t2 ⇐ TΓ ` t1&T t2 ⇒ TElabEqΓ ` T _ T⇒Type TypeiΓ ` t1_ t1 ⇐ T Γ ` t2_ t2 ⇐ TΓ ` t1 =T t2_ t1 =T t2 ⇒ TypeiCastEqΓ ` t1 ⇐ T Γ ` t2 ⇐ TΓ ` T⇒Type TypeiΓ ` t1 =T t2 ⇒ TypeiElabJΓ ` teq_ teq ⇒= t1 =T1 t2 Γ,x : T1 ` TP _ TP ⇒Type TypeiΓ ` t1_ t1 ⇐ T1 Γ ` t2_ t2 ⇐ T1 Γ ` tP1_ tP1 ⇐ [t1/x]TPΓ ` J(x.TP , t1, t2, tP1, teq)_ J(x.TP, t1, t2, tP1, teq)⇒ [t2/x]TPCastJΓ ` teq⇒= t1 =T t2 Γ,x : T ` TP⇒Type TypeiΓ ` t1 ⇐ T Γ ` t2 ⇐ T Γ ` tP1 ⇐ [t1/x]TPΓ ` J(x.TP, t1, t2, tP1, teq)⇒ [t2/x]TPFigure 5.3: CastEq: Syntax, Typing and Elaboration Rules147RedJJ(x.TP, t1, t2, tP1,re(tw)`t′1t′2 ){〈[t2/x]TP ⇐ [tw/x]TP〉〈[tw/x]TP ⇐ [t1/x]TP〉tP1RedEqGermt1 =T t2 ≠ germℓ (=)〈?Typeℓ ⇐ t1 =T t2〉t{〈?Typeℓ ⇐ ??Typeℓ =?Typeℓ ??Typeℓ 〉〈??Typeℓ =?Typeℓ ??Typeℓ ⇐ t1 =T t2〉tPropEqUnk?t1=Tt2 { re (t1&T t2)`t1t2PropEq(Unk,Err)ft1=Tt2 { re (fT )`t1t2RedCastEq〈t′1 =T′ t′2 ⇐ t1 =T t2〉re (tw)`t′′1 t′′2 { re ((〈T′⇐ T〉tw&T′ t′1&T′ t′2))`t′1t′2Figure 5.4: CastEq: Reductions for Casts and Equalityof type imprecision, J must perform casts. RedEqGerm casts an equality proof to?Typeℓ by casting through the germ type, just like with functions and constructors.We also need reductions for casts between equality types. Figure 5.4 givesreductions for J and casts. e RedJ rule reduces by casting through the motiveTP with x bound to the witness tw. e typing of equality guarantees that thiswitness tw is as precise as either t1 and t2. So [tw/x]TP is like a middle type, sinceit is more precise than [t1/x]TP (the type of tP1) and [t2/x]TP (the type of theresult).Why cast through the middle, and not directly from [t1/x]TP to [t2/x]TP?As Section 5.2.3 showed, the witness tracks constraints as the program runs, andsince composition is monotone, its precision only increases. So constraints are re-membered, and J only succeeds if the equated terms are consistent with all thoseremembered constraints, le ing the programmer see when a static constraint hasbeen dynamically violated. Also, the witness ensures that equalities between in-consistent values cannot be used without agging an error. Without a witness,one could have ?2=N5, despite the type being statically uninhabited. en J coulduse this equality to convert fromVec Float (2 mod 3) toVec Float (5 mod 3): thecast would succeed, despite the absurdity of the initial equality. Going through148the middle type catches such absurd cases.In addition to eliminating equality, we must also be careful when deningsemantics for the casts between equality types. e RedCastEq rule rst casts thewitness to the correct type. e typing rule CastRefl requires the witness to beas precise as the endpoints, but the result of casting the witness might not ful llthis! So the witness is composed with both endpoints, producing a precision-related result. ese casts are precisely why we need a composition operator.A key feature of GEq is that equality is, in some ways, treated as a negativetype. In particular, just like functions in gcic, there is no separate construct for ?or f. Instead, the propagation rules PropEqUnk and PropEqErr reduce ? and fat equality types to re with the least and most precise witnesses, respectively.5.3.4 Semantics of CompositionIn Fig. 5.5, we de ne the semantics for composing arbitrary CastEq terms. Tech-nically, we do not need composition as an operator in CastEq itself, but only forthe subset of GEq used in witnesses and cast type ascriptions. However, becausedependent types remove the separation between terms and types, witnesses andcast types need dynamic semantics. So for simplicity, we let witnesses and cast-types be any CastEq terms, and add composition to CastEq’s semantics, ratherthan duplicating CastEq’s semantics for a witness-speci c language.Several composition rules receive two or three di erent sets of type ascrip-tions, with one on the composition itself, and possibly one on each of the com-posed terms. In such cases, the choice of ascription in the reduct is arbitrary,because typing guarantees what value it should have, modulo conversion. Forexample, RedCompErrL uses the ascription from f, rather than what was on &.While we do not require that the ascriptions be syntactically equal, the typingrules ensure that syntactically distinct ascriptions are de nitionally equal, so thechoice of ascription in the reduct does not a ect the nal result of evaluation.Each composition rule resembles a uni cation rule, where each use of ? istreated as a uni cation variable. Terms that have di erent head tags composeto an error, and terms that have the same head tag compose by composing theirparts. Any place where one term has ?, but the other term contains more pre-149t1 { t2 (Composition reductions)RedCompUnkLUnkVal T?T&T′ t{ tRedCompUnkRUnkVal Tt&T′ ?T { tRedCompErrLUnkVal TfT&T′ t{ fTRedCompErrRUnkVal Tt&T′fT { fTRedCompGerm(〈?Typeℓ ⇐ germ(h)〉t1)&?Typeℓ (〈?Typeℓ ⇐ germ(h)〉t2){〈?Typeℓ ⇐ germ(h)〉(t1&germ(h) t2)RedCompGermErrh1 ≠ h2(〈?Typeℓ ⇐ germ(h1)〉t1)&?Typeℓ (〈?Typeℓ ⇐ germ(h2)〉t2){ f?TypeℓRedCompHeadErrhead(t1) = h1 head(t2) = h2h1 ≠ h2t1&T t2 { fTRedCompEqt′′1 := 〈T1&Typeℓ T2 ⇐ T1〉t1 &(T1&Typeℓ T2) 〈T1&Typeℓ T2 ⇐ T2〉t2t′′2 := 〈T1&Typeℓ T2 ⇐ T1〉t′1 &(T1&Typeℓ T2) 〈T1&Typeℓ T2 ⇐ T2〉t′2(t1 =T1 t′1) &Typeℓ (t2 =T2 t′2) { t′′1 =(T1&Typeℓ T2) t′′2RedCompReflre(t1)`tLtR &t′′L=Tt′′R re (t2)`t′Lt′R{ re (t1&T t2)`tLtRRedCompLamt1&(x:T1)→T2 t2{ 𝜆(x : T1). ((t1 x)&T2 (t2 x))RedCompIndC(−→t1 )&Typeℓ C(−→t2 ){ C(−→&(Params(C, i),−→t1 ,−→t2 ))RedCompConDC(−→t1 ,−→t2 )&C(−→𝑡 ′ )DC(−→t′′1 ,−→t′′2 ){ DC(−→t ,−→&(Args(C, i,Dk),−→t2 ,−→t′′2 ))RedCompPi(x : T1)→ T′1&Typeℓ (x : T2)→ T′2 {(x : (T1&Typeℓ T2))→[〈T1 ⇐ T1&Typeℓ T2〉x/x]T′1&Typeℓ [〈T2 ⇐ T1&Typeℓ T2〉x/x]T′2Figure 5.5: CastEq: Semantics for Composition150cise information, the precise information is retained in the output. We only ap-ply this rule for positive types (dened in Fig. 5.6) for which ? and f are values.Note that we consider equality a negative type, which is one of the insights thatmakes GEq work. e positivity restriction ensures that when t1&T t2 reduces,the result is a term that is as precise as both t1 and t2. For ?T &T t, we producet (RedCompUnk(L,R)), since t is always as precise as itself and ?T. Likewise, therules that produce f satisfy this, since it is the most precise term. We see this inRedCompUnk(L,R), which composes withf, and in RedCompHeadErr and Red-CompGermErr, where composing non-neutral terms with distinct heads reducesto f.e remaining rules compose terms with the same head h, such as when bothare functions or both are built with the same DC. In these cases, the head h isapplied to the respective composition of the arguments, e.g., the compositionof functions is a function returning the composition of the bodies. For equalityproofs and inhabitants of ?Typeℓ , the head can be applied directly (RedCompLam,RedCompRefl, RedCompGerm). In RedCompLam, composing functions yields anew function that composes the results of the given functions for each argument.In the remaining cases, we must account for how types of later arguments dependon the values of earlier arguments. RedCompPi produces a domain by composingthe argument domains, which is the type of the parameter x. e codomain x’seach have their own domain types, so we cast all uses of x from the composed typeto the expected type. RedCompEq composes equality types: the type ascriptionsare composed, then the equated terms are cast to this composed type. Composingthe results of these casts yields the result endpoints.e most complex rules are RedCompInd and RedCompCon. Because typeand data constructors have dependent function types, their arguments are tele-UnkVal T (Types with ? and f forms)UnkVal Typeℓ UnkVal C(−→𝑡 ) UnkVal ?TypeℓFigure 5.6: Positive Types151scopes: the type of later arguments may depend on the values of previous param-eters and arguments. To compose type or data constructor applications, we com-pose the parameters and arguments element-wise, but composing two argumentschanges the type of later arguments. To compose telescopes, the metafunction −→&traverses the types of type and data constructors, composing arguments element-wise and adding casts to the bound variables in later arguments (Fig. 5.7).To see why composing needs casts, consider dependent pairs formulated asan inductive type:data DPair : (X : Type)→ (P : X→ Type)→ Type wheremkDPair : (x : X)→ P x→ DPair X POne example of a dependent pair type is DPair (N×N) (𝜆x. (𝜋1 x) + (𝜋2 x) =N 3),i.e., the Curry-Howard equivalent of “there exists a pair of numbers such thatadding them yields 3.” Suppose we want to compose two inhabitants of this type,saymkDPair (1,?N) re(3)`1+?N3 andmkDPair (?N, 2) re (3)`?N+23. To composethe rst element, we can produce (1&N ?N,?N&N 2), which reduces to (1,2). How-ever, for the second element, the two proofs re (3)`1+?N3 and re (3)`?N+23 donot have the same type: they equate di erent terms, so we cannot compose them!Instead, we must rst cast each to type (1&N ?N) + (?N&N 2) =N 3, i.e., the valueobtained by replacing x with the composition of the pairs’ rst elements in theterm ((𝜋1 x) + (𝜋2 x) =N 3). e nal result is then mkDPair (1,2) (re (3)`33).−→&(−−−−→(x : T),−→t1 ,−→t2 ) (Telescope Composition)−→&(·, ·, ·) := ·−→&((x : T1) · −−−−−→(y : T2), t1 ·−→t′1 , t2 ·−→t′2 ) :=(t1&T1 t2) ·−→&(−−−−−−−−−−−−−−−−−−→(y : [(t1&T1 t2)/x]T2),𝑠𝑒𝑞1,𝑠𝑒𝑞2)where 𝑠𝑒𝑞1 :=−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→〈[(t1&T1 t2)/x]T2⇐[t1/x]T2〉t′1𝑠𝑒𝑞2 :=−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→〈[(t1&T1 t2)/x]T2⇐[t2/x]T2〉t′2Figure 5.7: Telescope Composition1525.4 Parameterized Metatheory: Criteria for Precisionand ConsistencyGEq is now dened except for CastEq’s precision and consistency relations. Fornon-dependent languages, the semantics of precision can be justi ed either interms of sets of static terms [67] or in terms of semantic precision [105]. Suchjusti cations are di cult with dependent types. Our approach is di erent: wede ne the important metatheoretic criteria forGEqwithout referring to precisionand consistency, then describe the criteria precision and consistency must ful llto prove the desired metatheoretic properties. Meeting these criteria guides andjusti es our de nition of precision and consistency (Section 5.5). We see precisionand consistency as a means to the end of the desired metatheory.5.4.1 Stating the Gradual GuaranteesTo state the gradual guarantees formally for GEq, we must de ne what precisionmeans for surface terms. We follow Lennon-Bertrand et al. [87] and de ne surfaceprecision as the relation generated by t vSurf ?@i, plus all the usual structural rules.Essentially, t vSurf t ′ holds if we can obtain t ′ by replacing some parts of t withsome ?@i. To guarantee preservation of typing, we also need such replacements tobe universe adequate [87]. We say that the judgment t vSurf t ′ is universe adequateif, for every subterm r of t, when Γ ` r_ r⇒ T and Γ ` T⇒Type Typei, then anyuses of r vSurf ?@j have i = j. is essentially says t is t ′ with some subtermsreplaced by ?@i for the right i. We can now state the static gradual guarantee:De nition 5.4.1 (Static Gradual Guarantee). If · ` t : T and t vSurf t ′ universe-adequately, then · ` t ′ : T .at is, reducing the precision of a program causes no new type errors.To state the dynamic guarantee without referring to CastEq precision, wemust formalize what it means to introduce no new dynamic errors. We followNew and Ahmed [105] and do this with semantic precision, which compares termsby quantifying over all possible boolean contexts. We use booleans because oftheir simplicity: gradual booleans have only the four values true, false, ?B andfB. If a context exists such that reducing a term’s precision changes the result153from true to false, then we have violated the guarantee that precision only aectsbehaviour via errors. Likewise, if a context exists such that reducing precisionturns true to fB, then reducing precision introduced a new error. By de ningsemantic precision in terms of all contexts, we capture the idea that the above be-haviours are impossible for precision-related terms. We formalize this as follows:De nition 5.4.2 (Semantic Precision). Boolean precision vB is de ned by:true vB truefalse vB falsefB vB bb vB ?Bfor all b : B. en two closed terms are related by semantic precision, wri en  t v t′ : Tif, for all 𝐶 : T→ B, whenever 𝐶 [t] −→∗ b, then 𝐶 [t′] −→∗ b′ and b vB b′.en the gradual guarantee states that reducing a surface term’s precisioncauses a corresponding reduction in the semantic precision of the surface terms’elaborations.De nition 5.4.3 (Dynamic Gradual Guarantee). Suppose · ` t _ t ⇐ T and · `t ′_ t′⇐ T. If t vSurf t ′ universe-adequately, then Γ  t v t′.5.4.2 Necessary Properties of Precision and ConsistencyNext, we list properties that, if satis ed by the v←−−→ and −→ referred to inthe CastEq typing rules, su ce to prove type safety, conservative extension ofcic, well typedness of elaboration, and the gradual guarantees. Each criterionis accompanied by a speci c case of the safety or gradual guarantee proofs thatmotivates its inclusion. We also include criteria that composition should satisfy.While the semantics appear in a prior section (Section 5.3.4), the criteria are newfrom gcic, so we list them to highlight our contribution.ough v←−−→ is ideal for typing witnesses, it is too lenient to express themonotonicity properties of CastEq. In particular, if the monotonicity of reduc-tion is phrased with v←−−→ , then consistency must also be closed under convert-154ibility, which would make it undecidable even when its operands terminate. Sowe introduce a strictly stronger relation v−→ which, like −→ , only comparesaer reductions, and not before. is distinction is acceptable because the preci-sion side-condition of CastRefl is never used to prove safety or monotonicity.Rather, the side-condition ensures that witnesses always entail at least as muchinformation as the equated terms. Including the side-condition in CastEq’s typeconveniently captures the invariant that, when re t is elaborated with initial wit-ness t, future witnesses are never lose the information from t. Moreover, this sidecondition justi es having ?t1=Tt2 reduce to re (t1&T t1)`t1t2 , since it is the leastprecise well typed term of type t1 =T t2.5.4.2.1 Safety and ElaborationFor elaboration to preserve types, precision must be re exive so the initial wit-ness for re is valid. For safety, progress requires that each well typed non-valuecan step. So composition must step for each non-value. For preservation, eachreduction must preserve types, including composition reductions. If compositionyields a precision lower-bound and precision is transitive, the side-conditions ofCastRefl can be preserved.Lemma 5.4.4 (Precision Re exive). If Γ ` t⇐ T then Γ |Γ ` t v−→ t (For ElabReflto produce an elaboration that satis es the v−→ side-condition of CastRefl).Lemma 5.4.5 (Composition Safety). If t1&T t2 is not a value and Γ ` t1&T t2 ⇐ T,then t1&T t2 −→ t3 for some t3 and Γ ` t3 ⇐ T (For progress and preservation)Lemma 5.4.6 (Composition Con uence). If t1&T t2 V t3 and t1&T t2 V t′3 maxi-mally, then t3 V t′3, where V is the parallel reduction relation, standard in con u-ence proofs [143] (For con uence, which is needed to show that 𝛽-reductions preservetypes);Lemma 5.4.7 (Composition Lower Bound). If Γ ` t1&T t2 ⇐ T, then Γ |Γ ` t1&Tt2 v−→ t1 and Γ |Γ ` t1&T t2 v−→ t2 (Preserving the v←−−→ condition of CastRefl forreduction RedCastEq);155Lemma 5.4.8 (Precision Transitive). If Γ1 |Γ2 ` t1 v−→ t2 and Γ2 |Γ3 ` t2 v−→ t3 : Tthen Γ1 |Γ3 ` t1 v−→ t3 (Preserving the v←−−→ side-condition ofCastRefl for reductionRedCastEq);Lemma 5.4.9 (Precision Modulo Conversion). If Γ1 |Γ2 ` t1 v←−−→ t2, where t2 −→∗t′2, then Γ1 |Γ2 ` t1 v←−−→ t′2 (Preservation of CastRefl under contextual reduction)5.4.2.2 ConservativityIf GEq is to conservatively extend cic, then a fully static program should be welltyped in cic if and only if it is well typed in GEq. For the most part, the rulesonly dier when ? is involved, but the major exception is ElabCst, which let usreplace a typewith any consistent type (a er conversion). So for fully static terms,consistency should coincide with syntactic equality.Lemma 5.4.10 (Static Consistency). For any static terms t1 and t2, let t1 and t2 betheir embedding in CastEq. en t1 −→ t2 i t1 =𝛼𝛽 t2, i.e., if they are staticallyde nitionally equal (For GEq to conservatively extend cic).5.4.2.3 Monotonicitye last group of properties relate to the gradual guarantees. e dynamic gradualguarantee requires that evaluating precision-related terms produces precision-related results. Because of the dependency in dependent types, proving the staticguarantee relies on the proof of the dynamic guarantee: ElabCst reduces typesbefore comparing for consistency, so precision of types before reduction should bepreserved, and reducing the precision of a type should make it consistent with nofewer types. Likewise, to show the static guarantee, elaboration must be mono-tone in both synthesized types and elaborated terms, since dependent applicationuses the argument’s elaboration in the return type.Lemma 5.4.11 (Cast Monotonicity). Suppose that Γ1 |Γ2 ` t1 v−→ t2, Γ1 ` t1 ⇒ T1and Γ2 ` t2 ⇒ T2 where Γ1 |Γ1 ` T1 v−→ T′1 and Γ2 |Γ2 ` T2 v−→ T′2. en Γ1 |Γ2 `〈T′1 ⇐ T1〉t1 v−→ 〈T′2 ⇐ T2〉t2 (For ElabCst to produce v−→ -related elaborationsfor vSurf-related inputs)156Lemma5.4.12 (SubstitutionMonotone). Suppose Γ1 |Γ2 ` t1 v−→ t2, where Γ1 ` t1 ⇒ T1and Γ2 ` t2 ⇒ T2. If Γ1(x : T1)Δ1 |Γ2(x : T2)Δ2 ` t′1 v−→ t′2,then Γ1 [t1/x]Δ1 |Γ2 [t2/x]Δ2 ` [t1/x]t′1 v−→ [t2/x]t′2 (For ElabApp to be monotonein the return type)Lemma 5.4.13 (Reduction Monotone). If Γ1 |Γ2 ` t1 v−→ t2 and t1 −→∗ t′1, thent2 −→∗ t′2 for some t′2 where Γ1 |Γ2 ` t′1 v−→ t′2 (For DGG, to preserve ElabCst whenreducing precision, and to preserve typing under contextual reduction ofre(tw)`t1t2 )Lemma 5.4.14 (Consistency Monotone for Precision). If Γ |Γ ` t1 v−→ t′1 andΓ |Γ ` t2 v−→ t′2, and t1 −→ t2, then t′1 −→ t′2 (So reducing precision of V and V′preserves ElabCst)Lemma 5.4.15 (Structural Precision). v−→ contains all structural rules (For ho-momorphic elaboration rules to produce v−→ -related elaboration for vSurf-relatedinputs)5.4.3 Metatheory: Proving Safety and the Gradual GuaranteesFinally, we summarize the properties that we can prove by assumingGEq satis esthe criteria of Section 5.4.2. e general idea is that each case in the proofs either(1) is the same as the proof for gcic [87] or (2) follows directly from one of ourcriteria.5.4.3.1 Type SafetyType safety is shown in the usual way for operational semantics, via progress andpreservation [155]. Each well typed CastEq term is either a value, or can step toa well typed term. Con uence is necessary to prove preservation for dependenttypes. e idea is to follow Lennon-Bertrand et al. [87], adding t1&T t2 as valuewhen t1 and t2 are values, neither of t1 and t2 is ? or f, and T is not a functiontype.157Lemma 5.4.16 (Conuence, Progress, Preservation and Elaboration). e follow-ing hold:• −→ is con uent.• If Γ ` t⇐ T, then t is a value or t −→ t′ for some t′.• If Γ ` t1 ⇐ T and t1 −→ t2 then Γ ` t2 ⇐ T.• If Γ ` t_ t⇐ T, then Γ ` t⇐ T.See proof in Appendix A .ese together yield the main safety theorem.eorem 5.4.17 (Type Safety). If · ` t : T , then t has an elaboration that eithersteps to a normal form or steps inde nitely.As a corollary, we can perform inversion on the typing derivations to obtainweak canonicity. at is, every well typed closed term that terminates steps to acanonical term of its type.Corollary 5.4.18 (Weak Canonicity). Suppose · ` t : V. en either t diverges, ort −→∗ v where v is ?V or fV, or the following hold:• If V is (x : T1)→ T2 then v is 𝜆x. t′• If V is C@{i}(−→t1 ) then v is DC@{i}(−→𝑡2 ) for some D.• If V is t1 =T′ t2 then v is re (t′)`t1t2• If V is Typei then v is one of C@{i}(−→t1 ), (x : T1)→ T2, Typei−1 or t1 =T′ t2.See proof in Appendix A .5.4.3.2 Conservatively Extending cicEach cic rule has a direct analogue in CastEq, so it is clear that it extends cic.Since most of the gradual-speci c rules refer to ? or f, knowing that consistencycollapses to 𝛼-equivalence on static terms is enough to show that said extensionis conservative.158eorem 5.4.19 (Conservativity). For any the Bidirectional Calculus of InductiveConstructions ( bcic )-terms t and T, let t and T be the GEq terms corresponding tot and T by mapping bcic 𝜆 to GEq 𝜆, etc. en · ` t⇐ T i · ` t : T .See proof in Appendix A .5.4.3.3 Gradual GuaranteesTo prove the gradual guarantees, we use the gradual criteria to show that elabora-tion is monotone. is, when combined with the monotonicity of{ with respectto semantic precision, gives us both the static and dynamic guarantees.Lemma5.4.20 (ElaborationGradual Guarantee). Suppose t1 vSurf t2 and Γ1 v−→ Γ2(i.e. entries in Γ1 and Γ2 are respectively related by v−→ ). en:• If Γ1 ` t1_ t1 ⇐ T then Γ2 ` t2_ t2 ⇐ T for some t2 where Γ1 |Γ2 ` t1 v−→ t2.• If Γ1 ` t1 _ t1 ⇒ T1 then Γ2 ` t2 _ t2 ⇒ T2 for some T2, t2 where we haveΓ2 ` T2⇒Type Typeℓ and Γ1 |Γ2 ` t1 v−→ t2.See proof in Appendix A .When combined with the preservation of precision under evaluation, thisis enough to prove the static and dynamic gradual guarantees as stated in Sec-tion 5.4.1. e hard work lies in proving that reduction preserves precision, whichwe leave to Section 5.5.3.5.5 Consistency and PrecisionMotivated by the criteria of Section 5.4.2, in this section we extend gcic’s preci-sion and consistency relations to accommodate propositional equality and com-position. We show that our relations ful ll the laws of Section 5.4.2, thus showingthat GEq ful lls type safety and the gradual guarantees, justifying the design ofprecision and consistency.1595.5.1 Precision and Consistency in gcicFigures 5.8 and 5.9 present structural precision from gcic, wrien as Γ ` t1 v𝛼 t2.Structural precision is the syntactic relation out of which de nitional precisionv−→ is built. e generating rules GenUnk andGenErr establish ?T andfT as theleast and most precise terms of type T. We include GenUnkUniv for consistencywith gcic, allowing some cumulativity for ?Typej . e rule GenErrLam encodes aversion of𝜂-expansion for errors. e diagonal rules (namedDiag*) are structural:terms are precision related if they are built with the same syntactic construct andthe corresponding sub-terms are precision-related. Finally, cast rules capture non-structural properties of casts. Rule Cast-L states that a casting t is more precisethat t′ if the cast’s source and destination types are both more precise than thetype of t′, and if t is more precise that t′. e rule Cast-R says the opposite:casting t is less precise than t if the source and destination are both less precisethan the type of t and t itself is less precise than t′.To use structural precision in GEq, we make one major change from the orig-inal presentation in gcic. In place of type synthesis, we use presynthesis, wri enΓ ` t ⇒∗ T, which is de ned to be exactly the type synthesis relation withoutthe v←−−→ side-condition in CastRefl. Presynthesis types strictly more termsthan synthesis, and both produce the same type, since they di er only in side-conditions. e side-condition is not used in the type-safety proof, so any run-time terms that presynthesize a type are safe. Unlike gcic, GEq uses precisionto type equality witnesses, so presynthesis avoids a circular dependency betweentyping and precision.Structural precision is de ned mutually with de nitional precision (Fig. 5.10)v−→, which acts as v−→ from Section 5.4. De nitional precision allows reduc-ing before comparing, and is used with type ascriptions, such as for functions,equality proofs and casts. Since the checking rule for CastCIC allowed arbitraryreductions, a term may be well typed even if its type ascriptions are not fullyreduced. Type ascriptions on a term may need to be reduced before structuralprecision is apparent. is de nition is due to Lennon-Bertrand et al. [87].160Γ ` t1 v𝛼 t2 (Precision: Generating and Cast Rules)GenUnkΓ1 ` t⇒∗ T′Γ1 |Γ2 ` T′v−→TΓ1 |Γ2 ` t v𝛼 ?TGenErrΓ1 ` t⇒∗ T′Γ1 |Γ2 ` Tv−→T′Γ1 |Γ2 `fT v𝛼 tGenUnkUnivΓ1 ` T⇒∗Type Typeii < jΓ1 |Γ2 ` T v𝛼 ?TypejCastLΓ2 ` t2 ⇒∗ T2Γ1 |Γ2 ` T1v−→T2Γ1 |Γ2 ` T′1v−→T2 Γ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` 〈T′1 ⇐ T1〉t1 v𝛼 t2CastRΓ1 ` t1 ⇒∗ T1Γ1 |Γ2 ` T1v−→T2Γ1 |Γ2 ` T1v−→T′2 Γ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` t1 v𝛼 〈T′2 ⇐ T2〉t2GenErrLamΓ2 ` t2⇒∗Π (x : T2)→ T′2Γ1 |Γ2 ` (x : T1)→ T′1v−→(x : T2)→ T′2Γ1 |Γ2 ` 𝜆(x : T1).fT′1 v𝛼 t2Figure 5.8: Structural Precision: Generating and Cast Rules5.5.2 Precision and Consistency for GEqe structural precision laws are not su cient for handling composition. In par-ticular, we want Γ |Γ′ ` t1&T t2 v t1, with the same holding for t2. However, thisfact is not derivable from the diagonal rule for composition. Instead, we must addrules to ensure that composing produces a lower bound. However, once we startadding non-structural rules, we must be careful not to disrupt the other prop-erties we need from precision. For example, Section 5.4.2 states that precisionmust be transitive. If (x&T y)&T z v x&T y and x&T y v x, but we also want(x&T y)&T z v x, then we must transitively apply the fact that composing pro-duces a lower bound.Figure 5.11 shows the precision rules for GEq’s new language forms. Di-agRefl, DiagComp, DiagEq and DiagJ are like the other diagonal rules. erules PrecCompL and PrecCompR encode that the composition is a precision-lower bound, but in a way that preserves transitivity. e rules for v←−−→, usedto de ne valid witnesses, are given in Fig. 5.12: structural rules can be applied161Γ ` t1 v𝛼 t2 (Precision: Diagonal Rules for gcic forms)DiagVarΓ1 |Γ2 ` x v𝛼 xDiagAbsΓ1 |Γ2 ` T1v−→T2Γ1, (x : T1)|Γ2, (x : T2) ` t1 v𝛼 t2Γ1 |Γ2 ` 𝜆(x : T1). t1 v𝛼 𝜆(x : T2). t2DiagCastΓ1 |Γ2 ` T1 v𝛼 T2 Γ1 |Γ2 ` T′1 v𝛼 T′2Γ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` 〈T′1 ⇐ T1〉t1 v𝛼 〈T′2 ⇐ T2〉t2DiagEqΓ1 |Γ2 ` T1v−→T2Γ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` t′1 v𝛼 t′2Γ1 |Γ2 ` t1 =T1 t′1 v𝛼 t2 =T2 t′2DiagIndΓ1 |Γ2 ` −−−−−→t1 v𝛼 t2Γ1 |Γ2 ` C@{i}−→t1 v𝛼 C@{i}−→t2DiagConsΓ1 |Γ2 ` −−−−−→t1 v𝛼 t2 Γ1 |Γ2 `−−−−−→t′1 v𝛼 t′2Γ1 |Γ2 ` DC( −→t1 ,−→t′1 ) v𝛼 DC( −→t2 ,−→t′2 )DiagAppΓ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` t′1 v𝛼 t′2Γ1 |Γ2 ` t1 t′1 v𝛼 t2 t′2DiagUnivΓ1 |Γ2 ` Typeℓ v𝛼 TypeℓDiagProdΓ1 |Γ2 ` T1 v𝛼 T2Γ1, (x : T1)|Γ2, (x : T2) ` T′1 v𝛼 T′2Γ1 |Γ2 ` (x : T1)→ T′1 v𝛼 (x : T2)→ T′2DiagFixΓ1 |Γ2 ` s v𝛼 s′Γ1 ` s⇒∗CC(−→𝑎 ) Γ2 ` s′⇒∗CC(−→𝑎′) Γ1, (z : C(−→𝑎 ))|Γ2, (z : C(−→𝑎′)) ` P v𝛼 P′Γ1, (f : (z : C(−→𝑎 ))),−−−−−−−−−−→(y : Yk [a/x])|Γ2, (f : (z : C(−→𝑎′))),−−−−−−−−−−−→(y : Yk [a′/x]) ` tk v𝛼 t′kΓ1 |Γ2 ` indC(s,z.P, f .y.t) v𝛼 indC(s′,z.P′, f .y.t′)Figure 5.9: Precision: Diagonal Rules for gcic forms162Γ1 |Γ2 ` t1v−→t2 (Denitional Precision)DefBaseΓ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` t1v−→t2DefStepLt1 −→ t′1Γ1 |Γ2 ` t′1v−→t2Γ1 |Γ2 ` t1v−→t2DefStepRt2 −→ t′2Γ1 |Γ2 ` t1v−→t′2Γ1 |Γ2 ` t1v−→t2Figure 5.10: De nitional Precision(PrecModStruct), and as with v−→ they allow for reductions before compar-ing with structural precision (PrecModStelP, PrecModStelR). ey also allowbackwards steps (PrecModStepBack), ful lling Lemma 5.4.9. We only allowbackwards-steps for the less precise term, since backwards steps on the le -handare admissible by Lemma 5.4.13.Last are the rules for (static) consistency for equality and composition (Fig. 5.13).Recall that Section 5.4.2 requires that reducing precision preserves consistency.Since composition is as precise as both its arguments, t1&T t2𝛼 t3 should implythat t1 and t2 are both consistent with t3. We conjecture that composition is a(semantic) greatest lower bound, which would mean that errors in composingwitnesses are never agged earlier than necessary. For this to hold, the composi-tion of two terms must be consistent with everything that is consistent with bothof those two terms. Our composition consistency rules express this: CstCompLand CstCompR ensure that t1&T t2 is consistent with exactly the terms that areconsistent with both t1 and t2.With consistency fully de ned, the di erence between static and dynamicconsistency is now clear: two terms that share a non-error lower-bound may bestatically inconsistent if they di er only in neutral terms. Variables are only stat-ically consistent with themselves (CstVar) or ? (CstUnkL,R). However, for anytwo variables x and y, x&Ty is a non-error term that is as precise as both, as givenby PrecComp(L,R). is disconnect between precision and consistency is justi edby the criteria of Section 5.4.2: we show below that reducing precision preservesconsistency. e separation of static and dynamic consistency enables the grad-ual guarantees and conservatively embedding cicwhile maintaining static equiv-alences.163DiagReflΓ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` t′1v−→t′2 Γ1 |Γ2 ` t′′1 v−→t′′2Γ1 |Γ2 ` re(t1)`t′1t′′1 v𝛼 re (t2)`t′2t′′2DiagCompΓ1 |Γ2 ` T1 v𝛼 T2 Γ1 |Γ2 ` t1 v𝛼 t2 Γ1 |Γ2 ` t′1 v𝛼 t′2Γ1 |Γ2 ` t1&T1 t′1 v𝛼 t2&T2 t′2PrecCompLΓ1 |Γ2 ` t1 v𝛼 t3Γ1 |Γ2 ` t1&T t2 v𝛼 t3PrecCompRΓ1 |Γ2 ` t2 v𝛼 t3Γ1 |Γ2 ` t1&T t2 v𝛼 t3DiagJΓ1 ` t1 ⇒∗ T Γ2 ` t′1 ⇒∗ T′ Γ1, (z : T)|Γ2, (z : T′) ` TP v𝛼 T′PΓ1 |Γ2 ` t1 v𝛼 t′1 Γ1 |Γ2 ` t2 v𝛼 t′2 Γ1 |Γ2 ` t3 v𝛼 t′3 Γ1 |Γ2 ` t4 v𝛼 t′4Γ1 |Γ2 ` J(z.TP, t1, t2, t3, t4) v𝛼 J(z.T′P, t′1, t′2, t′3, t′4)Figure 5.11: Precision for Propositional Equality and CompositionPrecModStructΓ1 |Γ2 ` t1 v𝛼 t2Γ1 |Γ2 ` t1v←−−→t2PrecModStepLt1 −→∗ t′1Γ1 |Γ2 ` t′1v←−−→t2Γ1 |Γ2 ` t1v←−−→t2PrecModStepRt2 −→∗ t′2Γ1 |Γ2 ` t1v←−−→t′2Γ1 |Γ2 ` t1v←−−→t2PrecModStepBackt′2 −→∗ t2Γ1 |Γ2 ` t1v←−−→t′2Γ1 |Γ2 ` t1v←−−→t2Figure 5.12: Precision Modulo ConversionCstCompLt1𝛼 t3 t2𝛼 t3t1&T t2𝛼 t3CstCompRt1𝛼 t3 t2𝛼 t3t3𝛼 t1&T t2CstCompDiagt1𝛼 t′1 t2𝛼 t′2t1&T t2𝛼 t′1&T′ t′2CstEqT1𝛼T2t1𝛼 t2 t′1𝛼 t′2t1 =T1 t′1𝛼 t2 =T2 t′2CstReflt1𝛼 t2t′1𝛼 t′2 t′′1 𝛼 t′′2re (t1)`t′1t′′1 𝛼re (t2)`t′2t′′2CstJ−−−→t𝛼 t′J(−→t )𝛼J(−→t′ )Figure 5.13: Consistency for Propositional Equality and Composition1645.5.3 Fulfilling The CriteriaGEq is now fully dened: we have de ned the precision relations v−→ and v←−−→and the consistency relation −→ to instantiate v−→ , v←−−→ and −→ . We nowestablish that these relations ful ll the criteria of Section 5.4.2. We give the intu-ition behind some of the cases that are new compared to gcic.• Immediate Results: Proving re exivity of v−→ (Lemma 5.4.4) is a straightfor-ward induction. e rules PrecCompL and PrecCompR make the compositionof terms as precise as either term, proving Lemma 5.4.7. e closure of v←−−→under convertibility is built into its de nition, proving Lemma 5.4.9. DiagCastgives that casts are monotone, proving Lemma 5.4.11. e monotonicity of sub-stitution (Lemma 5.4.12) is proved with a straightforward induction, relying onpresynthesis preserving types under substitution. e remaining diagonal rulesgive that v−→ has all structural rules, ful lling Lemma 5.4.15.• Composition Safety (Lemma 5.4.5) For progress, each composition of twocanonical forms of the same type has a reduction, where either the heads matchand the arguments are composed, or an error is produced. If one of the com-posed terms is not a canonical form, then either (1) one of the composed termscan reduce, (2) one term is a ?T or fT where T is not a function or equalitytype, and we can reduce with RedCompUnk or RedCompErr, or (3) one of thecomposed terms is neutral, and hence the composition is neutral. For preser-vation, either the result is immediate, or casts are inserted to ensure that typesare preserved.• CompositionCon uence (Lemma 5.4.6)RedCompUnk(L,R) ensures that com-posingwith ?T only reduces when ?T cannot reduce, avoiding a “diamond” prob-lem.• Precision Transitive (Lemma 5.4.8): We prove this a er monotonicity of re-duction, which lets us prove that precision-related types have precision-relatedterms, which is necessary to ful ll premises on terms’ types, such as in CastLand CastR. e rest is straightforward induction.165• Static Consistency (Lemma 5.4.10) e GEq rules not present in gcic are forequality, which are trivially handled, and consistency rules for composition, forwhich the result vacuously holds since composition is not present in the staticlanguage.• Monotonicity of Reduction (Lemma 5.4.13): e key fact is that, since Prec-CompL and PrecCompR only have composition on the le , all the inversions inthe gcic proofs are still valid for GEq. e interesting case is when precisionis derived using PrecCompL (PrecCompR is symmetric), and the compositionreduces. e result is trivial for RedCompUnk(L,R) and RedCompErr(L,R). Forthe remaining cases, two terms with the same head are being composed, andthe result is eitherf or another term with the same head. Whenf is producedthe result is trivial. When a term with the same head is produced, the Prec-CompL can be used with the appropriate diagonal rule. In the case that castsare present in the result of composition, CastL is used. e other notable caseis when J reduces, where the result is derived using DiagCast.• ConsistencyMonotone (Lemma 5.4.14)We rst show that consistency ismono-tone on the le , then prove that it is symmetric to obtain monotonicity for botharguments. e case when 𝛼 is derived with CstCompR or CstCastR mustbe handled specially, since they each take an operand that can be any term.e trick is to unwrap the chain of CstCompR and CstCastR uses, use the in-duction hypothesis on the contained derivation, then re-apply CstCompR andCstCastR in the same order to obtain the result. When precision is derivedwith PrecCompL or PrecCompR, then consistency must have either been de-rived with CstCompDiag, in which case the result follows from the inductionhypothesis, or with CstCompL or (symmetrically) CstCompR. For CstCompL,the premise gives that both composed terms are consistent with the right-handterm, yielding our result. e remaining cases are straightforward.1665.6 Discussion5.6.1 Extensions Enabled by EqualityIn addition to catching the kinds of bugs discussed in Section 5.2, we show somebenets of having propositional equality inGEq. ree new language features canbe encoded using propositional equality, without augmenting the cast calculus:empty types, Axiom K, and indexed inductive type families. For type families, wediscuss some limitations of the approach and workarounds for these limitations,showing how our cast calculus is expressive enough to pave the way for futureimprovements.5.6.1.1 The Empty TypeJust as the gradual J needed computation, eliminating the empty type has compu-tational content in a gradual language. In static languages, the empty type Emptyhas no closed values, so either Empty contains no terms, or (for logically incon-sistent languages) any such terms are non-terminating. e elimination functionexfalso : (X : Typei)→ Empty→ X produces a result of any type, given a value ofthe empty type. In a gradual language, however, ? andf can be used at any type,including the empty type. So a gradual exfalso must produce a value of type X.We again follow the goal of dynamically tracking constraints expressed bytypes. For the empty type, a value of type f : T→ Empty encodes the constraintthat T should be impossible, and a branch built using exfalso should be unreach-able. If f is applied to t : Empty, created using ? or casts, then the constraint hasbeen violated, and an error should be raised.We can encode this behaviour by de ning Empty to be:true =B falseand exfalso to be:𝜆X. 𝜆t. J (b. if b B X) true te key is ?Empty andfEmpty both evaluate to re (fB)`truefalse. So the only closedvalue of type Empty is a dynamic type error. Likewise, the eliminator exfalso casts167t to type fTypeℓ before casting it to type X, so the result is always fX . Withoutadding any features to CastEq, the bug-nding described in Section 5.2 handlesconstraints encoded as logical negation.5.6.1.2 Axiom KBecause ?t1=Tt2 steps to re (t1&T t2)`t1t2 , GEq is in the class of dependently typedlanguages where re is the only constructor for equality. Composition can beused to derive a (gradual) proof of this uniqueness, even though no such proofcan be derived in most static type theories [75]:K : (x : T)→ (pf : x =T x)→ pf =x=Tx re (x)`xxK x pf = re (pf &x=Tx re (x)`xx)`pfre (x)`xxAxiom K can be used to prove that all equality proofs of a given type are equal[141], so our proof-irrelevant J principle does not lose any expressivity, since anytypes parameterized by an equality proof can be rewri en with K. Also, AxiomK allows for conventional dependent pa ern matching to be elaborated into in-ductive eliminators [69], providing a lightweight alternative to the cumbersomeind form. e combination of Axiom K and function extensionality suggests aconnection to Observational Type eory ( ott ) [6, 124] that warrants futureexploration. Sadly Axiom K means that GEq is incompatible with univalence andhomotopy type theory [149], but we leave univalence-compatible gradual equal-ity to future work.5.6.1.3 Inductive TypesMcBride [95] describes how, using propositional equality, indexed inductive fam-ilies can be encoded. e main idea is, instead of having each constructor returndi erent indices, each index is a parameter, and each constructor takes an equalityproof that the parameter has the desired value. In the elimination principle, J isused to rewrite the type of the returned value using the stored equality. Consider168how the classic vector type:data Vec (X :Type) : (n :N)→Type whereNil : Vec X 0Cons : X→Vec X n→Vec X (1+n)is transformed into:data Vec′(X : Type)(n : N) :Type whereNil′ : (n =N 0)→ Vec X yCons′ : (z :N)→X→Vec X z→ n=N (1+z)→Vec′ X nis transformation gives a low-overhead way to incorporate indexed inductivefamilies with gradual dependent types. Since no extensions to CastEq are re-quired, the safety and gradual guarantee results from Section 5.4 apply. e con-structors take equality proofs, so violations of those equalities raise dynamic typeerrors.However, a naive transformation of inductive types is limited in its ability toeagerly detect errors. e problem is that dynamic consistency is fundamentallynot transitive, since otherwise all types are consistent through ?. Members ofinductive types are essentially trees, and equality constraints track constraintsat each level of the tree, but consistency across the entire tree is not ensured.e witnesses track the evolution of type information across time, but not acrossspace. Consider:Cons′ ?N true (Nil′ ?N re (0)`?N0) re (2)`2?N : Vec′ B 2a vector with one element, whose type says it has length 2. Constructing this vec-tor raises no run-time type errors. At each level, the equality proof is correct: 0 isconsistent with ?N, and 2 is consistent with 1+ ?N. Gradually, the non-transitivitymeans that imprecision at each level can cause disconnects between levels.ankfully, CastEq is expressive enough to encode a solution to this problem.169By having composition as an operator in the language, one can dene so-called“smart constructors” that have the same types as the normal constructors, butthat access the equality proofs stored in the previous level of the tree when con-structing new ones. For example, using J we can writecong1 : (m n : N)→m =N n→ 1+m = 1+nwhich can be used in a “smart” Cons:smartCons z h t eq =Cons z h t (eq &(1+z)=Nn (〈(1+z) =N n⇐ 1+z =N 1+z〉(cong1 (wit t))))where wit : Vec X z→ z =N zwit (Nil eq) = 〈z =N z⇐ 0 =N z〉eqwit (Cons x h t eq) = 〈z =N z⇐ 1+x =N z〉eqWhen smartCons is used in place of Cons′, the witness re (0)`?N0 is trans-formed to re (1)`?N?N , which produces an error when cast to 1+?N =N 2, since1&N 2 { fN. Formalizing the general version of this approach is beyond thescope of this chapter, but it shows how having composition as an operator en-ables more detailed manipulation of run-time type information.5.6.2 Future Work5.6.2.1 Termination and Approximate NormalizationAs presented, GEq has undecidable type checking. Precision and CastEq typingare not decidable. ankfully, we do not need to decide precision typing to de-cide GEq typing, since initial witnesses are always valid by re exivity. DecidingGEq typing is straightforward, except for normalization: some terms do not ter-minate and consistency compares modulo reduction. In gcic, Lennon-Bertrandet al. [87] show that termination can be obtained by sacri cing the gradual guar-antees, or by restricting universes so that they are not closed under function types.While useful for type theory, these sacri ces remove reasoning principles or re-duce expressivity, respectively, that make them unsuitable for programming. In170Chapter 6 we describe how to regain decidable type checking for GEq, adaptingthe techniques of approximate normalization from Chapter 3.5.6.2.2 Conjectures: EP-Pairs, Composition, Blame and Full AbstractionLennon-Bertrand et al. [87] prove a stronger property than the gradual guar-antees for gcic. ey show that casts between precision-related types form anembedding-projection pair (EP-pair) [105], so that increasing then decreasing pre-cision produces the same result modulo errors, and decreasing then increasingprecision produces an observationally-equivalent result. While the gradual guar-antees are helpful, they are satis ed by trivial languages where every cast pro-duces ?. Showing the EP-pair property would prove that casts in GEq never loserun-time information, giving more con dence in its ability to dynamically trackconstraints. We conjecture that GEq ful lls the EP-pair property, but suspectnovel proof techniques are needed to handle witness proofs. We also conjecturethat composition computes the greatest lower-bound for semantic precision, sothat each type forms a true semi-la ice. is would establish that witness compo-sition never prematurely raises dynamic errors, since two witnesses would com-pose to f only when all other options are impossible.Another desirable property of gradual languages is a blame theorem [153],stating that, for a dynamic cast error, the less-precise type is always blamed. GEqhas no notion of blame, but we conjecture that the techniques of Zalewski et al.[158] could be adapted to GEq.Finally, we conjecture that there is a variant of cic whose embedding intoGEq is fully abstract, meeting the criteria Jacobs et al. [81] set out for graduallanguages. Intuitively, we can form equalities between extensionally-equal func-tions, and use those to cast between types indexed by them, so any propertyof a function should apply to one that is extensionally-equal. Full abstractionguarantees that all static equivalences hold in GEq, giving the programmer moretools with which to reason about their code. Proving full abstraction for non-dependently typed gradual languages is a recent development, so more investiga-tion is needed to adapt these techniques to dependent types. e usual techniquefor full abstraction is to simulate the target language in the source, so every target171context can be translated into a source context that is unable to distinguish theterms. As a consequence, the embedded variant of cic must have capabilities fornon-termination added.5.6.3 Related Work5.6.3.1 Gradual Approaches to EqualityGRIP [90] extends CastCIC with propositional equality, but unlike GEq, thispropositional equality is in a separate sort, the types of which have all membersdenitionally equal. is propositional layer has no imprecision, and containsfeatures for catching dynamic type errors in the gradual layer. GRIP features aninternal notion of precision: while not all terms obey the gradual guarantees,self-precise terms do, and guarantees for such terms are available as a theoremin the propositional layer. GEq provides reasoning about equality within gradualprograms, whereas GRIP provides a layer for reasoning about gradual programs.GRIP is based on ott, and hence supports fully static proofs of function exten-sionality and Axiom K. GEq contains only gradual proofs of these. We conjecturethat, like in GRIP, ott could replace bcic as the underlying static language forGEq.Our work also relates to that of Lemay [85], which presents a dependentlytyped language where all de nitional equality checks are deferred to run time.Like in gcic and GEq, casts are inserted when a term’s synthesized type di ersfrom the type against which it is checked. However, there is no unknown ter-m/type, and no requirement that synthesized and checked-against types be con-sistent, so errors are raised only when safety is directly violated. Like in GEq,function equality is checked extensionally: casts accumulate on unapplied func-tions, and arguments are cast when cast-containing functions are applied, similarto composing functions in GEq. e work emphasizes clear error messages, andunlike GEq, features a rich notion of blame.5.6.3.2 Flexible Dependent TypesGEq builds on a long line of work mixing dynamic and static enforcement of spec-i cations. Ou et al. [114] support mixed static and dynamic checking of boolean-172valued properties, and Lehmann and Tanter [84] provide gradual typing for re-nement types. Similarly, Tanter and Tabareau [144] develop a system of castsfor Coq, using an unsound axiom to represent type errors. ese casts workedfor values of subset types, i.e. a value paired with a proof that some boolean-valued function returns true for that value, but not general inductive types. Oseraet al. [113] present dependent interoperability for principledmixing of dependentlytyped and non-dependently typed programs. Dependent interoperability was ex-tended by Dagand et al. [42, 43], who provide a general mechanism for li inghigher-order programs to the dependently typed se ing. All of these approachespresuppose separate simple and dependent versions of types, related by boolean-valued predicates. Our composition of witnesses provides similar checks, but bykeeping witnesses, types need not be reformulated in terms of subset types orboolean predicates.173Chapter 6A Syntactic Model ofApproximate and ExactGradual SemanticsIn the previous chapters, we saw a gradual language with decidable type check-ing but without inductive types, a cast-calculus based language with inductivetypes but without decidable type checking, and a method for adding proposi-tional equality into that cast calculus. Now, we combine the three of these into alanguage with decidable type checking, that supports inductive types, and propo-sitional equality, without sacricing the gradual guarantees or the expressivity ofcic.e resulting language, ⊲GEq, is nearly identical to GEq, with the only signif-icant di erence being how casts from function types to ? are handled during typechecking. However, the di culty lies in showing that type checking is decidable,i.e. that all compile-time computations terminate. We do this with a syntacticmodel: we write a translation from ⊲GEq to a static type theory. If each step ofcomputation during type checking in ⊲GEq corresponds to at least one step ofreduction in a strongly-normalizing language, then all terms must terminate.e syntactic model approach is useful for showing termination of approxi-mate normalization, but it can also be used tomodel exact execution, using a statictarget with a modality for unbounded recursion. Modelling the exact semantics174lays the groundwork for proving additional metatheory about ⊲GEq in the future.e model for exact execution is nearly identical to the model for approximatenormalization. Moreover, it suggests an implementation strategy, since terms canbe normalized or compiled by rst translating to a static type theory.6.1 IntroductionSo far, the story of gradual dependent types has been one of tension and compro-mise. Chapter 3 explored the tension between types depending on values and thee ects introduced by gradual code, with approximate normalization being thecompromise necessary to obtain both. Chapter 5 handled the inherent tensionbetween preservation of static equivalences and conservative extension of cic,balancing the two by separating static and dynamic notions of equality.Lennon-Bertrand et al. [87] present a deeper con ict: the “ re triangle” ofgradual dependent types. ey show that no gradual language can conservativelyextend cic, have all terms strongly normalizing (which implies decidability), andful ll the EP-pairs property (which implies the gradual guarantees). ey presentthree calculi, each of which ful lls two of the above properties.is chapter identi es a potential compromise to resolve the tension betweenconservatively extending cic, decidable type checking, and the gradual guaran-tees. We present a Guarded Gradual language with propositional Equality anddecidable type checking ( ⊲GEq ), which is nearly identical to GEq, except thatit features approximate normalization to ensure decidable type checking. We doso without restricting terms in the ways that prevent gcic variants from ful llingthe gradual guarantees or conservatively extending cic, and we conjecture that⊲GEq ful lls both these properties.Just as in Chapter 3, ⊲GEq has separate approximate and exact semantics forcompile time and run time respectively, which enable decidable type checkingwithout losing expressivity. e di cult part is actually proving that approximatenormalization terminates. e hereditary substitution strategy of Chapter 3 doesnot scale to inductive types, since eliminating a value from an inductive type isnot structurally decreasing in the type of the variable being replaced.Instead, we prove normalization using a syntacticmodel in the style of Bernardy175et al. [11], Boulier et al. [17]. at is, we show that every term has a normal formby translating said term to a term in Martin-Lo¨f Type eory ( mltt ), which isstrongly normalizing. By showing that each source reduction step corresponds toat least one reduction in the target, we prove that the number of source reductionsmust be nite.e choice to use a syntactic model in uences the design of approximate nor-malization. We use the cast-calculus approach of gcic andGEq rather than the ev-idence approach of gdtl because it integrates well with a syntactic model: sourcecasts can be implemented as target functions. Instead of approximating based onthe gdtl metric of arrow types at a given universe level, we approximate castsfrom function types to ?. is allows ? to be modelled as a strictly-positive induc-tive type, and hence allows it to be modelled in a strongly normalizing calculus.6.1.1 Three Problems, One SolutionAlong with our syntactic model for approximate normalization, we present amodel of exact execution. We do this because the model is nearly identical: byparameterizing over whether we are in approximate or exact mode, we are able re-use the vast majority of the machinery from our approximate model for the exactmodel. We do not use the exact model to prove any theorems other than sound-ness of the model with respect to the reduction semantics of ⊲GEq. Nevertheless,we provide it in anticipation of two future bene ts: mechanized metatheory andimplementation.6.1.1.1 Proving metatheory and reasoning about gradual programs.Lennon-Bertrand et al. [87] provide a syntactic model for GCICG , but they do soby extending cic with non-positive datatypes. e resulting target type theoryis logically inconsistent, and hence, theorems proven in it cannot necessarily betrusted. eir proof of the gradual guarantee relies on a complex simulation-basedargument, which GEq inherits in Chapter 5.By translating ⊲GEq to Guarded Type eory ( gtt ), we are able to describenon-termination for its exact semantics, while still having a target which is log-ically consistent. So one can prove metatheory about ⊲GEq in gtt. e denota-176tional nature of the model means that convertible terms are propositionally equal,so we can prove properties about ⊲GEq terms by reasoning about ⊲GEq values.is ability enables future developments to avoid the complicated simulation ar-guments used with gcic and GEq.6.1.1.2 Implementing conversion checking and compilation.Translating ⊲GEq to gtt provides a path towards implementation. Eventually,we would like a fully implemented compiler for a gradual dependently typed lan-guage, but writing a compiler for a dependently typed language is no easy task,even without gradual types. However, through the Curry-Howard correspon-dence, gtt is a usable programming language, and is very similar to the core lan-guages of proof assistants like Agda and Idris. ese languages already featuree cient procedures for comparing terms for convertibility, and for translatingterms to machine code. So instead of writing a new compiler for gradual depen-dent types, we can use the translation given by our syntactic model to translateto the core languages of these proof assistants. en, gradual terms can be com-pared for convertibility by comparing their translations, and can be compiled tomachine code through the translation.Moreover, using approximate normalization and translating to gtt lets uscompile to static dependently typed languages without altering their core typetheories. Languages like Idris and Agda allow for terms to be marked as total,which makes the type checker skip termination checking for said de nition. isfeature is useful for de nitions that are proven to be terminating with proofs thatcannot be expressed in type theory. However, gradual typing is morally di erent:since some terms really do not terminate, marking them as terminating would bea lie. Instead, Agda and Idris1 have a weaker feature, where a de nition can bemarked as partial. Partial de nitions are conservative: they are not normalizedduring type checking, so some safe programs may be rejected if partial values areconvertible but not syntactically identical. gtt as a theoretical model for this way1In Idris 1 had this behaviour, but Idris 2 has yet to implement this behaviour, and happilyruns the type checker forever when comparing non-terminating terms. Safety can be recovered byde ning partial functions in their ownmodule, and exposing themwith export rather than publicexport.177of representing non-termination, and producing well typed gtt terms shows thatwe could also produce well typed Agda or Idris terms bymarking exact denitionsas partial.6.2 A Birds Eye View of the Syntactic ModelTo begin, we present the various parts of the syntactic model of ⊲GEq, giving theintuition for what purpose they serve and how they t together.6.2.1 The Source LanguageWe do not describe the entirety of ⊲GEq here, since it very similar to GEq (orspeci cally, CastEq), as described in Chapters 4 and 5. We present ⊲GEq as acast calculus, though it could be the target of elaboration from a surface languagesimilar to GEq. e main di erence between ⊲GEq and CastEq is that ⊲GEq hastwo separate reduction relations, {𝐴𝑝𝑝𝑟𝑜𝑥 and {𝐸𝑥𝑎𝑐𝑡 , where the typing rulesonly ever use {𝐴𝑝𝑝𝑟𝑜𝑥 . e relation {𝐸𝑥𝑎𝑐𝑡 is identical to { in GEq, exceptthat reductions in equality witnesses use {𝐴𝑝𝑝𝑟𝑜𝑥 . e approximate reductionrules{𝐴𝑝𝑝𝑟𝑜𝑥 are the same as the correspondingGEq reductions, except for thosewe highlight in Section 6.2.1.3. Likewise, there are two pairs of typing relations,Γ ` t ⇒𝐴𝑝𝑝𝑟𝑜𝑥 T and Γ ` t ⇐𝐴𝑝𝑝𝑟𝑜𝑥 T versus Γ ` t ⇒𝐸𝑥𝑎𝑐𝑡 T and Γ ` t ⇐𝐸𝑥𝑎𝑐𝑡 T.However, even Γ ` t⇐𝐸𝑥𝑎𝑐𝑡 T uses{𝐴𝑝𝑝𝑟𝑜𝑥 to de ne convertibility.In general, we use the metavariable æ to range over {𝐴𝑝𝑝𝑟𝑜𝑥 ,𝐸𝑥𝑎𝑐𝑡}.6.2.1.1 Typing ModesOther than the changes we mark below, the typing rules of ⊲GEq follow GEq.However, each typing judgment has an approximate and exact version. In gen-eral, each rule has two identical copies, where the approximate/exact mode ofthe conclusion matches the mode of each parameter. e main exception is thattyping rules for type formers only have approximate forms, and only ever useapproximate forms in their premises. Also, equality witnesses are always typedwith the approximate rules. For example, consider the rules for conversion, casts178and equality proofs:CastCheckΓ ` t⇒æ T′T −→∗𝐴𝑝𝑝𝑟𝑜𝑥 T′′ T′ −→∗𝐴𝑝𝑝𝑟𝑜𝑥 T′′Γ ` t⇐æ TCastCastΓ ` T𝑗⇒Type 𝐴𝑝𝑝𝑟𝑜𝑥Typei for 𝑗 ∈ {1,2}Γ ` t⇐æ T1Γ ` 〈T2 ⇐ T1〉t⇒æ T2CastReflΓ ` tw ⇒𝐴𝑝𝑝𝑟𝑜𝑥 T Γ ` t1 ⇐𝐴𝑝𝑝𝑟𝑜𝑥 T Γ ` t2 ⇐𝐴𝑝𝑝𝑟𝑜𝑥 TΓ |Γ ` tw v t1 Γ |Γ ` tw v t2Γ ` re(tw)`t1t2 ⇒æ t1 =T t2In CastCheck, approximate reductions are used, regardless of the mode. Like-wise in CastCast, the source and destination types are checked in approximatemode regardless of what mode the whole term is synthesizing in. For CastRefl,endpoints and witnesses are checked in approximate mode, even for a term inexact mode. One nal simplifying assumption we make is that CastFun has bothtypes at the same level2.6.2.1.2 Tagged TermsIn gcic, a cast from germℓ (h) to ?Typeℓ does not reduce, but instead acts as a tagfor a value in type ?. To avoid confusion between the computation of casts andthe tagging of values in our model, we introduce two new explicit forms:t +F 〈hℓ〉t | 〈DCℓ 〉(−→𝑡 ,𝑛) (Additional term forms for tagged terms)e rst form is a value from the germ of h injected into ?Typeℓ . For example,if p : 1 =N 1, then 〈=0〉p : ?Type0 : the equality proof is injected into ? by tagging itwith the head and level of its type. e second form is a data constructorDCwith asequence of elds, injected into ?Typeℓ . For each eld the tag n stores themaximumnumber for which the rst n function domain types of the eld’s type do notcontain ?Typeℓ . is information is used to direct how such a term is approximately2Our Agda model has a notion of cumulativity, but we omit it to reduce the cognitive load ofreading this chapter.179normalized: to embed a member of an inductive type into ?, each eld has to becast to type ?, or to a function producing ? whose domain does not contain ?. Forexample, consider the inductive type which stores a proof that a type contains atleast as many terms as the naturals:data In nite (A : Type) : Type wheretofrom : (f : A→ N)→ (g : N→ A)→ ((x : N)→ f (g x) =N x)→ In nite AGiven tofrom f g p : In nite A, we can inject it into ? as:〈tofromIn nite0 〉((f , 0), (g, 1), (p, 1))Both g and p are functions with N as their domain, so they can be losslessly em-bedded into ? by casting to N→ ?Typeℓ , without violating strict positivity. How-ever, when injecting an In nite proof into ?, the parameterA is set to ?Type0 , sincethat is the least precise instantiation of this inductive type. So f has to be stored aspart of an element of ? by casting to ?Typeℓ → N, which would violate strict pos-itivity. So the 1 tags on g and p denote that the rst type to the le of the arrowneeds no approximation, while the 0 tag denotes that for f , none of the types leof the arrow are guaranteed to be free of ?. To embed f as a eld in a value of type?, it must be converted to ?, which approximates it to the least precise value in itsimage.180e corresponding typing rules for the new forms are as follows:CastTagΓ ` t⇐æ germℓ (h) h ∉ {Π} ∪ {C | C ∈ TypeCtors}Γ ` 〈hℓ〉t⇒æ ?TypeℓCastTagPiApproxΓ ` t⇐𝐴𝑝𝑝𝑟𝑜𝑥 ?TypeℓΓ ` 〈Πℓ〉𝜆x. t⇒𝐴𝑝𝑝𝑟𝑜𝑥 ?TypeℓCastTagPiExact(x : ?Typeℓ )Γ ` t⇐𝐸𝑥𝑎𝑐𝑡 ?TypeℓΓ ` 〈Πℓ〉𝜆x. t⇒𝐸𝑥𝑎𝑐𝑡 ?TypeℓCastTagInd−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→(x1 : T1)→ . . .→ (xnk : Tnk )→ T := Args𝑘 (C, i,D)[−−−−−−−−→?Paramsℓ (C),−−−−−−→?Argsℓ (C)]k−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→(x1 : T1)→ . . .→ (xnk : Tnk )→ T does not contain ?Typeℓk−−−−−−−−−−→n𝑘 maximalk −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→Γ ` t𝑘 ⇐æ (x1 : T1)→ . . .→ (xnk : Tnk )→ ?TypeℓkΓ ` 〈DCℓ 〉(−−−→tk ,nkk)⇒æ ?TypeℓA term in ?Typeℓ consists of a head and a level, along with a term from the germfor that head. e separate rules CastTagPiApprox and CastTagPiExact han-dle the function case. e exact rule works as in GEq, but the approximate rulehas two extra constraints. First, the function must be 𝜂-expanded (because therule only applies to 𝜆 terms), which we need for technical reasons. Second, thefunction must not refer to its argument.For inductive types in ?Typeℓ , the rule CastTagInd says that an inductivemember of ?Typeℓ is one where every non-function eld has type ?Typeℓ . A eldwith a function type has its parameter types taken from the germ of C, and itsreturn type is ?Typeℓ . Any dependencies between elds are erased: if the germ ofC has one eld’s type depend on a previous eld’s value, when converting to ?we use ? for the previous eld’s value. Also, only types that are “smaller” than?Typeℓ can be used in the domains of function-typed elds. is rule is essentiallyto ensure that parameterized inductive types cannot be used to circumvent Cast-TagPiApprox, which in turn helps us prove strong normalization later on. So wespecify that for each eld, we use the highest value of 𝑛 such that the domaintypes does not contain ?Typeℓ . Any functions whose domains refer to ?Typeℓ are181converted directly into ?Typeℓ , i.e. n is set to 0.In addition to the modied typing rules, we change the cast reduction rulesto produce these tagged terms instead of using casts as tags:RedTagFunGerm〈?Typei ⇐ (x : T1)→ T2〉t{𝐸𝑥𝑎𝑐𝑡 〈Πi〉(〈?Typei → ?Typei ⇐ (x : T1)→ T2〉t)RedTagIndGerm−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→(x1 : T1)→ . . .→ (xnk : Tnk )→ T := Args𝑘 (C, i,D)[−→tpar,−→targ]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→(x1 : T′1)→ . . .→ (xnk : T′nk )→ T′ := Args𝑘 (C, i,D)[−−−−−−−−→?Paramsℓ (C),−−−−−−→?Argsℓ (C)]〈?Typei ⇐ C(−−→𝑡𝑝𝑎𝑟 )〉DC(−−→𝑡 ′𝑝𝑎𝑟 ,−→𝑡k𝑘){æ〈DCℓ 〉((−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→〈(x : T′1)→ . . .→ (x : T′nk )→ ?Typeℓ ⇐ (x : T1)→ . . .→ (x : Tnk )→ T〉𝑡k ,𝑛k𝑘 ))RedTagEqGerm〈?Typeℓ ⇐ t1 =T t2〉t{æ 〈=ℓ〉(〈??Typeℓ =?Typeℓ ??Typeℓ ⇐ t1 =T t2〉t)RedTagUpDownheadMatch(h, t)〈T⇐ ?Typeℓ 〉〈hℓ〉t{æ fromGermℓ (h, t)RedTagIndUpDown−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→(x1 : T1)→ . . .→ (xnk : Tnk )→ T := Args𝑘 (C, i,D)[−→tpar,−→targ]𝑘−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→(x1 : T′1)→ . . .→ (xnk : T′nk )→ T′ := Args𝑘 (C, i,D)[−−−−−−−−→?Paramsℓ (C),−−−−−−→?Argsℓ (C)]𝑘〈C(−−→𝑡𝑝𝑎𝑟 )⇐ ?Typei〉〈DCℓ 〉((−−−→𝑡k ,𝑛k𝑘)){æDC(−−→𝑡𝑝𝑎𝑟 ,−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−→〈(x : T1)→ . . .→ (x : Tnk )→ T⇐ (x : T′1)→ . . .→ (x : T′nk )→ ?Typeℓ 〉tk𝑘 )To cast to ?, we cast to the germ, then tag that value. To cast from ?, we get thetagged value, which is a member of the germ type, then cast that to the desiredtarget type. We do so using an (omi ed) judgment headMatch, which checks if twas constructed with a term former matching h, and a metafunction fromGermthat behaves just like the GEq cast from a germ type to a type. Essentially, Red-TagUpDown behaves like RedCastUpDown in GEq, but does not reduce if theterm being cast is neutral, which helps our termination argument. For inductives,182we cast each eld to or from ?, or to/from a function type returning ?. We save thereduction that approximately converts functions to ? until Section 6.2.1.3, but allother reductions from GEq work both approximately and exactly without modi-cation.6.2.1.3 Approximating Functionse main di erence in the de nition of{𝐴𝑝𝑝𝑟𝑜𝑥 is that casting from (x : T1)→ T2to ?ℓ approximates in{𝐴𝑝𝑝𝑟𝑜𝑥 where it did not in GEq. e reduction rule Red-CastFunGerm is replaced with:RedCastFunGermApprox(x : T1)→ T2 ≠ germ𝑗 (Π) for 𝑗 ≥ 𝑖〈?Typei ⇐ (x : T1)→ T2〉t{𝐴𝑝𝑝𝑟𝑜𝑥〈Πℓ〉〈?Typei → ?Typei ⇐ (x : T1)→ T2〉𝜆y.〈[y/x]T2⇐[?T1/x]T2〉(t ?T1 )at is, a function is cast to ?ℓ by casting through the germ, but instead of castingthe function itself, we use the constant function producing the original function’sleast precise value. Because the function type might be dependent, we must castthe result from the codomain for input ?T1 to the codomain for the actual input.Notice how this approximation is less lossy than in gdtl (Section 3.5.2.1): weapproximate the input of the function to ? rather than the output. For example,𝜆(x : N).S x is approximated to 𝜆(x : N).S ?N, retaining the information that theresult of the function is not zero. Constant functions are not approximated at all.6.2.1.4 Terms in TypesWe must approximate terms when they cross the boundary between terms andtypes. Types always use the approximate judgment, and the approximate andexact typing judgments are di erent. So, when substituting within a type we183must use an approximate version of a term:CastAppΓ ` t⇒Π (x : T1)→ T2Γ ` t⇐ TΓ ` t0 t1 ⇒ [𝑡𝑜𝐴𝑝𝑝𝑟𝑜𝑥(t1)/x]T2Here the 𝑡𝑜𝐴𝑝𝑝𝑟𝑜𝑥 metafunction traverses a term and replaces all instances of〈Πℓ〉t with 〈Πℓ〉(𝜆x. t ?Typeℓ ).6.2.2 What’s In a Model?Now that we have appropriately modied GEq into ⊲GEq, we can discuss how tomodel it in a static type theory. Our approximate and exact models of ⊲GEq caneach be broken into the following parts:• A type C ℓ of codes, representing the ⊲GEq Typeℓ for each ℓ ;• A translation TÈ É mapping each ⊲GEq type to a code;• An “elements-of” function El : C ℓ → Typeℓ which interprets codes into tar-get types;• A translation EÈ É which maps each ⊲GEq term into a description of acomputation in the target, under some monad L. For approximate normal-ization, this monad is the identity;• A proof that for each t : T, that EÈtÉ : L (El TÈTÉ)• A proof that, for each reduction rule, applying EÈ É to the redex and reductproduces propositionally equal terms• A proof that, for each approximate reduction rule, applying EÈ É to theredex produces a target redexe last property is necessary to show termination of approximate normalization:if the number of ⊲GEq reductions is bounded by the number of target reductions,thenwe know the number of source reductions is nite, since the target is strongly184normalizing. is proof must be completed in the metalanguage, rather than inthe target type theory. All convertible terms are de nitionally equal, so there isno general way to express in a type theory that a term of that theory reduces toanother term using one or more steps.For the model, we need a target term for each source term. Each introductionform in the ⊲GEq corresponds to an introduction form (usually a constructor orfunction abstraction) in the target. Each elimination form in ⊲GEq correspondsto a function that we construct in the target, whose type matches the typing rulefor the eliminator (albeit, producing a result under L). So the hard work of themodel lies in constructing the types that denote values, and in constructing thesupporting functions that correspond to elimination forms. ese two tasks areinterrelated: how we construct the type for values in uences what operationswe can write for those values. For the approximate case, the challenge of provingtermination reduces to constructingwell typed elimination functions in the target.6.2.3 The Target LanguageTo establish our model, we translate ⊲GEq to gtt. However, gtt comes in manyavours, providing similar core operations with slightly di erent implementa-tions and metatheory. For our model, we use a variant of gtt called Ticked Cu-bical Type eory ( tctt ) [101]. We restrict our model to the subset of tcttwithout glue types or systems, extended with inductive-recursive datatypes. Werely heavily on function extensionality, but we do not rely on axiom K, nor dowe use univalence or homotopy type theory [149]. e details of tctt are notneeded to understand our model, other than the fact that it gives a logically con-sistent language with the primitives we need for guarded recursion, and that ithas a relatively faithful implementation in Guarded Cubical Agda [151].In general, we only give a sketch of the actual tctt terms we construct in ourmodel. e terms themselves are long, and a large portion of the developmentis devoted to proving inequalities about the sizes of terms that are immediatelyapparent to a human, or proving lemmas about transporting terms between var-ious equal types. In the name of clarity, we use Agda-style inductive and recordtype de nitions, and omit implicit arguments when they negatively impact the185readability of the given terms. We have mechanized our translation in GuardedCubical Agda. e interested reader can nd the complete translation archivedon Zenodo [56].6.2.3.1 The Exact Targete primitives of gtt (implemented by tctt) that we use are as follows:. : Type`→ Type`I : .Type`→ Type`next : A→ .A~ : .(A→ B)→ .A→ .BmapNext : (f : A→ B)→ (x : A)→ (next f)~(next x) =.B next (f x)dfix : (.A→ A)→ .Apfix : (f : .A→ A)→ dfix f = (next (f (dfix f)))EqI : (f : .Type`→ Type`)→ I(dfix f) = .(f (dfix f))e guarded modality ⊲ describes a type whose values are obtainable “one step”into the future, i.e. a er unfolding a guarded xed point once. Along with thismodality, an operation I turns a guarded type into a type. For any guarded typeT : ⊲Typeℓ , the type I T contains values available one step in the future from atype available one step in the future. e guardedmodality is applicative: next li sany value into the guarded modality, and ~ applies guarded functions to guardedvalues. However, it is not monadic: a value of type ⊲⊲T generally cannot be con-verted into one of type ⊲T, since a value obtainable a er two steps is not neces-sarily obtainable a er one step.e power of gtt comes from its xed-point operations: dfix nds the xedpoint of any function, provided it only refers to its argument behind the guardedmodality. pfix establishes that dfix actually computes a xed point, and EqI lets usget rid of I in the xed-points of types. e equality EqI protects tctt from non-termination: it is an axiom, rather than a de ned equality term, so transportingwith it does not reduce. is allows possibly-nonterminating computations to186be propositionally equal to their later states without having any tctt terms runforever.From these primitives, we can build functions that are easier to use, and morereadily show the usefulness of the guarded modality. For example, we can con-struct a fix operator as follows:fix : (f : .A→ A)→ Afix f = f (dfix f)e fix operator lets us take a “ xed point” of any guarded function and obtaina result that is not behind the guarded modality, that obeys a guarded version ofthe usual xed-point equation. ere are a few other helpful functions we canconstruct, whose types we give below:lo¨b : (f : .A→ A)→ fix f =A f (next (fix f))tyFix : (f : Type`→ Type`)→ Type`tylo¨b : (f : Type`→ Type`)→ tyFix f =Type` f (.(tyFix f))e lo¨b function is called Lo¨b-induction, and it lets us reason about an arbitrarynumber of unwrappings of fix. Likewise, tyFix says that we can turn a functionbetween types into a type, with tylo¨b establishing that any self-reference is behindthe guardedmodality. tyFix lets us de ne non-positive inductive datatypes so longas all non-positive references are behind the guarded modality, which is criticalwhen exactly modelling ? as an inductive type.6.2.3.2 The Approximate Targete approximate version of our model uses the subset of tctt that is equivalentto mltt with inductive-recursive types and an axiom for function extensionality.mltt with extensionality and induction-recursion is known to be strongly nor-malizing [53]. Because no guarded primitives are used in the approximate model,each ⊲GEq term’s reductions are simulated by some mltt term’s reductions. Onthe other hand, the exact translation produces a description of the term’s compu-tation, but reductions are only re ected as propositional equalities.1876.2.4 Mode TagsTo avoid redundancy in our model, we oen parameterize over whether we arein “approximate” or “exact” mode. To facilitate this, we de ne the following typeof tags:data Æ whereApprox : ÆExact : ÆWe commonly use the variable name æ to describe values of type Æ.6.2.5 Modelling Values and Expressions6.2.5.1 Codes and InterpretationsAt the core of our model is a Universe a` la Tarski, that is, a type that de nescodes for ⊲GEq language types, and an interpretation function that takes eachcode to a target type. Formally, we de ne a typeC : N→ Type, and an “Elements-of” interpretation El : (æ :Æ)→ (ℓ : N)→ C ℓ → Type. Here ℓ corresponds to the⊲GEq universe-level of a given type, which we omit from El when it is clear fromcontext. Likewise, we omit æ when it is clear from context, or when we are beinggeneric over any tag. Using codes instead of tctt types is critical for gradualtyping, because we need to access run-time type information that is not accessiblefrom target types. Unlike target types, we can pa ern match on codes and inspectwhat constructors were used to form a code. Also, all codes are able to reside inthe tctt universe Type0, regardless of the source ℓ they model, which simpli esthe development in some places.6.2.5.2 A Li ing MonadCodes can model ⊲GEq types and their values, but since some ⊲GEq terms arenon-terminating, they cannot model all run-time computations. Even the guardedmodality can only model computations one time-step into the future. To describe188possibly non-terminating computations, we use a guarded liing monad [117]:data L (A : Type`) : Type` whereNow : A→L ALater : .(L A)→L Ae li ing monad describes computations requiring some number of recursivefoldings. A computation is either available now (the Now constructor), or is acomputation requiring one unfolding plus some other number of unfoldings (theLater constructor). e Now constructors acts as the usual pure or return oper-ation to inject a pure value into the monad. e monadic a en can be imple-mented recursively:f la en : L (L A)→L Afla en (Now x) = xfla en (Later x) = Later ((next fla en)~x)In tctt, ~ and next are de ned in such a way that the recursive use of fla en inthe Later case is seen as structurally decreasing. With these operations, we cande ne a monadic bind in the usual way, and can use Haskell-style do-notation,which greatly improves the readability of our terms.6.2.5.3 FunctionsFunctions abstract over computation. Because of this, to model functions in exactmode, we need to capture functions that produce computations, not just purevalues. We do so using the li ing monad:El Exact (CΠ dom cod) = (x : El dom)→L (El (cod x))So functions internalize impure computations into the language of values: afunction can be a pure value that, when applied, performs impure (possibly non-terminating) computation. Having functions produce values from the li ingmonadlets us cast between ? and other function types, since we can use Later and the189monadic bind to apply a guarded value to a function whose result is monadic.6.2.5.4 The Unknown TypeSince ? is a type in ⊲GEq, our model needs a code corresponding to it, which wecall C?. But what should El C? be? For non-dependent types, New and Ahmed[105] use a recursive sum type to model ?, with a variant corresponding to eachtype former of the static language:𝑈𝑛𝑘 := N+ (𝑈𝑛𝑘 +𝑈𝑛𝑘) + (𝑈𝑛𝑘 →𝑈𝑛𝑘) + . . .However, tctt does not allow unrestricted recursive types, and the (𝑈𝑛𝑘→𝑈𝑛𝑘)variant is not strictly positive, so there can be no equivalent inductive type.Instead, we rely on guarded recursion to model ?. As with non-dependentgradual types, we dene an inductive type ?Ty ℓ for each level ℓ with a variantfor each type former. For the function case, we give the constructor the followingtype:?Π : (.(?Ty `)→L (?Ty `))→ ?Ty `e tyFix operator lets us de ne a type that is equivalent to this such a guardedinductive type, which we describe fully in Section 6.3. So we can inject arbi-trary functions into ?Ty ℓ , so long as they only refer to their arguments under theguarded modality.6.2.5.5 A Guarded AlgebraOne advantage of this chapter’s approach over Chapter 3 is that it gives uni edway of presenting the approximate and exact semantics. We can take this furtherby de ning an interface for both approximate and exact semantics, and usingthese abstract operations to describe approximate and exact computations. eoperations we need are as follows, modelled a er the operations of Guarded Cu-bical Agda [151].190⊲æ : Typeℓ → TypeℓIæ : ⊲æTypeℓ → Typeℓnextæ : A→ ⊲æA~æ : ⊲æ(A→ B)→ ⊲æA→ ⊲æBmapNextæ : (f : A→ B)→ (x : A)→ (nextæ f)~æ(nextæ x) =⊲æB nextæ (f x)dfixæ : (⊲æA→ A)→ ⊲æApfixæ : (f : ⊲æA→ A)→ dfixæ f =⊲æA (nextæ (f (dfixæ f)))EqIæ : (f : ⊲æTypeℓ → Typeℓ )→ Iæ(dfixæ f) =Typeℓ ⊲æ(f (dfixæ f))Whenæ = Exact, these operations are all easily implemented in terms of the prim-itives of gtt. For æ = Approx, the key is to set ⊲ApproxT = 1, which ensures that noapproximate computation can rely on a guarded value in a non-trivial way. eremainder of the methods are all easily implemented.Similarly, we can implement a generic li ing monad:data Læ : Typeℓ → TypeℓwhereNow : A→LæALater : (æ =Æ Exact)→ ⊲æ(LæA)→LæASo in exact mode, we get the li ing monad from above, but for approximate mode,we cannot use Later, so we get an identity monad. When in approximate mode,the monad has an escape operation, since Now is the only constructor:fromL : LApprox A→ AWe can use a single monadic de nition for both approximate and exact versionsof eliminators, without losing the ability to remove an approximate value fromthe monad when we need to.1916.2.6 Elimination OperationsWith our liing monad in hand, we have the essential tools to model the elimi-nation operations of ⊲GEq. GEq had three sorts of gradual elimination-speci crules: propagation rules (reducing ?), casting rules, and composition rules, so wede ne three main elimination functions corresponding to these. We model theseoperations using functions of the following types:cast : (c1 : C `)→ (c2 : C `)→ El c1→Læ (El c2)comp : (c : C `)→ El c→ El c→Læ(El c)codeComp : (c1 : C `)→ (c2 : C `)→ C `? : (c : C `)→ El cCasting takes two codes, and a value of the rst code’s type, and producesa value of the second code’s type. Composition takes a code and two values ofthe code’s type, and produces another value of that code’s type containing all theinformation from the input values. Code composition takes two codes and pro-duces the code containing all information from both input codes. Finally, ? takesa code and produces the value denoting ? for that code’s type. Casting and com-position produce a monadic result, because they may need to convert a functionto or from ?. However, computing ? and the composition of two codes only relieson the approximate normal forms of terms, so they can return pure values.e elimination operations of ⊲GEq are mutually dependent. As we saw inChapter 5, casting between equality types requires composing witnesses. Com-posing dependent function types or inductive types requires telescope composi-tion, which in turn requires casts. Casting an inductive type to ? requires comput-ing the germ, which requires computing ? for the type of indices, but computing? for equality types involves taking composing equated terms. So casting, com-position, and computing ? are all mutually dependent.1926.3 ModellingTheUnknown, Exactly andApproximatelyWe begin the presentation of our model with our representation of ?, the heartof gradual typing. In this section, we describe the inductive type that capturesvalues of type ?. We pay particular aention to how to model inductive types,since they are what could not be modelled in Chapter 3.6.3.1 HeadsWe use a target type to model head tags. We use these to compute germ types,and to compare codes or terms during casting or composition.data Head whereH0 : HeadH1 : HeadHType : HeadHΠ : HeadHΣ : HeadH= : HeadHCtor : CName→ Headese correspond fairly directly to the heads de ned in Sections 4.2 and 5.3.1.e main additions are the heads for empty, unit, and pair types. While thesecan be de ned as inductive types, having them as primitives helps us genericallyrepresent inductive types.6.3.2 An Inductive Representation of the Unknown TypeWe represent the unknown type and germ types for each head as an inductive fam-ily indexed by typeMaybe Head. An index of nothing indicates a value of type ?,whereas a value of type just h indicates a member of the germ for h. Represent-193ing these as dierent types in the same indexed family simpli es the terminationargument when traversing values of the unknown type. We also assume we haveconstructed the model for all levels lower than the current one, and that we canrefer toC−1 : Type, the code for the previous Universe a` la Tarski. In Section 6.4.3we tie the knot by de ning our codes by recursion on universe levels.data ?Germæ {` : N} : Maybe Head→ Type where?? : ?Ty?f : ?Ty?Tag : (h : Head)→ ?Germ (just h)→ ?Ty?1 : ?Germ (just H1)?Σ : (?Ty× ?Ty)→ ?Germ (just HΣ)?= : (?Ty)→ ?Germ (just H=)?Type : (` > 0)→ C−1→ ?Germ (just HType)?Π : (f : .æ(?Ty)→ (Læ (?Ty)))→ (limit : ?TyApprox)→ ?Germ (just HΠ)?Ctor : (tyctor : CName)→ (d : DName tyctor)→ ((r : GermResponse (germCtor ` tyctor d))→Læ(?Ty `))→ ((r : GermResponse (germCtor ` tyctor d))→ ?TyApprox `)→ ?Germ (just (HCtor tyctor))?Tyæ = ?Germæ nothingFor clarity, we write this type as if we had declared it directly as an inductivetype that was allowed to refer to itself negatively under the guarded modality.Taking its xed point with tyfix produces an equivalent type, but adds signi cantnotational overhead. An element of ?Ty is an element of ?Germ nothing, meaningthat it denotes ? or f, or is a tagged value of ?Germ (justh) for some head h. Anelement ?1 of the unit germ has no data, and an element of the pair germ con-tains two values of ?Ty. An element of the germ for equality is another member194of ?Ty, which serves as a GEq-style witness for the equality between ? and itself.A type from a lower universe can be injected into the germ with ?Type. Embed-ding values from a lower level is lossless: just as Lennon-Bertrand et al. [87] useuniverse restrictions on functions to make gcic↑ strongly normalizing, we candirectly inject functions from lower-level universes into a higher germ withoutapproximation or guardedness.e constructor ?Π for the function germ is the most subtle. It has two elds.e rst is a function from ⊲æ?Ty toLæ ?Ty. Having the domain under the guardedmodality ensures that the type is still strictly positive, and having the return un-der Læ ensures that we can actually produce a result that uses the argument, aswell as allowing possibly non-terminating computations to be represented. esecond eld is a limit, which is used in the exact version of ?Ty to produce anapproximation of the function that produces the same output for all inputs. elimit is necessary because wemay need to refer to the function in a type computa-tion, but the function itself returns a value under the Læ monad, and determiningif the described computation results in a pure value is equivalent to solving thehalting problem. When we de ne casts in Section 6.5, we ensure that the limit isalways instantiated to the function being cast, applied to ?.We explain ?Ctor in more detail in Section 6.3.3.1, but for now it su ces toknow that CName is the type of type constructors and DName tyctor is the typeof data constructors for a given type constructor. A member of the germ for aninductive type contains a data constructor for that type, and a mapping from thegerm response type for that constructor to elements of ?Ty. e germ responsetype is modelled a er responses from W-types (Section 2.2.3.2), and is essentiallya record that describes which eld of the constructor is being accessed. Like withfunctions, we need to store an approximate version outside the Læ monad thatwe can use in type computations. Unlike with the germ for functions, because thedomain is not ?Ty, we can store an approximate value for every input, as opposedto a single limit over all inputs.1956.3.3 The Germ for Inductive TypesOne of the major challenges in constructing our model is handling inductive typesgenerically. Our approach must be exible enough to give con dence that we canmodel any user-de ned inductive types, but structured enough to t within thecon nes of our model. Moreover, we need to build the infrastructure for induc-tives piece by piece. For example, we cannot describe the elds of a constructorin terms of codes until we have de ned codes.e germ for an inductive type has a tricky mutual dependency with the un-known type. We need to traverse the members of inductive types that are embed-ded into ?Ty, in order to cast them and compose them with each other. However,elds of those inductives may themselves be of the unknown type. Both traversalsneed to be done in a way that the tctt type system recognizes as terminating.Our strategy is to de ne the germ for inductive types mutually with the un-known type. More speci cally, we de ne it in the same inductive family ?Germwith a di erent index. So the usual eliminator for an inductive family can be usedto describe traversing both members of ?Ty and germ types. We use a version ofinductive descriptions to describe the eld structure of a data constructor in thegerm without needing to have the germ or ?Ty de ned beforehand. We then use aversion of W-types to incorporate these descriptions into the inductive structureof ?Germ.6.3.3.1 Signatures and Constructor Tagse rst piece of any inductive type is what we call a signature, which is a linked-list structure that speci es how many elds a data constructor has, and whethereach eld is merely an argument (not recursive) or an element of the type it-self. For argument and recursive elds, we store their arity, a lower-bound on thenumber of arrows in the type. e signature is then used to index descriptions ofinductive types, so that we can traverse di erent types in parallel if they have thesame signature (for example, if they are instantiations of the same parameterized196type).data IndSig whereEndE : IndSigArgE : (arity : N)→ IndSig→ IndSigRecE : (arity : N)→ IndSig→ IndSigWe parameterize the entire model over an arbitrary but xed set of inductivetypes. Nearly every module of our development takes such a record as a parame-ter, describing what inductive types are declared, what their constructors are, anda signature describing the shape of the elds for each constructor.record DataTypes wherenumTypes : NnumCtors : (tyctor : CName)→ NindSig : (tyctor : CName)→ (DName tyctor)→ IndSigWeuseCName := Fin numTypes andDName := 𝜆 tyctor→ Fin (numCtors tyctor)as shorthand for the types of type constructors and data constructors respectively.6.3.3.2 Descriptions for Germ ConstructorsWhat is in the germ for each inductive type? Above we saw that ?Ty can containelements of the germ for each constructor. In GEq the germ was the inductivetype with ? supplied for each parameter, but in our model we have not yet de-ned codes describing types, let alone a value ? for each code’s type. Moreover,replacing parameters with ?may violate strict positivity. One could de ne a typeC (A : Type) (B : Type) : Typewith a single constructorD : (A→ B)→ C A B. Butif the germ is C ? ? and ?Typeℓ embeds this germ, in the model ?Ty would containunguarded functions from ?Ty to itself.Instead, we store each eld by casting to ? or a function producing ?. estructure is given by a description for each germ constructor, which is a simpli ed197version of an inductive description (Section 2.2.3.3). ese descriptions give us away to describe how the germ of an inductive type looks, in terms of elds withtype ?Ty, before we have actually de ned ?Ty, which ensures that we can only useit strictly positively.data GermTele : N→ Type1 whereGNil : GermTele 0GCons : (A : Type)→ (A→ GermTele n)→ GermTele(S n)data GermCtor : IndSig→ Type whereGEnd : GermCtor SigEGArg : {n : N}{sig : IndSig}→ (dom : GermTele n)→ (D : GermCtor sig)→ GermCtor (SigA n sig)GRec : {n : N}{sig : IndSig}→ (dom : GermTele n)→ (D : GermCtor sig)→ GermCtor (SigA n sig)GEnd marks that there are no further constructors. GArg and GRec have identi-cal eld types, because the germ encodes both recursive and non-recursive eldsof inductives using ?Ty. Having separate argument and recursive constructors isuseful when de ning casts from inductive types to the germ (Section 6.5.5.3). Fora signature with arity n,GArg andGRec each take a telescope of length n, which isjust n nested dependent pair types. If the eld has type (x1 : T1)→ . . . (xn : Tn)→ T,then the domain telescope is (x1 : T1)× . . .×Tn.Our de nition of ?Germ is parameterized over a function:germCtor : (tytor : CName)→ (d : DName tyCtor)→ GermCtor (indSig tyctor d)As we add more machinery to our model, we will add more parameters re ningthe structure of inductive types.e GermCtor type describes the type of the germ for a particular type anddata constructor, but to actually store things of those types, we interpret them198into the germ response types that ?Ctor referred to:GermTeleEnv : GermTele n→ TypeGermTeleEnv GNil = 1GermTeleEnv (GCons A rest) = (x : A)×GermTeleEnv (rest x)GermResponse : GermCtor sig→ TypeGermResponse GEnd = 0GermResponse (GArg dom D) = GermTeleEnv dom+GermResponse DGermResponse (GRec dom D) = GermTeleEnv dom+GermResponse Den the ?Ctor constructor interprets the description for a germ constructor intoa simpli ed version of a W-type. Recall its type:?Ctor : (tyctor : CName)→ (d : DName tyctor)→ ((r : GermResponse (germCtor ` tyctor d))→Læ(?Ty `))→ ((r : GermResponse (germCtor ` tyctor d))→ ?TyApprox `)→ ?Germ (just (HCtor tyctor))So the germ contains an uncurried version of a function that, for each argu-ment, yields a function producing ?. In our example above, the eld with type(x1 : T1)→ . . . (xn : Tn)→ T is modelled as an uncurried function from the corre-sponding telescope ((x1 : T1)× . . . (Tn))→ ?Ty ℓ .6.3.3.3 Example : VectorsConsider the inductive type of vectors from Section 2.2.2.6, with equality con-straints instead of indices:data Vec (A : Type)(n : N) : Type whereNil : (n = 0)→ Vec A nCons : (m : N)→ A→ Vec A m→ (n = S m)→ Vec A n199e signatures for Nil and Cons would be:nilSig : SigA 0 SigEconsSig : SigA 0 (SigA 0 (SigR 0 (SigA 0 SigE)))e constructors would be:GArg GNil GEnd : GermCtor nilSigGArg GNil (GArg GNil(GRec GNil (GArg GrmTeleNil GEnd))) : GermCtor consSige responses for these are respectively:1+01+1+1+1+0All of this is a long-winded way to say that for Nil, our model’s germ for Veccontains one value of type ?Ty, storing the witness of the equality between n and0. For Cons it has four values of type ?Ty: the tail length, the head, the tail, andthe witness that the list length is one longer than the tail.If, for example, we designed a type SequenceVec, where Cons took a head oftype N→ A instead of just A, then the signature for Cons would be:consSig : SigA 0 (SigA 1 (SigR 0 (SigA 0 SigE)))e second GNil in the constructor is replaced with GCons N (𝜆x.GNil), and theresponse type for Cons would be:1+N+1+1+06.3.3.4 Approximation for Inductive TypesOur approach to inductives causes approximations to happen. By de ning allelds of inductive germ types to be ?Ty or function types with codomain ?Ty, we200obtain a straightforward way to traverse them within the connes of our targettype theory. However, with approximate normalization, converting to ?Ty is alossy operation.In approximate mode, constructor elds whose contents contain functionsmay be approximated. We try to reduce this approximation as much as possibleby only converting the results of functions to ?Ty. (We explain how this interactswith our termination argument in Section 6.5). However, if a eld’s type contains? to the le of a function arrow in the germ, then in our model, that eld must begiven arity 0 so that it can be approximated. is approximation is by design andis a critical part of our termination argument.However, some unnecessary approximations may happen on functions thatare nested deeper within data types. If a constructor eld has type List (N→ N),when a value for that eld is converted to ?Ty, all the functions in the list are con-verted to 1→ ?Ty, even though we could safely embed a function of typeN→ ?Tyinto ?Ty. Even in exact mode, these overapproximations can happen, because wit-nesses of equality are stored in approximate form.We believe that future workwill be able to remove these unnecessary approxi-mations. e main impediment to removing them now is extra restrictions placedon termination in Cubical Agda [63]. Since we do not use univalent features, theserestrictions can probably be soundly removed, but for this dissertation, we favourover-approximation over possibly compromising the soundness of the termina-tion argument.6.4 Modelling Types: A Gradual Universe of CodesWe now have a type to model ?, but ? is only one type in ⊲GEq. In this section, weshow how all the types of ⊲GEq are modelled, using a Universe a` la Tarski, withcodes that are interpreted to types.6.4.1 Gradual W-TypesIn this section, we use a modi ed version of W-types from Section 2.2.3.2, de nedas follows:201data Wæ (S : Type) (Pæ : S→Læ Type) (Papprox : S→ Type) whereWsup : (x : S)→ (Pæ x→Læ (Wæ S Pæ Papprox))→ (Papprox x→ (Wæ S Pæ Papprox))→Wæ S Pæ PapproxWf : Wæ S Pæ PapproxW? : Wæ S Pæ PapproxWe add two constructors,W?andWf, which correspond to ?C andfC for aninductive type C. We also modify the denition of Container to store two func-tions, one producing a result under Læ and one producing a pure approximation.is enables approx to be implemented in the next section.6.4.2 Codes for inductive typese universe of codes is de ned as a giant, mutually inductive-recursive de ni-tion, with several helper functions and types.C : N→ TypeElæ : C `→ Typeapprox : (c : C `)→ Elæ c→ ElApprox cexact : (c : C `)→ ElApprox c→ Elæ capproxExact : (c : C `)→ (x : ElApprox c)→ approx (exact x) = xCDesc : (cArg : C `)→ IndSig→ TypeinterpDesc : CDesc cArg sig→ ElApprox cArg→ ContainerFor clarity, we present each code along with its interpretation, instead of as twomonolithic de nitions. We omit the de nitions of approx, exact, and approxExact,202since they are conceptually straightforward but very long.6.4.2.1 Unknown and ErrorC? : C `Elæ C?= ?Tyæ `Cf : C `Elæ Cf = 1e codes denoting ?Typeℓ andfTypeℓ contain no arguments. e unknown type isinterpreted with our type from the previous section. e error type is interpretedto the unit type, since its only value is a dynamic type error. So ?fTypeℓ is equal toffTypeℓ .6.4.2.2 Unit and EmptyC1 : C `Elæ C1 = BC0 : C `Elæ C0 = 1e codes for unit and empty have no arguments. e interpretation of the unittype has two elements: one denoting unit : Unit and one denoting an error. So?Unit is equal to unit : Unit. For the empty type, the interpretation is identical tothe error type. However, we keep these as separate codes because they are treateddi erently by precision and consistency. If Cf shows up in a type, then an errorhas occurred when computing that type, but C0 denotes a perfectly reasonablestatic type and should not indicate an error. An inhabitant of either type must bean error.2036.4.2.3 FunctionsCΠ : (dom : C `)→ (cod : ElApprox dom→ C `)→ C `Elæ (CΠ dom cod) =(x : El dom)→ (Læ (Elæ (cod (approx x))))× (ElApprox (cod (approx x)))With functions, we start to see how approximation ts into the design of ourmodel. e code for a function takes a code for its domain type and a codomaincode for each approximate element of the domain, so that we can encode depen-dent function types. Functions (and other value-dependent types) are why weneed induction-recursion: we cannot de ne the type of the code for a functionwithout the interpretation of its domain code.For the interpretation of functions, we see the same pa ern that we saw with?Ty and inductive germs. A function code is interpreted to a function that, for ev-ery input, produces a pair containing an exact computation under Læ and a pureapproximation. e result type of the function is computed using the approxi-mation of the argument’s value, avoiding the need to handle non-termination intype computations.6.4.2.4 PairsCΣ : (dom : C `)→ (cod : ElApprox dom→ C `)→ C `Elæ (CΣ dom cod) =(x : El dom)× (ElApprox (cod (approx x)))Dependent pairs work like functions, butwithout the need to put anything behindthe Læ monad. e type of the code constructor is exactly the same: we have adomain code describing the type for the rst element, and a codomain code foreach approximate value of the rst element. e interpretation is a dependentpair type, where the second element’s type is computed using the approximationof the rst element’s value.2046.4.2.5 TypesCType : (` > 0)→ C `Elæ CType = C−1If we are constructing the universe of codes at a level higher than zero, then wecan include both codes and values from lower universes. e CType constructormodels Typeℓ−1, and is interpreted to be the type of all codes from one universelevel lower. In Section 6.4.3 we describe how we compute the lower-level codesrecursively.2056.4.2.6 EqualityC= : (c : C `)→ (ElApprox c)→ (ElApprox c)→ C `Elæ (C= c x y) = ElApprox cEquality is modelled in a straightforward adaptation of GEq’s equality, with onemajor change: witnesses are approximate. e code constructor takes a codefor the type of elements being compared, and two approximate elements of thatcode’s type, which are the equated values. e interpretation of an equality code isthe approximation of the type of the equated values: an inhabitant of the gradualequality between terms is a witness of their consistency.Having the equated terms in the code be approximate is necessary for decid-able type checking, but having the witness be approximate is a design choice. Wecould change the interpretation to be Elæ c and for the most part the languagewould be unchanged. However, having approximate witnesses helps with the us-ability of the language: since witnesses are not in GEq’s surface language (andhence, not in a hypothetical ⊲GEq surface language), their computations shouldbe opaque to the programmer. If a witness computation does not terminate, thennding the source of the error is extremely di cult for the programmer, becausethe loop is happening in code they did not write and cannot see.6.4.2.7 Inductive TypesAs with the germ types, handling inductive types introduces fairly signi cantcomplexity into our universe of codes. To generically describe inductive typesin terms of codes, we use a technique originated by Diehl and Sheard [49]. Wede ne an inductive type of descriptions, specifying inductive types whose eldsare themselves denoted by codes. We then interpret those “closed-universe” de-scriptions to an open-universe description, in our case, a gradual W-type.First, a helper predicate HasArityAtLeast ensures a given nested function or206pair type has the required depth:data HasArityAtLeast : Head→ N→ C `→ Type whereArity0 : (c : C `)→ HasArityAtLeast h 0 cArityΠ : (dom : C `)→ (cod : ElApprox dom→ C `)→ ((x : ElApprox dom)→ HasArityAtLeast HΠ n (cod x))→ HasArityAtLeast HΠ (S n) (CΠ dom cod)ArityΣ : (dom : C `)→ (cod : ElApprox dom→ C `)→ ((x : ElApprox dom)→ HasArityAtLeast HΣ n (cod x))→ HasArityAtLeast HΣ (S n) (CΣ dom cod)en, we have a type of descriptions over a given signature.data CDesc : (cArg : C `)→ IndSig→ Type whereCEnd : CDesc cArg SigECArg : (cField : ElApprox cArg→ C `)→ ((arg : ElApprox cArg)→ HasArityAtLeast HΠ n (cfield arg))→ (D : CDesc (CΣ cArg cField) sigRest)→ CDesc cArg (SigA n sigRest)CRec : (dom : C `)→ ((arg : ElApprox cArg)→ HasArityAtLeast HΣ n (dom arg))→ (D : CDesccArg sigRest)→ CDesc cArg (SigR n sigRest)e cArg index captures the types from previous elds on which this eld candepend. ough not typically used in inductive descriptions, they enable us toensure that even if eld types depend on previous argument values, the signatureof an inductive type is statically known. Every description starts with an index ofC1, but builds the index up in deeper elds.eCEnd constructor denotes no more elds. eCArg constructor describesa non-recursive eld with argument type given by interpreting cField, which can207depend on the values of previous elds. We take a predicate to ensure that thetype is at least n nested function types, which lets us avoid unnecessarily ap-proximating the rst n layers of functions when converting to ?Ty. Finally, thedescription contains a recursive eld describing the rest of the constructor, withthis eld type added to the argument type, because later eld types may dependon the value of this eld. e CRec constructor describes a recursive eld. If weare constructing datatype C, then the domain code for CRec denotes the type Tfor which this eld has type T→ C. Again we ensure that the domain has thegiven arity, although we uncurry and ensure that it is n nested pair types, sincethe function’s nal domain type is the recursive reference, and is not given by thecode. We then have a description giving the remainder of the elds.Consider our vector type from Section 6.3.3.3. Assuming codes CA and CNdescribing the vector’s content type and natural numbers respectively, the de-scriptions for nil and cons of type Vec (El A) n would be:CArg (λ .C= n 0) : CDesc C1 nilSigCArg (λ.CN) Arity0 (CArg (λ .cA) Arity0 (CRec (λ .1) Arity0 (CArg (λ( ,m).C= cN (S m) n) Arity0 CEnd))): CDesc C1 consSigLike with the germ, Nil is modelled with a single eld that stores an equalitywitness between the length and zero. ere are four elds for Cons: the lengthof the tail, the head, the tail, and the witness between the length and one plus thetail length.e function interpDesc interprets descriptions into a command and response(Section 2.2.3.2), which make up the container whose xed-points we take usinggradual W-types. e command and response components are computed as fol-208lows:CommandD : CDesc cArg sig→ ApproxEl cArg→ TypeCommandD CEnd arg = 1CommandD (CArg cField D) arg =(x : El (cField arg)× (CommandD D (arg,approx x)))CommandD (CRec D) arg = CommandD D argResponseD : (D : CDesc cArg sig)→ (arg : ApproxEl cArg)→ (CommandD D arg)→ TypeResponseD CEnd arg com = 0ResponseD (CArg ) arg com = ResponseD arg comResponseD(CRec dom D) arg = (El (dom arg)) + (ResponseD D arg)mergeContainers : (DName tyctor→ Container)→ ContainermergeContainers f = ((d : DName tyCtor)× fst (f d), λcom.snd (f (fst com))For CArg, we store data in the command and just calculate the response recur-sively, and for CRec, we calculate the response recursively and use the domaintype as the response, so our nal eld has a function from the domain type tothe inductive type. e mergeContainers helper function turns a container foreach data constructor into one container with a eld containing a constructor tagfollowed by the elds for that constructor.209Finally, we have what we need to dene the codes for inductive types:Cµ : (tyctor : CName)→ (cI : C `)→ (Ds : (d : DName tyCtor)→ CDesc C1 (indSkeleton tyCtor d))→ ApproxEl cI→ C `Elæ (Cµ tyctor cI Ds i) =W (interpDesc (mergeContainers(λd. interpDesc (Ds d) true))e code constructor for inductive types takes a type constructor and an indextype for that constructor. ere is a map Ds containing a description for eachdata constructor, and a value for the index. In principle, the code of the indextype for a given type constructor should be xed, or at least xed for a given setof parameters. However, we cannot de ne the codes for each constructor’s indextype until we have nished de ning codes, so we pass the index type in explicitly.e index value is not used, apart from when computing the meet of two codes,but we anticipate it being useful for future work that extends the metatheory ofthis model.e interpretation of an inductive code type is the xed point of the containerthat contains all of its constructors’ containers. Because W is strictly positive inits parameter, such a xed point is allowed in our target type theory.6.4.3 Tying the KnotFinally, we have a code for each ⊲GEq type former, and a type corresponding toelements of that type. e last detail is to ll in the references to C−1. We can dothis inductively: we de ne C 0 with C−1 := 0. De ning it this way does not causeissues because any references to C−1 were hidden behind a proof that ℓ > 0, sowhen ℓ is 0, the constructors that references C−1 cannot be used. In the recursivecase, for C (ℓ +1), we can set C−1 to C ℓ .2106.5 Elimination Operations on ValuesIn this section we describe how we model the ⊲GEq elimination forms. Due tothe way we establish termination, the actual terms for these operations are un-fortunately quite long. at said, the implementations are o en straightforwardadaptations of the reduction rules, including those inherited from GEq or gcic.We a empt to strike a balance between providing the details of how the modelis actually constructed, and omi ing detail so that the core intuition can be pro-vided. As such, in some parts we give a high-level prose description of the terms,or write them in pseudocode rather than the full detail of the theory. As always,the masochistic curious reader can see the full Agda code in [56].6.5.1 Operations for InductivesTo de ne our operations, we parameterize over one more property for inductives.e codes for inductive types contained descriptions, whichwere themselves builtout of codes. However, the descriptions for germs were not, since they were de-ned before codes. ese de nitions are parameterized over a predicate whichgives, for each germ constructor, a code for each type in its domain telescope,along with proofs that the code’s element type is isomorphic to the domain type.So we can cast to and from code types whenmanaging the arguments to functionsin the germ of an inductive type.at said, we do not write out the terms for casting and composition of induc-tive types. Because ofW-type approach to inductives, casting and composition forinductives is e ectively a combination of the same operations on dependent func-tions and pairs. e functions for dealing with W-types are nigh incomprehensi-ble, so we choose instead to describe the interesting parts of the implementation.6.5.2 Dynamic ErrorsEach code has an operation to compute an error at its type. It is computed usingstraightforward recursion, and because it does not rely on composition or casting,211it does not need to be part of our mutual recursion.fFor : (c : C `)→ Elæ cfForæ C? = ?ffForæ Cf = unitfForæ C0 = unitfForæ C1 = falsefForæ CType = CffForæ (CΠ dom cod) =pure (fForæ (cod (fForæ dom)))),λx. (fForApprox (cod (fForApprox dom))fForæ (CΣ dom cod) = (fForæ dom,fForæ (cod (fForApprox dom)))fForæ (C= c x y) =fFor cfForæ (Cµ tyctor c D x) = WfWe use this as a result when composing terms or casting between codes whoseheads are mismatched.6.5.3 Well-Founded Recursion on Codes and ValuesModelling the sizes of ⊲GEq types requires some subtle tricks, which we outlinehere. When casting between types or composing two types, we need sizes for twocodes. e symmetry of both of these operations means that we cannot comparethe sizes using a lexicographic ordering, since neither argument’s size can dom-inate the other. We also need to use ordinals, rather than the depth of the trees,because we need the code size for (x : T1)→ T2 to be strictly larger than T2 in-stantiated with any value for x. Finally, we need our ordinals to be constructive,so we can express them in tctt.To see why we cannot use a lexicographic ordering, consider the composition:(x : T1)→ T2&Type (x : T′1)→ T′2We compose the domains to get T1&Type T′1. However, to compose the codomains,212we need to cast the argument x from T1&Type T′1 to both T1 and T′1. So we needboth of the following inequalities to hold:(T1&Type T′1 , T1)<((x : T1)→ T2 , (x : T′1)→ T′2)(T1&Type T′1 , T′1)<((x : T1)→ T2 , (x : T′1)→ T′2)is inequality does not hold in general for a lexicographical order: there is noreason that T′1 cannot be massively larger than both T1 and T2.Instead, we compare pairs of types by de ning a maximum operation∨onthe ordinals describing their sizes. In addition to being a true least upper-bound,we also need∨to be strictly monotone, that is, to satisfy 𝑠1∨𝑠2 < 𝑠′1∨𝑠 ′2 whenever𝑠1 < 𝑠′1 and 𝑠2 < 𝑠 ′2. is inequality arises because each recursive call must be madeon a strictly smaller argument. Finally, we show that the size of the compositionof two types is bounded by the maximum of the size of either types. Given theseproperties, we can properly order the sizes in the rst inequality above:(T1&Type T′1∨T1)≤(T1∨T′1∨T1)≤(T1∨T′1)<((x : T1)→ T2∨(x : T′1)→ T′2)6.5.3.1 Brouwer TreesUnfortunately, it was not immediately apparent that any of the “o -the-shelf”formulations of constructive ordinals satis ed our critera, so we built our own213formulation. We use a rened version of Brouwer trees:data Ord : Type whereOZ : OrdO↑ : Ord→OrdOLim : (c : C `)→ (ElApprox c→Ord)→Ordere is a zero ordinal, a successor operator, and a limit ordinal that is the leastupper bound of the image for a function from a code’s type to ordinals. We borrowthe trick of taking the limits over types (or in our case, codes) from Chan [27],since this lets us easily model the sizes of dependent functions and pairs. eordering on these trees is de ned following Kraus et al. [83]:data ≤o : Ord→Ord→ Type where≤oZ : (o : Ord)→OZ≤o o≤osucMono : (o1 : Ord)→ (o2 : Ord)→ o1 ≤o o2→O↑ o1 ≤o O↑ o2≤ococone : (c : C `)→ (o : Ord)→ (f : ElApprox c→Ord)→ (k : ElApprox c)→ o≤o f k→ o≤o OLim c f≤olimiting : (o : Ord)→ (c : C `)→ (f : ElApprox c→Ord)→ ((k : ElApprox c)→ f k≤o o)→OLim c f ≤o oo1 <o o2 = O↑ o1 ≤o o2at is, zero is the smallest ordinal, the successor is monotone, and the limit isactually the least upper bound of the function’s image. Unlike Kraus et al. [83],we do not include transitivity as a rule, but we can prove it as a theorem. e214maximum function on ordinals is dened as follows:maxo : Ord→Ord→Ordmaxo OZ o = omaxo o OZ = omaxo (O↑ o1) (O↑ o2) = O↑ (maxo o1 o2)maxo (OLim c f) o = OLim c (λk.maxo (f k) o)maxo o (OLim c f) = OLim c (λk.maxo o (f k))Long but straightforward proofs show that𝑚𝑎𝑥𝑜 is monotone and computes andupper bound of its inputs. It reduces when given O↑ for both inputs, so it isstrictly monotone. However, we cannot prove that it is a least upper-bound. eproblem is that limits are not well-behaved with respect to the maximum. Wecould instead construct the maximum using OLim, but this version would not bestrictly monotone.6.5.3.2 A Least Upper BoundWe solve the problems with maxo using a type of sizes, which include only thesubset of ordinals that are idempotent with respect to the maximum. We can then215dene a type of sizes with the same interface as ordinals.Size : TypeSize = (o : Ord)× (maxo o o≤o o)∨: Size→ Size→ Sizes1∨s2 = (maxo (fst s1) (fst s2), . . .)SZ : SizeSZ = (OZ,≤oZ)S↑ : Size→ SizeS↑ s = (O↑ (fst s),≤ssucMono (snd s))Critically, the sizes are closed under the maximum operation: ifmaxo o1 o1 ≤o o1and maxo o2 o2 ≤o o2, then maxo (maxo o1 o2) (maxo o1 o2) ≤ (maxo o1 o2). Zeroand a successor operation for sizes are easily implemented. e di culty is con-structing a limit operator for sizes, since the self-idempotent ordinals are notclosed under OLim. Our trick is to take the limit of maxing an ordinal with it-self. We assume we have a code CN whose elements have an injection CtoN intoN. e natural numbers can be de ned as an inductive type, but in our Agda de-velopment we add it as an extra code constructor. Having numbers lets us take themaximum of an ordinal with itself in nitely many times, resulting in an ordinal216that is as large as the original but idempotent with respect to maxo.nmax : Ord→ N→Ordnmax o Z = OZnmax o (S n) = omax (nmax o n) omax∞ : Ord→Ordmax∞ o = OLim CN (λk.nmax o (CtoN k))max∞Idem : {o : Ord}→maxo (max∞ o) (max∞ o)≤o (max∞ o)SLim : (c : C `)→ (ElApprox c→ Size)→ SizeSLim c f = (max∞ (OLim c (λk. fst (f k))), max∞Idem)Sizes satisfy all the same inequalities as raw ordinals, listed in Fig. 6.1. emonotonicity of∨follows from the monotonicity of maxo, and the idempotenceof∨follows by the de nition of Size. Monotonicity, idempotence, and transitivityof ≤s together imply that∨ is a least upper bound, and strict monotonicity followsfrom the strict monotonicity of maxo.6.5.4 Defining the OperationsWith our type of sizes, we can outline our approach for proving termination forthe approximate versions of our operations.6.5.4.1 Termination StrategyWe de ne a function codeSize : C ℓ → Size which computes a Size in a straight-forward way. Each term’s size is S↑ applied to the maximum of its subterms’ sizes.When a term binds a variable, we use SLim to take the limit over all values of thatvariable. Leaves in the syntax tree have size one, i.e. S↑ SZ.217≤s : Size→ Size→ Sizes1 ≤s s2 = (fst s1)≤o (fst s2)<s : Size→ Size→ Sizes1 <s s2 = (S↑ s1)≤s s2≤strans : (s1 : Size)→ (s2 : Size)→ (s3 : Size)→(s1 ≤s s2)→ (s2 ≤s s3)→ (s1 ≤s s3)≤sZ : (s : Size)→ SZ≤s s≤ssucMono : (s1 : Size)→ (s2 : Size)→ s1 ≤s s2→ S↑ s1 ≤s S↑ s2≤scocone : (c : C `)→ (s : Size)→ (f : ElApprox c→ Size)→ (k : ElApprox c)→ s≤s f k→ s≤s SLim c f≤slimiting : (s : Size)→ (c : C `)→ (f : ElApprox c→ Size)→ ((k : ElApprox c)→ f k≤s s)→ SLim c f ≤s s∨≤: (s1 : Size)→ (s2 : Size)→ (s1 ≤s s1∨s2)× (s2 ≤2 s1∨s2)∨mono : (s1 : size)→ (s2 : Size)→ (s′1 : Size)→ (s′2 : Size)→ (s1 ≤s s′1)→ (s2 ≤s s′2)→ (s1∨s2)≤s (s′1∨s′2)∨idem : (s : Size)→ (s∨s)≤s s∨lub : (s1 : size)→ (s2 : size)→ (s : Size)→ (s1 ≤s s)→ (s2 ≤s s)→ (s1∨s2 ≤s s)Figure 6.1: Ordering on Sizes218To construct our operations, we use a record type:record CastComp (` : N) (notInUnkNeg : B) (cSize : Size) : Type where?Forsæ : (c : C `)→ (codeSize c =Size cSize)→ Elæ cmeetsæ : (c : C `)→ Elæ c→ Elæ c→ codeSize c =Size cSize→Læ (Elæ c)codeMeets : (c1 : C `)→ (c2 : C `)→ (codeSize c1∨codeSize c2 =Size cSize)→ (c : C `)× (codeSize c≤s codeSize c1∨codeSize c2)castsæ : (cDest : C `)→ (cSource : C `)→ (Elæ cSource)→ (codeSize cDest∨codeSize cSource =Size cSize)→Læ (Elæ cDest)e boolean ag indicates whether we are currently traversing a subterm of aterm of type ?. We explain the need for this in Section 6.5.5. e record’s elds arethe operations we are building, with an additional proof that the size parameteris either the size of the code argument or the maximum of the two code sizes. Sofor any given code or codes, there is exactly one value of cSize where CastCompcontains an operation that can be used.To construct an instance of CastComp we use well-founded recursion. Weshow that there are no in nite descending chains of sizes using the usual acces-sibility predicate technique [18], then do well-founded recursion on the lexico-graphic ordering of ℓ ,notInUnkNeg and cSize. us, when writing the functionfor each operation, we can access a record containing the operations for everycode size smaller than the current code, and for all smaller universes. We omitthe proofs that each recursive call is on a smaller code, as well as the proofs aboutthe size of composing codes: once we have determined the decreasing measure,the actual proofs are long but straightforward.6.5.4.2 CompositionWe describe the computational content of the meet function in Fig. 6.2. e meetfor dependent pairs (and hence, inductive types) relies on casts. When we changethe value of the pair’s rst element, the type of the second element may change.Also, the call to codeMeet is not on a strictly smaller code, but on a strictly smaller219universe level.In general, the non-trivial rules for composition are between terms built withthe same syntax former whose subterms are metavariables. So the redex corre-sponds directly to the paern we match upon in our model function. In the caseof data constructors DC1 and DC2 for an inductive C, we perform an additionalcheck that the constructors are the same, which is possible because propositionalequality is decidable for nite numbers. Likewise, when composing two elementsof ?Typeℓ , we compare their heads using a similar decidable equality procedure.e reduct then contains compositions or casts of terms of smaller types. So ingeneral, for a reduction t1&T t2 { t, t1 and t2 give the pa erns for a clause ofour function, and EÈtÉ gives the right-hand side. Since casts and compositionsof subterms produce a result in the Læ monad, the monadic bind can be used toincorporate them into the nal result.When we take the meet of two terms of type ?Ty, we are no longer decreasingin the size of the codes, since the code is C? at each stage. However, becausewe have formulated ?Ty as a self-contained recursive type, we can use structuralrecursion to compose its values. Even though the domains of functions may notbe of type ?Ty, we never actually need to compose values of the domains, only ofthe return types. We omit this function, since each case is just a simpler versionof a non-? case.e idea is largely the same for codeMeet (Fig. 6.3), with the main di erencebeing that the nal result is not under a monad. However, recall that the functionfromL can extract pure values from LApprox, because the monad was the identity.So whenever we use casts ormeets when composing codes, we rst approximatetheir inputs, ensuring that only pure computations are used to compute the codes.6.5.5 Casting6.5.5.1 Same-Headed CodesFigures 6.4 and 6.5 gives our implementation of casting. Similar to composition,the rules for casting generally are between types with the same head, where thesubterms of the type are metavariables. Translating the reduct informs us as tohow that case should be implemented. e interesting cases are for function types220meetsæC? (?Tag h1 x) (? Tag h2 y) =case (decEqh1 h2) of(yes refl)⇒ germmeetsæx y(no npf)⇒ pure ?fmeetsæ Cf x y = pure unitmeetsæ C0 x y = pure unitmeetsæ C1 x y = pure (and x y)meetsæ CType x y = pure (codeMeets x y)meetsæ (CΠ dom cod)f g = pure λx. letfx = fst (f x)gx = fst (f x)fgx = meetsApprox(cod (approx x)) (approx fx) (approx gx)fgExact = dofEx← snd(f x)gEx← snd(g x)meetsæ(cod (approx x)) fEx gExin (fgx, fgExact)meetsæ (CΣ dom cod) (x1, y1) (x2, y2) = dox12←meetsæ x1 x2y′1← castsæ (cod (approx x12)) (cod x1) y1y′2← castsæ (cod (approx x12)) (cod x2) y2y12←meetsæ(cod (approx x12)) y′1 y′2pure (x12,y12)meetsæ (C= c x y) w1 w2 = meetsApprox w1 w2meetsæ c x y = pure (fFor c) --catch-all for remaining cases, produces errorFigure 6.2: Model of Composition221codeMeets (C?) c = ccodeMeets c (C?) = ccodeMeets (Cf) c = CfcodeMeets c (Cf) = CfcodeMeets C1 C1 = C1codeMeets C0 C0 = C1codeMeets CType CType = CTypecodeMeets (CΠ dom1 cod1) (CΠ dom2 cod2) = letdom12 = meetsApprox dom1 dom2cod12 = λx12. letx1← castsApprox dom1 dom12 x12x2← castsApprox dom2 dom12 x12in codeMeets (cod1 x1) (cod2 x2)in CΠ dom12 cod12codeMeets (CΣ dom1 cod1) (CΣ dom2 cod2) = . . . (same as for CΠ)codeMeets(C= c1 x1 y1) (C= c2 x2 y2) = letc12 = codeMeets c1 c2x′1 = castsApprox (codeMeets c1 c2) c1 x1x′2 = castsApprox (codeMeets c1 c2) c2 x1y′1 = castsApprox (codeMeets c1 c2) c1 y1y′2 = castsApprox (codeMeets c1 c2) c2 y1x12 = fromL (meetsApprox x′1 x′2)y12 = fromL (meetsApprox y′1 y′2)in C= c12 x12 y12codeMeets c1 c2 = Cf --catch-all for remaining cases, produces errorFigure 6.3: Model of Composition for Codes222and equality types. For functions, we must cast the argument back to the source’sdomain type, then cast the result. For equality, we cast the witness to the newtype, but additionally take its meet with both of the new equated terms, to ensurethat it is as precise as they are.6.5.5.2 Functions and The Unknown Typee only interesting cases for casting to or from ? are for functions and inductivetypes, so we omit the helper functions toGerm and fromGerm. In Fig. 6.6 we showthe cases for casting from a function type to the germ and vice versa, which arethe main places where the approximate and exact semantics di er.To convert a function to the germ for function types, we need to produce anapproximation of type ?Ty, and a function of type ⊲æ ?Ty→Læ ?Ty. To computethe approximation, we apply the approximation in the input to ?For of the domaintype. is call is why ?For is in our group of mutually dependent operations. Tocompute the non-approximated function, we branch based on whether we are inapproximate or exact mode. In the approximate case the “full” function is just aduplication of the approximation, because ⊲æ ?Ty = 1. In the exact case, we canapply (pure next) to the guarded argument with ~ to get a value of type ⊲(L ?Ty),then apply Later to getL ?Ty. e monadic bind then lets us give it as an argumentto the exact function.e key to logical consistency of the model is hidden in how we apply func-tions that take guarded arguments. Because ?Ty ℓ is de ned as a guarded xed-point, when applying a function taking a guarded argument, we must manuallytransport the argument in or out of the guarded type using EqI . is accountsfor how, when de ning ?Ty, it could only refer to itself by a value of type IType,and hence had to apply I to obtain a type. is transport does not reduce, so theterm itself does not run forever, even if it describes a computation that does.When casting from ?, we check if the tag matches the type we are casting to. Ifit does, we use a helper function to cast to the destination type, and if it does not,then we produce an error. Converting from ? to a function type is much simplerthan the converse. We cast the argument to ?Ty, use next to guard the result ofcasting, then apply the germ function and cast the result. e result has the same223castsæ (C?) cSrc x = dox′← toGerm cSrc xpure (?Tag (codeHead cSrc) x′)castsæ cDest (C?) ??= pure (?Forsæ cDest)castsæ cDest (C?) ?f = pure (fForsæ cDest)castsæ cDest (C?) (?Tag h x) = case (decEq h (codeHead cDest)) ofyes refl⇒ fromGerm cDest xno npf⇒ pure (fForsæ cDest)castsæ (Cf) cSrc x = pure unitcastsæ cDest (Cf) x = pure (fFor c)castsæ C1 C1 x = pure xcastsæ C0 C0 x = pure xcastsæ CType CType x = pure xFigure 6.4: Model of Castingapproximation for every value, regardless of the argument x. is case is whereapproximation is lossy: a function can have an approximation for every input, butonce we cast to ? and back, the result has a single approximation for all inputs.6.5.5.3 Casting Between InductivesWhen casting between inductive types and ? in either direction, we must han-dle the fact that the germ’s encoding of elds with function types may havearguments that are not of type ?. As casts, these work just like casts betweenfunction types. e di erence is in the termination argument, and is where thenotInUnkNeg ag comes into play. When casting the results of the function appli-cation, we are casting between a code’s codomain and ?Ty, giving a pair of codesstrictly smaller than the function type and C?. However, no such guarantee existsfor the arguments, because the germ’s arguments are not of type ?Ty, and hencemight have larger codes. We can take advantage of two facts. First, C? shouldnot occur anywhere within the code of the germ’s domain type, because of strict224castsæ (CΠ domDest codDest) (CΠ domSrc codSrc) x = pure λxDest. letxApproxSrc = fromL (castsApprox domSrc domDest xDest)fApprox =fromL(castsApprox (codDest (approx xDest))(codSrc xApproxSrc) fst (f xApproxSrc))fExact = doxSrc← castsæ domSrc domDest xDestfxSrc← snd (f xSrt)castsæ (codDest (approx xDest)) (codSrc (approx xSrc)) fxSrcin (fApprox, fExact)castsæ (CΣ domDest codDest) (CΣ domSrc codSrc) (xSrc, ySrc) = doxDest← castsæ domDest domSrc xSrcyDest← castsæ (codDest (approx xDest)) (codSrc (approx xSrc)) ySrcpure (xDest, yDest)castsæ(C= cDest xDest yDest) (C= cSrc xSrc ySrc) wSrc = letwDest = fromL (castsæ cDest cSrc wSrc)xybound = fromL (meetsæcDest xDest yDest)wbounded = fromL (meetsæcDest wDest xybounded)in pure wboundedcastsæ cDest cSrcx = pure (fFor cDest)Figure 6.5: Model of Casting (ctd.)positivity. Second, the germ’s domain type should be no more precise than theinput code’s domain type, because the germ is supposed to be the least preciseinstantiation of a particular inductive type.ese two facts let us make a recursive call that is smaller in terms of thenotInUnkNeg ag. If the ag is false, then we know we have already traversedinto the le -hand side of a function arrow in the germ, so we should not be seeingthe codeC?. Likewise, because the domain type is as precise as the germ, it shouldalso not contain C?. Internalizing this proof within the type theory is di cult, so225toGermæ (CΠ dom cod) f = letf?= fst (f (?For dom))fApprox = fromL (castsApprox C? (cod (?For dom)) f?)fExact = λ(x. : .æ?Ty).case æ ofApprox⇒ pure fApproxExact⇒ doxSrc← Later ((next Now)~(transport EqI x.))x?← casts dom C? xSrcfx← snd(f x?)cast C? (cod (approx x?)) fxin pure (?Tag HΠ (?Π (λ . fApprox) fExact))fromGerm (CΠ dom cod) (?Π fLim fExact) = pure λx. letretApprox = fromL (cast (cod (approx x)) C? (fLim unit))x? = cast C? dom xretExact = dolet x. = next x?fx← fExact (transport (sym EqI) x.)cast (cod (approx x)) C? fxin (retApprox, retExact)Figure 6.6: Casting Functions To and From the Germ226in this case we approximate the argument to ? as a dummy value. If the ag istrue, we can make a recursive call on a larger code, because our overall metric issmaller in the lexicographic order.e nal detail to highlight is howwe use the arity parameter of inductive sig-natures to handle inductive types that contain ?Ty→ ?Ty within a eld. Becausethe constructor descriptions for inductive germs were de ned before ?Ty, theycannot refer to ?Ty. So any elds that contain ?Ty→ ?Ty must be encoded in thegerm by casting to type ?Ty, which ensures that any functions are approximatedor guarded for the approximate or exact modes respectively. e arity number ishow we track this when casting between an inductive and ?Ty. Since we knowfunctions in inductive germs take exactly n parameters as speci ed in their arity,we process the rst n parameters of a eld, then convert whatever is le to ?Ty,function type or not.6.5.5.4 The Unknown TermComputing the unknown term for a given type is the simplest of our four opera-tions, and follows the reduction rules quite directly. e notable case is computingthe unknown term for an equality type, where we compose the equated terms toobtain the least precise witness of their consistency. e call to the meet hereis the reason we must de ne ?For as part of the mutual recursion, as opposed tode ning it beforehand like with fFor.6.5.5.5 Removing Sizese nal step in modelling eliminations is to use the record we constructed toexpose the actual operations without size constraints. Suppose the record weconstructed above using well-founded recursion is:castComp : (ℓ : N)→ (notInUnkNeg : B)→ (cSize : Size)→ CastComp ℓ notInUnkNeg cSize227?Forsæ C? = ???Forsæ Cf = unit?Forsæ C0 = unit?Forsæ C1 = true?Forsæ CType = C??Forsæ (CΠ dom cod) =λx. (?ForsApprox (cod (?ForsApprox dom)),pure (?Forsæ (cod (?Forsæ dom))))?Forsæ (CΣ dom cod) = (?Forsæ dom,?Forsæ (cod (?ForsApprox dom)))?Forsæ (C= c x y) = fromL (meetsApprox c x y)?Foræ (Cµ tyctor c D x) = W?Figure 6.7: e Unknown Term for Codesen we can de ne our operations by instantiating the size parameter with thecode size or code size maximum, and providing refl for the equality proof.?Foræ : (c : C `)→ Elæ c?Foræ c = (castComp ` false (codeSize c)).?Forsæ c reflmeetæ : (c : C `)→ Elæ c→ Elæ c→Læ (Elæ c)meetæ c x y = (castComp ` false (codeSize c)).meetsæ c x y reflcodeMeet : C `→ C `→ C `codeMeet c1 c2 =fst ((castComp ` false (codeSize c1∨codeSize c2)).codeMeets c1 c2 refl)castæ : (cDest : C `)→ (cSource : C `)→ (Elæ cSource)→Læ (Elæ cDest)castæ cDest cSource x =(castComp ` false (codeSize c1∨codeSize c2)).castsæ cDest cSource x refl2286.6 Inductives in the Modele last missing piece of our model is specifying how to interpret inductive typesin our model. As before, we assume that there is an a priori set of declared ⊲GEqinductive types. We now describe what codes and code-related functions for in-ductives we parameterize the translation over.Each inductive has a code describing its parameters and indices. e param-eter code is in the level one above the level of the inductive type. Having theparameter at a higher level allows types like List to take a Type0 parameter whilestill living in Type0.Params : CName→ C (`+1)Indices : CName→ ElApprox Params→ C `Each inductive declaration is translated into aC Desc in the straightforward way:a CArg node describes the data constructor tags, then each non-recursive or re-cursive eld is described using CArg or CRec respectively. is yields:descFor : (tyctor : CName)→ (xpars : ElApprox (Params tyctor))→ ElApprox (Indices tyctor xpars)→ CDesc 1 (indSig tyctor)6.6.1 Inductive Constructors and EliminatorsWecan use interpDesc, descFor, and theW-type constructorWsup tomake genericconstructors for each inductive type, whose arguments are codes denoting the⊲GEq types of each eld. e traversal to do so is straightforward and uses knowntechniques[48], but it is very long. We use the meta-notation ctorForC to indicateits construction, to avoid obfuscating the conceptual content of this chapter.Our model also needs eliminators for inductive types. ankfully, these canbe computed from their descriptions, using well known techniques [48]. e com-putational content of the eliminators is straightforward, and follows the compu-tational intuition of pa ern matching by inspecting a constructor tag, then exe-229cuting a particular branch based on that tag, substituting in the stored values. Ouronly additions are handling ? and f. Consider an elimination where the motiveis modelled bycmotive :W DC → C ℓat is, it takes an element of the gradual W-type given by an inductive type’sdescription, and produces a code describing the result type for each input. en,when givenW?, our eliminator produces:pure (?For (cmotive W?))Likewise, when givenWf, we producepure (fFor (cmotive Wf))We use the meta-notation elimForC to indicate the elimination form, againbecause the construction is both straightforward and not of speci c interest forgradual dependent types.Note: At the time of submission, generic inductive constructors and eliminatorshave not been implemented in our Agda mechanization, but since the technique fordoing so is not novel, adding them should be straightforward, albeit time consuming.6.7 Bringing it All Together6.7.1 The TranslationFigure 6.8 gives the nal translation from ⊲GEq to tctt using our de nitions fromthe previous chapters.6.7.2 Key PropertiesWith our model complete, we present the nal lemmas and theorem.First, reducible terms translate to propositionally equal terms in the model.Lemma 6.7.1 (Soundness). If Γ ` t⇐ T and t{Æ t′ then−−−−−−−−−−−−−−−−→(xk : LæTÈΓ(xk)É)𝑘→ (EÈtÉ =TÈTÉ EÈt′É) is inhabited in tctt. Moreover, EÈtÉ is230TÈTypeℓÉ = CTypeTÈ?TypeℓÉ = C?TÈfTypeℓÉ = CfTÈ(x : T1)→ T2É = CΠ TÈT1É (𝜆x.TÈT2É)TÈC(−−−−−→𝑡𝑝𝑎𝑟𝑎𝑚𝑠 ,−−−−→𝑡𝑖𝑛𝑑𝑖𝑐𝑒𝑠 )É = (C𝜇 C (Indices C)(descFor (fromL EÈtparamsÉ) (fromL EÈtindicesÉ))(fromL EÈtindicesÉ))EÈTypeℓÉæ = pure CTypeEÈ(x : T1)→ T2Éæ = pure (CΠ TÈE1É (𝜆x.TÈE2É))EÈC(−−−−−→𝑡𝑝𝑎𝑟𝑎𝑚𝑠 ,−−−−→𝑡𝑖𝑛𝑑𝑖𝑐𝑒𝑠 )Éæ = pure (C𝜇 C (Indices C)(descFor (fromL EÈtparamsÉ) (fromL EÈtindicesÉ))(fromL EÈtindicesÉ))EÈC(tparams, tindices, targs)Éæ = 𝑐𝑡𝑜𝑟𝐹𝑜𝑟C (fromL EÈtparamsÉ) (fromL EÈtindicesÉ) EÈtargsÉEÈindC(tscrut,TP, trhs)Éæ = 𝑒𝑙𝑖𝑚𝐹𝑜𝑟C EÈtscrutÉ (fromL EÈtPÉ)−−−−−−→EÈtrhsÉEÈ?TÉæ = (pure ?Foræ TÈTÉ)EÈfTÉæ = (pure fFor TÈTÉ)EÈ𝜆(x : T). tÉæ = pure 𝜆(x : Elæ TÈTÉ). (fromL EÈtÉApprox, EÈtÉæ)EÈt1 t2Éæ = bind2Læ (𝜆f 𝜆x . snd (f x)) EÈt1É EÈt2ÉEÈ〈T1 ⇐ T2〉tÉæ = bindLæ (castæ TÈT2É TÈT1É) EÈtÉEÈ〈h〉tÉæ = bindLæ (castæ C?TÈgerm(h)É) EÈtÉEÈt1&T t2Éæ = bind2Læ (meetæ TÈTÉ) EÈt1É EÈt2ÉEÈJ T t1 t2 tP1 twÉæ = do T1 ← snd (bind EÈTÉ EÈt1É)T2 ← snd (bind EÈTÉ EÈt2É)Tw ← snd (bind EÈTÉ EÈt2É)tPw ← bind (cast Tw T1) EÈtP1Écast T2 Tw tPwFigure 6.8: Syntactic Model of ⊲GEq: Summary231reducible.See proof in Appendix A .Second, we note that the translation produces well typed terms.Lemma 6.7.2 (Model Preserves Types). If Γ ` t⇐ T thenEÈtÉæ :−−−−−−−−−−−−−−−−−→(xk : Læ TÈΓ(xk)É)𝑘→ (Læ TÈTÉ) in tctt.See proof in Appendix A .e isomorphism between LApprox A and A, combined with type safety andthe fact that each ⊲GEq reduction corresponds to one or more reductions, givesus our strong termination result, from which decidable type checking follows.eorem 6.7.3 (Strong Approximate Normalization). If Γ ` t⇐ T, then for somenormal form v, t −→∗𝐴𝑝𝑝𝑟𝑜𝑥 v.Corollary 6.7.4 (Decidable Checking). Type checking in ⊲GEq is decidable.6.7.3 A Final ExampleSince ⊲GEq is the culmination of the ideas presented in this thesis, we discussits limitations and possible future work in Chapter 7. Instead, we conclude thechapter showing how the ⊲GEq handles Ω, the quintessential non-terminatingterm. De ne:F := 𝜆(x : ?Typeℓ ). (〈?Typeℓ → ?Typeℓ ⇐ ?Typeℓ 〉x) x232en Ω := F F. e exact translation of F in our model is (a er some let-bindingsand inlinings for readability):F : ?Ty `→ ?Ty `F = λ(x : ?Ty `). letfA = fromL (castApprox (CΠ C? (λ .C?)) C? x)retA = fromL(snd(fA x))retE = dofE← castExact (CΠ C? (λ .C?)) C? xsnd(fE x)in (retA, retE)To apply F to itself, we must inject the argument into ?Ty ℓ , that is, using:F? := cast C? (CΠ C? (𝜆 .C?))Substituting in and expanding the de nition of cast yields:F?−→∗(?Tag (?Π(λ .??)(λx..dox?← Later ((next Now)~(transport EqI x.))fE← castExact (CΠ C? (λ .C?)) C? x?snd (fE x?))))To inject F into ?Ty, we compute an approximate and exact version. For theapproximate version, ?? replaces x in F. In the function position, it is cast to ?Forat the function type ?Ty→ ?Ty. is is the constant function that produces ? asthe result for all arguments, so the approximate part of F?always produces ??. For233the exact version, F is converted to a function that takes a guarded argument, sowe use the monadic bind to apply F to the guarded argument.Now we create Ω by applying F to F?. Again the approximate part yields a ??on every input. Let us examine the reduction of the exact part:snd (F F?) : L (?Ty `)−→∗(1)dofE← castExact (CΠ C? (λ .C?)) C? F?snd (fE F?))−→∗(2)dofE← pure λx. (??,dox?← Later ((next Now)~(transport EqI (transport (sym EqI) (next x))))fE′← castExact (CΠ C? (λ .C?)) C? (transport (sym EqI) (next x))snd (fE′ (transport (sym EqI) (next x))))snd (fE F?)−→∗(3)dox?← Later ((next Now)~(transport EqI (transport (sym EqI) (next F?))))fE′← castExact (CΠ C? (λ .C?)) C? x?snd (fE′ x?))At this point, reduction stops, because the monadic bind cannot reduce on thetransported version of next F?. We can, however, apply a fact about propositionalequality: transporting a term by a proof, then back by sym of that proof, yields234the original term. is gives us:dofE′← castExact (CΠ C? (λ .C?)) C? F?snd (fE′ F?))is is exactly the reduct of −→∗ (1). So we can unfold the transport of EqIan arbitrary number of times, and always end up with the same term, which isexactly how we expect f to behave.235Chapter 7DiscussionTo conclude this dissertation, we discuss the main issues, limitations, and possiblefuture work surrounding our research.7.1 Does Approximate Normalization Maer?One question that has gone unanswered until this point is whether we should ac-tually care about approximate normalization. Lennon-Bertrand et al. [87] presenttwo languages satisfying the gradual guarantees without approximate normaliza-tion, one without decidable type checking and one with restrictions on the uni-verses of types in dependent functions. Not all static dependently typed languageshave decidable type checking. Proving approximate normalization required sig-ni cant machinery, both in the Chapter 3 and Chapter 6 versions. And the endresult is a programming language where some faulty programs could be rejectedwith static type errors, but are instead accepted.We argue that approximate normalization is worthwhile. In a talk, Sterling[139] notes that, while the time complexity bound on dependent type checkingis high, in practice it can be done quite quickly. Keeping type checking decidablecould help ensure that gradual dependent types can be checked quickly for mostreal-world programs. Moreover, decidable type checking lets gradual dependenttypes integrate more easily into the existing ecosystem for dependently typedprogramming. In Chapter 6, we mentioned how decidable type checking allowed236gradual dependent types to compile to existing core languages without needingto modify them. We suspect that this benet will extend when integrating toolslike proofs search or SMT into a gradual dependently typed language.Even if future gradual dependently typed languages do not use approximatenormalization, the knowledge gained from developing it will be useful to the fu-ture of gradual dependent types. Gradual types introduce e ects into dependenttypes’ normally pure conversion checking, and some technique must be used tohandle them. For instance, our model could be adapted using exact but unde-cidable conversion checking if, for instance, we introduced an operator with thetype Læ Type→ Type. But the framework of dividing the model into e ectfuland non-e ectful portions would still be useful with a di erent model of typechecking.By exposing the compromises necessary for decidable checking with gradualdependent types, we hope to give the programming languages community theinformation necessary to determine whether the bene ts of decidable checkingjustify the compromises.7.1.1 Approximate WitnessesOne design decision that deserves further exploration is whether approximatenormalization should be used to track witnesses of consistency. In gdtl, all typecomparisons happen with normal forms, so evidence must use approximate se-mantics, since exact execution does not normalize under binders. ⊲GEq inheritedthis design choice. However, since its dynamic and static semantics di er only incasts to and from ?, it is not strictly necessary to use approximate witnesses.With approximatewitnesses, the question iswhetherwitnesses are too opaqueto the programmer to allow non-termination. e danger is that the programmercould write ? in the surface language and have it elaborate into a non-terminatingterm. For example, if the programmer writes ? in a context expecting a proof ofy (𝜆x .x x) ? = y ? (𝜆x .x x), this elaborates with the witness y (𝜆x.x x) (𝜆x.x x). Ify is ever instantiated to 𝜆f x . f x, the witness will run forever. e programmerwould be debugging an in nite loop where the source of the bug is the types, notthe term.237However, the above example is highly contrived, and it is possible that allsuch examples are. e use of approximate witnesses is not without downsides.It means that ⊲GEq does not satisfy the EP-pairs property, which was useful forproving that casts did not needlessly produce ? as a result. Moreover, it means thatthere are programs that either never raise a dynamic error when a static equalityis violated, or they raise it later than is necessary, because information is lost toapproximation. e issue is one of ergonomics, and will likely not be resolveduntil there is an implementation of a gradual programming language with at leasta few users.7.2 Limitations and Future WorkWe present our limitations and future work simultaneously, because each limita-tion of our contributions comes with a suggestion for future work to address thelimitation.7.2.1 Adequacyough we established the soundness of our model in Chapter 6, we did not proveanother important property of denotational models: adequacy. A model is ade-quate if the translations of two terms are equal in the model if and only if theyare observationally equivalent in the source language. Adequacy establishes thatthere are not too many equalities in the target. For example, if we were to mapevery source type to the same target type, and every value to the same targetvalue, our model would be sound but not adequate. When a model is adequate,theorems about the model can be easily translated back to the source language.We conjecture that our model is adequate, but proving it is le to future work.7.2.2 Approximating Inductive TypesIn Chapter 6, we modelled the germ of inductive data types by casting every eldto ? or a function producing ?. Doing so made the termination argument easy, butbecause witnesses are stored in approximate form, converting terms to ? need-lessly forgets consistency information in equality proofs. We hope that in the fu-238ture, Agda’s termination checker can be rened to allow for ?Ty to refer to typesother than itself in function codomains. More study of induction-recursion andits implementation in Agda should help nd a solution to this issue.In general, the current handling of inductive types is unsatisfactory, since itassumes either a programmer or mechanical system will generate the relevantinstances for each inductive type. e problem is that in gcic and its derivatives,the germ of an inductive type relies on replacing its parameters with ?. e pre-sentations of generic inductive types we used do not treat parameters at all: aparameterized type is just a function producing a description or container. Fur-ther exploration into generic ways of representing inductives could let our modeluse a completely closed type theory.7.2.3 Mechanized MetatheoryBecause Chapter 6 provided a model of both approximate and exact normaliza-tion, it has potential far beyond proving strong normalization. Having a seman-tic model of ⊲GEq could let future developments move past complex simulation-based arguments for the gradual guarantees. We conjecture that a proof techniquesimilar to the EP-pairs used by Lennon-Bertrand et al. [87], New and Ahmed [105]can be adapted to ⊲GEq, but using Galois connections instead of EP-pairs. Because⊲GEq uses approximate normal forms for equality witnesses, it violates the fullEP-pairs property: casting to ? then back can reduce the precision of a witness.To show that precision in terms is not needlessly lost, we could establish a Galoisconnection for a more restrictive consistency relation, where terms are comparedpurely based on their error behaviour, and ? is not the top of the precision lat-tice. is would establish that reducing an exact term’s precision may cause itto raise an error in fewer contexts, but if the term terminates without error, thenal value is unchanged. Likewise, semantic techniques could be used to showthat composition computes a true meet for precision, guaranteeing that precisionis never needlessly lost when composing terms.A major limitation of Chapter 5 is that, despite designing the language aroundpreserving static equivalences, we never actually establish that we preserve staticequivalences. e most general version of this property is full abstraction, which239says that all observationally-equivalent static terms are gradually equivalent. How-ever, the usual technique to prove full abstraction does not scale well to gradualdependent types. e problem is this technique requires simulating the graduallanguage in the static language in a way that produces the same e ects, but staticdependent types lack e ects. However, the semantic model of Chapter 6 could beused to prove a weaker version of the theorem, which is that all propositionallyequal static terms are observationally equivalent in the gradual language. If staticterms are propositionally equal, then the equality proof could be li ed into thegradual language as a fully-precise witness. If we proved that composition com-puted a greatest lower bound, then we would know that the composing two staticterms produced an equi-precise term. If we proved that all equi-precise termswere equal in the model, this would establish that the two terms were equal.7.2.3.1 Simplifying the ModelOur currentmodel of gradual dependent types involves one giantmutually-recursivetype of codes, with the elimination operations de ned mutually with each other.is technique is complex, and frankly, has resulted in a model that works, butis di cult to read and understand. Directly modelling ⊲GEq in gtt was usefulfor proving termination, but for the broader goal of reasoning about the metathe-oretic properties of ⊲GEq, we could use the more conventional model-theoreticapproach of de ning a semantic domain denoting the types of ⊲GEq, then show-ing that it is closed under semantic versions of ⊲GEq’s type formers. Such anapproach should either help reduce the mutual dependencies, or at least revealwhere and why they are strictly necessary.7.2.4 Symbolic Gradual Dependent TypesOur gradual dependently typed languages have a number of limitations that canall be addressed with symbolic means. We believe that there is a deep connectionbetween gradual dependent types and symbolic execution waiting to be explored.We outline the potential connections below.2407.2.4.1 Remembering ConstraintsIn Chapter 5, we touted the use of equality witnesses for catching bugs by dy-namically tracking equalities. Unfortunately, the version of equality there doesnot capture all equality constraints that would be implied in a static program. Aswe discussed in that chapter, the problem is that witnesses remember constraintsacross time, not space. at is, if an equality proof is copied, there is no memorythat the two copies referred to the same value. Likewise, if an equality proof istransformed by applying a function to it, and constraints are learned about theresult of that function, then no constraints are learned about the original proof.We propose that monotonic references [137] could be integrated with gradualpropositional equality, so that constraints were remembered across both time andspace. For non-dependent gradual types, monotonic references were developedfor statefully tracking precision information that increases as a program runs.Because arbitrary terms can be equated, a system of dynamic higher-order uni -cation would need to be developed to track constraints between gradual terms.7.2.4.2 Pa ern Matching and Gradual UnionsOur notion of pa ernmatching on ? is needlessly lossy. In Chapter 3, we justify ? treducing to ? in terms of agt: because every possible static function is denoted by?, every result is possible. When eliminating ? as a member of an inductive type,we also produce ? as a result. However, the agt justi cation does not apply in thiscase: for a given elimination, the possible outcomes are restricted by the branchesgiven to the eliminator. For example, the term if x then 0 else 1 never produces 2for any x. So why should if ? then 0 else 1 denote every possible term?We propose that this issue could be solvedwith a dependent version of gradualunion types [24, 145] and gradual recursive types [133]. e set of possible out-comes of an elimination could be modelled as the recursive union of all branchesof the eliminator, where each recursive invocation of the eliminator is replacedwith a recursive self-reference.As is expected with gradual dependent types, some compromise would benecessary. e challenge is in comparing recursive unions of gradual terms. De-termining if two recursive unions of terms are consistent is likely to be undecid-241able, just as it is undecidable to determine if two functions agree on every input.However, set constraints [5, 115] or regular tree languages [25, 36] could be usedto provide an upper-bound on the possible results of an elimination.7.2.4.3 Gradual AGTUnfortunately, Chapters 5 and 6 do not provide principled justication for theirinterpretation of gradual types. In Chapter 3, we provide such justi cation usingagt, but with a very limited calculus.We propose that a syntactic model in the style of ⊲GEq could be used to de nean AGT-style gradual language with inductive types and propositional equality.For ⊲GEq, we use a type to model the values of ⊲GEq, then use monadic functionsto model computations on terms and casts between types. A similar approachcould be used to model agt-style evidence based semantics instead of casts. Amonad-like typeM : C ℓ → Type could track gradual computations, where a termof typeM c contained a code c′, an inhabitant of El c′, and evidence that c and c′were dynamically consistent.7.2.4.4 Gradual Symbolic ExecutionMonotonic references, gradual unions, and agt suggest a deeper connection be-tween gradual dependent types and symbolic execution. Under the agt interpre-tation, executing an imprecise program could be interpreted as determining whatvalues are in the set of results of executions of the static programs denoted by thegradual program’s concretization. Symbolic execution is a technique to analyzewhat the set of results is for a set of programs, where the input set is representedas a single symbolic static program. So a gradual dependently typed programcorresponds to a symbolic static dependently typed program, where the impre-cise parts of the gradual program correspond to the symbolic parts of the staticprogram. We suspect that techniques like choice calculi [31, 62] and higher-ordersymbolic execution [106] could aid in executing gradual programs, more preciselyhandling branching and pa ern matching.2427.2.5 Broader Applications of Approximate NormalizationIn Chapters 3 and 6, we used approximate normalization as a way to handle non-termination as an eect in terms on which types depend. is technique couldprovide a general way to handle e ectful code in dependent types: if a type de-pends on an e ectful term, that term can be approximated to ? and checked asa gradual term, with any deferred checks inserted at run-time. For example, onecould have a proof that readInt > 0, which was treated at compile time as a proofthat ? > 0, but at run time read an integer from stdin and ensured that its valuewas greater than zero.7.2.6 Implementatione translation of Chapter 6 lends itself well to taking a gradual surface languageand translating to the core language of an existing implementation of dependenttypes. For example, as of 2023, the Idris 2 developers are in themidst of developinga new core language that would be an ideal target for such translation. Similarly,systems like macros in Lean [102] or Cur [28], or Agda’s tactic arguments, couldsupport a lightweight gradual language.Several issues would need to be addressed for such an implementation to beusable. Dependent types are extremely verbose without implicit arguments, butimplicits are resolvedwith uni cation. So a full implementationwould need a uni-er that is aware of consistency when solving for metavariables, possibly addinghigher-order uni cation to the work of Siek and Vachharajani [134] Garcia andCimini [66].Likewise, languages like Idris rely heavily on typeclasses. In general, grad-ual handling of typeclasses is an open problem, even without dependent types.However, the ability to model imprecision in both terms and types could helpwith nding a solution. For example, typeclasses could integrate with the gradualunions of terms above. Each typeclass dictionary could take an extra parameter,equating the actual typeclass parameters to those speci ed for the particular im-plementation. When calling a typeclass method on an imprecisely typed term,one could supply the gradual union of all available implementations of the class.en, as type information was gained, the available implementations would nar-243row as the extra equality parameters reduced to errors for some implementations.7.3 ConclusionWhen we began this track of research, all major developments in gradual depen-dent types were focused around subset types and boolean predicates. Our workhas shown that a full spectrum gradual dependently typed language is feasible,where ? enjoys rst-class status as a term. Allowing ? to be used as a term resultsin a highly granular notion of precision for indexed types. We have only begunto explore how the hole-based programming of dependent types can mesh withrepl and test-based development, but we now have the theoretical foundation tomake that exploration possible.at said, the major lesson of this dissertation is one of compromise, and wesuspect this will continue to be at the heart of the story of gradual dependenttypes. To achieve decidable type checking, we needed to compromise on whatit meant for two types to be convertible. To achieve run-time consistency track-ing, we needed to compromise what it meant for two terms to be dynamicallyconsistent. Our work shows that these are concessions, not defeats.So ware is ubiquitous, and it seems that it will be for the foreseeable future.Release cycles for so ware tend to be short, and there is pressure to write andrelease so ware quickly. Furthermore, it seems that tools to automatically gen-erate code are here, whether or not we have the tools to specify how that codeshould behave and to verify whether it meets that speci cation. Dependent typesprovide a uni ed, principled, theoretically justi ed framework for speci cationand veri cation, and gradual dependent types extend that framework to dynamicchecking. We have not removed the barrier to entry for dependent types, but wehave lowered it. Our hope is that this in turn helps reduce the barriers to writingsafe, dependable code.244Bibliography[1] M. Abbo, T. Altenkirch, and N. Ghani. Containers: Constructing strictlypositive types. eoretical Computer Science, 342(1):3–27, 2005. ISSN0304-3975. doi:h ps://doi.org/10.1016/j.tcs.2005.06.002. AppliedSemantics: Selected Topics. → page 42[2] A. Abel and J. Chapman. Normalization by evaluation in the delay monad:A case study for coinduction via copa erns and sized types. In P. Levyand N. Krishnaswami, editors, Proceedings 5th Workshop onMathematically Structured Functional Programming,Grenoble, France, 12 April 2014, volume 153 of Electronic Proceedings ineoretical Computer Science, pages 51–67, 2014. Open PublishingAssociation. doi:10.4204/EPTCS.153.4. → page 55[3] A. Abel and B. Pientka. Higher-order dynamic pa ern uni cation fordependent types and records. In L. Ong, editor, Typed Lambda Calculi andApplications, volume 6690 of Lecture Notes in Computer Science, pages10–26. Springer Berlin Heidelberg, 2011. ISBN 978-3-642-21690-9.doi:10.1007/978-3-642-21691-6 5. → page 50[4] A. Ahmed, R. B. Findler, J. G. Siek, and P. Wadler. Blame for all. SIGPLANNot., 46(1):201–214, Jan. 2011. ISSN 0362-1340.doi:10.1145/1925844.1926409. → page 23[5] A. Aiken. Introduction to set constraint-based program analysis. Scienceof Computer Programming, 35(2):79 – 111, 1999. ISSN 0167-6423.doi:h ps://doi.org/10.1016/S0167-6423(99)00007-6. → page 242[6] T. Altenkirch, C. McBride, and W. Swierstra. Observational equality, now!In Proceedings of the 2007 Workshop on Programming Languages MeetsProgram Veri cation, PLPV ’07, pages 57–68, 2007. ACM. ISBN978-1-59593-677-6. doi:10.1145/1292597.1292608. → page 168245[7] R. Atkey and C. McBride. Productive coprogramming with guardedrecursion. SIGPLAN Not., 48(9):197–208, Sept. 2013. ISSN 0362-1340.doi:10.1145/2544174.2500597. → page 55[8] F. Ban˜ados Schwerter, A. M. Clark, K. A. Jafery, and R. Garcia. Abstractinggradual typing moving forward: Precise and space-ecient. Proc. ACMProgram. Lang., 5(POPL), Jan. 2021. doi:10.1145/3434342. → page 133[9] F. Ban˜ados Schwerter, R. Garcia, and E´. Tanter. Gradual type-and-e ectsystems. Journal of Functional Programming, 26:19:1–19:69, Sept. 2016.doi:h p://dx.doi.org/10.1017/S0956796816000162. → page 23[10] BBC News. Microso excel blamed for gene study errors. BBC News, Aug2016. URL h ps://www.bbc.com/news/technology-37176926. → page 1[11] J.-P. Bernardy, P. Jansson, and R. Paterson. Proofs for free: Parametricityfor dependent types. Journal of Functional Programming, 22(2):107–152,2012. doi:10.1017/S0956796812000056. → pages 51, 176[12] Y. Bertot and P. Caste´ran. Interactive eorem Proving and ProgramDevelopment. Springer Berlin Heidelberg, 2004.doi:10.1007/978-3-662-07964-5. → page 27[13] L. Birkedal and R. E. Møgelberg. Intensional type theory with guardedrecursive types qua xed points on universes. In 2013 28th AnnualACM/IEEE Symposium on Logic in Computer Science, pages 213–222,2013. doi:10.1109/LICS.2013.27. → page 55[14] L. Birkedal, R. E. Mogelberg, J. Schwinghammer, and K. Stovring. Firststeps in synthetic guarded domain theory: Step-indexing in the topos oftrees. In 2011 IEEE 26th Annual Symposium on Logic in ComputerScience, pages 55–64, 2011. doi:10.1109/LICS.2011.16. → pages 16, 55[15] L. Birkedal, A. Bizjak, R. Clouston, H. B. Grathwohl, B. Spi ers, andA. Vezzosi. Guarded Cubical Type eory: Path Equality for GuardedRecursion. In J.-M. Talbot and L. Regnier, editors, 25th EACSL AnnualConference on Computer Science Logic (CSL 2016), volume 62 of LeibnizInternational Proceedings in Informatics (LIPIcs), pages 23:1–23:17, 2016.Schloss Dagstuhl–Leibniz-Zentrum fuer Informatik. ISBN978-3-95977-022-4. doi:10.4230/LIPIcs.CSL.2016.23. → pages 16, 55[16] A. Bizjak, H. B. Grathwohl, R. Clouston, R. E. Møgelberg, and L. Birkedal.Guarded dependent type theory with coinductive types. In B. Jacobs and246C. Lo¨ding, editors, Foundations of Soware Science and ComputationStructures, pages 20–35, 2016. Springer Berlin Heidelberg. ISBN978-3-662-49630-5. → page 55[17] S. Boulier, P.-M. Pe´drot, and N. Tabareau. e next 700 syntactical modelsof type theory. In Proceedings of the 6th ACM SIGPLAN Conference onCerti ed Programs and Proofs, CPP 2017, page 182–194, 2017. Associationfor Computing Machinery. ISBN 9781450347051.doi:10.1145/3018610.3018620. → pages 15, 51, 176[18] A. Bove and V. Capre a. Modelling general recursion in type theory.Mathematical Structures in Computer Science, 15(4):671–708, 2005.doi:10.1017/S0960129505004822. → page 219[19] E. Brady. Idris, a general-purpose dependently typed programminglanguage: Design and implementation. Journal of FunctionalProgramming, 23(5):552–593, 2013. doi:10.1017/S095679681300018X. →pages 27, 55, 58, 110, 111[20] E. Brady, C. McBride, and J. McKinna. Inductive families need not storetheir indices. In Types for Proofs and Programs, International Workshop,TYPES 2003, Torino, Italy, April 30 - May 4, 2003, Revised Selected Papers,pages 115–129, 2003. doi:10.1007/978-3-540-24849-1\ 8. → page 112[21] V. Capre a. General Recursion via Coinductive Types. Logical Methods inComputer Science, Volume 1, Issue 2, July 2005.doi:10.2168/LMCS-1(2:1)2005. → page 55[22] F. Cardone and M. Coppo. Type inference with recursive types: Syntaxand semantics. Information and Computation, 92(1):48–80, 1991. ISSN0890-5401. doi:h ps://doi.org/10.1016/0890-5401(91)90020-3. → page 32[23] C. Casinghino, V. Sjo¨berg, and S. Weirich. Combining proofs andprograms in a dependently typed language. In Proceedings of the 41stACM SIGPLAN-SIGACT Symposium on Principles of ProgrammingLanguages, POPL ’14, pages 33–45, 2014. ACM. ISBN 978-1-4503-2544-8.doi:10.1145/2535838.2535883. → pages 54, 59, 110[24] G. Castagna and V. Lanvin. Gradual typing with union and intersectiontypes. Proc. ACM Program. Lang., 1(ICFP):41:1–41:28, Aug. 2017. ISSN2475-1421. doi:10.1145/3110285. → pages 23, 241247[25] G. Castagna, K. Nguyen, Z. Xu, and P. Abate. Polymorphic functions withset-theoretic types: Part 2: Local type inference and type reconstruction.In Proceedings of the 42Nd Annual ACM SIGPLAN-SIGACT Symposiumon Principles of Programming Languages, POPL ’15, pages 289–302, 2015.ACM. ISBN 978-1-4503-3300-9. doi:10.1145/2676726.2676991. → page 242[26] I. Cervesato and F. Pfenning. A linear spine calculus. Journal of Logic andComputation, 13(5):639–688, 2003. doi:10.1093/logcom/13.5.639. → pages49, 67[27] J. H. Chan. Sized dependent types via extensional type theory (Mastersesis). PhD thesis, University of British Columbia, 2022. → page 214[28] S. Chang, M. Ballantyne, M. Turner, and W. J. Bowman. Dependent typesystems as macros. Proc. ACM Program. Lang., 4(POPL), Dec. 2019.doi:10.1145/3371071. → pages 4, 27, 243[29] J. Chapman, P.-E. Dagand, C. McBride, and P. Morris. e gentle art oflevitation. In Proceedings of the 15th ACM SIGPLAN InternationalConference on Functional Programming, ICFP ’10, pages 3–14, 2010. ACM.ISBN 978-1-60558-794-3. doi:10.1145/1863543.1863547. → pages 29, 44[30] C. Chen and H. Xi. Combining programming with theorem proving. InProceedings of the Tenth ACM SIGPLAN International Conference onFunctional Programming, ICFP ’05, pages 66–77, 2005. ACM. ISBN1-59593-064-7. doi:10.1145/1086365.1086375. → page 110[31] S. Chen, M. Erwig, and E. Walkingshaw. A Calculus for VariationalProgramming. In S. Krishnamurthi and B. S. Lerner, editors, 30thEuropean Conference on Object-Oriented Programming (ECOOP 2016),volume 56 of Leibniz International Proceedings in Informatics (LIPIcs),pages 6:1–6:28, 2016. Schloss Dagstuhl–Leibniz-Zentrum fuer Informatik.ISBN 978-3-95977-014-9. doi:10.4230/LIPIcs.ECOOP.2016.6. → page 242[32] D. Christiansen and E. Brady. Elaborator re ection: Extending idris inidris. In Proceedings of the 21st ACM SIGPLAN International Conferenceon Functional Programming, ICFP 2016, pages 284–297, 2016. ACM. ISBN978-1-4503-4219-3. doi:10.1145/2951913.2951932. → page 4[33] M. Cimini and J. G. Siek. e gradualizer: A methodology and algorithmfor generating gradual type systems. In Proceedings of the 43rd AnnualACM SIGPLAN-SIGACT Symposium on Principles of Programming248Languages, POPL ’16, pages 443–455, 2016. ACM. ISBN978-1-4503-3549-2. doi:10.1145/2837614.2837632. → page 11[34] J. Cockx, D. Devriese, and F. Piessens. Paern matching without k. InProceedings of the 19th ACM SIGPLAN International Conference onFunctional Programming, ICFP ’14, pages 257–268, 2014. ACM. ISBN978-1-4503-2873-9. doi:10.1145/2628136.2628139. → page 38[35] J. Cockx, D. Devriese, and F. Piessens. Uni ers as equivalences:Proof-relevant uni cation of dependently typed data. In Proceedings ofthe 21st ACM SIGPLAN International Conference on FunctionalProgramming, ICFP 2016, pages 270–283, 2016. ACM. ISBN978-1-4503-4219-3. doi:10.1145/2951913.2951917. → page 38[36] H. Comon, M. Dauchet, R. Gilleron, C. Lo¨ding, F. Jacquemard, D. Lugiez,S. Tison, and M. Tommasi. Tree automata techniques and applications.Available on: h p://www.grappa.univ-lille3.fr/tata, 2007. release October,12th 2007. → page 242[37] T. Coquand. An analysis of girard’s paradox. In LICS, pages 227–236,1986. IEEE Computer Society. ISBN 0-8186-0720-3. URLh p://dblp.uni-trier.de/db/conf/lics/lics86.html#Coquand86. → page 31[38] T. Coquand. An analysis of Girard’s paradox. Technical Report RR-0531,INRIA, May 1986. URL h ps://hal.inria.fr/inria-00076023. → page 88[39] T. Coquand and G. Huet. e calculus of constructions. Information andComputation, 76(2):95 – 120, 1988. ISSN 0890-5401.doi:h ps://doi.org/10.1016/0890-5401(88)90005-3. → pages 31, 65, 110[40] H. B. Curry. Functionality in combinatory logic. Proceedings of theNational Academy of Sciences of the United States of America, 20(11):584–590, 1934. ISSN 00278424. URL h p://www.jstor.org/stable/86796. →page 30[41] P.-E. Dagand and C. McBride. Transporting functions across ornaments.In Proceedings of the 17th ACM SIGPLAN International Conference onFunctional Programming, ICFP ’12, pages 103–114, 2012. ACM. ISBN978-1-4503-1054-3. doi:10.1145/2364527.2364544. → page 10[42] P.-E. Dagand, N. Tabareau, and E. Tanter. Partial type equivalences forveri ed dependent interoperability. In Proceedings of the 21st ACMSIGPLAN International Conference on Functional Programming, ICFP2492016, page 298–310, 2016. Association for Computing Machinery. ISBN9781450342193. doi:10.1145/2951913.2951933. → pages 5, 53, 111, 173[43] P.-E´. Dagand, N. Tabareau, and E´. Tanter. Foundations of dependentinteroperability. Journal of Functional Programming, 28:e9, 2018.doi:10.1017/S0956796818000011. → pages 53, 64, 111, 173[44] L. Damas and R. Milner. Principal type-schemes for functional programs.In Proceedings of the 9th ACM SIGPLAN-SIGACT Symposium onPrinciples of Programming Languages, POPL ’82, pages 207–212, 1982.ACM. ISBN 0-89791-065-6. doi:10.1145/582153.582176. → page 50[45] Dan Goodin. Really stupid “smart contract” bug let hackers steal $31million in digital coin. Ars Technica, Dec 2021. URLhps://arstechnica.com/information-technology/2021/12/hackers-drain-31-million-from-cryptocurrency-service-monox-finance/.→ page 1[46] L. de Moura, S. Kong, J. Avigad, F. van Doorn, and J. von Raumer. e leantheorem prover (system description). In A. P. Felty and A. Middeldorp,editors, Automated Deduction - CADE-25, pages 378–388, 2015. SpringerInternational Publishing. ISBN 978-3-319-21401-6. → page 27[47] N. Dershowitz and Z. Manna. Proving termination with multisetorderings. In H. A. Maurer, editor, Automata, Languages andProgramming, pages 188–202, 1979. Springer Berlin Heidelberg. ISBN978-3-540-35168-9. → pages 71, 88[48] L. Diehl and T. Sheard. Generic constructors and eliminators fromdescriptions: Type theory as a dependently typed internal dsl. InProceedings of the 10th ACM SIGPLAN Workshop on GenericProgramming, WGP ’14, page 3–14, 2014. Association for ComputingMachinery. ISBN 9781450330428. doi:10.1145/2633628.2633630. → pages45, 229, 284[49] L. Diehl and T. Sheard. Generic lookup and update for in nitaryinductive-recursive types. In Proceedings of the 1st InternationalWorkshop on Type-Driven Development, TyDe 2016, page 1–12, 2016.Association for Computing Machinery. ISBN 9781450344357.doi:10.1145/2976022.2976031. → page 206[50] P. Dybjer. Inductive families. Formal Aspects of Computing, 6(4):440–465,Jul 1994. ISSN 1433-299X. doi:10.1007/BF01211308. → page 37250[51] P. Dybjer. Internal type theory. In S. Berardi and M. Coppo, editors, Typesfor Proofs and Programs, pages 120–134, 1996. Springer Berlin Heidelberg.ISBN 978-3-540-70722-6. → page 51[52] P. Dybjer and A. Setzer. A nite axiomatization of inductive-recursivede nitions. In J.-Y. Girard, editor, Typed Lambda Calculi and Applications,pages 129–146, 1999. Springer Berlin Heidelberg. ISBN 978-3-540-48959-7.→ page 44[53] P. Dybjer and A. Setzer. Induction–recursion and initial algebras. Annalsof Pure and Applied Logic, 124(1):1 – 47, 2003. ISSN 0168-0072.doi:h ps://doi.org/10.1016/S0168-0072(02)00096-9. → page 187[54] H. Eades and A. Stump. Hereditary substitution for strati ed system F. InInternational Workshop on Proof-Search in Type eories, PSTT,volume 10, 2010. → page 71[55] R. A. Eisenberg. Dependent types in haskell: eory and practice, 2016.→ pages 27, 54, 59[56] J. Eremondi. JoeyEremondi/GuardedModel: GEq model submi ed withdissertation. Mar. 2023. doi:10.5281/zenodo.7735111. → pages 186, 211[57] J. Eremondi, W. Swierstra, and J. Hage. A framework for improving errormessages in dependently typed languages. Open Computer Science (toappear), Topical issue on type error diagnosis, 2018. → page 4[58] J. Eremondi, E. Tanter, and R. Garcia. Approximate normalization forgradual dependent types. Proc. ACM Program. Lang., 3(ICFP):88:1–88:30,July 2019. ISSN 2475-1421. doi:10.1145/3341692. → pages vi, 7, 51, 54, 56,87, 93, 109, 113, 133, 269[59] J. Eremondi, E. Tanter, and R. Garcia. Approximate normalization forgradual dependent types. Proc. ACM Program. Lang., 3(ICFP):88:1–88:30,July 2019. ISSN 2475-1421.[60] J. Eremondi, R. Garcia, and E. Tanter. Propositional equality for gradualdependently typed programming. Proc. ACM Program. Lang., 6(ICFP),August 2022. doi:10.1145/3547627. → pages vi, 113[61] J. Eremondi, R. Garcia, and E. Tanter. Propositional equality for gradualdependently typed programming. Proc. ACM Program. Lang., 6(ICFP),August 2022.251[62] M. Erwig and E. Walkingshaw. e choice calculus: A representation forso ware variation. ACM Trans. So w. Eng. Methodol., 21(1):6:1–6:27,Dec. 2011. ISSN 1049-331X. doi:10.1145/2063239.2063245. → page 242[63] U. N. et. al. Agda documentation: Without k - restrictions on terminationchecking. h ps://agda.readthedocs.io/en/v2.6.2.2.20230105/language/without-k.html#restrictions-on-termination-checking, 2023. → page 201[64] L. Fennell and P. iemann. Gradual security typing with references. InProceedings of the 26th Computer Security Foundations Symposium(CSF), pages 224–239, June 2013. → page 23[65] R. B. Findler and M. Felleisen. Contracts for higher-order functions. InProceedings of the Seventh ACM SIGPLAN International Conference onFunctional Programming, ICFP ’02, pages 48–59, 2002. ACM. ISBN1-58113-487-8. doi:10.1145/581478.581484. → pages 52, 141[66] R. Garcia and M. Cimini. Principal type schemes for gradual programs. InProceedings of the 42Nd Annual ACM SIGPLAN-SIGACT Symposium onPrinciples of Programming Languages, POPL ’15, pages 303–315, 2015.ACM. ISBN 978-1-4503-3300-9. doi:10.1145/2676726.2676992. → pages50, 243[67] R. Garcia, A. M. Clark, and E. Tanter. Abstracting gradual typing. InProceedings of the 43rd Annual ACM SIGPLAN-SIGACT Symposium onPrinciples of Programming Languages, POPL ’16, pages 429–442, 2016.ACM. ISBN 978-1-4503-3549-2. doi:10.1145/2837614.2837670. → pages 11,18, 20, 23, 26, 58, 74, 101, 109, 131, 133, 143, 153[68] J.-Y. Girard. Interpre´tation fonctionelle et e´limination des coupures del’arithme´tique d’ordre supe´rieur. PhD thesis, PhD thesis, Universite´ ParisVII, 1972. → page 88[69] H. Goguen, C. McBride, and J. McKinna. Eliminating Dependent Pa ernMatching, pages 521–540. Springer Berlin Heidelberg, 2006. ISBN978-3-540-35464-2. doi:10.1007/11780274 27. → pages 38, 168[70] B. Greenman and M. Felleisen. A spectrum of type soundness andperformance. Proc. ACM Program. Lang., 2(ICFP):71:1–71:32, July 2018.ISSN 2475-1421. doi:10.1145/3236766. → pages 20, 107, 114[71] A. Gundry and C. McBride. A tutorial implementation of dynamic pa ernuni cation. Unpublished dra , h p://adam.gundry.co.uk/pub/pa ern-unify/pa ern-unification-2012-07-10.pdf, 2013. → page 50252[72] R. Harper and D. R. Licata. Mechanizing metatheory in a logicalframework. Journal of Functional Programming, 17(4-5):613–673, 2007.doi:10.1017/S0956796807006430. → pages 49, 110[73] R. Harper, F. Honsell, and G. Plotkin. A framework for dening logics. J.ACM, 40(1):143–184, Jan. 1993. ISSN 0004-5411.doi:10.1145/138027.138060. → page 110[74] M. Hofmann. Extensional concepts in intensional type theory. 1995. →page 41[75] M. Hofmann and T. Streicher. e groupoid interpretation of type theory.Twenty- ve years of constructive type theory (Venice, 1995), 36:83–111,1998. doi:h ps://doi.org/10.1093/oso/9780198501275.003.0008. → page 168[76] W. A. Howard. e formulae-as-types notion of construction. To HBCurry: essays on combinatory logic, lambda calculus and formalism, 44:479–490, 1980. → page 30[77] G. Huet. A uni cation algorithm for typed 𝜆-calculus. eoreticalComputer Science, 1(1):27 – 57, 1975. ISSN 0304-3975.doi:10.1016/0304-3975(75)90011-0. → page 50[78] G. P. Huet. e undecidability of uni cation in third order logic.Information and Control, 22(3):257 – 267, 1973. ISSN 0019-9958.doi:10.1016/S0019-9958(73)90301-X. → page 50[79] J. Hugunin. Why Not W? In U. de’Liguoro, S. Berardi, and T. Altenkirch,editors, 26th International Conference on Types for Proofs and Programs(TYPES 2020), volume 188 of Leibniz International Proceedings inInformatics (LIPIcs), pages 8:1–8:9, 2021. Schloss Dagstuhl –Leibniz-Zentrum fu¨r Informatik. ISBN 978-3-95977-182-5.doi:10.4230/LIPIcs.TYPES.2020.8. → page 44[80] A. Igarashi, P. iemann, V. T. Vasconcelos, and P. Wadler. Gradualsession types. pages 38:1–38:28. → page 23[81] K. Jacobs, A. Timany, and D. Devriese. Fully abstract from static togradual. Proc. ACM Program. Lang., 5(POPL), Jan. 2021.doi:10.1145/3434288. → pages 22, 171[82] L. Jia, J. A. Vaughan, K. Mazurak, J. Zhao, L. Zarko, J. Schorr, andS. Zdancewic. AURA: a programming language for authorization and253audit. In Proceeding of the 13th ACM SIGPLAN international conferenceon Functional programming, ICFP 2008, Victoria, BC, Canada, September20-28, 2008, pages 27–38, 2008. doi:10.1145/1411204.1411212. → page 110[83] N. Kraus, F. N. Forsberg, and C. Xu. Connecting constructive notions ofordinals in homotopy type theory. In F. Bonchi and S. J. Puglisi, editors,46th International Symposium on Mathematical Foundations of ComputerScience, MFCS 2021, August 23-27, 2021, Tallinn, Estonia, volume 202 ofLIPIcs, pages 70:1–70:16, 2021. Schloss Dagstuhl - Leibniz-Zentrum fu¨rInformatik. doi:10.4230/LIPIcs.MFCS.2021.70. → page 214[84] N. Lehmann and E. Tanter. Gradual renement types. In Proceedings ofthe 44th ACM SIGPLAN Symposium on Principles of ProgrammingLanguages, POPL 2017, pages 775–788, 2017. ACM. ISBN978-1-4503-4660-3. doi:10.1145/3009837.3009856. → pages 52, 111, 130, 173[85] M. Lemay. A Dependently Typed Programming Language With DynamicEquality. PhD thesis, Boston University, 2022. URLh ps://github.com/marklemay/thesis. → page 172[86] M. Lennon-Bertrand. Complete Bidirectional Typing for the Calculus ofInductive Constructions. In L. Cohen and C. Kaliszyk, editors, 12thInternational Conference on Interactive eorem Proving (ITP 2021),volume 193 of Leibniz International Proceedings in Informatics (LIPIcs),2021. Schloss Dagstuhl – Leibniz-Zentrum fu¨r Informatik. ISBN978-3-95977-188-7. doi:10.4230/LIPIcs.ITP.2021.24. → pages 27, 47, 114,117, 281[87] M. Lennon-Bertrand, K. Maillard, N. Tabareau, and E. Tanter. Gradualizingthe calculus of inductive constructions. ACM Trans. Program. Lang. Syst.,44(2), apr 2022. ISSN 0164-0925. doi:10.1145/3495528. → pages vi, xviii,15, 22, 28, 51, 53, 113, 114, 117, 121, 124, 129, 130, 131, 133, 140, 146, 153,157, 160, 170, 171, 175, 176, 195, 236, 239, 272, 280, 281, 282[88] X. Leroy. A formally veri ed compiler back-end. J. Autom. Reason., 43(4):363–446, dec 2009. ISSN 0168-7433. doi:10.1007/s10817-009-9155-4. →page 4[89] A. Lo¨h, C. McBride, and W. Swierstra. A tutorial implementation of adependently typed lambda calculus. Fundam. Inf., 102(2):177–207, Apr.2010. ISSN 0169-2968. doi:10.3233/FI-2010-304. → pages 47, 110254[90] K. Maillard, M. Lennon-Bertrand, N. Tabareau, and E. Tanter. Areasonably gradual type theory. Proc. ACM Program. Lang., 6(ICFP), aug2022. doi:10.1145/3547655. → pages 51, 54, 172[91] C. Mangin and M. Sozeau. Equations for hereditary substitution inleivant’s predicative system F: A case study. CoRR, abs/1508.00455, 2015.URL hp://arxiv.org/abs/1508.00455. → page 71[92] P. Martin-Lo¨f. About models for intuitionistic type theories and thenotion of de nitional equality. In S. Kanger, editor, Proceedings of theird Scandinavian Logic Symposium, volume 82 of Studies in Logic andthe Foundations of Mathematics, pages 81 – 109. Elsevier, 1975.doi:10.1016/S0049-237X(08)70727-4. → page 144[93] P. Martin-Lo¨f and G. Sambin. Intuitionistic type theory, volume 9.Bibliopolis Naples, 1984. → pages 27, 48[94] P. Martin-L o¨ f. Constructive mathematics and computer programming.In L. J. Cohen, J. Łos´, H. Pfei er, and K.-P. Podewski, editors, Logic,Methodology and Philosophy of Science VI, volume 104 of Studies inLogic and the Foundations of Mathematics, pages 153–175. Elsevier, 1982.doi:h ps://doi.org/10.1016/S0049-237X(09)70189-2. → pages 27, 38, 130[95] C. McBride. Dependently typed functional programs and their proofs.PhD thesis, University of Edinburgh, UK, 2000. URLh p://hdl.handle.net/1842/374. → pages 39, 130, 168[96] C. McBride. Elimination with a Motive. In P. Callaghan, Z. Luo,J. McKinna, R. Pollack, and R. Pollack, editors, Types for Proofs andPrograms, Lecture Notes in Computer Science, pages 197–216, 2002.Springer. ISBN 9783540458425. doi:10.1007/3-540-45842-5 13. → page 118[97] C. McBride. Ornamental algebras, algebraic ornaments, 2011. URLh p://plv.mpi-sws.org/plerg/papers/mcbride-ornaments-2up.pdf. → page44[98] C. McBride. Turing-completeness totally free. In R. Hinze andJ. Voigtla¨nder, editors, Mathematics of Program Construction, pages257–275, 2015. Springer International Publishing. ISBN 978-3-319-19797-5.→ page 55[99] M. Might. A ph.d. thesis proposal is a contract, 2010. URLh p://ma .might.net/articles/advice-for-phd-thesis-proposals/. → page14255[100] D. Miller. Unication under a mixed pre x. J. Symb. Comput., 14(4):321–358, Oct. 1992. ISSN 0747-7171. doi:10.1016/0747-7171(92)90011-R.→ page 50[101] R. E. Møgelberg and N. Veltri. Bisimulation as path type for guardedrecursive types. Proc. ACM Program. Lang., 3(POPL), jan 2019.doi:10.1145/3290317. → page 185[102] L. d. Moura and S. Ullrich. e lean 4 theorem prover and programminglanguage. In A. Platzer and G. Sutcli e, editors, Automated Deduction –CADE 28, pages 625–635, 2021. Springer International Publishing. ISBN978-3-030-79876-5. → page 243[103] H. Nakano. A modality for recursion. In Proceedings Fi eenth AnnualIEEE Symposium on Logic in Computer Science (Cat. No.99CB36332),pages 255–266, 2000. doi:10.1109/LICS.2000.855774. → page 55[104] A. Nanevski, F. Pfenning, and B. Pientka. Contextual modal type theory.ACM Trans. Comput. Logic, 9(3):23:1–23:49, June 2008. ISSN 1529-3785.doi:10.1145/1352582.1352591. → page 112[105] M. S. New and A. Ahmed. Graduality from embedding-projection pairs.Proc. ACM Program. Lang., 2(ICFP), July 2018. doi:10.1145/3236768. →pages xviii, 22, 41, 54, 153, 171, 190, 239[106] P. C. Nguy˜eˆn, S. TOBIN-HOCHSTADT, and D. VAN HORN. Higher ordersymbolic execution for contract veri cation and refutation. Journal ofFunctional Programming, 27:e3, 2017. doi:10.1017/S0956796816000216. →page 242[107] P. C. Nguy˜eˆn, T. Gilray, S. Tobin-Hochstadt, and D. Van Horn.Size-change termination as a contract: Dynamically and staticallyenforcing termination for higher-order programs. In Proceedings of the40th ACM SIGPLAN Conference on Programming Language Design andImplementation, PLDI 2019, pages 845–859, 2019. ACM. ISBN978-1-4503-6712-7. doi:10.1145/3314221.3314643. → page 112[108] U. Norell. Towards a practical programming language based on dependenttype theory. PhD thesis, Chalmers University of Technology, 2007.h p://www.cse.chalmers.se/ ulfn/papers/thesis.pdf. → page 37[109] U. Norell. Dependently typed programming in Agda. In Proceedings ofthe 4th International Workshop on Types in Language Design and256Implementation, TLDI ’09, pages 1–2, 2009. ACM. ISBN978-1-60558-420-1. doi:10.1145/1481861.1481862. → pages 27, 50, 111[110] C. Omar, I. Voysey, M. Hilton, J. Aldrich, and M. A. Hammer. Hazelnut: Abidirectionally typed structure editor calculus. In Proceedings of the 44thACM SIGPLAN Symposium on Principles of Programming Languages,POPL ’17, page 86–99, 2017. Association for Computing Machinery. ISBN9781450346603. doi:10.1145/3009837.3009900. → page 6[111] C. Omar, I. Voysey, R. Chugh, and M. A. Hammer. Live functionalprogramming with typed holes. Proc. ACM Program. Lang., 3(POPL), jan2019. doi:10.1145/3290327. → page 6[112] C. Omar, I. Voysey, R. Chugh, and M. A. Hammer. Live functionalprogramming with typed holes. PACMPL, 3(POPL):14:1–14:32, 2019. URLhps://dl.acm.org/citation.cfm?id=3290327. → page 111[113] P.-M. Osera, V. Sjo¨berg, and S. Zdancewic. Dependent interoperability. InProceedings of the Sixth Workshop on Programming Languages MeetsProgram Veri cation, PLPV ’12, pages 3–14, 2012. ACM. ISBN978-1-4503-1125-0. doi:10.1145/2103776.2103779. → pages 53, 111, 173[114] X. Ou, G. Tan, Y. Mandelbaum, and D. Walker. Dynamic typing withdependent types. In J.-J. Levy, E. W. Mayr, and J. C. Mitchell, editors,Exploring New Frontiers of eoretical Informatics, pages 437–450, 2004.Springer US. ISBN 978-1-4020-8141-5.doi:h ps://doi.org/10.1007/1-4020-8141-3 34. → pages 52, 111, 172[115] L. Pacholski and A. Podelski. Set constraints: A pearl in research onconstraints, pages 549–561. Springer Berlin Heidelberg, 1997. ISBN978-3-540-69642-1. doi:10.1007/BFb0017466. → page 242[116] C. Paulin-Mohring. Introduction to the Calculus of InductiveConstructions. In B. W. Paleo and D. Delahaye, editors,All about Proofs, Proofs for All, volume 55 of Studies in Logic(Mathematical logic and foundations). College Publications, Jan. 2015.URL h ps://hal.inria.fr/hal-01094195. → page 27[117] M. Pavio i, R. E. Møgelberg, and L. Birkedal. A model of pcf in guardedtype theory. Electronic Notes in eoretical Computer Science, 319:333 –349, 2015. ISSN 1571-0661. doi:h ps://doi.org/10.1016/j.entcs.2015.12.020.e 31st Conference on the Mathematical Foundations of ProgrammingSemantics (MFPS XXXI). → page 189257[118] P.-M. Pe´drot and N. Tabareau. Failure is not an option. In A. Ahmed,editor, Programming Languages and Systems, pages 245–271, 2018.Springer International Publishing. ISBN 978-3-319-89884-1. → pages51, 53[119] P.-M. Pe´drot and N. Tabareau. e re triangle: How to mix substitution,dependent elimination, and e ects. Proc. ACM Program. Lang., 4(POPL),Dec. 2019. doi:10.1145/3371126. → page 53[120] P.-M. Pe´drot, N. Tabareau, H. J. Fehrmann, and E. Tanter. A reasonablyexceptional type theory. Proc. ACM Program. Lang., 3(ICFP):108:1–108:29,July 2019. ISSN 2475-1421. doi:10.1145/3341712. → pages 51, 53[121] F. Pfenning. Church and curry: Combining intrinsic and extrinisic typing.In C. Benzmu¨ller, C. Brown, J. Siekmann, and R. Statman, editors,Reasoning in Simple Type eory – Festschri in Honor ofPeter B. Andrews on His 70th Birthday, Studies in Logic, MathematicalLogic and Foundations, 2008. College Publications. ISBN978-1-904987-70-3. URLh p://www.collegepublications.co.uk/logic/mlf/?00010. → pages 49,100, 110[122] B. Pientka and J. Dun eld. Programming with proofs and explicitcontexts. In Proceedings of the 10th International ACM SIGPLANConference on Principles and Practice of Declarative Programming, PPDP’08, pages 163–173, 2008. ACM. ISBN 978-1-60558-117-0.doi:10.1145/1389449.1389469. → page 112[123] B. C. Pierce and D. N. Turner. Local type inference. ACM Trans. Program.Lang. Syst., 22(1):1–44, Jan. 2000. ISSN 0164-0925.doi:10.1145/345099.345100. → page 47[124] L. Pujet and N. Tabareau. Observational equality: Now for good. Proc.ACM Program. Lang., 6(POPL), jan 2022. doi:10.1145/3498693. → pages41, 168[125] J. C. Reynolds. Towards a theory of type structure. In ProgrammingSymposium, Proceedings Colloque Sur La Programmation, pages 408–423,1974. Springer-Verlag. ISBN 3-540-06859-7. URLh p://dl.acm.org/citation.cfm?id=647323.721503. → page 50258[126] T. Ringer, K. Palmskog, I. Sergey, M. Gligoric, and Z. Tatlock. QED atLarge: A Survey of Engineering of Formally Veried So ware. now, 2019.ISBN null. URL h ps://ieeexplore.ieee.org/document/8824174. → page 4[127] T. Ringer, N. Yazdani, J. Leo, and D. Grossman. Ornaments for Proof Reusein Coq. In J. Harrison, J. O’Leary, and A. Tolmach, editors, 10thInternational Conference on Interactive eorem Proving (ITP 2019),volume 141 of Leibniz International Proceedings in Informatics (LIPIcs),pages 26:1–26:19, 2019. Schloss Dagstuhl–Leibniz-Zentrum fuerInformatik. ISBN 978-3-95977-122-1. doi:10.4230/LIPIcs.ITP.2019.26. →page 4[128] I. Sergey and D. Clarke. Gradual ownership types. pages 579–599. →page 23[129] T. Sheard and N. Linger. Programming in omega. In Central EuropeanFunctional Programming School, Second Summer School, CEFP 2007,Cluj-Napoca, Romania, June 23-30, 2007, Revised Selected Lectures, pages158–227, 2007. doi:10.1007/978-3-540-88059-2\ 5. → page 110[130] J. Siek, P. iemann, and P. Wadler. Blame and coercion: Together againfor the rst time. In Proceedings of the 36th ACM SIGPLAN Conferenceon Programming Language Design and Implementation, PLDI ’15, page425–435, 2015. Association for Computing Machinery. ISBN9781450334686. doi:10.1145/2737924.2737968. → page 137[131] J. G. Siek and T. Chen. Parameterized cast calculi and reusablemeta-theory for gradually typed lambda calculi. Journal of FunctionalProgramming, 31:e30, 2021. doi:10.1017/S0956796821000241. → page 132[132] J. G. Siek and W. Taha. Gradual typing for functional languages. InScheme and Functional Programming Workshop, pages 81–92, 2006. URLh p://scheme2006.cs.uchicago.edu/scheme2006.pdf. → pages 2, 107[133] J. G. Siek and S. Tobin-Hochstadt. e Recursive Union of Some GradualTypes, pages 388–410. Springer International Publishing, 2016. ISBN978-3-319-30936-1. doi:10.1007/978-3-319-30936-1 21. → page 241[134] J. G. Siek and M. Vachharajani. Gradual typing with uni cation-basedinference. In Proceedings of the 2008 Symposium on Dynamic Languages,DLS ’08, 2008. Association for Computing Machinery. ISBN9781605582702. doi:10.1145/1408681.1408688. → pages 50, 243259[135] J. G. Siek and P. Wadler. reesomes, with and without blame. InProceedings of the 37th Annual ACM SIGPLAN-SIGACT Symposium onPrinciples of Programming Languages, POPL ’10, pages 365–376, 2010.ACM. ISBN 978-1-60558-479-9. doi:10.1145/1706299.1706342. → pages131, 137, 143[136] J. G. Siek, M. M. Vitousek, M. Cimini, and J. T. Boyland. Re ned Criteriafor Gradual Typing. In T. Ball, R. Bodik, S. Krishnamurthi, B. S. Lerner,and G. Morrise , editors, 1st Summit on Advances in ProgrammingLanguages (SNAPL 2015), volume 32 of Leibniz International Proceedingsin Informatics (LIPIcs), pages 274–293, 2015. SchlossDagstuhl–Leibniz-Zentrum fuer Informatik. ISBN 978-3-939897-80-4.doi:10.4230/LIPIcs.SNAPL.2015.274. → pages 2, 19, 20, 58, 59, 106, 107, 132[137] J. G. Siek, M. M. Vitousek, M. Cimini, S. Tobin-Hochstadt, and R. Garcia.Monotonic references for e cient gradual typing. In J. Vitek, editor,Programming Languages and Systems, pages 432–456, 2015. SpringerBerlin Heidelberg. ISBN 978-3-662-46669-8. → pages 23, 241[138] V. Sjo¨berg, C. Casinghino, K. Y. Ahn, N. Collins, H. D. Eades III, P. Fu,G. Kimmell, T. Sheard, A. Stump, and S. Weirich. Irrelevance,heterogeneous equality, and call-by-value dependent type systems. InJ. Chapman and P. B. Levy, editors, Proceedings Fourth Workshop onMathematically Structured Functional Programming,Tallinn, Estonia, 25 March 2012, volume 76 of Electronic Proceedings ineoretical Computer Science, pages 112–162, 2012. Open PublishingAssociation. doi:10.4204/EPTCS.76.9. → pages 54, 59, 110[139] J. Sterling. Make three to throw away: Frontiers in homotopical proofassistants (WITS 2022 keynote). URLh ps://www.youtube.com/watch?v=lqBFq7aRReY. → page 236[140] J. Sterling and R. Harper. Guarded computational type theory. InProceedings of the 33rd Annual ACM/IEEE Symposium on Logic inComputer Science, LICS ’18, page 879–888, 2018. Association forComputing Machinery. ISBN 9781450355834.doi:10.1145/3209108.3209153. → pages 16, 55[141] T. Streicher. Investigations into intensional type theory. PhD thesis,Ludwig Maximilian Universita¨t, 1993. URLh ps://www2.mathematik.tu-darmstadt.de/∼streicher/HabilStreicher.pdf.Habilitation thesis. → pages 38, 168260[142] N. Swamy, C. Hrit¸cu, C. Keller, A. Rastogi, A. Delignat-Lavaud, S. Forest,K. Bhargavan, C. Fournet, P.-Y. Strub, M. Kohlweiss, J.-K. Zinzindohoue´,and S. Zanella-Be´guelin. Dependent types and multi-monadic eects inF*. In 43rd ACM SIGPLAN-SIGACT Symposium on Principles ofProgramming Languages (POPL), pages 256–270, Jan. 2016. ACM. ISBN978-1-4503-3549-2. URL h ps://www.fstar-lang.org/papers/mumon/. →pages 27, 110[143] M. Takahashi. Parallel reductions in 𝜆-calculus. Information andComputation, 118(1):120–127, 1995. ISSN 0890-5401.doi:h ps://doi.org/10.1006/inco.1995.1057. → pages 155, 270[144] E. Tanter and N. Tabareau. Gradual certi ed programming in coq. InProceedings of the 11th Symposium on Dynamic Languages, DLS 2015,pages 26–40, 2015. ACM. ISBN 978-1-4503-3690-1.doi:10.1145/2816707.2816710. → pages 52, 63, 111, 173[145] M. Toro and E´. Tanter. A gradual interpretation of union types. InInternational Static Analysis Symposium, pages 382–404, 2017. Springer.→ pages 23, 241[146] M. Toro, R. Garcia, and E´. Tanter. Type-driven gradual security withreferences. ACM Transactions on Programming Languages and Systems,40(4):16:1–16:55, Nov. 2018. → page 23[147] M. Toro, E. Labrada, and E´ric Tanter. Gradual parametricity, revisited,2018. → pages 23, 101[148] G. Travis. How the boeing 737 max disaster looks to a so ware developer.IEEE Spectrum, Jul 2021. URL h ps://spectrum.ieee.org/how-the-boeing-737-max-disaster-looks-to-a-so ware-developer. →page 1[149] T. Univalent Foundations Program. Homotopy Type eory: UnivalentFoundations of Mathematics. h ps://homotopytypetheory.org/book, 2013.→ pages 27, 42, 168, 185[150] N. Vazou, E. L. Seidel, R. Jhala, D. Vytiniotis, and S. Peyton-Jones.Re nement types for haskell. In Proceedings of the 19th ACM SIGPLANInternational Conference on Functional Programming, ICFP ’14, pages269–282, 2014. ACM. ISBN 978-1-4503-2873-9.doi:10.1145/2628136.2628161. → page 27261[151] N. Veltri and A. Vezzosi. Formalizing 𝜋-calculus in guarded cubical agda.In Proceedings of the 9th ACM SIGPLAN International Conference onCertied Programs and Proofs, CPP 2020, page 270–283, 2020. Associationfor Computing Machinery. ISBN 9781450370974.doi:10.1145/3372885.3373814. → pages 185, 190[152] M. M. Vitousek, C. Swords, and J. G. Siek. Big types in li le runtime:Open-world soundness and collaborative blame for gradual type systems.SIGPLAN Not., 52(1):762–774, Jan. 2017. ISSN 0362-1340.doi:10.1145/3093333.3009849. → page 107[153] P. Wadler and R. B. Findler. Well-typed programs can’t be blamed. InProceedings of the 18th European Symposium on ProgrammingLanguages and Systems: Held as Part of the Joint European Conferenceson eory and Practice of So ware, ETAPS 2009, ESOP ’09, page 1–16,2009. Springer-Verlag. ISBN 9783642005893.doi:10.1007/978-3-642-00590-9 1. → pages 112, 171[154] K. Watkins, I. Cervesato, F. Pfenning, and D. Walker. A concurrent logicalframework I: Judgments and properties. Technical ReportCMU-CS-02-101, 2003.h ps://www.cs.cmu.edu/∼fp/papers/CMU-CS-02-101.pdf. → pages 49,63, 66, 110[155] A. Wright and M. Felleisen. A syntactic approach to type soundness.Information and Computation, 115(1):38–94, 1994. ISSN 0890-5401.doi:h ps://doi.org/10.1006/inco.1994.1093. → page 157[156] H. Xi. Applied type system. In S. Berardi, M. Coppo, and F. Damiani,editors, Types for Proofs and Programs, pages 394–408, 2004. SpringerBerlin Heidelberg. ISBN 978-3-540-24849-1. → page 27[157] H. Xi and F. Pfenning. Dependent types in practical programming. InProceedings of the 26th ACM SIGPLAN-SIGACT Symposium onPrinciples of Programming Languages, POPL ’99, pages 214–227, 1999.ACM. ISBN 1-58113-095-3. doi:10.1145/292540.292560. → pages 27, 110[158] J. Zalewski, J. McKinna, J. Morris, and P. Wadler. 𝜆db: Blame tracking athigher delity, 2020. URLh ps://wgt20.irif.fr/wgt20-final98-acmpaginated.pdf. First ACMSIGPLAN Workshop on Gradual Typing 2020, WGT 2020 ; Conferencedate: 19-01-2020 rough 25-01-2020. → pages 52, 171262Appendix AFull Proofseorem 3.4.1 (Soundness). For all ∅ * 𝑆 ⊆ Snf, 𝑆 ⊆ 𝛾 (𝛼(𝑆)).Proof of eorem 3.4.1. We assign a depth number to each set 𝑆 ⊆ Snf. De ne:• 𝐷(𝑆) = 0 if 𝑆 contains two or types built with di erent head constructors.• 𝐷({C t1 . . . tn | t1 ∈ 𝑆1, . . . , tn ∈ 𝑆𝑛}) =max𝑆′∈𝑆1 ...𝑆𝑛 (𝐷(𝑆 ′)) for a head construc-tor C.We perform induction on this𝐷(𝑆), proving the corresponding result mutually for𝛼𝑁 and 𝛾𝑁 . e cases are nearly identical, so we highlight the core technique. Wealso note that in the de nitions, 𝛼𝑁 and 𝛾𝑁 only ever take argument sets whereall the neutrals have the same head variable.I Case 𝐷(𝑆) = 0 :en 𝛼(𝑆) = ?, so 𝛾 (𝛼(𝑆)) is Snf ⊇ 𝑆 .I Case 𝐷(𝑆) = 1+𝑛 :en all terms in 𝑆 are constructed with the same head. Proceed by caseson this head.I Case 𝑆 = {Typeℓ } :263en 𝛾 (𝛼({Typeℓ })) = 𝛾 (Typeℓ ) = {Typeℓ } ⊇ {Typeℓ }. Same reasoningholds for x.I Case 𝑆 = {𝜆x. t | t ∈ 𝑆 ′} :If 𝑆 is nonempty then so is 𝑆 ′. So𝛼(𝑆) = 𝜆x .𝛼(𝑆 ′). Our hypothesis gives that𝛾 (𝛼(𝑆 ′)) ⊇ 𝑆 ′, since 𝑆 ′ has a depth bounded by 𝑛. So 𝛾 (𝛼(𝑆)) =𝛾 (𝜆x .𝛼(𝑆 ′)) ={𝜆x. t′ | t′ ∈ 𝛾 (𝛼(𝑆 ′))}. Since 𝛾 (𝛼(𝑆 ′)) ⊇ 𝑆 ′, our result holds. e reasoningis similar for the remaining cases.eorem 3.4.2 (Optimality). For ∅ * 𝑆 ⊆ Snf and U ∈ Gnf, if 𝑆 ⊆ 𝛾 (U ) then𝛼(𝑆) v U. at is, 𝛾 (𝛼(𝑆)) ⊆ 𝛾 (U ).Proof of eorem 3.4.2. By induction on r, proving the corresponding result mu-tually for 𝛼𝑁 and 𝛾𝑁 .I Case Typeℓ :en 𝛾 (u) = {Typeℓ }, so if S is nonemtpy then 𝑆 = {Typeℓ }, so 𝛼(𝐴) =Typeℓ v Typeℓ . Same reasoning holds for x.I Case ? :Trivial: 𝛼(𝑆) v ? since ? is the least precise term.I Case 〈N ′〉N :en𝛾 (〈N ′〉N ) = {〈N′〉N | N′ ∈ 𝛾𝑁 (N ′),N ∈ 𝛾 (N )}. 𝛾𝑁 produces termswiththe same head for both N and N ′. If 𝑆 is nonempty, then it must be of theform {〈N′〉N | N′ ∈ 𝑆1,𝑠𝑁 ∈ 𝑆2}. So 𝛼(𝑆) has the form 〈N ′S〉NS . By our in-duction hypothesis, Similar reasoning holds for the remaining cases.Lemma A.0.1 ( Composition preserves typing ). Suppose Γ ` N1 ⇒ N1 and Γ `N2 ⇒ U2. If N1uN2 = N and U1uU2 = U then Γ ` N ⇒ U.Suppose Γ ` u1 ⇐ U and Γ ` u2 ⇐ U. If u1uu2 = u then Γ ` u⇐ U.264Proof of Lemma A.0.1. We do mutual induction onthe two above statements.For neutrals:I Case Variable :Trivial becuase x ux = xI Case Application :Straightforward induction shows that u distributes over substitution, sothe substituting the meet of the arguments produces the meet of the re-sults of substitution. e result then follows from IH on the arguments.For normals: straightforward induction. Most cases are straightforward fromIH. e one interesting case is:I Case 〈𝜀1〉N1u 〈𝜀2〉N2 :e resulting evidence is valid because composition produces a term thatis as precise as both inputs. Likewise, by our premise N1 and N2 checkagainst the same type U , so they must synthesize types U1 and U2 thatare both consistent with U . By our premise the meet of the evidence𝜀1u𝜀2 is de ned, and since the meet is monotone, this combined evidenceis as precise as, and hence consistent with, U . Again, since the meet ismonotone, U1uU2 must be de ned and 𝜀1u𝜀2 v U1uU2. So then U1uU2 isconsistentwithU , giving uswhatwe need to preserve the typing relation.Lemma A.0.2. If Γ1 ` u1 ⇐ U1 and Γ1 |Γ2 ` 〈U2 ⇐ U2〉u1 { u2, then Γ2 ` u2 ⇐ U2.If Γ1 ` N1 ⇒ U1 and Γ1 |Γ2 ` (N1 : U1){ (N2 : U2), then Γ2 ` N2 ⇒ U2.Proof of Lemma A.0.2. Weprove the two statementsmutually, by induction on thederivation of the casting or re-typing relation.I Case Neutral retyping variables :Trivial from premise, since types are in Γ.I Case Neutral retyping application :265e premises mirror the premises of the typing rule for neutral applica-tions. By our IH, u′ produces a well-formed output because it is the resultof casting u to the type of the variable in U ′. e nal result type is com-puted using codomain substitution, which is exactly how the synthesisrule for spine application produces its result.I Case Normals :Straightforward induction in each case: the casts in the premises werechosen precisely to preserve typing.eorem3.5.1 (Normalization preserves typing). If Γ ` u {t ⇐ U, then Γ ` u⇐ U.Proof of eorem 3.5.1. By induction on the normalization derivation, mutual withthe following: if Γ ` t { u⇒𝑈 , then Γ ` u⇐ U . Note that synthesis is not pre-served by normalization, only checking.Straightforward induction establishes taht that hereditary substitution pre-serves typing, i.e. replacing x by u in the input produces a result typeable byreplacing x with u in the input type.For normalization, most cases are trivial, because the premises of normaliza-tion are directly mirror the premises of normal typing. e exceptions are below:I Case GNSynthDyn :e normalization rule is a synthesis rule, but the typing rule is a checkingrule. However we can type ? at any type with GWFUnk, which gives ourresult.I Case GNSynthType :As above, normalization is a synthesis rule, but types are checked in nor-mal forms, but because GNSynthType synthesizes the universe at thelevel that GWFType expects, we can type the result.I Case GNSynthAnn :266We have by our premise that u is the result of normalizing at type U (i.e.the synthesized type), so IH gives that u checks against the synthesizedtype U , so the reslt is immediate.I Case GNCheckSynth :Our hypothesis gives that u′ checks against U ′, which is consistent withU . e result then follows from casting preserving typing.Lemma A.0.3. If (x : U ) and (xp : U ′), both well typed, then 𝑠𝑖𝑧𝑒(U ) >= 𝑠𝑖𝑧𝑒(U ′),and if p is non-empty, then 𝑠𝑖𝑧𝑒(U ) > 𝑠𝑖𝑧𝑒(U ′).Proof of Lemma A.0.3. By induction on m.Base case: Trivial if p is the empty spine.Inductive case: suppose p is (p′′u′′) where (xp′′ : U ′′). en IH gives 𝑠𝑖𝑧𝑒(U )>=𝑠𝑖𝑧𝑒(𝑈 ′′). If xp′′u′′ is well typed, thenU ′′must be a function type, say (y : U ′′1)→i U ′′2,where u′′ : U ′′1, and i is themax of the levels ofU ′′1 andU ′′2 . Predicativity/universe-hierarchy gives us that 𝑠𝑖𝑧𝑒(u′′)(i) = 0, since otherwise U ′′1 would need a largerlevel. e type U ′ of xp is computed by replacing u with u; ; in U ′′2 , but because𝑠𝑖𝑧𝑒(u′′)(i) = 0, then 𝑠𝑖𝑧𝑒(U ′)(i) = 𝑠𝑖𝑧𝑒(𝑈 ′′)(𝑖), i.e replacing y with u′′ doesn’t intro-duce any new arrows at level i. So 𝑠𝑖𝑧𝑒(U ′′)(i) = 1 + 𝑠𝑖𝑧𝑒(𝑈 ′)(𝑖). en 𝑠𝑖𝑧𝑒(U ) >=𝑠𝑖𝑧𝑒(𝑈 ′′) > 𝑠𝑖𝑧𝑒(𝑈 ′).Looking at SHSubRSpine: our lemma gives that 𝑠𝑖𝑧𝑒(U )>= 𝑠𝑖𝑧𝑒((𝑦 :𝑈 ′1)→𝑈 ′2)>𝑠𝑖𝑧𝑒(𝑈 ′1 ).We only need to be decreasing in the superscripted type U, since all otherrecursive references are structurally decreasing. So the recursive references forSHSubRSpine are all on structurally smaller arguments with variable type U ′, oron strictly smaller variable types. eorem 3.7.1 (Type safety). If · ` t : U, then either t −→∗ v for some v, t −→∗ f,or t diverges.Proof of eorem 3.7.1. We prove progress and preservation in the usual way.267For progress, inversion on the typing derivations gives a canonical formslemma: every closed value is either canonical for its type, f or ?. Every non-value form has a corresponding reduction rule, and the canonical forms lemmaguarantees that if non-canonical form is not a redex, then one of its sub-terms canbe reduced.For preservation, most of the reasoning was explained in the chapter. e re-sult holds because of the careful use of evidence: tagging a term with evidenceallows it to be assigned any type, so long as the evidence is consistent with boththe term’s type and its target type. If building evidece ever fails, then f is pro-duced, which can be assigned any type. Since the meet always produces a termas precise as its inputs, the evidence applied ensures the reduct has the same typeas the redex. eorem 3.7.3. For any untyped 𝜆-term 𝑡 and closing environment Γ that mapsall variables to type ?, then Γ ` d𝑡e ⇒ ?. Moreover, if 𝑡 is closed, then 𝑡 −→∗ 𝑣 impliesthat d𝑡e elaborates to t where t −→∗ v and stripping evidence from v yields 𝑣 .Proof of eorem 3.7.3. First we prove that typing holds.I Case Variable :Every variable has type ? in Γ, so the variable synthesizes ΓI Case Abstraction :d𝜆𝑥.𝑡e = 𝜆x .d𝑡e:: ?, and d𝑡e synthesizes ? by IH, so we synthesize type ?by the ascription rule. I Case Application :Holds by IH and the typing rule for applications, since ? has do-main and codomain of ?For the semantics, we can use a simple simulation argument, whereeach untyped 𝛽-reduction corresponds to a 𝛽-reduction and a removal ofan ascription.eorem 3.7.4 (Gradual Guarantee).268(Static Guarantee) Suppose Γ ` t ⇐ U and U v U ′. If Γ v Γ′ and t v t ′, thenΓ′ ` t ′⇐ U ′.(Dynamic Guarantee) Suppose that · ` t1 : U, · ` t1 : U ′, t1 v t1, and U v U ′. Ift1 −→∗ t2, then t1 −→∗ t2 where t2 v t2.Proof of eorem 3.7.4. e static guarantee is shown by induction on the typingderivation. We omit the details, but the key lemmas are the normalization guar-antee (below), that synthesis is monotone in the synthesized type, and the factthat reducing a term’s precision makes it consistent with no less terms.e dynamic gradual guarantee is proved using a (weak) simulation. at is,for each step e1 −→ e2 where e1 v e′1, we show that e′1 −→∗ e′2 where e2 v e′2. Weperform induction on the derivation of e1 −→ e2.First note that if e′1 is ? the result holds trivially, likewise if e2 is f.We outline the strategy for the remaining cases. StepAppEv,StepAppEvRawen the functions and arguments are precision-relatex respectively. If the func-tion in e′2 is a lambda term, then we can 𝛽-reduce e′2. e result then follows fromthe monotonicity of substitution.If the function position in e′2 is ?, then we can step to ? with StepAppDyn,and our result holds because ? is the least precise term. StepAscr From themonotonicity of the meet StepContext en the result holds from IH combinedwith the fact that precision contains all structural rules. Lemma 3.7.5 (Normalization Gradual Guarantee). Suppose Γ1 ` u1 {t1 ⇐ U1. IfΓ1 v𝜂 Γ2, t1 v t2, and U1 v𝜂 U2, then Γ2 ` u2 {t2 ⇐ U2 where u1 v𝜂 u2.Proof of Lemma 3.7.5. Unlike in [58], we do not have separate cases for the bound-ary between checking and synthesis based on whether precision is increasing ordecreasing. e key lemmas are the monotonicity of casting and the meet, both ofwhich are proved with straightforward induction. For casting, any time there is arule with non-? evidence, there is a corresponding rule for ? evidence, so reducingthe precision of evidence to ? does not cause new failures.e full result is then obtained by straightforward induction on the normal-ization derivation, showing that normalization is monotone in both the normalform and, when present, the synthesized type. In particular, ? synthesizes ?, so269the normal form and synthesized type are both less precise than any other term.Using the body function ensures that reducing the precision of a function in anapplication produces a less precise result and does not cause failure. Lemma 5.4.4 (Precision Reexive). If Γ ` t⇐ T then Γ |Γ ` t v−→ t (For ElabReflto produce an elaboration that satis es the v−→ side-condition of CastRefl).Proof of Lemma 5.4.4. Straightforward induction on the de nition of precision.Works because every form has a diagonal rule. Lemma 5.4.5 (Composition Safety). If t1&T t2 is not a value and Γ ` t1&T t2 ⇐ T,then t1&T t2 −→ t3 for some t3 and Γ ` t3 ⇐ T (For progress and preservation)Proof of Lemma 5.4.5. Each composition of two canonical forms of the same typehas a reduction. If one of the composed terms is not a canonical form, then either(1) one of the composed terms can reduce, (2) one term is a ?T or fT where T isnot a function or equality type, and we can reduce with RedCompUnk or Red-CompErr, or (3) one of the composed terms is neutral, and hence the compositionis neutral. Lemma 5.4.6 (Composition Con uence). If t1&T t2 V t3 and t1&T t2 V t′3 maxi-mally, then t3 V t′3, where V is the parallel reduction relation, standard in con u-ence proofs [143] (For con uence, which is needed to show that 𝛽-reductions preservetypes);Proof of Lemma 5.4.6. e proof is straightforward. We provide the case for com-position that ts into the overall induction proof of con uence. If t′3 is obtainedonly by stepping within t1 and t2 then the result follows from IH. If t′3 and t′3 areboth the results a RedComp* rule, then the result follows from IH, plus the preser-vation of parallel reduction under substitution (since some rules use −→&). Finally, ift′3 is the result of a RedComp* rule but t3 is not, then we can step t3 with that samerule, and apply the IH and preservation under substitution to get the result. ekey is that in each case, there is only one possible non-contextual reduction. Lemma 5.4.7 (Composition Lower Bound). If Γ ` t1&T t2 ⇐ T, then Γ |Γ ` t1&Tt2 v−→ t1 and Γ |Γ ` t1&T t2 v−→ t2 (Preserving the v←−−→ condition of CastRefl forreduction RedCastEq);270Proof of Lemma 5.4.7. Given by PrecComp(L,R). LemmaA.0.4 (Presynthesis is Monotone). If Γ ` t1⇒∗ T1, Γ ` t2⇒∗ T2 and Γ1 |Γ2 `t1 v𝛼 t2, then Γ1 |Γ2 ` T1 v𝛼 T2.Proof of Lemma A.0.4. Straightforward induction on the type derivation. Lemma 5.4.12is used forCastApp, and Lemma 5.4.13 and the catch-up lemmas are used to showthat the results of constrained synthesis are precision related. Lemma 5.4.8 (Precision Transitive). If Γ1 |Γ2 ` t1 v−→ t2 and Γ2 |Γ3 ` t2 v−→ t3 : Tthen Γ1 |Γ3 ` t1 v−→ t3 (Preserving the v←−−→ side-condition ofCastRefl for reductionRedCastEq);Proof of Lemma 5.4.8. We prove for by mutual induction for structural and deni-tional precision. For de nitional precision, it follows from the inductive hypoth-esis, plus con uence.For structural precision, we proceed by induction on the combined depths ofthe derivationsD1 :: Γ1 |Γ2 ` 𝑡1 v𝛼 𝑡2 andD2 :: Γ2 |Γ3 ` 𝑡2 v𝛼 𝑡3. Cases where both usethe same diagonal rule are straightforward, as are any with f on the le or ? onthe right. We show a few examples for remaining cases, the reasoning is similarin those we omit.I Case DiagComp, PrecCompL (PrecCompR symmetric) :en t1 = t1L&T1 t1R, and t2 = t2L&T2 t2R, where Γ1 |Γ2 ` t1L v𝛼 t2L, Γ1 |Γ2 `t1R v𝛼 t2R, and Γ2 |Γ3 ` t2L v𝛼 t3. IH gives that Γ1 |Γ3 ` t1L v𝛼 t3, so Prec-CompL yields our result.I Case D1 with CastL or D2 with CastR :Follows from IH, plus Lemma A.0.4 to obtain the type precision premisesof CastL or CastR.I Case D1 with CastR or DiagCast, D2 with CastL :Similar reasoning to above, IH gives us a precision relation between theterms being cast, and then we can apply CastL to obtain result.271Lemma 5.4.9 (Precision Modulo Conversion). If Γ1 |Γ2 ` t1 v←−−→ t2, where t2 −→∗t′2, then Γ1 |Γ2 ` t1 v←−−→ t′2 (Preservation of CastRefl under contextual reduction)Proof of Lemma 5.4.9. Immediate from the denition of precision modulo conver-sion. Lemma 5.4.10 (Static Consistency). For any static terms t1 and t2, let t1 and t2 betheir embedding in CastEq. en t1 −→ t2 i t1 =𝛼𝛽 t2, i.e., if they are staticallyde nitionally equal (For GEq to conservatively extend cic).Proof of Lemma 5.4.10. In the static fragment of gcic, ?, f and & are absent, andall closed equality proofs have the form re (tw)`tt′ where t2, t and t′ are all def-initionally equal. So mutual induction on the derivations of 𝛼-consistency andde nitional consistency shows the result: rules CstCompDiag, CstComp(L,R),and CstUnk(L,R) can never occur. All other rules are a head constructor withconsistency premises between the arguments. Lemma 5.4.11 (Cast Monotonicity). Suppose that Γ1 |Γ2 ` t1 v−→ t2, Γ1 ` t1 ⇒ T1and Γ2 ` t2 ⇒ T2 where Γ1 |Γ1 ` T1 v−→ T′1 and Γ2 |Γ2 ` T2 v−→ T′2. en Γ1 |Γ2 `〈T′1 ⇐ T1〉t1 v−→ 〈T′2 ⇐ T2〉t2 (For ElabCst to produce v−→ -related elaborationsfor vSurf-related inputs)Proof of Lemma 5.4.11. Given by DiagCast. LemmaA.0.5 (SubstitutionMonotone for Structural Precision). Suppose Γ1 |Γ2 ` t1 v𝛼 t2,where Γ1 ` t1 ⇒ T1 and Γ2 ` t2 ⇒ T2. If Γ1, (x : T1),Δ1 |Γ2, (x : T2),Δ2 ` t′1 v𝛼 t′2,then Γ1 [t1/x]Δ1 |Γ2 [t2/x]Δ2 ` [t1/x]t′1 v𝛼 [t2/x]t′2 (For ElabApp to be monotone inthe return type)Proof of Lemma A.0.5. As Lennon-Bertrand et al. [87] say, the proof follows fromweakening of typing, with induction on the precision derivation. e only non-trivial new case is for PrecComp(L) (PrecCompR is symmetric). In this case, wehave Γ1(x : 𝑇1)Δ1 |Γ2(x : 𝑇2)Δ2 ` 𝑡 ′𝐿1&𝑇𝑡 ′𝑅1 v𝛼 𝑡 ′2, where Γ1(x : 𝑇1)Δ1 |Γ2(x : 𝑇2)Δ2 `𝑡 ′𝐿1 v𝛼 𝑡 ′2. IH Γ1 [t1/x]Δ1 |Γ2 [𝑡2/x]Δ2 ` [𝑡1/x]𝑡 ′𝐿1 v𝛼 [𝑡2/x]𝑡 ′2, so we apply Prec-CompL to get our result. 272Lemma5.4.12 (SubstitutionMonotone). Suppose Γ1 |Γ2 ` t1 v−→ t2, where Γ1 ` t1 ⇒ T1and Γ2 ` t2 ⇒ T2. If Γ1(x : T1)Δ1 |Γ2(x : T2)Δ2 ` t′1 v−→ t′2,then Γ1 [t1/x]Δ1 |Γ2 [t2/x]Δ2 ` [t1/x]t′1 v−→ [t2/x]t′2 (For ElabApp to be monotonein the return type)Proof of Lemma 5.4.12. Follows from Lemma A.0.5 for v𝛼 , plus the preservationof reduction under substitution. Lemma A.0.6 (Catch-up Lemmas). Suppose Γ1 v𝛼 Γ2, and Γ1 |Γ2 ` t1 v𝛼 t2 wheret1 has head h, and Γ1 ` t1 ⇒ T. en t2 −→∗ t′2 where either (1) t′2 has head h andΓ1 |Γ2 ` t1 v𝛼 t′2, or (2) t′2 is ?T′ where Γ1 |Γ2 ` T1 v𝛼 T2. e same holds for v−→.Proof of Lemma A.0.6. e proof is by induction on the precision derivation, andis identical to gcic, except for the cases regarding equality. First, we note that ift1 has head h, it cannot be a composition or a cast expression. e only rules thatallow composition on the right require that the term on the le either be a cast ora composition, so t2 cannot be a composition.I Case DiagEq :Identical to the gcic case for function types.I Case DiagRefl :en t2 = 〈T′2 ⇐ T′1〉 . . . 〈T′k ⇐ T′k−1〉t′2, since CastL and DiagRefl are theonly rules that apply. All of the T′is are de nitionally less precise thanT, but T must be some tL =Telem tR by CastEq. So each T′i must eitherreduce to either tiL =Telemi tiR or ?Typeℓ (using the previous case for headType). And the typing premise of CastL, T′k must be tkL =Telemk tkR. Ift′2 is ?tkL=Telemk tkR (because the rst non-cast precision rule was GenUnk)then it reduces with PropEqUnk to re (tkL&Telemk tkR)`tkLtkR . Otherwiseit already has the form re (tkw)`tkLtkR (because the rst non-cast pre-cision rule was DiagRefl). All casts can then be reduced using one ofRedCastEq, RedUpDown, RedEqUnk or RedEqGerm. Since we beginand end with an equality type, the resulting term must have the formre (t′′w)`t′′1 t′′2 .273Lemma 5.4.13 (Reduction Monotone). If Γ1 |Γ2 ` t1 v−→ t2 and t1 −→∗ t′1, thent2 −→∗ t′2 for some t′2 where Γ1 |Γ2 ` t′1 v−→ t′2 (For DGG, to preserve ElabCst whenreducing precision, and to preserve typing under contextual reduction ofre(tw)`t1t2 )Proof of Lemma 5.4.13. We simultaneously prove the result for v−→ and v𝛼 bymutual induction on the precision derivation. Because PrecComp(L,R) have com-position on the le -hand side, it is never a possibility in the inversions performedin the gcic proof. So the gcic case for each of its reductions still holds for GEq.We show the cases for the rules added to GEq. If we ever take a contextual step,the result is immediate from the IH and the corresponding diagonal rule.I Case CastL :e only case now from GCIC is the cast for equality:I Case RedCastEq :en t1 = 〈tendL =Tend tendR ⇐ tstartL =Tstart tendR〉re (tw)`tstartLtendR ,and Γ2 ` t2 ⇒∗ T2, where Γ1 |Γ2 ` tstartL =Tstart tendR v−→ T2, Γ1 |Γ2 `tendL =Tend tendR v−→ T2, and Γ1 |Γ2 ` re (tw)`tstartLtendR v𝛼 t2. Ourgoal is to show that Γ1 |Γ2 ` re (〈Tend ⇐ Tstart〉tw&Tend tendL&Tend tendR)`tendLtendR v𝛼t′2 and t2 −→∗ t′2. By LemmaA.0.6, we have (1) t2 −→∗ re (t′2w)`t′2Lt′2Rwith Γ1 |Γ2 ` re (tw)`tstartLtendR v𝛼 re (t′2w)`t′2Lt′2R , or (2) t2 −→∗ ?T2 .e result is immediate for (2) by GenPrecUnk.For (1), inversion on typing gives that T2 = t′2L =T′2 t′2R, so in-version on tstartL =Tstart tstartR v−→ T2 gives Γ1 ` Γ2 ` tstartL v𝛼 t′2L,Γ1 ` Γ2 ` tstartR v𝛼 t′2R, and Γ1 |Γ2 ` Tstart v𝛼 T′2. We get the same fortendL, tendR, andTend. Inversion on the precision fromLemmaA.0.6gives Γ1 |Γ2 ` tw v𝛼 t′2w, so thenCastL gives Γ1 |Γ2 ` 〈Tend ⇐ Tstart〉tw v𝛼t′2w. Two applications of PrecCompR give Γ1 |Γ2 ` 〈Tend ⇐ Tstart〉tw&TendtendL&Tend tendR v𝛼 t′2w, so then our result is built with DiagRefl.I Case PrecCompL (PrecCompR is symmetric) :274en t1 = t1L&T t1R, withD :: Γ1 |Γ2 ` t1L v𝛼 t2. We proceed by cases on thereduction rule used on t1L&T t1R.I Case RedCompGerm :en t1L = 〈?Typeℓ⇐germ(h)〉t′1L and t1R = 〈?Typeℓ⇐germ(h)〉t′1R.We proceed by inversion on D.I Case DiagCast :en t2 = 〈T2end ⇐ T2start〉t′2, with Γ1 |Γ2 ` t′1L v𝛼 t′2, Γ1 |Γ2 `germ(h) v𝛼 T2start and Γ1 |Γ2 ` ?Typeℓ v𝛼 T2end. en T2endis ?Typeℓ with some number of casts, so we can apply Ge-nUnk and CastL to get Γ1 |Γ2 ` germ(h) v𝛼 T2end. So byPrecCompL we have Γ1 |Γ2 ` t′1L&germ(h) t′1R v𝛼 t′2. en byDiagCast we have our result.I Case CastL :en we have Γ1 |Γ2 ` t′1L v𝛼 t2, so by PrecCompLwe haveΓ1 |Γ2 ` t′1L&germ(h) t′1R v𝛼 t2. e result then follows fromCastL.I Case RedCompUnkL :en t2 −→∗ ?T , giving our result.I Case RedCompUnkR :Follows from premise of PrecCompL.I Case RedCompErr, RedCompHeadErr, RedCompGermErr :Trivial since f is least.ICaseRedCompEq,RedCompRefl,RedCompInd,RedCompLam,RedCompCon,RedCompPi:In each case, t2 has the same head as t1L and t1R, so we can pushthe use of PrecCompL deeper, applying the necessary diagonalrules, along with Lemma 5.4.12.275I Case DiagComp :By cases on the reduction rule used on the le.I Case RedCompGerm :enwe have Γ1 |Γ2 ` 〈?Typeℓ⇐germ(h)〉tL&Typeℓ 〈?Typeℓ⇐germ(h)〉tL v𝛼t2L&T2 t2R. en by Lemma A.0.6 T2 must reduce to ?Typeℓ , since itis less precise than ?Typeℓ . e precision relation between 〈?Typeℓ⇐germ(h)〉tLand t2L must either use DiagCast or CastL, likewise for on theRHS. If both useDiagCast, then we can step t2L&T2 t2R with Red-CompGerm and use DiagCast and DiagComp for our result.Consider then the case where the precision relation with t2Luses CastL, and with t2R uses DiagCast (the case for vice versais symmetric). We will get our result in zero steps of the RHS.Here, Γ1 |Γ2 ` t1L v𝛼 t2L, with and t2R = 〈T2end ⇐ T2start〉t′2R withΓ1 |Γ2 ` t1R v𝛼 t′2R, Γ1 |Γ2 ` germ(h) v𝛼 T2start and Γ1 |Γ2 ` ?Typeℓ v𝛼T2end. en T2end is ?Typeℓ with some number of casts, so we canapply GenUnk and CastL to get Γ1 |Γ2 ` germ(h) v𝛼 T2end. enbyCastR, we have Γ1 |Γ2 ` t1R v𝛼 〈T2end ⇐ T2start〉t′2R. So byDiag-Compwe have Γ ` t1L&germ(h) t1R v𝛼 t2L&T2end 〈T2end ⇐ T2start〉t′2R.Finally, our result comes from applying CastL. e case whereboth use CastL is similar, but without the need to use CastR.I Case RedCompUnk :We handle RedCompUnk(L), the other case is symmetric. In thiscase, we have Γ1 |Γ2 ` ?T1 &T1 t1R v𝛼 t2L &T2 T2R. Inversion givesthat t2L must be some sequence of casts applied to ?T′2 , where eachcast type and T′2 are all less precise than T1. Because T is one ofTypeℓ , C(−→𝑡 ) or ?Typeℓ , and because each cast type is less precise,t2L −→∗ ?T2 . So we can step with RedCompUnk(L) and get ourresult from inversion on the original precision derivation.I Case RedCompErr, RedCompHeadErr, RedCompGermErr :276Trivial since f is least.ICaseRedCompEq,RedCompRefl,RedCompInd,RedCompLam,RedCompCon,RedCompPi:en we have Γ1 |Γ2 ` t1L&T t1R v𝛼 t2L&T2 t2R, where t1L and t2Lhave the same head h. We have 𝑡1𝐿&T t1R −→∗ t′1 and want to ndt′2 such that t2L&T2 t2R −→∗ t′2 and Γ1 |Γ2 ` t′1 v𝛼 t′2. Lemma A.0.6 oneach side of & gives t2L&T2 t2R −→∗ t′2L&T2 t′2R that is less precisethan t1L&T t1R, where t′2L and t′2R both have head h. is termthen steps with the same reduction as t1L&T t1R, and using theappropriate diagonal rules and the monotonicity of substitutiongives our result.I Case DiagJ :en the step is with RedJ. So we can step the RHS with RedJ, and obtainour result with DiagCast and the monotonicity of substitution.I Case DiagEq :en only a contextual step is possible, and the result follows from IH,since the type-comparisons in DiagEq are all modulo reduction.I Case DiagRefl :en only a contextual step is possible, so we take the same step in theRHS and use DiagRefl for our result.Lemma A.0.7 (𝛼-Consistency Monotone for Precision). If Γ |Γ ` tlowL v𝛼 thighLand tlowL𝛼 tR, then thighL𝛼 tRProof of Lemma A.0.7. By induction on the derivations of Γ1 |Γ2 ` 𝑡𝑙𝑜𝑤𝐿 v𝛼 𝑡 ′ℎ𝑖𝑔ℎ𝐿 .I Case 𝛼 derived with CstCompR or CstCastR :277If some sequence of CstCompR and CstCastR was used, we can unwrapthe derivation from these until there is a use of a rule that constrains thesyntax of the LHS. We then use the derivation from the correspondingcase below, then re-apply the same sequence of CstCompR andCstCastRto obtain our result.I Case PrecCompL (PrecCompR is symmetric) :So tlowL = t1&T t2, and Γ1 |Γ2 ` t1 v𝛼 thighL. en by IH we have thighL𝛼 tR.I Case DiagComp :en tlowL = t1&T t2 and highL = t′1&T t′2, where Γ1 |Γ2 ` t1 v𝛼 t′1 and Γ1 |Γ2 `t2 v𝛼 t′2. If 𝛼 was derived with CstCompDiag, inversion gives tR =tR1&TR (tR2), so we can apply IH and CstCompDiag. If 𝛼 was derivedwith CstCompL, we can use IH and CstCompL.I Case DiagRefl :Follows from IH plus CompRefl.I Case Remaining cases :Same as gcicLemma A.0.8 (𝛼-Consistency Symmetric). 𝛼 Is symmetric.Proof of Lemma A.0.8. Straightforward induction. RulesCstVar andCstType haveidentical terms on each side. Any uses of CstCompL can be turned into Cst-CompR and vice versa, likewise for CstCastL and CstCastR. e other casesfollow easily from IH. Lemma 5.4.14 (Consistency Monotone for Precision). If Γ |Γ ` t1 v−→ t′1 andΓ |Γ ` t2 v−→ t′2, and t1 −→ t2, then t′1 −→ t′2 (So reducing precision of V and V′preserves ElabCst)Proof of Lemma 5.4.14. Follows fromLemmaA.0.8, LemmaA.0.7 and Lemma 5.4.13.278Lemma 5.4.15 (Structural Precision). v−→ contains all structural rules (For ho-momorphic elaboration rules to produce v−→ -related elaboration for vSurf-relatedinputs)Proof of Lemma 5.4.15. Given by the diagonal rules of precision. Lemma A.0.9 (Canonical Forms). If Γ ` v⇐ T or Γ ` v⇒ T, and v is not neutral,then v is either ?T′ or fT′ where T′ is convertible with T, or one of the followingholds:• T = (x : T1)→ T2 and v = 𝜆(x : T′1). t• T = t1 =T′ t2 and v = re(tw)`t′1t′2• T = C(−→𝑡 ) and v = DC(−→𝑡 ′ )• T = Typeℓ and v = (x : T1)→ T2 or v = C(−→𝑖 ) or v = t1 =T t2 or v = Typeℓ′ forℓ ′ < ℓ .Proof of Lemma A.0.9. By induction on the typing derivation.I Case CastCheck :Follows from IH on the synthesis derivationI Case CastVar,CastApp,CastMatch,CastCast,CastJ,CastComp :If v is not neutral, then it cannot be a value, since the only value formsfor eliminations are neutrals.ICaseCastFun,CastType,CastFun,CastApp,CastInd,CastCtor,CastUnk,CastErr,CastEq,CastRefl:Immediate from the form of the typing derivation.Lemma 5.4.16 (Con uence, Progress, Preservation and Elaboration). e follow-ing hold:• −→ is con uent.279• If Γ ` t⇐ T, then t is a value or t −→ t′ for some t′.• If Γ ` t1 ⇐ T and t1 −→ t2 then Γ ` t2 ⇐ T.• If Γ ` t_ t⇐ T, then Γ ` t⇐ T.Proof of Lemma 5.4.16. (1) As in [87]. e proof uses the usual parallel reductionstrategy. e additional cases are for RedJ, RedCastEq, PropEqUnk and PropE-qEq, all of which are straightforward, and for &, which is given by our criteria.(2) As in [87]. We performmutual induction on the typing derivation with thecorresponding propositions for synthesis and constrained synthesis. e grad-ual criteria guarantee that the composition does not interfere with the canonical-forms property for functions, types (in cast statements) and members of inductivetypes, so all cases from gcic are readily adapted to CastEq. Additional cases areforCastUnk, CastErr, CastEq, CastRefl, CastJ, and possibly &. ForCastUnkand CastErr, there is a new case because of the new type former =, but we al-ways step with PropEqUnk or PropEqErr. For CastEq and CastRefl, by ourhypothesis, either we can take a step in a sub-term or all sub-terms are normal,meaning the entire term is normal. For CastJ, the arguments to J must all benormal, or a step can be taken in one of them. If they are all normal, then thecanonical forms lemma gives that the scrutinee must be re , enabling a reductionwith RedJ. Our gradual criteria ensure that any non-value & terms can step.(3) As in [87]. We perform mutual induction on the typing derivation withthe corresponding propositions for synthesis and constrained synthesis. e newcases are for RedJ, RedCastEq, PropEqUnk and PropEqErr, as well as &. ForRedJ, the cast types are well typed by preservation of typing under substitution,and the whole expression can be typed with two applications of CastCast. ForRedCastEq, the witness and cast-types are well typed by the premise, so cast-ing the witness is well typed at the destination type by CastCast. Our gradualcriteria give that composing terms of the same type preserves that type. Finally,we have that the witness is more precise than both endpoints, by transitivity andthe lower-bound property from the gradual criteria, allowing us to apply Cas-tRefl. e cases for PropEqUnk and PropEqErr are trivial, and the case for &follows from the gradual criteria. Finally, we have contextual steps. ese are280all straightforward, or identical to gcic, except for preserving the precision side-conditions of CastRefl, where it follows from our denition of precision moduloconvertibility.(4) As in [87]. We perform mutual induction on the typing derivation withthe corresponding propositions for synthesis and constrained synthesis. e newcases are ElabEq, which is trivial, along with ElabRefl. For ElabRefl, our crite-ria give re exivity of v−→ , so this combined with our premises allow us to applyCastRefl to type the elaboration. Corollary 5.4.18 (Weak Canonicity). Suppose · ` t : V. en either t diverges, ort −→∗ v where v is ?V or fV, or the following hold:• If V is (x : T1)→ T2 then v is 𝜆x. t′• If V is C@{i}(−→t1 ) then v is DC@{i}(−→𝑡2 ) for some D.• If V is t1 =T′ t2 then v is re (t′)`t1t2• If V is Typei then v is one of C@{i}(−→t1 ), (x : T1)→ T2, Typei−1 or t1 =T′ t2.Proof of Corollary 5.4.18. Follows from Lemma A.0.9 with type safety. eorem 5.4.19 (Conservativity). For any bcic-terms t and T, let t and T be theGEq terms corresponding to t and T by mapping bcic 𝜆 to GEq 𝜆, etc. en · ` t⇐ Ti · ` t : T .Proof of eorem 5.4.19. bcic as given by Lennon-Bertrand [86] does not have propo-sitional equality, but it is easily added with the types given in Fig. 5.2. We identifyreflt : t =T t with re (t)`tt.e “only if” direction is straightforward, since each bcic rule has an analoguein GEq. For the other direction, we need to transform each gcic type derivationinto a bcic derivation. However, this is straightforward induction: all typing ruleshave corresponding bcic rules, except forCastComp,CastUnk andCastErr, butthese all use gradual features not present in the embedding of a gcic term intobcic. For CastCheck, the result follows from Lemma 5.4.10. Lemma5.4.20 (ElaborationGradual Guarantee). Suppose t1 vSurf t2 and Γ1 v−→ Γ2(i.e. entries in Γ1 and Γ2 are respectively related by v−→ ). en:281• If Γ1 ` t1_ t1 ⇐ T then Γ2 ` t2_ t2 ⇐ T for some t2 where Γ1 |Γ2 ` t1 v−→ t2.• If Γ1 ` t1 _ t1 ⇒ T1 then Γ2 ` t2 _ t2 ⇒ T2 for some T2, t2 where we haveΓ2 ` T2⇒Type Typeℓ and Γ1 |Γ2 ` t1 v−→ t2.Proof of Lemma 5.4.20. Our gradual criteria ensure that every rule of structuralprecision from [87] is admissible for v−→ , so our proof follows the same format.e new cases are for ElabEq, and ElabRefl, which are immediate from the IH.We reiterate the case for ElabCst to show how it ts with the gradual criteria.Suppose that Γ1 ` t1_ t1⇒𝑇1, that Γ2 ` t2_ t2⇒𝑇2, and that t1 vSurf t2. We knowthat T−→T1, and our goal is to show that Γ1 |Γ2 ` 〈T1 ⇐〉𝑇𝑡1 v−→ 〈T2 ⇐〉𝑇𝑡2 andthat T−→T2. e former is immediate from Lemma 5.4.11. e la er followsfrom Lemma 5.4.14. Lemma 6.7.1 (Soundness). If Γ ` t⇐ T and t{Æ t′ then−−−−−−−−−−−−−−−−→(xk : LæTÈΓ(xk)É)𝑘→ (EÈtÉ =TÈTÉ EÈt′É) is inhabited in tctt. Moreover, EÈtÉ isreducible.Proof of Lemma 6.7.1. Each eliminator form is reducible because it corresponds toa pa ern-matching de nition, so reducing the entire match to the correspondingbranch (or equivalently, the proper argument given to an inductive eliminator) isa reduction step. Likewise, for function application, taking the second element ofthe produced pair is a reduction step.In each case the equality is de nitional, except for casting functions to andfrom ?Ty, which are blocked by transporting across EqI . ICase Propagation reductions:For computing ? and f, the result holds from our de nition of fFromand ?From: we 𝜂-expand at function types and compute the meet of theendpoints for equality. For eliminating or casting ? or f of an inductivetype, we produce W? or Wf, which is equal to the translations of ? andf respectively.I Case RedTagUpDown :282headMatch and fromGerm are dened to directly mirror the behavior ofFromGerm.I Case RedTagUpDownInd :e reduction rule was designed speci cally to mirror the behavior of themodel.I Case Other casting rules, composition rules :In each case, reducing the de nition of cast on the translation of the redexgives exactly the translation of the reduct. One important detail is thatthe model constructs terms using the monadic bind, just like cast does, soeven in the exact case equal computations are produced.I Case RedJ :e translation of J performs precisely the cast speci ed by the reductionrule. e presentation omi ed it for clarity, but in the Agda model wewrap witnesses in a wrapper type, which ensures that computing such acast pa ern matches on the equality proof, so it invokes the reduction weneed for our termination argument.Lemma 6.7.2 (Model Preserves Types). If Γ ` t⇐ T thenEÈtÉæ :−−−−−−−−−−−−−−−−−→(xk : Læ TÈΓ(xk)É)𝑘→ (Læ TÈTÉ) in tctt.Proof of Lemma 6.7.2. By induction on the typing derivation. e approach isstandard: typedness of subterms derives from the hypothesis. We give the generalstrategy for each case.I Case CastCheck, constrained synthesis :Follows from soundnessI Case CastVar :TrivialI Case CastType, CastFun :283El C (ℓ +1) is C ℓ , and the corresponding types both translated to codes inC ℓI Case CastApp :Application takes the exact component of the function, which has thedesired type (the codomain applied to the approximation of the argument,under the Læ monad).I Case CastAbs :e translation for a lambda term produces a function producing a pureapproximate andmonadic exact result, which alignswith El (CΠ dom cod). I Case CastInd :e result is a code, which matches the expected type, and we assumedescFor was provided matching the parameter and index types.I Case CastEq :e approximate translations of the equated terms produces a result that,when extracted with fromL, yields the element type for the given code.e entire expression produces amember ofC ell, whichmatches El CType. I Case CastCtor,CastMatch :We omit the details, but follow the approach of Diehl and Sheard [48]I Case Remaining rules :e elimination operations, along with ? and f, produce the elements ofthe given code, under Læ, which is precisely the expected type of eachoperation.284
Thesis/Dissertation
eng
Computer Science
Vancouver : University of British Columbia Library
Graduate
Garcia, Ronald (Professor of computer science)
On the design of a gradual dependently typed language for programming
Text