Reference. Live functional programming with typed holes
Live programming environments aim to provide programmers (and sometimes audiences) with continuous feedback about a program’s dynamic behavior as it is being edited. The problem is that programming languages typically assign dynamic meaning only to programs that are complete, i.e. syntactically well-formed and free of type errors. Consequently, live feedback presented to the programmer exhibits temporal or perceptive gaps. This paper confronts this “gap problem” from type-theoretic first principles by developing a dynamic semantics for incomplete functional programs, starting from the static semantics for incomplete functional programs developed in recent work on Hazelnut. We model incomplete functional programs as expressions with holes, with empty holes standing for missing expressions or types, and non-empty holes operating as membranes around static and dynamic type inconsistencies. Rather than aborting when evaluation encounters any of these holes as in some existing systems, evaluation proceeds around holes, tracking the closure around each hole instance as it flows through the remainder of the program. Editor services can use the information in these hole closures to help the programmer develop and confirm their mental model of the behavior of the complete portions of the program as they decide how to fill the remaining holes. Hole closures also enable a fill-and-resume operation that avoids the need to restart evaluation after edits that amount to hole filling. Formally, the semantics borrows machinery from both gradual type theory (which supplies the basis for handling unfilled type holes) and contextual modal type theory (which supplies a logical basis for hole closures), combining these and developing additional machinery necessary to continue evaluation past holes while maintaining type safety. We have mechanized the metatheory of the core calculus, called Hazelnut Live, using the Agda proof assistant. We have also implemented these ideas into the Hazel programming environment. The implementation inserts holes automatically, following the Hazelnut edit action calculus, to guarantee that every editor state has some (possibly incomplete) type. Taken together with this paper’s type safety property, the result is a proof-of-concept live programming environment where rich dynamic feedback is truly available without gaps, i.e. for every reachable editor state.
Cite
Cited by (9)
Hazel Deriver: A Live Editor for Constructing Rule-Based Derivations zhong-2025-hazel
Polymorphism with Typed Holes chen-2025-polymorphism
Statically Contextualizing Large Language Models with Typed Holes blinn-2024-statically
Large language models (LLMs) have reshaped the landscape of program synthesis. However, contemporary LLM-based code completion systems often hallucinate broken code because they lack appropriate code context, particularly when working with definitions that are neither in the training data nor near the cursor. This paper demonstrates that tighter integration with the type and binding structure of the programming language in use, as exposed by its language server, can help address this contextualization problem in a token-efficient manner. In short, we contend that AIs need IDEs, too! In particular, we integrate LLM code generation into the Hazel live program sketching environment. The Hazel Language Server is able to identify the type and typing context of the hole that the programmer is filling, with Hazel’s total syntax and type error correction ensuring that a meaningful program sketch is available whenever the developer requests a completion. This allows the system to prompt the LLM with codebase-wide contextual information that is not lexically local to the cursor, nor necessarily in the same file, but that is likely to be semantically local to the developer’s goal. Completions synthesized by the LLM are then iteratively refined via further dialog with the language server, which provides error localization and error messages. To evaluate these techniques, we introduce MVUBench, a dataset of model-view-update (MVU) web applications with accompanying unit tests that have been written from scratch to avoid data contamination, and that can easily be ported to new languages because they do not have large external library dependencies. These applications serve as challenge problems due to their extensive reliance on application-specific data structures. Through an ablation study, we examine the impact of contextualization with type definitions, function headers, and errors messages, individually and in combination. We find that contextualization with type definitions is particularly impactful. After introducing our ideas in the context of Hazel, a low-resource language, we duplicate our techniques and port MVUBench to TypeScript in order to validate the applicability of these methods to higher-resource mainstream languages. Finally, we outline ChatLSP, a conservative extension to the Language Server Protocol (LSP) that language servers can implement to expose capabilities that AI code completion systems of various designs can use to incorporate static context when generating prompts for an LLM.
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.
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.
Contextualized Programming Language Documentation potter-2022-contextualized
An Integrative Human-Centered Architecture for Interactive Programming Assistants blinn-2022-an
Filling typed holes with live GUIs omar-2021-filling
Program sketching with live bidirectional evaluation lubin-2020-program
We present a system called Smyth for program sketching in a typed functional language whereby the concrete evaluation of ordinary assertions gives rise to input-output examples, which are then used to guide the search to complete the holes. The key innovation, called live bidirectional evaluation, propagates examples “backward” through partially evaluated sketches. Live bidirectional evaluation enables Smyth to (a) synthesize recursive functions without trace-complete sets of examples and (b) specify and solve interdependent synthesis goals. Eliminating the trace-completeness requirement resolves a significant limitation faced by prior synthesis techniques when given partial specifications in the form of input-output examples. To assess the practical implications of our techniques, we ran several experiments on benchmarks used to evaluate Myth, a state-of-the-art example-based synthesis tool. First, given expert examples (and no partial implementations), we find that Smyth requires on average 66% of the number of expert examples required by Myth. Second, we find that Smyth is robust to randomly-generated examples, synthesizing many tasks with relatively few more random examples than those provided by an expert. Third, we create a suite of small sketching tasks by systematically employing a simple sketching strategy to the Myth benchmarks; we find that user-provided sketches in Smyth often further reduce the total specification burden (i.e. the combination of partial implementations and examples). Lastly, we find that Leon and Synquid, two state-of-the-art logic-based synthesis tools, fail to complete several tasks on which Smyth succeeds.
Cites 123 works (2 here)
With notes (2)
Hazelnut: a bidirectionally typed structure editor calculus omar-2017-hazelnut
Complete and easy bidirectional typechecking for higher-rank polymorphism dunfield-2013-complete
External (121)
- Exploratory and Live, Programming and Coding - A Literature Study Comparing Perspectives on Liveness (2019)
- Live Functional Programming with Typed Holes (2019)
- A Survey of Symbolic Execution Techniques (2018)
- Systematic identification and communication of type errors (2018)
- An Introduction to Elm (2018)
- Extensible type-directed editing (2018)
- Augmenting Source Code Lines with Sample Variable Values (2018)
- Evaluating CoBlox: A Comparative Study of Robotics Programming Environments for Adult Novices (2018)
- Consistent Subtyping for All (2018)
- Using Elm to Introduce Algebraic Thinking to K-8 Students (2018)
- Graphics Programming in Elm Develops Math Knowledge & Social Cohesion (2018)
- Parametricity versus the universal type (2017)
- On polymorphic gradual typing (2017)
- Gradual refinement types (2017)
- Comprehension First: Evaluating a Novel Pedagogy and Tutoring System for Program Tracing in CS1 (2017)
- Toward Semantic Foundations for Program Editors (2017)
- Imperative functional programs that explain their work (2017)
- Visualizing the Evaluation of Functional Programs for Debugging (2017)
- SHErrLoc: A Static Holistic Error Locator (2017)
- Automatically generating the dynamic semantics of gradually typed languages (2017)
- Technical Overview - Flutter (2017)
- Edit Code and Continue Debugging in Visual Studio (C#, VB, C++) (2017)
- Principled syntactic code completion using placeholders (2016)
- Programmatic and direct manipulation, together at last (2016)
- The gradualizer: a methodology and algorithm for generating gradual type systems (2016)
- Example-directed synthesis: a type-theoretic interpretation (2016)
- Practical Foundations for Programming Languages (2nd ed.) (2016)
- Semi-Automated SVG Programming via Direct Manipulation (2016)
- Dynamic witnesses for static type errors (or, ill-typed programs usually go wrong) (2016)
- Principal Type Schemes for Gradual Programs (2015)
- Practical SMT-based type error localization (2015)
- Inductive Beluga: Programming Proofs (2015)
- Monotonic References for Efficient Gradual Typing (2015)
- Towards Practical Gradual Typing (2015)
- To block or not to block, that is the question: students' perceptions of blocks-based programming (2015)
- Refined Criteria for Gradual Typing (2015)
- Envision: A fast and flexible visual code editor with fluid interactions (Overview) (2014)
- Counter-factual typing for debugging type errors (2014)
- Bidirectional Elaboration of Dependently Typed Programs (2014)
- Adapton: composable, demand-driven incremental computation (2014)
- Towards User-Friendly Projectional Editors (2014)
- A longitudinal study of programmers' backtracking (2014)
- Language options — Glasgow Haskell Compiler User's Guide (Typed Holes) (2014)
- Idris, a general-purpose dependently typed programming language: Design and implementation (2013)
- It's alive! continuous feedback in UI programming (2013)
- Calculating threesomes, with blame (2013)
- Online python tutor: embeddable web-based program visualization for cs education (2013)
- All Your IFCException Are Belong to Us (2013)
- Template-based program verification and program synthesis (2013)
- A perspective on the evolution of live programming (2013)
- Bidirectional Typing Rules: A Tutorial (2013)
- Liberating the programmer with prorogued programming (2012)
- Inductive Types in Homotopy Type Theory (2012)
- Elm : Concurrent FRP for Functional GUIs (2012)
- Specifying and Verifying the Correctness of Dynamic Software Updates (2012)
- Functional programs that explain their work (2012)
- Obtaining and reasoning about good enough software (2012)
- mbeddr: an extensible C-based programming language and IDE for embedded systems (2012)
- Equality proofs and deferred type errors: a compiler pearl (2012)
- Inventing on principle (2012)
- Always-available static and dynamic feedback (2011)
- Explicit Substitutions for Contextual Type Theory (2010)
- Supercompilation by evaluation (2010)
- Space-efficient gradual typing (2010)
- Beluga: Programming with Dependent Types, Contextual Data, and Contexts (2010)
- Threesomes, with and without blame (2010)
- Providing rapid feedback in generated modular language environments: adding error recovery to scannerless generalized-LR parsing (2009)
- Dependently typed programming in Agda (2009)
- Scratch: programming for all (2009)
- The Sketching Approach to Program Synthesis (2009)
- Well-Typed Programs Can't Be Blamed (2009)
- Debugging: finding, fixing and flailing, a multi-institutional study of novice debuggers (2008)
- Debugging: a review of the literature from an educational perspective (2008)
- Contextual modal type theory (2008)
- Programming with proofs and explicit contexts (2008)
- Living it up with a live programming language (2007)
- IPython: A System for Interactive Scientific Computing (2007)
- Gradual Typing for Objects (2007)
- Mutatis Mutandis: Safe and predictable dynamic software updating (2007)
- Barendregt's Variable Convention in Rule Inductions (2007)
- Spreadsheet functional programming (2007)
- Towards a practical programming language based on dependent type theory (2007)
- Seminal: searching for ML type-error messages (2006)
- Gradual Typing for Functional Languages (2006)
- Mechanized Metatheory for the Masses: The PoplMark Challenge (2005)
- Strict bidirectional type checking (2005)
- Dynamic software updating (2005)
- Sharing in the Weak Lambda-Calculus (2005)
- A structural approach to operational semantics (2004)
- On the Strong Normalisation of Intuitionistic Natural Deduction with Permutation-Conversions (2002)
- Open Proofs and Open Terms: A Basis for Interactive Logic (2002)
- Types and Programming Languages (2002)
- A modal analysis of staged computation (2001)
- Colored local type inference (2001)
- A Type-Theoretic Interpretation of Standard ML (2000)
- Local type inference (2000)
- Dependently typed functional programs and their proofs (2000)
- Explicit Substitutions and Programming Languages (1999)
- Implementing level 4 liveness in declarative visual programming languages (1998)
- Interactive and Automated Proof Construction in Type Theory (1998)
- Combinatory Weak Reduction in Lambda Calculus (1998)
- The implementation of ALF: a proof editor based on Martin-Löf's monomorphic type theory with explicit substitution (1995)
- A Debugger for Standard ML (1995)
- A Syntactic Approach to Type Soundness (1994)
- Partial evaluation and automatic program generation (1993)
- The Revised Report on the Syntactic Theories of Sequential Control and State (1992)
- Explicit Substitutions (1991)
- An Abstract Framework for Environment Machines (1991)
- A Practical Method for Constructing Efficient LALR(k) Parsers with Automatic Error Recovery (1991)
- The lazy lambda calculus (1990)
- VIVA: A visual language for image processing (1990)
- The Lambda Calculus: Its Syntax and Semantics (1984)
- Smalltalk-80: the language and its implementation (1983)
- Principal type-schemes for functional programs (1982)
- Confluent Reductions: Abstract Properties and Applications to Term Rewriting Systems (1980)
- Practical LR error recovery (1979)
- Coroutines and Networks of Parallel Processes (1977)
- Symbolic execution and program testing (1976)
- A Minimum Distance Error-Correcting Parser for Context-Free Languages (1972)
- The Psychology of Computer Programming (1971)
- Some properties of conversion (1936)