Reference. Bidirectional Typing
Bidirectional typing combines two modes of typing: type checking, which checks that a program satisfies a known type, and type synthesis, which determines a type from the program. Using checking enables bidirectional typing to support features for which inference is undecidable; using synthesis enables bidirectional typing to avoid the large annotation burden of explicitly typed languages. In addition, bidirectional typing improves error locality. We highlight the design principles that underlie bidirectional type systems, survey the development of bidirectional typing from the prehistoric period before Pierce and Turner’s local type inference to the present day, and provide guidance for future investigations.
Cite
Cited by (9)
Canonical bidirectional typechecking mihejevs-2025-canonical
We demonstrate that the checkable/synthesisable split in bidirectional typechecking coincides with existing dualities in polarised System L, also known as polarised -calculus. Specifically, positive terms and negative coterms are checkable, and negative terms and positive coterms are synthesisable. This combines a standard formulation of bidirectional typechecking with Zeilberger’s ‘cocontextual’ variant. We extend this to ordinary ‘cartesian’ System L using Mc Bride’s co-de Bruijn formulation of scopes, and show that both can be combined in a linear-nonlinear style, where linear types are positive and cartesian types are negative. This yields a remarkable 3-way coincidence between the shifts of polarised System L, LNL calculi, and bidirectional calculi.
Incremental Bidirectional Typing via Order Maintenance porter-2025-incremental
Live programming environments provide various semantic services, including type checking and evaluation, continuously as the user is editing the program. The live paradigm promises to improve the developer experience, but liveness is an implementation challenge, particularly when working with large programs. This paper specifies and efficiently implements a system that is able to incrementally update type information for a live program in response to fine-grained program edits. This information includes type error marks and information about the expected and actual type of every expression. The system is specified type-theoretically as a small-step dynamics that propagates updates through the marked and annotated program. Most updates flow according to a base bidirectional type system. Additional pointers are maintained to connect bound variables to their binding locations, with type updates traversing these pointers directly. Order maintenance data structures are employed to efficiently maintain these pointers and to prioritize the order of update propagation. We prove this system is equivalent to naive reanalysis in the Agda theorem prover, along with other important metatheoretic properties. We then provide an efficient OCaml implementation, detailing a number of impactful optimizations. We evaluate this implementation’s performance with a large stress-test and find that it is able to achieve multiple orders of magnitude speed-up compared to from-scratch reanalysis.
Grove: A Bidirectionally Typed Collaborative Structure Editor Calculus adams-2025-grove
Version control systems typically rely on a patch language , heuristic patch synthesis algorithms like diff , and three-way merge algorithms . Standard patch languages and merge algorithms often fail to identify conflicts correctly when there are multiple edits to one line of code or code is relocated. This paper introduces Grove, a collaborative structure editor calculus that eliminates patch synthesis and three-way merge algorithms entirely. Instead, patches are derived directly from the log of the developer’s edit actions and all edits commute, i.e. the repository state forms a commutative replicated data type (CmRDT). To handle conflicts that can arise due to code relocation, the core datatype in Grove is a labeled directed multi-graph with uniquely identified vertices and edges. All edits amount to edge insertion and deletion, with deletion being permanent. To support tree-based editing, we define a decomposition from graphs into groves , which are a set of syntax trees with conflicts–including local, relocation, and unicyclic relocation conflicts–represented explicitly using holes and references between trees. Finally, we define a type error localization system for groves that enjoys a totality property, i.e. all editor states in Grove are statically meaningful, so developers can use standard editor services while working to resolve these explicitly represented conflicts. The static semantics is defined as a bidirectional marking system in line with recent work, with gradual typing employed to handle situations where errors and conflicts prevent type determination. We then layer on a unification-based type inference system to opportunistically fill type holes and fail gracefully when no solution exists. We mechanize the metatheory of Grove using the Agda theorem prover. We implement these ideas as the Grove Workbench , which generates the necessary data structures and algorithms in OCaml given a syntax tree specification.
Polymorphism with Typed Holes chen-2025-polymorphism
Total Type Error Localization and Recovery with Holes zhao-2024-total
Type systems typically only define the conditions under which an expression is well-typed, leaving ill-typed expressions formally meaningless. This approach is insufficient as the basis for language servers driving modern programming environments, which are expected to recover from simultaneously localized errors and continue to provide a variety of downstream semantic services. This paper addresses this problem, contributing the first comprehensive formal account of total type error localization and recovery: the marked lambda calculus. In particular, we define a gradual type system for expressions with marked errors, which operate as non-empty holes, together with a total procedure for marking arbitrary unmarked expressions. We mechanize the metatheory of the marked lambda calculus in Agda and implement it, scaled up, as the new basis for Hazel, a full-scale live functional programming environment with, uniquely, no meaningless editor states. The marked lambda calculus is bidirectionally typed, so localization decisions are systematically predictable based on a local flow of typing information. Constraint-based type inference can bring more distant information to bear in discovering inconsistencies but this notoriously complicates error localization. We approach this problem by deploying constraint solving as a type-hole-filling layer atop this gradual bidirectionally typed core. Errors arising from inconsistent unification constraints are localized exclusively to type and expression holes, i.e., the system identifies unfillable holes using a system of traced provenances, rather than localized in an ad hoc manner to particular expressions. The user can then interactively shift these errors to particular downstream expressions by selecting from suggested partially consistent type hole fillings, which returns control back to the bidirectional system. We implement this type hole inference system in Hazel.
Focusing on Refinement Typing economou-2023-focusing
We present a logically principled foundation for systematizing, in a way that works with any computational effect and evaluation order, SMT constraint generation seen in refinement type systems for functional programming languages. By carefully combining a focalized variant of call-by-push-value, bidirectional typing, and our novel technique of value-determined indexes, our system generates solvable SMT constraints without existential (unification) variables. We design a polarized subtyping relation allowing us to prove our logically focused typing algorithm is sound, complete, and decidable. We prove type soundness of our declarative system with respect to an elementary domain-theoretic denotational semantics. Type soundness implies, relatively simply, the total correctness and logical consistency of our system. The relative ease with which we obtain both algorithmic and semantic results ultimately stems from the proof-theoretic technique of focalization.
Dependent Type Refinements for Futures somayyajula-2023-dependent
Type refinements combine the compositionality of typechecking with the expressivity of program logics, offering a synergistic approach to program verification. In this paper we apply dependent type refinements to SAX, a futures-based process calculus that arises from the Curry-Howard interpretation of the intuitionistic semi-axiomatic sequent calculus and includes unrestricted recursion both at the level of types and processes. With our type refinement system, we can reason about the partial correctness of SAX programs, complementing prior work on sized type refinements that supports reasoning about termination. Our design regime synthesizes the infinitary proof theory of SAX with that of bidirectional typing and Hoare logic, deriving some standard reasoning principles for data and (co)recursion while enabling information hiding for codata. We prove syntactic type soundness, which entails a notion of partial correctness that respects codata encapsulation. We illustrate our language through a few simple examples.
A Dependently Typed Language with Dynamic Equality lemay-2023-a
Live Pattern Matching with Typed Holes yuan-2023-live
Several modern programming systems, including GHC Haskell, Agda, Idris, and Hazel, support typed holes . Assigning static and, to varying degree, dynamic meaning to programs with holes allows program editors and other tools to offer meaningful feedback and assistance throughout editing, i.e. in a live manner. Prior work, however, has considered only holes appearing in expressions and types. This paper considers, from type theoretic and logical first principles, the problem of typed pattern holes. We confront two main difficulties, (1) statically reasoning about exhaustiveness and irredundancy when patterns are not fully known, and (2) live evaluation of expressions containing both pattern and expression holes. In both cases, this requires reasoning conservatively about all possible hole fillings. We develop a typed lambda calculus, Peanut, where reasoning about exhaustiveness and redundancy is mapped to the problem of deriving first order entailments. We equip Peanut with an operational semantics in the style of Hazelnut Live that allows us to evaluate around holes in both expressions and patterns. We mechanize the metatheory of Peanut in Agda and formalize a procedure capable of deciding the necessary entailments. Finally, we scale up and implement these mechanisms within Hazel, a programming environment for a dialect of Elm that automatically inserts holes during editing to provide static and dynamic feedback to the programmer in a maximally live manner, i.e. for every possible editor state. Hazel is the first maximally live environment for a general-purpose functional language.
Cites 79 works (6 here)
With notes (6)
A theory of linear typings as flows on 3-valent graphs zeilberger-2018-a
Do be do be do lindley-2017-do
I Got Plenty o’ Nuttin’ mcbride-2016-i
Complete and easy bidirectional typechecking for higher-rank polymorphism dunfield-2013-complete
A judgmental reconstruction of modal logic pfenning-2001-a
Dependent types in practical programming xi-1999-dependent
External (73)
- A quick look at impredicativity (2020)
- Sound and complete bidirectional typechecking for higher-rank polymorphism with existentials and indexed types (2019)
- A mechanical formalization of higher-ranked polymorphic type inference (2019)
- Bidirectional Type Checking for Relational Properties (2019)
- Guarded impredicative polymorphism (2018)
- Consistent Subtyping for All (2018)
- Let Arguments Go First (2018)
- Disjoint Polymorphism (2017)
- The Polarized λ -calculus (2017)
- The exp-log normal form of types: decomposing extensional equality and representing terms compactly (2017)
- Deciding equivalence with sums and the empty type (2017)
- Sums of uncertainty: refinements go gradual (2017)
- Lecture Notes on Verifications (2017)
- Visible Type Application (2016)
- Disjoint intersection types (2016)
- Program Synthesis from Polymorphic Refinement Types (2016)
- Elaborating evaluation-order polymorphism (2015)
- Programming up to Congruence (2015)
- Balanced polymorphism and linear lambda calculus (2015)
- Structural Focalization (2014)
- Elaborating intersection and union types (JFP) (2014)
- An insider's look at LF type reconstruction: everything you (n)ever wanted to know (2013)
- Elaborating intersection and union types (2012)
- On irrelevance and algorithmic equality in predicative type theory (2012)
- OutsideIn(X) Modular type inference with local assumptions (2011)
- Gradual Typestate (2011)
- Type inference in context (2010)
- ΠΣ: Dependent Types without the Sugar (2010)
- Greedy bidirectional polymorphism (2009)
- Focusing on pattern matching (2009)
- Substructural Operational Semantics as Ordered Logic Programming (2009)
- Lecture Notes on Harmony (2009)
- Contextual modal type theory (2008)
- A type-theoretic foundation for programming with higher-order abstract syntax and first-class substitutions (2008)
- Programming with proofs and explicit contexts (2008)
- Practical type inference for arbitrary-rank types (2007)
- A Unified System of Type Refinements (2007)
- Stratified type inference for generalized algebraic data types (2006)
- Boxy types: inference for higher-rank types and impredicativity (2006)
- Strict bidirectional type checking (2005)
- On equivalence and canonical forms in the LF type theory (2005)
- Practical Refinement-Type Checking (2005)
- Tridirectional typechecking (2004)
- Sequent Calculus (lecture notes, 15-317) (2004)
- A Linear Spine Calculus (2003)
- Guarded recursive datatype constructors (2003)
- A concurrent logical framework I: Judgments and properties (2003)
- The Essence of Principal Typings (2002)
- Call-By-Push-Value (2001)
- Colored local type inference (2001)
- Intersection types and computational effects (2000)
- Local type inference (2000)
- Proofs about a folklore let-polymorphic type inference algorithm (1998)
- Normal Natural Deduction Proofs (in classical logic) (1998)
- Local Type Inference (POPL) (1998)
- Dependent Types in Practical Programming (PhD thesis) (1998)
- Local type inference (Technical Report CSCI #493) (1997)
- An algorithm for type-checking dependent types (1996)
- Design of the programming language Forsythe (1996)
- What are principal typings and what are they good for? (1995)
- A behavioral notion of subtyping (1994)
- An Implementation of F<: (1993)
- A typed foundation for directional logic programming (1993)
- Refinement Types for ML (1991)
- Proofs and Types (1989)
- Preliminary design of the programming language Forsythe (1988)
- Cartesian closed categories and typed λ-calculi (1986)
- Typing and Computational Properties of Lambda Expressions (1986)
- A filter lambda model and the completeness of type assignment (1983)
- Principal type-schemes for functional programs (1982)
- A theory of type polymorphism in programming (1978)
- Applied Logic – its use and implementation as a programming tool (1977)
- The principal type-scheme of an object in combinatory logic (1969)