rtifact Comple * A t * te n * te A is W s E * e n l l C o

L D

C

o

P *

* c

u

e

m s

Hazelnut: A Bidirectionally Typed O

E

u

e

e

P

n

R

t

v e

o

d t

* y * s E a a

l d u e

a Structure Editor Calculus t Extended Version

Cyrus Omar1 Ian Voysey1 Michael Hilton2 Jonathan Aldrich1 Matthew A. Hammer3 1Carnegie Mellon University, USA 2Oregon State University, USA 3University of Colorado Boulder, USA {comar, iev, aldrich}@cs.cmu.edu [email protected] [email protected]

Abstract of development effort. However, this indirection through text also introduces some fundamental complexity into the Structure editors allow programmers to edit the tree structure programming process. of a program directly. This can have cognitive benefits, partic- First, it requires that programmers learn the subtleties of ularly for novice and end-user programmers. It also simplifies the textual syntax (e.g. operator precedence.) This is particu- matters for tool designers, because they do not need to con- larly challenging for novices [2, 34, 56], and even experienced tend with malformed program text. programmers frequently make mistakes [24, 26, 34]. This paper introduces Hazelnut, a structure editor based Second, many sequences of characters do not correspond to on a small bidirectionally typed lambda calculus extended meaningful programs. This complicates the design of program with holes and a cursor. Hazelnut goes one step beyond syn- editors and other interactive programming tools. In a dataset tactic well-formedness: its edit actions operate over statically gathered by Yoon and Myers consisting of 1460 hours of meaningful incomplete terms. Na¨ıvely, this would force the Eclipse edit logs [67], 44.2% of edit states were syntactically programmer to construct terms in a rigid “outside-in” man- malformed. Some additional percentage of edit states were ner. To avoid this problem, the action semantics automatically well-formed but ill-typed (the dataset was not complete places terms assigned a type that is inconsistent with the ex- enough to determine the exact percentage.) Collectively, we pected type inside a hole. This meaningfully defers the type refer to these edit states as meaningless edit states, because they consistency check until the term inside the hole is finished. are not given static or dynamic meaning by the language Hazelnut is not intended as an end-user tool itself. Instead, definition. As a consequence, it is difficult to design useful it serves as a foundational account of typed structure editing. language-aware editor services, e.g. [53], To that end, we describe how Hazelnut’s rich metatheory, type-aware code completion [39, 43], and refactoring services which we have mechanized using the Agda proof assistant, [36]. Editors must either disable these editor services when serves as a guide when we extend the calculus to include they encounter meaningless edit states or deploy ad hoc binary sum types. We also discuss various interpretations heuristics, e.g. by using whitespace to guess the intent [15, 27]. of holes, and in so doing reveal connections with gradual These complications have motivated a long line of research typing and contextual modal type theory, the Curry-Howard into structure editors, i.e. program editors where every edit interpretation of contextual modal logic. Finally, we discuss 1 how Hazelnut’s semantics lends itself to implementation state corresponds to a program structure [59]. as an event-based functional reactive program. Our simple Most structure editors are syntactic structure editors, i.e. the reference implementation is written using js_of_ocaml. edit state corresponds to a syntax tree with holes that stand for branches of the tree that have yet to be constructed, and the Categories and Subject Descriptors D.3.1 [Programming Lan- edit actions are context-free tree transformations. For example, guages]: Formal Definitions and Theory; D.2.3 [Software Engi- Scratch is a syntactic structure editor that has achieved success neering]: Coding Tools and Techniques—Program Editors as a tool for teaching children how to program [51]. arXiv:1607.04180v5 [cs.PL] 4 Feb 2019 Keywords structure editors, bidirectional type systems, grad- Researchers have also designed syntactic structure editors ual typing, mechanized metatheory for more sophisticated languages with non-trivial static type systems. Contemporary examples include mbeddr, a structure 1. Introduction editor for a C-like language [63], TouchDevelop, a structure Programmers typically interact with meaningful programs editor for an object-oriented language [60], and Lamdu, a only indirectly, by editing text that is first parsed according structure editor for a functional language similar to Haskell to a textual syntax and then typechecked according to a static [33]. Each of these editors presents an innovative user inter- semantics. This indirection has practical benefits, to be sure – face, but the non-trivial type and binding structure of the text editors and other text-based tools benefit from decades underlying language complicates its design. The problem is that syntactic structure editors do not assign static meaning to every edit state – they guarantee only that every edit state corresponds to a syntactically well-formed tree. These edi- tors must also either selectively disable editor services that require an understanding of the semantics of the program being written, or deploy ad hoc heuristics.

1 Structure editors are also variously known as structured editors, structural editors, syntax-directed editors and projectional editors. This paper develops a principled solution to this problem. # Z-Expression Next Action Rule We introduce Hazelnut, a typed structure editor based on a 1 . / construct lam x (13e) bidirectionally typed lambda calculus extended to assign 2 (λLMx. ) : (. / → ) construct num (12b) static meaning to expressions and types with holes, which 3 (λx.LM) : (.numLM / →LM ) move parent (6c) we call H-expressions and H-types. Hazelnut’s formal action 4 (λx.LM) : .(num → L)M/ move child 2 (6b) semantics maintains the invariant that every edit state is a 5 (λx.LM) : (num → .LM/) construct num (12b) statically meaningful (i.e. well-H-typed) H-expression with 6 (λx.LM) : (num → .numLM /) move parent (6d) a single superimposed cursor. We call H-expressions and H- 7 (λx.LM) : .(num → num)/ move parent (8d) types with a cursor Z-expressions and Z-types (so prefixed 8 .(λxL.M ) : (num → num)/ move child 1 (8a) because our encoding follows Huet’s zipper pattern [25].) 9 .(λx.LM)/ : (num → num) move child 1 (8e) Na¨ıvely, enforcing an injunction on ill-H-typed edit states 10 (λx..LM/) : (num → num) construct var x (13c) would force programmers to construct programs in a rigid 11 (λx..LxM/) : (num → num) construct plus (13l) “outside-in” manner. For example, the programmer would 12 (λx.(x + . /)) : (num → num) construct lit 1 (13j) often need to construct the outer function application form 13 (λx.(x + .1LM/)) : (num → num) — — before identifying the intended function. To address this problem, Hazelnut leaves newly constructed expressions Figure 1. Constructing the increment function in Hazelnut. inside a hole if the expression’s type is inconsistent with the expected type. This meaningfully defers the type consistency now assume incr : num → num check until the expression inside the hole is finished. In other # Z-Expression Next Action Rule words, holes appear both at the leaves and at the internal 14 . / construct var incr (13c) nodes of an H-expression that remain under construction. 15 .LincrM / construct ap (13h) The remainder of this paper is organized as follows: 16 incr(. /) construct var incr (13d) • We begin in Sec. 2 with two examples of edit sequences to 17 incr( .LMincr/ ) construct ap (13h) develop the reader’s intuitions. 18 incr(Lincr(.M /) ) construct lit 3 (13j) • We then give a detailed overview of Hazelnut’s semantics 19 incr(Lincr(.3LM/) M) move parent (8j) and metatheory, which has been mechanized using the 20 incr(L.incr(3)/M) move parent (8p) Agda proof assistant, in Sec. 3. 21 incr(L. incr(3) /M) finish (16b) incr(.Lincr( )/M) • Hazelnut is a foundational calculus, i.e. a calculus that 22 3 — — language and editor designers are expected to extend with Figure 2. Applying the increment function. higher level constructs. We extend Hazelnut with binary sum types in Sec. 4 to demonstrate how Hazelnut’s rich 3 metatheory guides one such extension. the cursor, typeset .e˙/ or .τ˙ /, respectively. For example, on Line 1, the empty expression hole, , is under the cursor. • In Sec. 5, we briefly describe how Hazelnut’s action seman- Actions act relative to the cursor.LM The first action, on Line tics lends itself to efficient implementation as a functional 1, is construct lam x. This results in the Z-expression on Line reactive program. Our reference implementation is written 2, consisting of a lambda abstraction with argument x under using the OCaml React library and js_of_ocaml. an arrow type ascription. The cursor is placed (arbitrarily) on • In Sec. 6, we summarize related work. In particular, much the argument type hole. of the technical machinery needed to handle type holes The actions on Lines 2-5 complete the type ascription. In coincides with machinery developed for gradual type particular, the construct num action constructs the num type systems. Similarly, expression holes can be interpreted at the cursor and the move parent and move child 2 action as the closures of contextual modal type theory, which, by sequence moves the cursor to the next hole. In practice, an its correspondence with contextual modal logic, suggests editor would also define compound movement actions, e.g. logical foundations for the system. an action that moves the cursor directly to the next hole, in • We conclude in Sec. 7 by summarizing our vision of a terms of these primitive movement actions. principled science of structure editor design rooted in type After moving to the function body, Lines 10-12 complete it theory, and suggest a number of future directions. by first constructing the variable x, then constructing the plus The supplemental material can be accessed from: form, and finally constructing the number literal 1. Notice that we did not need to construct the function body in an “outside- http://cs.cmu.edu/ comar/hazelnut-popl17/ ~ in” manner, i.e. we constructed x before constructing the outer 2. Programming in Hazelnut plus form inside which x ultimately appears. The transient function bodies, x and (x + ), can be checked against the 2.1 Example 1: Constructing the Increment Function given return type, num (as weL willM detail in Sec. 3.1.) Figure 1 shows an edit sequence that constructs the increment function, of type (num → num), starting from the empty 2.2 Example 2: Applying the Increment Function hole via the indicated sequence of actions. We will introduce Figure 2 shows an edit sequence that constructs the expression Hazelnut’s formal syntax and define the referenced rules in incr(incr(3)), where incr is assumed bound to the increment Sec. 3.2 First, let us build some high-level intuitions. function from Figure 1. The edit state in Hazelnut is a Z-expression, eˆ. Every Z- We begin on Line 14 by constructing the variable incr. Line expression has a single H-expression, e˙, or H-type, τ˙, under 15 then constructs the application form with incr in function position, leaving the cursor on a hole in the argument position. 2 For concision, the column labeled Rule in Figures 1 and 2 indicates Notice again that we did not construct the outer application only the relevant non-zipper rule (see Sec. 3.3.8.) The reader is en- form before identifying the function being applied. couraged to follow along with these examples using the reference implementation. The derivations for these examples are also available 3 The reference implementation omits the triangles, while the Agda in the Agda mechanization. mechanization necessarily omits the colors. We now need to apply incr again, so we perform the same HTyp τ˙ ::=( τ˙ → τ˙ ) | num | action on Line 16 as we did on Line 14, i.e. construct var incr. HExp e˙ ::= x | (λx.e˙) | e˙(e˙) L|Mn | (e˙ + e˙) | e˙ : τ˙ | | e˙ In a syntactic structure editor, performing such an action LM L M would result in the following edit state: Figure 3. Syntax of H-types and H-expressions. Metavariable x ranges over variables and n ranges over numerals. incr(.incr/) This edit state is ill-typed (after cursor erasure): the argument Γ˙ ` e˙ ⇒ τ˙ e˙ synthesizes τ˙ of incr must be of type num but here it is of type (num → num). (1a) Hazelnut does not allow such an edit state to arise. Γ˙ , x : τ˙ ` x ⇒ τ˙ We could alternatively have performed the construct ap action on Line 16. This would result in the following edit state, ˙ ˙ Γ ` e˙1 ⇒ τ˙1 τ˙1 I→ (τ˙2 → τ˙ ) Γ ` e˙2 ⇐ τ˙2 which is well-typed according to the static semantics that we (1b) ˙ ` ( ) ⇒ will define in the next section: Γ e˙1 e˙2 τ˙ (1c) incr( (. /)) ˙ ` ⇒ LM LM Γ n num The problem is that the programmer is not able to identify Γ˙ ` e˙ ⇐ num Γ˙ ` e˙ ⇐ num the intended function, incr, before constructing the function 1 2 (1d) application form. This stands in contrast to Lines 14-15. Γ˙ ` (e˙1 + e˙2) ⇒ num Hazelnut’s action semantics addresses this problem: rather construct var Γ˙ ` e˙ ⇐ τ˙ than disallowing the incr action on Line 16, it (1e) leaves incr inside a hole: Γ˙ ` e˙ : τ˙ ⇒ τ˙ incr( .incr/ ) (1f) L M Γ˙ ` ⇒ This defers the type consistency check, exactly as an empty LM LM hole in the same position does. One way to think about non- Γ˙ ` e˙ ⇒ τ˙ empty holes is as an internalization of the “squiggly underline” (1g) Γ˙ ` e˙ ⇒ that text or syntactic structure editors display to indicate a L M LM type inconsistency. By internalizing this concept, the presence Γ˙ ` e˙ ⇐ τ˙ e˙ analyzes against τ˙ of a type inconsistency does not leave the entire program ˙ formally meaningless. τ˙ I→ (τ˙1 → τ˙2) Γ, x : τ˙1 ` e˙ ⇐ τ˙2 (2a) The expression inside a non-empty hole must itself be well- Γ˙ ` (λx.e˙) ⇐ τ˙ typed, so the programmer can continue to edit it. Lines 17-18 proceed to apply the inner mention of incr to a number literal, Γ˙ ` e˙ ⇒ τ˙ 0 τ˙ ∼ τ˙ 0 (2b) 3. Finally, Lines 18-19 move the cursor to the non-empty hole ˙ and Line 21 performs the finish action. The finish action Γ ` e˙ ⇐ τ˙ removes the hole if the type of the expression inside the hole is consistent with the expected type, as it now is. This results Figure 4. H-type synthesis and analysis. in the final edit state on Line 22, as desired. In practice, the editor might automatically perform the finish action as soon τ˙ ∼ τ˙ 0 τ˙ and τ˙ 0 are consistent as it becomes possible, but for simplicity, Hazelnut formally 0 0 τ˙1 ∼ τ˙1 τ˙2 ∼ τ˙2 requires that it be performed explicitly. 0 0 (3a-d) ∼ τ˙ τ˙ ∼ τ˙ ∼ τ˙ (τ˙1 → τ˙2) ∼ (τ˙1 → τ˙2) 3. Hazelnut, Formally LM LM τ˙ I→ (τ˙1 → τ˙2) τ˙ has matched arrow type (τ˙1 → τ˙2) The previous section introduced Hazelnut by example. In this section, we systematically define the following structures: (4a) (4b) I→ ( → ) (τ˙1 → τ˙2) I→ (τ˙1 → τ˙2) • H-types and H-expressions (Sec. 3.1), which are types and LM LM LM expressions with holes. H-types classify H-expressions Figure 5. H-type consistency and matched arrow types. according to Hazelnut’s bidirectional static semantics. • Z-types and Z-expressions (Sec. 3.2), which superimpose 3.1 H-types and H-expressions a cursor onto H-types and H-expressions, respectively Figure 3 defines the syntax of H-types, τ˙, and H-expressions, (following Huet’s zipper pattern [25].) Every Z-type (resp. Z- e˙. Most forms correspond directly to those of the simply typed expression) corresponds to an H-type (resp. H-expression) lambda calculus (STLC) extended with a single base type, num, by cursor erasure. of numbers (cf. [22].) The number expression corresponding • Actions (Sec. 3.3), which act relative to the cursor accord- to the mathematical number n is drawn n, and for simplicity, ing to Hazelnut’s bidirectional action semantics. The ac- we define only a single arithmetic operation, (e˙ + e˙). The tion semantics enjoys a rich metatheory. Of particular note, form e˙ : τ˙ is an explicit type ascription. In addition to these the sensibility theorem establishes that every edit state is standard forms, type holes and empty expression holes are both well-typed after cursor erasure. drawn and non-empty expression holes are drawn e˙ . Types Our overview below omits certain “uninteresting” details. and expressionsLM that contain no holes are completeL typesM and The supplement includes the complete collection of rules, in complete expressions, respectively. definitional order. These rules, along with the proofs of all Hazelnut’s static semantics is organized as a bidirectional of the metatheorems discussed in this section (and several type system [9, 10, 14, 47] around the two mutually defined omitted auxiliary lemmas), have been mechanized using the judgements in Figure 4. Derivations of the type analysis Agda proof assistant [41] (discussed in Sec. 3.5.) judgement, Γ˙ ` e˙ ⇐ τ˙, establish that e˙ can appear where an expression of type τ˙ is expected. Derivations of the type ZTyp τˆ ::= .τ˙ / | (τˆ → τ˙ ) | (τ˙ → τˆ) synthesis judgement, Γ˙ ` e˙ ⇒ τ˙, synthesize (a.k.a. locally infer ZExp eˆ ::= .e˙/ | (λx.eˆ) | eˆ(e˙) | e˙(eˆ) | (eˆ + e˙) | (e˙ + eˆ) [47]) a type from e˙. Type synthesis is necessary in positions | eˆ : τ˙ | e˙ : τˆ | eˆ where an expected type is not available (e.g. at the top level.) L M Algorithmically, the type is an “input” of the type analysis Figure 6. Syntax of Z-types and Z-expressions. judgement, but an “output” of the type synthesis judgement. Making a judgemental distinction between these two notions The rules described so far are sufficient to type complete will be essential in our action semantics (Sec. 3.3.) H-expressions. The two remaining rules give H-expressions If an expression is able to synthesize a type, it can also with holes a well-defined static semantics. be analyzed against that type, or any other consistent type, Rule (1f) states that the empty expression hole synthe- according to the subsumption rule, Rule (2b). sizes the type hole. Non-empty holes, which contain an H- The H-type consistency judgement, τ˙ ∼ τ˙ 0, that appears as a expression that is “under construction” as described in Sec. premise in the subsumption rule is a reflexive and symmetric 2, also synthesize the hole type. According to Rule (1g), the (but not transitive) relation between H-types defined judge- enveloped expression must synthesize some (arbitrary) type. mentally in Figure 5. This relation coincides with equality for (We do not need non-empty type holes because every H-type complete H-types. Two incomplete H-types are consistent if is a valid classifier of H-expressions.) they differ only at positions where a hole appears in either Because the hole type is consistent with every type, expres- type. The type hole is therefore consistent with every type. sion holes can be analyzed against any type by subsumption. This notion of H-type consistency coincides with the notion For example, it is instructive to derive the following: of type consistency that Siek and Taha discovered in their incr : (num → num) ` incr ⇐ num foundational work on gradual type systems, if we interpret L M 3.2 Z-types and Z-expressions the type hole as the ? (i.e. unknown) type [54]. Typing contexts, Γ˙ , map each variable x ∈ dom(Γ˙ ) to an Figure 6 defines the syntax of Z-types, τˆ, and Z-expressions, hypothesis x : τ˙. We identify contexts up to exchange and eˆ. A Z-type (resp. Z-expression) represents an H-type (resp. contraction and adopt the standard identification convention H-expression) with a single superimposed cursor. for structures that differ only up to alpha-renaming of bound The only base cases in these inductive grammars are .τ˙ / variables. All hypothetical judgements obey a standard weak- and .e˙/, which identify the H-type or H-expression that the ening lemma. Rule (1a) establishes that variable expressions cursor is on. All of the other forms correspond to the recursive synthesize the hypothesized H-type, in the standard manner. forms in the syntax of H-types and H-expressions, and contain Rule (2a) defines analysis for lambda abstractions, (λx.e˙). exactly one “hatted” subterm that identifies the subtree where There is no type synthesis rule that applies to this form, so the cursor will be found. Any other sub-term is “dotted”, i.e. lambda abstractions can appear only in analytic position, i.e. it is either an H-type or H-expression. Taken together, every Z-type and Z-expression contains exactly one selected H-type where an expected type is known.4 Rule (2a) is not quite the or H-expression by construction. This can be understood as standard rule, as reproduced below: an instance of Huet’s zipper pattern [25] (which, coincidentally, ˙ Γ, x : τ˙1 ` e˙ ⇐ τ˙2 Huet encountered while implementing a structure editor.)  Γ˙ ` (λx.e˙) ⇐ (τ˙1 → τ˙2) We write τˆ for the H-type constructed by erasing the The problem is that this standard rule alone leaves us unable cursor from τˆ, which we refer to as the cursor erasure of τˆ. This to analyze lambda abstractions against the type hole, because straightforward metafunction is defined as follows: . / = the type hole is not immediately of the form (τ˙1 → τ˙2). There τ˙ τ˙ are two plausible solutions to this problem. One solution (τˆ → τ˙ ) =( τˆ → τ˙ ) would be to define a second rule specifically for this case: (τ˙ → τˆ) =( τ˙ → τˆ) Γ˙ , x : ` e˙ ⇐  LM LM Similarly, we write eˆ for cursor erasure of eˆ. The definition Γ˙ ` (λx.e˙) ⇐ of this metafunction is analogous, so we omit it for concision. LM Instead, we combine these two possible rules into a single rule This zipper structure is not the only way to model a cursor, through the simple auxiliary matched arrow type judgement, though we have found it to be the most elegant for our present τ˙ I→ (τ˙1 → τ˙2), defined in Figure 5. This judgement leaves purposes. Another plausible strategy would be to formalize arrow types alone and assigns the type hole the matched the notion of a relative path into an H-expression. This would arrow type ( → ). It is easy to see that the two rules above then require defining the notion of consistency between a are admissibleLM byL appealM to Rule (2a) and the matched arrow relative path and an H-expression, so we avoid it. type judgement. Encouragingly, the matched arrow type 3.3 Actions judgement also arises in gradual type systems [11, 18, 49]. We now arrive at the heart of Hazelnut: its bidirectional action Rule (1b) is again nearly the standard rule for function semantics. Figure 7 defines the syntax of actions, α, some of application. It also makes use of the matched function type which involve directions, δ, and shapes, ψ. judgement to combine what would otherwise need to be two Expression actions are governed by two mutually defined rules for function application – one for when e synthesizes 1 judgements, 1) the synthetic action judgement: an arrow type, and another for when e synthesizes . 1 α Rule (1c) states that numbers synthesize the num type.LM Rule Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0 (1d) states that e˙1 + e˙2 behaves like a function over numbers. and 2) the analytic action judgement: Rule (1e) defines type synthesis of expressions of ascription ˙ α 0 form, e˙ : τ˙. This allows the programmer to explicitly state a Γ ` eˆ −−→ eˆ ⇐ τ˙ type for the ascribed expression to be analyzed against. In some Z-expressions, the cursor is in a type ascription, so we also need a type action judgement: 4 It is possible to also define a “half-annotated” synthetic lambda α 0 form, λx:τ.e, but for simplicity, we leave it out [9]. τˆ −−→ τˆ Action α ::= move δ | construct ψ | del | finish 3.3.4 Relative Movement Dir = child | parent δ :: n The rules below define relative movement within Z-types. Shape = arrow | num ψ :: They should be self-explanatory: | asc | var x | lam x | ap | lit n | plus | nehole move child 1 (6a) .(τ˙1 → τ˙2)/ −−−−−−−→ (.τ˙1/ → τ˙2) Figure 7. Syntax of actions. move child 2 (6b) .(τ˙1 → τ˙2)/ −−−−−−−→ (τ˙1 → .τ˙2/) 3.3.1 Sensibility move parent (6c) These judgements are governed by a critical metatheorem, (.τ˙1/ → τ˙2) −−−−−−−→ .(τ˙1 → τ˙2)/ action sensibility (or simply sensibility): move parent (6d) (τ˙1 → .τ˙2/) −−−−−−−→ .(τ˙1 → τ˙2)/ Theorem 1 (Action Sensibility). Two more rules are needed to recurse into the zipper structure.  α 0 0 1. If Γ˙ ` eˆ ⇒ τ˙ and Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ ⇒ τ˙ then We define these zipper rules in an action-independent manner Γ˙ ` eˆ0 ⇒ τ˙ 0. α in Sec. 3.3.8. 2. If Γ˙ ` eˆ ⇐ τ˙ and Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ then Γ˙ ` eˆ0 ⇐ τ˙. The rules for relative movement within Z-expressions are In other words, if a Z-expression is statically meaningful, i.e. similarly straightforward. Movement is type-independent, so its cursor erasure is well-typed, then performing an action we defer to an auxiliary expression movement judgement in on it leaves the resulting Z-expression statically meaningful. both the analytic and synthetic case: More specifically, the first clause of Theorem 1 establishes that move δ eˆ −−−−→ eˆ0 when an action is performed on a Z-expression whose cursor (7a) move δ erasure synthesizes an H-type, the result is a Z-expression Γ˙ ` eˆ ⇒ τ˙ −−−−→ eˆ0 ⇒ τ˙ whose cursor erasure also synthesizes some (possibly differ- move δ ent) H-type. The second clause establishes that when an action eˆ −−−−→ eˆ0 is performed using the analytic action judgement on an edit (7b) ˙ move δ 0 state whose cursor erasure analyzes against some H-type, the Γ ` eˆ −−−−→ eˆ ⇐ τ˙ result is a Z-expression whose cursor erasure also analyzes The expression movement judgement is defined as follows. against the same H-type. Ascription This metatheorem deeply informs the design of the rules, move child 1 (8a) given starting in Sec. 3.3.3. Its proof is by straightforward .e˙ : τ˙ / −−−−−−−→ .e˙/ : τ˙ induction, so the reader is encouraged to think about the move child 2 (8b) relevant proof case when considering each action rule below. .e˙ : τ˙ / −−−−−−−→ e˙ : .τ˙ / No sensibility theorem is needed for the type action judge- move parent (8c) ment because every syntactically well-formed type is mean- .e˙/ : τ˙ −−−−−−−→ .e˙ : τ˙ / ingful in Hazelnut. (Adding type variables to the language move parent (8d) would require defining both a type-level sensibility theorem e˙ : .τ˙ / −−−−−−−→ .e˙ : τ˙ / and type-level non-empty holes.) Lambda 3.3.2 Type Inconsistency move child 1 (8e) .(λx.e˙)/ −−−−−−−→ (λx..e˙/) In some of the rules below, we will need to supplement our (8f) definition of type consistency from Figure 5 with a definition move parent 0 (λx..e˙/) −−−−−−−→ .(λx.e˙)/ of type inconsistency, written τ˙  τ˙ . One can define this Application notion either directly as the constructive negation of type (8g) consistency, or as a separate inductively defined judgement move child 1 .e˙ (e˙ )/ −−−−−−−→ .e˙ /(e˙ ) with the following key rule, which establishes that arrow 1 2 1 2 types are inconsistent with num: move child 2 (8h) .e˙1(e˙2)/ −−−−−−−→ e˙1(.e˙2/) ( → ) num  τ˙1 τ˙2 move parent (8i) The mechanization proves that the judgemental definition of .e˙1/(e˙2) −−−−−−−→ .e˙1(e˙2)/ type inconsistency is indeed the negation of type consistency. move parent (8j) e˙ (.e˙ /) −−−−−−−→ .e˙ (e˙ )/ 3.3.3 Action Subsumption 1 2 1 2 Plus The action semantics includes a subsumption rule similar to (8k) the subsumption rule, Rule (2b), in the statics: move child 1 .(e˙ + e˙ )/ −−−−−−−→ (.e˙ / + e˙ ) α 1 2 1 2 Γ˙ ` eˆ ⇒ τ˙ 0 Γ˙ ` eˆ ⇒ τ˙ 0 −−→ eˆ0 ⇒ τ˙ 00 τ˙ ∼ τ˙ 00 move child 2 (8l) α (5) .(e˙ + e˙ )/ −−−−−−−→ (e˙ + .e˙ /) Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ 1 2 1 2 (8m) In other words, if the cursor erasure of the edit state synthe- move parent (.e˙1/ + e˙2) −−−−−−−→ .(e˙1 + e˙2)/ sizes a type, τ˙ 0, then we defer to the synthetic action judge- move parent (8n) ment. The cursor erasure of the Z-expression resulting from (e˙1 + .e˙2/) −−−−−−−→ .(e˙1 + e˙2)/ performing the action α synthetically could have a different Non-Empty Hole type, τ˙ 00, so we must check that it is consistent with the type provided for analysis, τ˙. The case for Rule (5) in the proof of move child 1 (8o) Theorem 1 goes through by induction and static subsumption, . e˙ / −−−−−−−→ .e˙/ i.e. Rule (2b). Algorithmically, subsumption should be the L M L M move parent (8p) rule of last resort (see Sec. 3.4 for further discussion.) .e˙/ −−−−−−−→ . e˙ / L M L M Again, additional rules are needed to recurse into the zipper ActionList α¯ ::= · | α; α¯ structure, but we will define these zipper rules in an action- α¯ independent manner in Sec. 3.3.8. τˆ −−→∗ τˆ0 α 0 0 α¯ ∗ 00 The rules above are numerous and fairly uninteresting. τˆ −−→ τˆ τˆ −−→ τˆ · (9a) (9b) That makes them quite hazardous – we might make a typo ∗ α;α¯ τˆ −−→ τˆ τˆ −−→∗ τˆ00 or forget a rule absent-mindedly. One check against this is α¯ to establish that movement actions do not change the cursor Γ˙ ` eˆ ⇒ τ˙ −−→∗ eˆ0 ⇒ τ˙ 0 erasure, as in Theorem 2. α Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0 Theorem 2 (Movement Erasure Invariance). 0 0 α¯ ∗ 00 00 move δ Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ ⇒ τ˙ 1. If τˆ −−−−→ τˆ0 then τˆ = τˆ0. (10a-b) · ∗ α;α¯ move δ Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ ⇒ τ˙ ˙ ` ⇒ −−→∗ 00 ⇒ 00 2. If Γ˙ ` eˆ ⇒ τ˙ and Γ˙ ` eˆ ⇒ τ˙ −−−−→ eˆ0 ⇒ τ˙ 0 then eˆ = eˆ0 Γ eˆ τ˙ eˆ τ˙ and τ˙ = τ˙ 0. move δ α¯ 0 ˙  ˙ 0  0 Γ˙ ` eˆ −−→ eˆ ⇐ τ˙ α 3. If Γ ` eˆ ⇐ τ˙ and Γ ` eˆ −−−−→ eˆ ⇐ τ˙ then eˆ = eˆ . Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ α¯ Theorem 2 is useful also in that the relevant cases of Theorem Γ˙ ` eˆ0 −−→∗ eˆ00 ⇐ τ˙ 1 are straightforward by its application. (11a-b) · ∗ α;α¯ ∗ 00 Another useful check is to establish reachability, i.e. that it Γ˙ ` eˆ −−→ eˆ ⇐ τ˙ Γ˙ ` eˆ −−→ eˆ ⇐ τ˙ is possible, through a sequence of movement actions, to move the cursor from any position to any other position within a Figure 8. Iterated Action Judgements well-typed H-expression. This requires developing machinery for reasoning about in the mechanization do not produce the shortest sequence sequences of actions. There are two possibilities: we can either of actions to witness reachability, which would resemble add a sequencing action, α; α, directly to the syntax of actions, something like a lowest common ancestor computation. In ¯ or we can define a syntax for lists of actions, α, together with future versions of Hazelnut that use the produced witnesses iterated action judgements. To keep the core of the action for automatic tool support it may make sense to engineer semantics small, we take the latter approach in Figure 8. these proofs differently; here we are only concerned with ¯ movements A simple auxiliary judgement, α (not shown) whether the theorems are true. establishes that α¯ consists only of actions of the form move δ. With these definitions, we can state reachability as follows: 3.3.5 Construction Theorem 3 (Reachability). The construction actions, construct ψ, are used to construct 1. If τˆ = τˆ0 then there exists some α¯ such that α¯ movements terms of a shape indicated by ψ at the cursor. α¯ and τˆ −−→∗ τˆ0. Types The construct arrow action constructs an arrow type. 2. If Γ˙ ` eˆ ⇒ τ˙ and eˆ = eˆ0 then there exists some α¯ such that The H-type under the cursor becomes the argument type, and α¯ the cursor is placed on an empty return type hole: α¯ movements and Γ˙ ` eˆ ⇒ τ˙ −−→∗ eˆ0 ⇒ τ˙.   0 3. If Γ˙ ` eˆ ⇐ τ˙ and eˆ = eˆ then there exists some α¯ such that construct arrow (12a) α¯ .τ˙ / −−−−−−−−−−→ (τ˙ → . /) ¯ movements and ˙ ` eˆ −−→∗ eˆ0 ⇐ ˙. LM α Γ τ This choice is formally arbitrary – it would have also been The simplest way to prove Theorem 3 is to break it into sensible to use the type under the cursor as the return type, two lemmas. Lemma 4 establishes that you can always move for example. Indeed, we could consider defining both of these the cursor to the outermost position in an expression. This using different shapes. We avoid this for the sake of simplicity. serves as a check on our move parent rules. The construct num action replaces an empty type hole num Lemma 4 (Reach Up). under the cursor with the type:  1. If τˆ = τ˙ then there exists some α¯ such that α¯ movements and construct num (12b) α¯ ∗ . / −−−−−−−−→ .num/ τˆ −−→ .τ˙ /. LM 2. If Γ˙ ` e˙ ⇒ τ˙ and eˆ = e˙ then there exists some α¯ such that Ascription The construct asc action operates differently α¯ depending on whether the H-expression under the cursor α¯ movements and Γ˙ ` eˆ ⇒ τ˙ −−→∗ .e˙/ ⇒ τ˙. ˙  synthesizes a type or is being analyzed against a type. In the 3. If Γ ` e˙ ⇐ τ˙ and eˆ = e˙ then there exists some α¯ such that first case, the synthesized type appears in the ascription: α¯ α¯ movements and Γ˙ ` eˆ −−→∗ .e˙/ ⇐ τ˙. construct asc (13a) Lemma 5 establishes that you can always move the cursor Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−→ e˙ : .τ˙ / ⇒ τ˙ from the outermost position to any other position. This serves In the second case, the type provided for analysis appears in as a check on our move child n rules. the ascription: Lemma 5 (Reach Down). (13b) ˙ construct asc 1. If τˆ = τ˙ then there exists some α¯ such that α¯ movements and Γ ` .e˙/ −−−−−−−−→ e˙ : .τ˙ / ⇐ τ˙ α¯ .τ˙ / −−→∗ τˆ. Variables The construct var x action places the variable x 2. If Γ˙ ` e˙ ⇒ τ˙ and eˆ = e˙ then there exists some α¯ such that into an empty hole. If that hole is being asked to synthesize a α¯ type, then the result synthesizes the hypothesized type: α¯ movements and Γ˙ ` .e˙/ ⇒ τ˙ −−→∗ eˆ ⇒ τ˙. ˙  (13c) 3. If Γ ` e˙ ⇐ τ˙ and eˆ = e˙ then there exists some α¯ such that ˙ construct var x ¯ Γ, x : τ˙ ` . / ⇒ −−−−−−−−−→ .x/ ⇒ τ˙ movements ˙ ` . / −−→α ∗ ⇐ LM LM α¯ and Γ e˙ eˆ τ˙. If the hole is being analyzed against a type that is consistent Theorem 3 follows by straightforward composition of these with the hypothesized type, then the action semantics goes two lemmas. The proofs we give of these three theorems through the action subsumption rule described in Sec. 3.3.3. If the hole is being analyzed against a type that is inconsistent Otherwise, we must place that expression inside a hole: with the hypothesized type, x is placed inside a hole: τ˙ num 0  τ˙ τ˙ construct plus (13m)  ˙ construct var x (13d) Γ ` .e˙/ ⇒ τ˙ −−−−−−−−−→ ( e˙ + . /) ⇒ num Γ˙ , x : τ˙ 0 ` . / −−−−−−−−−→ .x/ ⇐ τ˙ L M LM LM L M Non-Empty Holes The final shape is nehole. This explicitly The rule above featured on Line 16 of Figure 2. places the expression under the cursor inside a hole: Lambdas The construct lam x action places a lambda ab- construct nehole (13n) straction binding x into an empty hole. If the empty hole is Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−−−→ .e˙/ ⇒ being asked to synthesize a type, then the result of the action L M LM is a lambda ascribed the type ( → ), with the cursor on The nehole shape is grayed out in Figure 7 because we do the argument type hole (again, arbitrarily):LM LM not generally expect the programmer to perform it explicitly – other actions automatically insert holes when a type incon- α = construct lam x sistency would arise. The inclusion of this rule simplifies the α Γ˙ ` . / ⇒ −−→ (λx. ) : (. / → ) ⇒ ( → ) statement of the constructability theorem, discussed next. LM LM LM LM LM LM LM(13e) Constructability To check that we have defined “enough” The type ascription is necessary because lambda expressions construct actions, we need to establish that we can start from do not synthesize a type. (Type-annotated function defini- an empty hole and arrive at any well-typed expression with tions often arise as a single syntactic construct in full-scale the cursor on the outside. This simpler statement is sufficient languages like ML.) because Lemma 5 allows us to then move the cursor anywhere If the empty hole is being analyzed against a type with else inside the constructed term. As with reachability, we rely matched arrow type, then no ascription is necessary: on the iterated action judgements defined in Figure 8. τ˙ I→ (τ˙1 → τ˙2) (13f) Theorem 6 (Constructability). construct lam x α¯ Γ˙ ` . / −−−−−−−−−→ (λx.. /) ⇐ τ˙ 1. For every τ˙ there exists α¯ such that . / −−→∗ .τ˙ /. LM LM ˙ LM Finally, if the empty hole is being analyzed against a type 2. If Γ ` e˙ ⇒ τ˙ then there exists α¯ such that: that has no matched arrow type, expressed in the premise α¯ Γ˙ ` . / ⇒ −−→∗ .e˙/ ⇒ τ˙ as inconsistency with ( → ), then a lambda ascribed the LM LM type ( → ) is insertedLM insideLM a hole, which defers the type 3. If Γ˙ ` e˙ ⇐ τ˙ then there exists α¯ such that: LM LM inconsistency as previously discussed: α¯ Γ˙ ` . / −−→∗ .e˙/ ⇐ τ˙ τ˙  ( → ) (13g) LM construct lam x LM LM Without the nehole shape, this theorem as stated would Γ˙ ` . / −−−−−−−−−→ (λx. ) : (. / → ) ⇐ τ˙ LM L LM LM LM M not hold. For example, it is not possible to construct well- Application The construct ap action applies the expression typed H-expressions where non-empty holes appear super- under the cursor. The following rule handles the case where fluously without the nehole shape. Note also that although the synthesized type has matched function type: none of the shapes that we have defined can be dropped with- out losing this theorem, some construction rules could be τ˙ I→ (τ˙1 → τ˙2) construct ap (13h) dropped. In particular, rules that insert non-empty holes au- Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−→ e˙(. /) ⇒ τ˙2 tomatically could be dropped because the construct nehole LM If the expression under the cursor synthesizes a type that action can always be used instead. We included them because is inconsistent with an arrow type, then we must place that we are interested in the mechanics of automatic non-empty expression inside a hole to maintain Theorem 3.1: hole insertion. τ˙  ( → ) 3.3.6 Deletion (13i) constructLM apLM del Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−→ e˙ (. /) ⇒ The action inserts an empty hole at the cursor, deleting L M LM LM what was there before. Numbers The construct lit n action replaces an empty hole The type action rule for del is self-explanatory: with the number expression n. If the empty hole is being asked to synthesize a type, then the rule is straightforward: del (14) .τ˙ / −−→ . / LM construct lit n (13j) Γ˙ ` . / ⇒ −−−−−−−−−−→ .n/ ⇒ num Deletion within a Z-expression is similarly straightforward: LM LM If the empty hole is being analyzed against a type that del (15a) is inconsistent with num, then we must place the number Γ˙ ` .e˙/ ⇒ τ˙ −−→ . / ⇒ expression inside the hole: LM LM (15b) ˙ del τ˙  num Γ ` .e˙/ −−→ . / ⇐ τ˙ LM construct lit n (13k) Unlike the relative movement and construction actions, there Γ˙ ` . / −−−−−−−−−−→ .n/ ⇐ τ˙ is no “checksum” theorem for deletion. The rules do not LM L M The construct plus action constructs a plus expression inspect the structure of the expression in the cursor, so they with the expression under the cursor as its first argument both match our intuition and will be correct in any extension (again, arbitrarily.) If that expression synthesizes a type con- of the language without modification. num sistent with , then the rule is straightforward: 3.3.7 Finishing τ˙ ∼ num The final action we need to consider is finish, which finishes construct plus (13l) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−−→ (e˙ + . /) ⇒ num the non-empty hole under the cursor. LM If the non-empty hole appears in synthetic position, then erasure might have changed (in practice, one would optimize it can always be finished: this check to only occur if the cursor erasure did change): 0 α Γ˙ ` e˙ ⇒ τ˙ τˆ −−→ τˆ0 Γ˙ ` e˙ ⇐ τˆ0 (16a) finish α (18g) Γ˙ ` . e˙ / ⇒ −−−−→ .e˙/ ⇒ τ˙ 0 Γ˙ ` e˙ : τˆ ⇒ τˆ −−→ e˙ : τˆ0 ⇒ τˆ0 L M LM If the non-empty hole appears in analytic position, then it Finally, if the cursor is inside a non-empty hole, the rele- can only be finished if the type synthesized for the enveloped vant zipper rule mirrors Rule (1f): expression is consistent with the type that the hole is being ˙ `  ⇒ ˙ ` ⇒ −−→α 0 ⇒ 0 analyzed against. This amounts to analyzing the enveloped Γ eˆ τ˙ Γ eˆ τ˙ eˆ τ˙ α (18h) expression against the provided type (by subsumption): Γ˙ ` eˆ ⇒ −−→ eˆ0 ⇒ L M LM L M LM Γ˙ ` e˙ ⇐ τ˙ Theorem 1 directly checks the correctness of these rules. finish (16b) Moreover, the zipper rules arise ubiquitously in derivations Γ˙ ` . e˙ / −−−−→ .e˙/ ⇐ τ˙ L M of edit steps, so the proofs of the other “check” theorems, e.g. Like deletion, there is no need for a “checksum” theorem for Reachability and Constructability, serve as a check that none the finishing action. of these rules have been missed. 3.3.8 Zipper Cases 3.4 Determinism The rules defined so far handle the base cases, i.e. the cases A last useful property to consider is action determinism, i.e. that where the action has “reached” the expression under the cur- performing an action produces a unique result. The following sor. We also need to define the recursive cases, which propa- theorem establishes determinism for type actions: gate the action into the subtree where the cursor appears, as −−→α 0 encoded by the zipper structure. For types, the zipper rules Theorem 7 (Type Action Determinism). If τˆ τˆ and α 00 0 00 are straightforward: τˆ −−→ τˆ then τˆ = τˆ . α τˆ −−→ τˆ0 The corresponding theorem for expression actions would (17a) be stated as follows: α 0 α (τˆ → τ˙ ) −−→ (τˆ → τ˙ ) 1. If Γ˙ ` eˆ ⇒ τ˙ and Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0 and α 00 00 0 00 0 00 α Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ ⇒ τ˙ then eˆ = eˆ and τ˙ = τ˙ . τˆ −−→ τˆ0 (17b) ˙  ˙ α 0 ˙ α 00 α 0 2. If Γ ` eˆ ⇐ τ˙ and Γ ` eˆ −−→ eˆ ⇐ τ˙ and Γ ` eˆ −−→ eˆ ⇐ τ˙ (τ˙ → τˆ) −−→ (τ˙ → τˆ ) then eˆ0 = eˆ00. For expressions, the zipper rules essentially follow the struc- This is not a theorem of the system as described so far. ture of the corresponding rules in the statics. The reason is somewhat subtle: two construction actions, In particular, when the cursor is in the body of a lambda construct asc and construct lam x, behave differently in expression, the zipper case mirrors Rule (2a): the analytic case than they do in the synthetic case. The ˙ α 0 problem is that both rules can “fire” when considering a Z- τ˙ I→ (τ˙1 → τ˙2) Γ, x : τ˙1 ` eˆ −−→ eˆ ⇐ τ˙2 (18a) α 0 expression in analytic position due to action subsumption. Γ˙ ` (λx.eˆ) −−→ (λx.eˆ ) ⇐ τ˙ This is a technically valid but “morally” invalid use of action When the cursor is in the function position of an applica- subsumption: subsumption is included in the system to be tion, the rule mirrors Rule (1b): used as a rule of last resort, i.e. it should only be applied when no other analytic action rule can fire.  α 0 Γ˙ ` eˆ ⇒ τ˙2 Γ˙ ` eˆ ⇒ τ˙2 −−→ eˆ ⇒ τ˙3 There are several possible ways to address this problem. ˙ τ˙3 I→ (τ˙4 → τ˙5) Γ ` e˙ ⇐ τ˙4 One approach would be to modify the judgement forms to α (18b) Γ˙ ` eˆ(e˙) ⇒ τ˙ −−→ eˆ0(e˙) ⇒ τ˙ internalize this notion of “rule of last resort”. This approach 1 5 is related to focusing from proof theory [55]. However, this The situation is similar when the cursor is in argument approach would substantially complicate our presentation of position: the system. α The approach that we take leaves the system unchanged. Γ˙ ` e˙ ⇒ τ˙ τ˙ (τ˙ → τ˙ ) Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ 2 2 I→ 3 4 3 Instead, we define predicates over derivations of the expression α 0 Γ˙ ` e˙(eˆ) ⇒ τ˙1 −−→ e˙(eˆ ) ⇒ τ˙4 action judgements that exclude those derivations that apply (18c) subsumption prematurely, i.e. when another rule could have The rules for the addition operator mirror Rule (1d): been applied. We call such derivations subsumption-minimal α derivations. We can establish determinism for subsumption- Γ˙ ` eˆ −−→ eˆ0 ⇐ num (18d) minimal derivations. ˙ α 0 Γ ` (eˆ + e˙) ⇒ num −−→ (eˆ + e˙) ⇒ num Theorem 8 (Expression Action Determinism). α 0  α 0 0 Γ˙ ` eˆ −−→ eˆ ⇐ num 1. If Γ˙ ` eˆ ⇒ τ˙ and D1 : Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ ⇒ τ˙ and α α (18e) D ˙ ` ⇒ −−→ 00 ⇒ 00 submin (D ) Γ˙ ` (e˙ + eˆ) ⇒ num −−→ (e˙ + eˆ0) ⇒ num 2 : Γ eˆ τ˙ eˆ τ˙ and ⇒ 1 and submin (D ) 0 = 00 0 = 00 When the cursor is in the expression position of an ascrip- ⇒ 2 then eˆ eˆ and τ˙ τ˙ .  α 0 tion, we use the analytic judgement, mirroring Rule (1e): 2. If Γ˙ ` eˆ ⇐ τ˙ and D1 : Γ˙ ` eˆ −−→ eˆ ⇐ τ˙ and D2 : Γ˙ ` α 00 α 0 eˆ −−→ eˆ ⇐ τ˙ and submin⇐(D1) and submin⇐(D2) then Γ˙ ` eˆ −−→ eˆ ⇐ τ˙ 0 00 (18f) eˆ = eˆ . ˙ ` ⇒ −−→α 0 ⇒ Γ eˆ : τ˙ τ˙ eˆ : τ˙ τ˙ The mechanization, discussed next, defines the predicates When the cursor is in the type position of an ascription, submin⇒(D) and submin⇐(D). In addition, it defines a map- we must re-check the ascribed expression because the cursor ping from any derivation into a corresponding subsumption- minimal derivation. Implementations of Hazelnut need only ˙ ∼ ˙ 0 0 τ1 τ2 τ˙1 ∼ τ˙1 τ˙2 ∼ τ˙2 implement this subsumption-minimal fragment. 0 0 (19) (τ˙1 + τ˙2) ∼ τ˙1 + τ˙2 3.5 Mechanization τ˙ τ˙ + τ˙ τ˙ has matched sum type τ˙ + τ˙ In order to formally establish that our design meets our I+ 1 2 1 2 stated objectives, we have mechanized the semantics and (20a) (20b) I+ + (τ˙1 + τ˙2) I+ (τ˙1 + τ˙2) metatheory of Hazelnut as described above using the Agda LM LM LM proof assistant [41] (also see the Agda Wiki, hosted at http: Γ˙ ` e˙ ⇐ τ˙ //wiki.portal.chalmers.se/agda/.) This development is available in the supplemental material. The mechanization τ˙+ I+ (τ˙L + τ˙R) Γ˙ ` e˙ ⇐ τ˙i (i ∈ {L, R}) (21a) also includes the extension to Hazelnut described in Sec. 4. Γ˙ ` inj (e˙) ⇐ τ˙+ The documentation includes a more detailed discussion of i ˙ the technical representation decisions that we made. The main Γ ` e˙ ⇒ τ˙+ τ˙+ I+ (τ˙1 + τ˙2) idea is standard: we encode each judgement as a dependent Γ˙ , x : τ˙1 ` e˙1 ⇐ τ˙ Γ˙ , y : τ˙2 ` e˙2 ⇐ τ˙ type. The rules defining the judgements become the construc- (21b) Γ˙ ` case(e˙, x.e˙ , y.e˙ ) ⇐ τ˙ tors of this type, and derivations are terms of these type. This 1 2 is a rich setting that allows proofs to take advantage of pat- Figure 9. The statics of sums. tern matching on the shape of derivations, closely matching standard on-paper proofs. No proof automation was used, α 0 τˆ −−→ τˆ construct sum (22a) because the proof structure itself is likely to be interesting to .τ˙ / −−−−−−−−→ (τ˙ + . /) researchers who plan to build upon our work. α 0 LMα 0 We adopt Barendregt’s convention for bound variables [61]. τˆ −−→ τˆ τˆ −−→ τˆ α (22b) α (22c) Hazelnut’s semantics does not need substitution, so we do not (τˆ + τ˙ ) −−→ (τˆ0 + τ˙ ) (τ˙ + τˆ) −−→ (τ˙ + τˆ0) need to adopt more sophisticated encodings (e.g. [32, 48].) α Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ 4. Extending Hazelnut τ˙+ I+ (τ˙1 + τ˙2) In this section, we will conservatively extend Hazelnut with (23a) ˙ construct inj i binary sum types to demonstrate how the rules and the rich Γ ` . / −−−−−−−−−→ inji(. /) ⇐ τ˙+ metatheory developed in the previous section serve to guide LM LM and constrain this and other such efforts. τ˙  ( + ) LM LM (23b) Syntax. ˙ construct inj i The first step is to extend the syntax of H-types and Γ ` . / −−−−−−−−−→ inji( ) : (. / + ) ⇐ τ˙ H-expressions with the familiar forms [22]: LM L LM LM LM M (23c) HTyp = · · · | ( + ) construct case x y τ˙ :: τ˙ τ˙ Γ˙ ` . / −−−−−−−−−−−→ case(. /, x. , y. ) ⇐ τ˙ HExp e˙ ::= · · · | inji(e˙) | case(e˙, x.e˙, y.e˙) LM LM LM LM α 0 Recall that binary sum types introduce a new type-level τ˙+ I+ (τ˙L + τ˙R) Γ˙ ` eˆ −−→ eˆ ⇐ τ˙i (i ∈ {L, R}) (23d) connective, (τ˙1 + τ˙2). The introductory forms are the injections, ˙ α 0 Γ ` inji(eˆ) −−→ inji(eˆ ) ⇐ τ˙+ inji(e˙); here, we consider only binary sums, so i ∈ {L, R}. The elimination form is case analysis, case(e˙, x.e˙ , y.e˙ ).  1 2 Γ˙ ` eˆ ⇒ τ˙0 Next, we must correspondingly extend the syntax of Z- α ˙ ` eˆ ⇒ ˙ −−→ eˆ0 ⇒ ˙ ˙ ( ˙ + ˙ ) types and Z-expressions, following Huet’s zipper pattern [25]: Γ τ0 τ+ τ+ I+ τ1 τ2 Γ˙ , x : τ˙ ` e˙ ⇐ τ˙ Γ˙ , y : τ˙ ` e˙ ⇐ τ˙ 1 1 2 2 (23e) ZTyp τˆ ::= · · · | (τˆ + τ˙ ) | (τ˙ + τˆ) α 0 Γ˙ ` case(eˆ, x.e˙1, y.e˙2) −−→ case(eˆ , x.e˙1, y.e˙2) ⇐ τ˙ ZExp eˆ ::= · · · | inji(eˆ) | case(eˆ, x.e˙, y.e˙) | case(e˙, x.eˆ, y.e˙) | case(e˙, x.e˙, y.eˆ) Γ˙ ` e˙ ⇒ τ˙+ ˙ α 0 Notice that for each H-type or H-expression form of arity τ˙+ I+ (τ˙1 + τ˙2) Γ, x : τ˙1 ` eˆ1 −−→ eˆ1 ⇐ τ˙ n, there are n corresponding Z-type or Z-expression forms, (23f) ˙ ` ( ) −−→α ( 0 ) ⇐ each of which has a single “hatted” subterm. The remaining Γ case e˙, x.eˆ1, y.e˙2 case e˙, x.eˆ1, y.e˙2 τ˙ subterms are “dotted”. We must also extend the definition of Γ˙ ` e˙ ⇒ τ˙+ cursor erasure, e.g. for types: ˙ α 0   τ˙+ I+ (τ˙1 + τ˙2) Γ, y : τ˙2 ` eˆ2 −−→ eˆ ⇐ τ˙ (τˆ + τ˙ ) =( τˆ + τ˙ ) 2 (23g) α 0   ˙ ` case( ) −−→ case( ) ⇐ ˙ (τ˙ + τˆ) =( τ˙ + τˆ ) Γ e˙, x.e˙1, y.eˆ2 e˙, x.e˙1, y.eˆ2 τ α The rules for Z-expressions are analogous: Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0   inji(eˆ) = inji(eˆ ) α = construct inj i   (24a) case(eˆ, x.e˙1, y.e˙2) = case(eˆ , x.e˙1, y.e˙2) ˙ α Γ ` . / ⇒ τ˙ −−→ inji( ) : (. / + ) ⇒ +   LM LM LM LM LM LM case(e˙, x.eˆ1, y.e˙2) = case(e˙, x.eˆ1, y.e˙2)   α = construct case x y τ˙ I+ (τ˙1 + τ˙2) case(e˙, x.e˙1, y.eˆ2) = case(e˙, x.e˙1, y.eˆ ) 2 α (24b) Finally, we must extend the syntax of shapes: Γ˙ ` .e˙/ ⇒ τ˙ −−→ case(e˙, x.. /, y. ) : ⇒ LM LM LM LM Shape ψ ::= · · · | sum | inj i | case x y α = construct case x y τ˙  ( + ) α LM LM (24c) Notice that for each H-type or H-expression form, there is Γ˙ ` .e˙/ ⇒ τ˙ −−→ case( .e˙/ , x. , y. ) : ⇒ a corresponding shape. The injection form had a formal pa- L M LM LM LM LM rameter, i, so the corresponding shape takes a corresponding Figure 10. The construction & zipper action rules for sums. move δ 0 actions τˆ −−−−→ τˆ (25a-d) act

move child 1 α1 α2 … .(τ˙1 + τ˙2)/ −−−−−−−→ (.τ˙1/ + τ˙2) move child 2 .(τ˙1 + τ˙2)/ −−−−−−−→ (τ˙1 + .τ˙2/) edit states move parent α1 α2 (.τ˙1/ + τ˙2) −−−−−−−→ .(τ˙1 + τ˙2)/ ê τ ê τ ê τ move parent 1⇒ 1 2⇒ 2 3⇒ 3 (τ˙1 + .τ˙2/) −−−−−−−→ .(τ˙1 + τ˙2)/ views Programmer view move δ 0 eˆ −−−−→ eˆ (26a-h) v1 v2 v3 move child 1 .inji(e˙)/ −−−−−−−→ inji(.e˙/) move parent Figure 12. Implementation Concepts inji(.e˙/) −−−−−−−→ .inji(e˙)/ move child 1 Figure 11 gives the relevant movement axioms. For conci- .case(e˙, x.e˙1, y.e˙2)/ −−−−−−−→ case(.e˙/, x.e˙1, y.e˙2) move child 2 sion and clarity, we write these axioms in tabular form. Had .case(e˙, x.e˙1, y.e˙2)/ −−−−−−−→ case(e˙, x..e˙1/, y.e˙2) move child 3 we made a mistake in any of these rules, the Movement Era- .case(e˙, x.e˙1, y.e˙2)/ −−−−−−−→ case(e˙, x.e˙1, y..e˙2/) sure Invariance theorem (Theorem 2) would not be conserved. move parent Had we forgotten any of these rules, the Reachability Theorem case(.e˙/, x.e˙1, y.e˙2) −−−−−−−→ .case(e˙, x.e˙1, y.e˙2)/ move parent (Theorem 3) would not be conserved. case(e˙, x..e˙1/, y.e˙2) −−−−−−−→ .case(e˙, x.e˙1, y.e˙2)/ move parent case(e˙, x.e˙1, y..e˙2/) −−−−−−−→ .case(e˙, x.e˙1, y.e˙2)/ 5. Implementation 5.1 Implementation Concepts Figure 11. Movement actions for sums. Central to any implementation of Hazelnut is a stream of edit states whose cursor erasures synthesize types under an argument (like lit n.) The case form included two variable empty context according to the synthetic action judgement, binders, so the corresponding shape takes two variable argu- α 0 0 ments (like lam x.) ∅ ` eˆ ⇒ τ˙ −−→ eˆ ⇒ τ˙ . The middle row of Figure 12 diagrams this stream of edit states. For example, the reader Statics. We can now move on to the static semantics. is encouraged to re-examine the examples in Figure 1 and 2 – First, we must extend the type consistency relation as the cursor erasure of each edit state synthesizes a type. shown in Figure 9, following the example of covariant type Because Theorem 1 expresses an invariant, the editor does consistency rule for arrow types in Figure 5. Similarly, we not need to typecheck the edit state anew on each action need a notion of a matched sum type analogous to the notion of (though in some of the rules, e.g. Rule (18g) which handles the a matched arrow type defined in Figure 5. situation where the type in a type ascription changes, portions The type analysis rules shown in Figure 9 are essentially of the program would need to be typechecked again.) In other standard, differing only in that instead of immediately requir- words, many of the problems related to incrementality are ing that a type be of the form (τ˙1 + τ˙2), we use the matched simply not relevant. Storing the types of subtrees would allow sum type judgement. We combine the two injection rules for for further optimizations (e.g. of the zipper rules.) concision and define only a type analysis rule for the case The programmer examines a view generated from each form for simplicity (see [11] for additional machinery that edit state and produces actions in some implementation- would be necessary for a synthetic rule.) defined manner (e.g. using a keyboard, mouse, touchscreen, Action Semantics. Figures 10 and 11 extend Hazelnut’s action voice interface, or neural interface), as diagrammed in Figure semantics to support bidirectionally typed structure editing 12. Each new action causes a new abstract edit state to arise with sums. according to an implementation of the action semantics. This Rule (22a), the construction rule for sum types, and Rules then causes a new view to arise. This is a simple event-based (22b)-(22c), the zipper rules for sum types, follow the corre- functional reactive programming model [66]. sponding rules for arrow types. Were we to have missed any If an action is not well-defined according to Hazelnut’s of these, the first clause of Theorem 6, i.e. Constructability, action semantics, the implementation must reject it. In fact, the would not be conserved. implementation is encouraged to present an “action palette” Rule (23a) constructs an injection when the type provided that either hides or visibly disables actions that are not well- for analysis has a matched sum type. This is analogous to Rule defined (see below.) (13f) for lambdas. Rule (23b) constructs an injection when the 5.2HZ type provided for analysis is not consistent with sum types. This is analogous to Rule (13g) for lambdas. Rule (23c) is We have developed a simple reference implementation, HZ, of a straightforward rule for constructing case expressions in Hazelnut extended with sum types as described in Sec. 4. In empty holes. Rules (23d)-(23g) are the zipper cases, which order to reach a wide audience, we decided to implement follow the structure of the statics. Finally, we also define a HZ in the web browser. To take advantage of a mature single new synthetic action rule, Rule (24a), which allows for implementation of the FRP model, we chose to implement HZ the construction of an injection in synthetic position, with using OCaml5, the OCaml React library6, and the js of ocaml automatic insertion of an ascription. This is analogous to Rule and associated libraries [4]7. (13e). If we had defined any of these rules incorrectly, the 5 Sensibility Theorem (Theorem 1) would not be conserved. https://ocaml.org/ Had we forgotten the analytic rules, the Constructability 6 http://erratique.ch/software/react Theorem (Theorem 6) would not be conserved. 7 http://ocsigen.org/js_of_ocaml/ The core semantics have been implemented in a functional decisions about the (other than our choice to use style that follows the presentation in this paper closely. an explicit cursor.) In contrast, these editors have developed The view computation renders the model (i.e. a Z- innovative user interfaces (e.g. see the discussion in [64]) but expression paired with a type) as nested HTML div elements lack a principled foundational calculus. In this respect, we matching the tree structure of the corresponding Z-expression. follow the philosophical approach taken by languages that This tree is stylized separately using CSS. The action palette is are rooted in the type theoretic tradition and have gone to a collection of buttons and text boxes which are disabled when great effort to develop a clear metatheory, like Standard ML the corresponding action cannot be performed. We determine [23, 29, 37]. In the future, we hope that these lines of research this by simply attempting to perform the action internally will merge to produce a human-usable typed structure editor and handling the exception that is raised when an action is with sound formal foundations. Our contribution, then, is in undefined. (An optimization that is not in HZ would be to defining and analyzing the theoretical properties of a small implement a version of the action semantics that simply com- foundational calculus that could be extended to achieve this putes a boolean, rather than the resulting edit state, for the vision. Our implementation resembles the minimal structure purposes of action validation.) Each action form also has a editor defined in Haskell by Sufrin and De Moor [58]. corresponding keyboard shortcut. For actions that take argu- Some structure editor generators do operate on formal or ments, the keyboard shortcut moves the cursor into a text box. semi-formal definitions of an underlying language. For exam- The action validation occurs on every change to the text box. ple, the Synthesizer Generator [50] allows the user to define an This implementation is not, of course, meant to score marks attribute grammar-based language implementation that then for usability or performance (though both are surprisingly can be used to generate a structured editor. CENTAUR [5] good for such a simple system.) Instead, as a simple reference produces a language specific environment from a user defined implementation, it allows the reader to interact with the formal specification of a language. Barista is a programmatic system presented in this paper, to aid in their understanding. toolkit for building structure editors [28]. mbeddr is built on Additionally, we expect its to be of use to others top of the commercial JetBrains MPS framework for construct- who are interested in layering a more fluid user interface atop ing structure editors [62, 65]. These systems do not give a the core semantics, or extensions thereof. semantics to the edit states of the structure editor itself, or maintain non-trivial edit invariants, as Hazelnut does. 6. Related Work and Discussion Related to structure editors are value editors, which oper- 6.1 Structure Editors ate directly on simple values (but not generally expressions or functions) of a . For example, Eros Syntactic structure editors have a long history – the Cornell is a typed value editor based in Haskell [17]. Program Synthesizer [59] was first introduced in 1981. Novice Other work has attempted to integrate structure editing programmers have been a common target for structure editors. features into text editors. For example, recent work has used For example, GNOME [20] was developed to teach program- syntactic placeholders reminiscent of our expression holes to ming to undergraduates. Alice [12] is a 3-D programming lan- decrease the percentage of edit states that are malformed [3]. guage with an integrated structure editor for teaching novice This work does not consider the semantics of placeholders. CS undergraduate students. Scratch [51] is a structure editor Prior work has also explored formal definitions of text targeted at children ages 8 to 16. TouchDevelop [60] incor- editor commands, e.g. using functional combinators [57]. porates a structure editor for programming on touch-based devices, and is used to teach high school students. An imple- 6.2 Gradual Type Systems mentation of Hazelnut might be useful in teaching students about the typed lambda calculus, though that has not been A significant contribution of this paper is the discovery of a our explicit aim with this work. clear technical relationship between typed structure editing Not all structure editors are for educational purposes. For and gradual typing. In particular, the machinery necessary to example, mbeddr [63] is a structure editor for a C-based pro- give a reasonable semantics to type holes – i.e. type consis- gramming language (nominally, for programming embedded tency and type matching – coincides with that developed in systems.) Lamdu [33], like Hazelnut, is a structure editor for the study of gradual type systems for functional languages. a statically typed functional language. It is designed for use The pioneering work of Siek and Taha [54] introduced type by professional programmers. consistency. Subsequent work developed the concept of type The examples given so far either do not attempt to rea- matching [18, 49] and has further studied the notion of type son statically about types and binding, or do not attempt to consistency [19]. In retrospect, this relationship is perhaps maintain well-typedness as an edit invariant. This can pose unsurprising: gradual typing is, notionally, also motivated problems, for reasons discussed in Sec. 1. One apparent ex- by the idea of iterated development of a program where ev- ception is Unison [8], a structure editor for a typed functional ery intermediate state is well-defined in some sense, albeit at language similar to Haskell. Like Hazelnut, it seems to de- different granularity. fine some notion of well-typedness for expressions with holes Recent work has discovered a systematic procedure for (though there is no technical documentation on virtually any generating a “gradual version” of a standard type system aspect of its design.) Unlike Hazelnut, it does not have a [11]. This system, called the Gradualizer, operates on a logic notion analogous to Hazelnut’s notion of a non-empty hole. program that specifies a simple type assignment system with As such, programmers must construct programs in a rigid some additional annotations to generate a corresponding spec- outside-in manner, as discussed in Sec. 2. Another system ification of a gradual type system. The authors leave support with the same problem is Polymorphic Blocks, a block-based for working with bidirectional type systems as future work. user interface where the structure of block connectors encodes This suggests the possibility of an analogous “Editorializer” a type [31]. that generates a specification of a typed structure editor from We fundamentally differ from these projects in our design a simple language definition. Our exposition in Sec. 4 certainly philosophy: we consider it essential to start by building type suggests that many of the necessary definitions follow seem- theoretic foundations, which are independent of nearly all ingly mechanically from the definition of the static semantics, and the relationship with gradual typing suggests that many programming model where indicated expression holes are of the technical details of this transformation may already treated as sites where the system can be asked to automatically exist in the Gradualizer. One possibility we have explored generate an expression of an appropriate type. informally is to use Agda’s reflection features to implement The Graphite system borrowed Eclipse’s heuristic model such a system. of typed holes for Java to allow library providers to associate An aspect of gradual typing that we did not touch on interactive code generation interfaces with types [43]. directly here is its concern with assigning a dynamics to More generally, the topic of type-directed program syn- programs where type information is not known, by inserting thesis an active area of research, e.g. [45]. By maintaining dynamic type casts [54] or deducing evidence for consistency static well-definedness throughout the editing process, Hazel- during evaluation [19]. This would correspond to assigning nut provides researchers interested in editor-integrated type- a dynamics to Hazelnut expressions with type holes such directed program synthesis with a formal foundation upon that a run-time error occurs when a type hole is found to which to build. be unfillable through evaluation. This may be useful as an exploratory programming tool. 6.7 Tactics 6.3 Bidirectional Type Systems Hazelnut is bidirectionally typed [9, 10, 14, 42, 47]. Bidirec- tional type systems are notable in that they are easy to define, Interactive proof refinement systems, e.g. those in LCF [21], easy to implement, produce simple error messages and sup- and more recent typed tactic systems, e.g. Mtac for Coq [68], port advanced language features [16]. For example, Scala [42] support an explicit model of a “current” typed hole that serves and Agda [41] are both fundamentally bidirectionally typed as the target of program synthesis. Hazelnut differs in that languages. edits can occur anywhere within a term. A related approach is to interpret expression holes as the 6.4 Type Reconstruction metavariables of contextual modal type theory (CMTT) [40]. In An alternative approach to type inference is to use a particular, expression holes have types and are surrounded unification-based type reconstruction system, as in functional by contexts, just as metavariables in CMTT are associated languages like ML and Haskell [13]. This is difficult to recon- with types and contexts. This begins to clarify the logical cile with the approach presented in this paper, because edit ac- meaning of a typing derivation in Hazelnut – it conveys tions could introduce new unification constraints that would well-typedness relative to an (implicit) modal context that require placing non-empty holes around terms far from the extracts each expression hole’s type and context. The modal cursor. A whole-program hole insertion pass after each edit context must be emptied – i.e. the expression holes must action could perhaps be used to recover invariants similar to be instantiated with expressions of the proper type in the those presented here, but we leave the details as future work. proper context – before the expression can be considered Our contention is that a bidirectional approach is a sweet spot complete. This corresponds to the notion of modal necessity in the design space of interactive systems like Hazelnut be- in contextual modal logic. cause it precludes “spooky errors at a distance”. Instead, the We did not make the modal context explicit in our seman- interaction is a sort of local dialog between the programmer tics because interactive program editing is not merely hole and the system involving simple, familiar concepts – types filling in Hazelnut (i.e. the cursor need not be on a hole.) with holes – rather than sets of constraints. Moreover, the hole’s type and context become apparent as our An intermediate approach would be to layer unification- action semantics traverses the zipper structure on each step. based type generation features atop the bidirectional system. For interactive proof assistants that support a tactic model This would amount to interpreting type holes as unification based directly on hole filling, as just discussed, the connection variables. For a simple calculus, e.g. the STLC upon which to CMTT and similar systems is more useful. For example, Hazelnut is based, type inference for complete expressions is Beluga [46] is based on dependent CMTT and aspects of Idris’ known to be decidable, so type holes could be instantiated editor support [6] are based on McBride’s OLEG [35] and Lee automatically once the expression that they appear within has and Friedman have explored a lambda calculus with contexts been constructed. It would also be possible to flag expressions for a similar purpose [30]. for which there does not exist any way to fill the type holes. In One interesting avenue of future work is to elaborate more complex settings, e.g. in a dependently typed language, expression holes to CMTT’s closures, i.e. CMTT terms of the a partial decision procedure may still be useful in this regard, form clo(u; id(Γ)) where u is a unique metavariable associated both at edit-time and (just prior to) run-time. Indeed, text with each hole and id(Γ) is the explicit identity substitution. editor modes for dependently typed proof assistants, e.g. for This would allow us to evaluate expressions with holes such Agda, attempt to do exactly this for indicated “type holes” that the closure “accumulates” substitutions explicitly. When (and do not always succeed.) evaluation gets “stuck” (as it can, for CMTT does not define 6.5 Exceptions a dynamics equipped with a notion of progress under a Expression holes can be interpreted in several ways. One non-empty modal context), it would then be possible for straightforward interpretation is to treat them like expressions the programmer to choose a hole from the visible holes that raise exceptions. Indeed, placing raise Unimplemented (which may have been duplicated) to edit in their original or similar in portions of an expression that are under construc- context. Once finished, the CMTT hole instantiation operation, tion is a common practice across programming languages together with a metatheorem that establishes that reduction today. The GHC dialect of Haskell recently introduced an commutes with instantiation, would enable an “edit and explicit notion of a typed hole that behaves similarly [1]. resume” feature with a clear formal basis. This notion of reduction commuting with instantiation has also been studied 6.6 Type-Directed Program Synthesis in other calculi [52]. Being able to edit a running program also Some modes, e.g. those for proof assistants like has connections to less formal work on “live programming” Agda [41] and Idris [6], support a more explicit hole-based interfaces [7, 33]. 7. Conclusion Designing a action suggestion semantics and a rigorous typed This paper presented Hazelnut, a type theoretic structure probability model over actions is one avenue of research that editor calculus. Our aim was to take a principled approach to we have started to explore, with intriguing initial results. its design by formally defining its static semantics as well 7.1.4 Programmable Actions as its action semantics and developing a rich metatheory. Our language of actions is intentionally primitive. However, Moreover, we have mechanized substantial portions of the even now it acts much like a simple imperative command lan- metatheory, including the crucial Sensibility theorem that guage. This suggests future expansion to, for example, a true establishes that every edit state is statically meaningful. action macro language, whereby functional programs could In addition to simplifying the job of an editor designer, themselves be lifted to the level of actions to compute non- typed structure editors also promise to increase the speed trivial compound actions. Such compound actions would give of development by eliminating redundant syntax and sup- a uniform description of transformations ranging from the porting higher-level primitive actions. However, we did not simple – like “move the cursor to the next hole to the right” – discuss such “edit costs” here, because they depend on par- to quite complex whole program refactoring, while remain- ticular implementation details, e.g. whether a keyboard or a ing subject to the core Hazelnut metatheory. Techniques like mouse is in use. Indeed, we consider it a virtue of this work those in advanced tactic systems, e.g. Mtac, might be useful that such implementation details do not enter into our design. in proving these action macros correct [68]. 7.1 Future Work 7.1.5 Views 7.1.1 Richer Languages Another research direction is in exploring how types can Hazelnut is, obviously, a very limited language at its core. be used to control the presentation of expressions in the So the most obvious avenue for future work is to increase editor. For example, following an approach developed in a the expressive power of this language by extension. Our textual setting of developing type-specific languages (TSLs), plan is to simultaneously maintain a mechanization and it should be possible to have the type that an expression is implementation (following, for example, Standard ML [29]) being analyzed against define alternative display forms and as we proceed, ultimately producing the first large-scale, interaction modes [44]. formally verified bidirectionally typed structure editor. It should also be possible to develop the concept of seman- It is interesting to note that the demarcation between the tic comments, i.e. comments that mention semantic structures language and the editor is fuzzy (indeed, non-existent) in or even contain values. These would be subject to the same Hazelnut. There may well be interesting opportunities in operations, e.g. renaming, as other structures, helping to ad- language design when the language is being codesigned dress the problem of comments becoming inconsistent with with a typed structure editor. It may be that certain language code. This system, generalized sufficiently, could one day help features are unnecessary given a sufficiently advanced type- unify document editing with program editing. open aware structure editor (e.g. SML’s ?), while other features 7.1.6 Collaborative Programming may only be practical with editor support. We intend to use Hazelnut and derivative systems thereof as a platform for Finally, we did not consider any aspects of collaborative pro- rigorously exploring such questions. gramming, such as a packaging system, a differencing algo- rithm for use in a source control system, support for multiple 7.1.2 Evaluation Strategies: A High-Dimensional Space simultaneous cursors for different users, and so on. These are The related work brought up in the previous section suggests all interesting avenues for future work. three different evaluation strategies in the presence of type 7.1.7 Empirical Evaluation holes: Although we make few empirical claims in this paper, it 1. ...as preventing evaluation (the standard approach.) is ultimately an empirical question as to whether structure 2. ...as unknown types, in the gradual sense. editors, and typed structure editors, are practical. We hope to 3. ...as unification variables. conduct user studies once a richer semantics and a practical In addition, we have discussed four different evaluation implementation thereof has been developed. strategies in the presence of expression holes: 7.1.8 More Theory 1. ...as preventing evaluation (the standard approach.) Connections with gradual type systems and CMTT, discussed 2. ...as causing exceptions. in the previous section, seem likely to continue to be revealing. 3. ...as sites for automatic program synthesis. The notion of having one of many possible locations within 4. ...as the closures of CMTT. a term under a cursor has a very strong intuitive connection to the proof theoretic notion of focusing [55]. Building closer Every combination of these choices could well be consid- connections with proof theory (and category theory) is likely ered in the design of a full-scale programming system in the to be a fruitful avenue of further inquiry. spirit of Hazelnut. Indeed, the user might be given several options from among these combinations, depending on their In any case, these are but steps toward more graphical usage scenario. Many of these warrant further inquiry. program-description systems, for we will not forever stay 7.1.3 Editor Services confined to mere strings of symbols. There are various aspects of the editor model that we have — Marvin Minsky, Turing Award lecture [38] not yet formalized. For example, our action model does not consider how actions are actually entered using, for example, Acknowledgments key combinations or chords. In practice, we would want also The authors would like to thank the anonymous referees at to suggest sensible compound actions, and to rank these POPL and TFP 2016 for useful feedback on earlier drafts suggested actions in some reasonable manner (perhaps based of this paper; Ed Morehouse and Carlo Angiuli for counsel on usage data gathered from other users or code repositories.) on mechanization and Barendrecht’s Convention; Vincent Zeng for pro bono artistic services; and YoungSeok Yoon [22] R. Harper. Practical Foundations for Programming Languages. 2nd for reanalyzing the data from [67]. This work was partially edition, 2016. URL https://www.cs.cmu.edu/~rwh/plbook/ funded through a gift from Mozilla; the NSF grant #CCF- 2nded.pdf. 1619282, 1553741 and 1439957; by AFRL and DARPA under [23] R. Harper and C. Stone. A Type-Theoretic Interpretation of agreement #FA8750-16-2-0042; and by NSA lablet contract Standard ML. In Proof, Language and Interaction: Essays in Honour #H98230-14-C-0140. of Robin Milner. MIT Press, 2000. [24] G. J. Holzmann. Brace yourself. IEEE Software, 33(5):34–37, Sept References 2016. ISSN 0740-7459. doi: 10.1109/MS.2016.123. [1] Typed holes in GHC. https://wiki.haskell.org/GHC/Typed_ [25] G. Huet. The Zipper. Journal of Functional Programming, 7(5), holes. Retrieved Nov. 7, 2016. Sept. 1997. Functional Pearl. [2] A. Altadmri and N. C. Brown. 37 Million Compilations: Inves- [26] D. Jones. Developer beliefs about binary operator precedence. C tigating Novice Programming Mistakes in Large-Scale Student Vu, 18(4):14–21, 2006. Data. In ACM Technical Symposium on Computer Science Education [27] L. C. L. Kats, M. de Jonge, E. Nilsson-Nyman, and E. Visser. (SIGCSE), 2015. Providing rapid feedback in generated modular language envi- [3] L. E. d. S. Amorim, S. Erdweg, G. Wachsmuth, and E. Visser. ronments: adding error recovery to scannerless generalized-LR Principled syntactic code completion using placeholders. In SLE, parsing. In OOPSLA, 2009. 2016. [28] A. J. Ko and B. A. Myers. Barista: An Implementation Framework [4] V. Balat. Ocsigen: Typing Web Interaction with Objective Caml. for Enabling New Tools, Interaction Techniques and Views In ACM Workshop on ML, 2006. in Code Editors. In SIGCHI Conference on Human Factors in [5] P. Borras, D. Clement,´ T. Despeyroux, J. Incerpi, G. Kahn, B. Lang, Computing Systems (CHI), 2006. and V. Pascual. CENTAUR: The System. In Proceedings of the [29] D. K. Lee, K. Crary, and R. Harper. Towards a mechanized ACM SIGSOFT/SIGPLAN Software Engineering Symposium on metatheory of Standard ML. In POPL, 2007. Practical Software Development Environments, pages 14–24, 1988. [30] S. Lee and D. P. Friedman. Enriching the Lambda Calculus with [6] E. Brady. Idris, A General-Purpose Dependently Typed Pro- Contexts: Toward a Theory of Incremental Program Construction. gramming Language: Design and Implementation. Journal of In ICFP, 1996. Functional Programming, 23(05):552–593, 2013. [31] S. Lerner, S. R. Foster, and W. G. Griswold. Polymorphic blocks: [7] S. Burckhardt, M. Fahndrich,¨ P. de Halleux, S. McDirmid, Formalism-inspired UI for structured connectors. In ACM M. Moskal, N. Tillmann, and J. Kato. It’s alive! continuous feed- Conference on Human Factors in Computing Systems (CHI), 2015. back in UI programming. In PLDI, 2013. [32] D. R. Licata and R. Harper. A Universe of Binding and Compu- [8] P. Chiusano. Unison. http://www.unisonweb.org/. Accessed: tation. In ICFP, 2009. 2016-04-25. [33] E. Lotem and Y. Chuchem. Project Lamdu. http://www.lamdu. [9] A. Chlipala, L. Petersen, and R. Harper. Strict bidirectional type org/. Accessed: 2016-04-08. checking. In ACM SIGPLAN International Workshop on Types in [34] G. Marceau, K. Fisler, and S. Krishnamurthi. Do values grow Languages Design and Implementation (TLDI), 2005. on trees?: Expression integrity in functional programming. In [10] D. R. Christiansen. Bidirectional Typing Rules: A Tutorial. http: Seventh International Workshop on Computing Education Research //davidchristiansen.dk/tutorials/bidirectional.pdf, (ICER), 2011. 2013. [35] C. McBride. Dependently typed functional programs and their proofs. [11] M. Cimini and J. G. Siek. The gradualizer: a methodology and PhD thesis, University of Edinburgh. College of Science and algorithm for generating gradual type systems. In POPL, 2016. Engineering. School of Informatics., 2000. [12] M. Conway, S. Audia, T. Burnette, D. Cosgrove, and K. Chris- [36] T. Mens and T. Tourwe.´ A survey of software refactoring. IEEE tiansen. Alice: Lessons Learned from Building a 3D System for Transactions on Software Engineering, 30(2):126–139, 2004. Novices. In SIGCHI Conference on Human Factors in Computing [37] R. Milner, M. Tofte, R. Harper, and D. MacQueen. The Definition Systems (CHI), 2000. of Standard ML (Revised). The MIT Press, 1997. [13] L. Damas and R. Milner. Principal type-schemes for functional [38] M. Minsky. Form and content in computer science (1970 ACM programs. In POPL, 1982. Turing Lecture). J. ACM, 17(2):197–215, 1970. [14] R. Davies and F. Pfenning. Intersection types and computational [39] M. Mooty, A. Faulring, J. Stylos, and B. A. Myers. Calcite: Com- effects. In ICFP, 2000. pleting code completion for constructors using crowds. In IEEE [15] M. de Jonge, E. Nilsson-Nyman, L. C. L. Kats, and E. Visser. Symposium on Visual Languages and Human-Centric Computing Natural and flexible error recovery for generated parsers. In SLE, (VL/HCC), 2010. 2009. [40] A. Nanevski, F. Pfenning, and B. Pientka. Contextual modal type [16] J. Dunfield and N. R. Krishnaswami. Complete and easy bidi- theory. ACM Trans. Comput. Log., 9(3), 2008. rectional typechecking for higher-rank polymorphism. In ICFP, [41] U. Norell. Towards a practical programming language based on 2013. dependent type theory. PhD thesis, Department of Computer [17] C. Elliott. Tangible Functional Programming. In ICFP, 2007. Science and Engineering, Chalmers University of Technology, [18] R. Garcia and M. Cimini. Principal Type Schemes for Gradual SE-412 96 Goteborg,¨ Sweden, September 2007. Programs. In POPL, 2015. [42] M. Odersky, C. Zenger, and M. Zenger. Colored local type [19] R. Garcia, A. M. Clark, and E. Tanter. Abstracting gradual typing. inference. In POPL, 2001. In POPL, 2016. [43] C. Omar, Y. Yoon, T. D. LaToza, and B. A. Myers. Active code [20] D. B. Garlan and P. L. Miller. GNOME: An introductory pro- completion. In ICSE, 2012. gramming environment based on a family of structure editors. In [44] C. Omar, D. Kurilova, L. Nistor, B. Chung, A. Potanin, and First ACM SIGSOFT/SIGPLAN Software Engineering Symposium J. Aldrich. Safely composable type-specific languages. In ECOOP, on Practical Software Development Environments, 1984. 2014. [21] M. Gordon, R. Milner, L. Morris, M. Newey, and C. Wadsworth. [45] P. Osera and S. Zdancewic. Type-and-example-directed program A metalanguage for interactive proof in LCF. In POPL, 1978. synthesis. In PLDI, 2015. [46] B. Pientka. Beluga: Programming with dependent types, contex- the work of Tony Hoare, 1999. tual data, and contexts. In International Symposium on Functional [59] T. Teitelbaum and T. Reps. The Cornell Program Synthesizer: A and (FLOPS), 2010. Syntax-directed Programming Environment. Commun. ACM, 24 [47] B. C. Pierce and D. N. Turner. Local type inference. ACM Trans. (9):563–573, 1981. Program. Lang. Syst., 22(1):1–44, Jan. 2000. [60] N. Tillmann, M. Moskal, J. de Halleux, and M. Fahndrich. [48] N. Pouillard. Nameless, painless. In ICFP, 2011. TouchDevelop: Programming Cloud-connected Mobile Devices [49] A. Rastogi, A. Chaudhuri, and B. Hosmer. The ins and outs of via Touchscreen. In SIGPLAN Symposium on New Ideas, New gradual type inference. In POPL, 2012. Paradigms, and Reflections on Programming and Software, 2011. [50] T. Reps and T. Teitelbaum. The synthesizer generator. SIGSOFT [61] C. Urban, S. Berghofer, and M. Norrish. Barendregt’s variable Softw. Eng. Notes, 9(3):42–48, Apr. 1984. ISSN 0163-5948. convention in rule inductions. In Conference on Automated Deduction (CADE), 2007. [51] M. Resnick, J. Maloney, A. Monroy-Hernandez,´ N. Rusk, E. East- mond, K. Brennan, A. Millner, E. Rosenbaum, J. Silver, B. Silver- [62] M. Voelter. Language and IDE Modularization and Composition man, and Y. Kafai. Scratch: Programming for All. Commun. ACM, with MPS. In International Summer School on Generative and 52(11):60–67, Nov. 2009. Transformational Techniques in Software Engineering, pages 383–430. Springer, 2011. [52] D. Sands. Computing with contexts: A simple approach. Electr. Notes Theor. Comput. Sci., 10:134–149, 1997. [63] M. Voelter, D. Ratiu, B. Schaetz, and B. Kolb. Mbeddr: An Exten- sible C-based Programming Language and IDE for Embedded [53] A. Sarkar. The impact of syntax colouring on program compre- Systems. In SPLASH, 2012. hension. In Annual Conference of the Psychology of Programming Interest Group (PPIG), 2015. [64] M. Voelter, J. Siegmund, T. Berger, and B. Kolb. Towards User- International Conference on [54] J. G. Siek and W. Taha. Gradual typing for functional languages. Friendly Projectional Editors. In Software Language Engineering (SLE) In Scheme and Functional Programming Workshop, 2006. , 2014. [55] R. J. Simmons and F. Pfenning. Weak Focusing for Ordered [65] M. Voelter, J. Warmer, and B. Kolb. Projecting a Modular Future. Linear Logic. Technical Report CMU-CS-10-147, Carnegie Mellon IEEE Software, 32(5):46–52, 2015. University, 2011. Revision of April 2011. [66] Z. Wan and P. Hudak. Functional Reactive Programming from [56] A. Stefik and S. Siebert. An empirical investigation into program- First Principles. In PLDI, 2000. ming language syntax. ACM Transactions on Computing Education [67] Y. S. Yoon and B. A. Myers. A longitudinal study of programmers’ (TOCE), 13(4):19, 2013. backtracking. In IEEE Symposium on Visual Languages and Human- [57] B. Sufrin. Formal specification of a display-oriented text editor. Centric Computing (VL/HCC), 2014. Sci. Comput. Program., 1(3):157–202, 1982. [68] B. Ziliani, D. Dreyer, N. R. Krishnaswami, A. Nanevski, and [58] B. Sufrin and O. De Moor. Modeless structure editing. In V. Vafeiadis. Mtac: A monad for typed tactic programming in Proceedings of the Oxford-Microsoft Symposium in Celebration of Coq. Journal of Functional Programming, 25:e12, 2015. A. Hazelnut The full collection of rules defining the semantics of Hazelnut (not including the rules for the extension described in Sec. 4) are reproduced here in their definitional order for reference. The rule names coincide with the corresponding constructors in the Agda mechanization. A.1 H-Types and H-Expressions A.1.1 Type Compatibility and Incompatibility

τ˙ ∼ τ˙ 0 (TCREFL) τ˙ ∼ τ˙

(TCHOLE1) τ˙ ∼ LM (TCHOLE2) ∼ τ˙ LM 0 0 τ˙1 ∼ τ˙1 τ˙2 ∼ τ˙2 0 0 (TCARR) (τ˙1 → τ˙2) ∼ (τ˙1 → τ˙2) 0 τ˙  τ˙ (ICNUMARR1) num  (τ˙1 → τ˙2)

(ICNUMARR2) (τ˙1 → τ˙2)  num

τ˙1  τ˙3 (ICARR1) (τ˙1 → τ˙2)  (τ˙3 → τ˙4)

τ˙2  τ˙4 (ICARR2) (τ˙1 → τ˙2)  (τ˙3 → τ˙4) A.1.2 Function Type Matching

τ˙ I→ (τ˙1 → τ˙2) (MAHOLE) I→ ( → ) LM LM LM (MAARR) (τ˙1 → τ˙2) I→ (τ˙1 → τ˙2) A.1.3 Synthesis and Analysis The judgements Γ˙ ` e˙ ⇒ τ˙ and Γ˙ ` e˙ ⇐ τ˙ are defined mutually inductively. Γ˙ ` e˙ ⇒ τ˙ Γ˙ ` e˙ ⇐ τ˙ (SASC) Γ˙ ` e˙ : τ˙ ⇒ τ˙

(SVAR) Γ˙ , x : τ˙ ` x ⇒ τ˙ ˙ 0 ˙ Γ ` e˙1 ⇒ τ˙ τ˙ I→ (τ˙2 → τ˙ ) Γ ` e˙2 ⇐ τ˙2 0 (SAP) Γ˙ ` e˙1(e˙2) ⇒ τ˙

(SNUM) Γ˙ ` n ⇒ num

Γ˙ ` e˙1 ⇐ num Γ˙ ` e˙2 ⇐ num (SPLUS) Γ˙ ` (e˙1 + e˙2) ⇒ num

(SHOLE) Γ˙ ` ⇒ LM LM Γ˙ ` e˙ ⇒ τ˙ (SNEHOLE) Γ˙ ` e˙ ⇒ L M LM Γ˙ ` e˙ ⇐ τ˙ Γ˙ ` e˙ ⇒ τ˙ 0 τ˙ ∼ τ˙ 0 (ASUBSUME) Γ˙ ` e˙ ⇐ τ˙ ˙ τ˙ I→ (τ˙1 → τ˙2) Γ, x : τ˙1 ` e˙ ⇐ τ˙2 (ALAM) Γ˙ ` (λx.e˙) ⇐ τ˙ A.2 Z-Types and Z-Expressions A.2.1 Type Cursor Erasure τˆ = τ˙ is a metafunction defined as follows:  .τ˙ / = τ˙ (ETTOP)   (τˆ → τ˙ ) =( τˆ → τ˙ ) (ETARRL)   (τ˙ → τˆ) =( τ˙ → τˆ ) (ETARRR) A.2.2 Expression Cursor Erasure eˆ = e˙ is a metafunction defined as follows:  .e˙/ = e˙ (EETOP)   eˆ : τ˙ = eˆ : τ˙ (EEASCL)   e˙ : τˆ = e˙ : τˆ (EEASCR)   (λx.eˆ) =( λx.eˆ ) (EELAM)   eˆ(e˙) = eˆ (e˙) (EEAPL)   e˙(eˆ) = e˙(eˆ ) (EEAPR)   (eˆ + e˙) =( eˆ + e˙) (EEPLUSL)   (e˙ + eˆ) =( e˙ + eˆ ) (EEPLUSR)   eˆ = eˆ (EENEHOLE) L M L M A.3 Action Model A.3.1 Type Actions α τˆ −−→ τˆ0 Type Movement RR HILD move child 1 (TMA C 1) .(τ˙1 → τ˙2)/ −−−−−−−→ (.τ˙1/ → τ˙2)

RR HILD move child 2 (TMA C 2) .(τ˙1 → τ˙2)/ −−−−−−−→ (τ˙1 → .τ˙2/)

move parent (TMARRPARENT1) (.τ˙1/ → τ˙2) −−−−−−−→ .(τ˙1 → τ˙2)/

move parent (TMARRPARENT2) (τ˙1 → .τ˙2/) −−−−−−−→ .(τ˙1 → τ˙2)/ Type Deletion EL del (TMD ) .τ˙ / −−→ . / LM Type Construction construct arrow (TMCONARROW) .τ˙ / −−−−−−−−−−→ (τ˙ → . /) LM

construct num (TMCONNUM) . / −−−−−−−−→ .num/ LM Zipper Cases α τˆ −−→ τˆ0 α (TMARRZIP1) (τˆ → τ˙ ) −−→ (τˆ0 → τ˙ )

α τˆ −−→ τˆ0 α (TMARRZIP2) (τ˙ → τˆ) −−→ (τ˙ → τˆ0) A.3.2 Expression Movement Actions

move δ eˆ −−−−→ eˆ0 Ascription SC HILD move child 1 (EMA C 1) .e˙ : τ˙ / −−−−−−−→ .e˙/ : τ˙

SC HILD move child 2 (EMA C 2) .e˙ : τ˙ / −−−−−−−→ e˙ : .τ˙ /

move parent (EMASCPARENT1) .e˙/ : τ˙ −−−−−−−→ .e˙ : τ˙ /

move parent (EMASCPARENT2) e˙ : .τ˙ / −−−−−−−→ .e˙ : τ˙ / Lambda AM HILD move child 1 (EML C 1) .(λx.e˙)/ −−−−−−−→ (λx..e˙/)

move parent (EMLAMPARENT) (λx..e˙/) −−−−−−−→ .(λx.e˙)/ Plus LUS HILD move child 1 (EMP C 1) .(e˙1 + e˙2)/ −−−−−−−→ (.e˙1/ + e˙2)

LUS HILD move child 2 (EMP C 2) .(e˙1 + e˙2)/ −−−−−−−→ (e˙1 + .e˙2/)

move parent (EMPLUSPARENT1) (.e˙1/ + e˙2) −−−−−−−→ .(e˙1 + e˙2)/

move parent (EMPLUSPARENT2) (e˙1 + .e˙2/) −−−−−−−→ .(e˙1 + e˙2)/ Application P HILD move child 1 (EMA C 1) .e˙1(e˙2)/ −−−−−−−→ .e˙1/(e˙2)

P HILD move child 2 (EMA C 2) .e˙1(e˙2)/ −−−−−−−→ e˙1(.e˙2/)

move parent (EMAPPARENT1) .e˙1/(e˙2) −−−−−−−→ .e˙1(e˙2)/

move parent (EMAPPARENT2) e˙1(.e˙2/) −−−−−−−→ .e˙1(e˙2)/ Non-Empty Hole OLE HILD move child 1 (EMNEH C 1) . e˙ / −−−−−−−→ .e˙/ L M L M

move parent (EMNEHOLEPARENT) .e˙/ −−−−−−−→ . e˙ / L M L M A.3.3 Synthetic and Analytic Expression Actions The synthetic and analytic expression action performance judgements are defined mutually inductively. α Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0 Movement move δ eˆ −−−−→ eˆ0 (SAMOVE) move δ Γ˙ ` eˆ ⇒ τ˙ −−−−→ eˆ0 ⇒ τ˙ Deletion EL del (SAD ) Γ˙ ` .e˙/ ⇒ τ˙ −−→ . / ⇒ LM LM Construction construct asc (SACONASC) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−→ e˙ : .τ˙ / ⇒ τ˙

ON AR construct var x (SAC V ) Γ˙ , x : τ˙ ` . / ⇒ −−−−−−−−−→ .x/ ⇒ τ˙ LM LM ON AM construct lam x (SAC L ) Γ˙ ` . / ⇒ −−−−−−−−−→ (λx. ) : (. / → ) ⇒ ( → ) LM LM LM LM LM LM LM τ˙ I→ (τ˙1 → τ˙2) construct ap (SACONAPARR) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−→ e˙(. /) ⇒ τ˙2 LM τ˙  ( → ) constructLM apLM (SACONAPOTW) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−→ e˙ (. /) ⇒ L M LM LM ON UM IT construct lit n (SAC N L ) Γ˙ ` . / ⇒ −−−−−−−−−−→ .n/ ⇒ num LM LM τ˙ ∼ num ON LUS construct plus (SAC P 1) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−−→ (e˙ + . /) ⇒ num LM τ˙  num ON LUS construct plus (SAC P 2) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−−→ ( e˙ + . /) ⇒ num L M LM ON OLE construct nehole (SAC NEH ) Γ˙ ` .e˙/ ⇒ τ˙ −−−−−−−−−−→ .e˙/ ⇒ L M LM Finishing Γ˙ ` e˙ ⇒ τ˙ 0 INISH finish (SAF ) Γ˙ ` . e˙ / ⇒ −−−−→ .e˙/ ⇒ τ˙ 0 L M LM Zipper Cases α Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ α (SAZIPASC1) Γ˙ ` eˆ : τ˙ ⇒ τ˙ −−→ eˆ0 : τ˙ ⇒ τ˙

α τˆ −−→ τˆ0 Γ˙ ` e˙ ⇐ τˆ0 α (SAZIPASC2) Γ˙ ` e˙ : τˆ ⇒ τˆ −−→ e˙ : τˆ0 ⇒ τˆ0

 α 0 Γ˙ ` eˆ ⇒ τ˙2 Γ˙ ` eˆ ⇒ τ˙2 −−→ eˆ ⇒ τ˙3 ˙ τ˙3 I→ (τ˙4 → τ˙5) Γ ` e˙ ⇐ τ˙4 (SAZIPAPARR) α 0 Γ˙ ` eˆ(e˙) ⇒ τ˙1 −−→ eˆ (e˙) ⇒ τ˙5 ˙ ˙ α 0 Γ ` e˙ ⇒ τ˙2 τ˙2 I→ (τ˙3 → τ˙4) Γ ` eˆ −−→ eˆ ⇐ τ˙3 (SAZIPAPANA) α 0 Γ˙ ` e˙(eˆ) ⇒ τ˙1 −−→ e˙(eˆ ) ⇒ τ˙4 α Γ˙ ` eˆ −−→ eˆ0 ⇐ num α (SAZIPPLUS1) Γ˙ ` (eˆ + e˙) ⇒ num −−→ (eˆ0 + e˙) ⇒ num

α Γ˙ ` eˆ −−→ eˆ0 ⇐ num α (SAZIPPLUS2) Γ˙ ` (e˙ + eˆ) ⇒ num −−→ (e˙ + eˆ0) ⇒ num

α Γ˙ ` eˆ ⇒ τ˙ Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0 α (SAZIPHOLE) Γ˙ ` eˆ ⇒ −−→ eˆ0 ⇒ α L M LM L M LM Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ Subsumption α Γ˙ ` eˆ ⇒ τ˙ 0 Γ˙ ` eˆ ⇒ τ˙ 0 −−→ eˆ0 ⇒ τ˙ 00 τ˙ ∼ τ˙ 00 α (AASUBSUME) Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ Movement move δ eˆ −−−−→ eˆ0 (AAMOVE) move δ Γ˙ ` eˆ −−−−→ eˆ0 ⇐ τ˙ Deletion EL del (AAD ) Γ˙ ` .e˙/ −−→ . / ⇐ τ˙ LM Construction construct asc (AACONASC) Γ˙ ` .e˙/ −−−−−−−−→ e˙ : .τ˙ / ⇐ τ˙ 0 τ˙  τ˙ ON AR construct var x (AAC V ) Γ˙ , x : τ˙ 0 ` . / −−−−−−−−−→ .x/ ⇐ τ˙ LM L M τ˙ I→ (τ˙1 → τ˙2) ON AM construct lam x (AAC L 1) Γ˙ ` . / −−−−−−−−−→ (λx.. /) ⇐ τ˙ LM LM τ˙  ( → ) ON AM construct lam x LM LM (AAC L 2) Γ˙ ` . / −−−−−−−−−→ (λx. ) : (. / → ) ⇐ τ˙ LM L LM LM LM M τ˙  num ON UM IT construct lit n (AAC N L ) Γ˙ ` . / −−−−−−−−−−→ .n/ ⇐ τ˙ LM L M Finishing Γ˙ ` e˙ ⇐ τ˙ INISH finish (AAF ) Γ˙ ` . e˙ / −−−−→ .e˙/ ⇐ τ˙ L M Zipper Cases ˙ α 0 τ˙ I→ (τ˙1 → τ˙2) Γ, x : τ˙1 ` eˆ −−→ eˆ ⇐ τ˙2 α (AAZIPLAM) Γ˙ ` (λx.eˆ) −−→ (λx.eˆ0) ⇐ τ˙ A.3.4 Iterated Action Judgements

ActionList α¯ ::= · | α; α¯

α¯ τˆ −−→∗ τˆ0 · (DOREFL) τˆ −−→∗ τˆ

α α¯ τˆ −−→ τˆ0 τˆ0 −−→∗ τˆ00 (DOTYPE) α;α¯ τˆ −−→∗ τˆ00 α¯ Γ˙ ` eˆ ⇒ τ˙ −−→∗ eˆ0 ⇒ τ˙ 0 · (DOREFL) Γ˙ ` eˆ ⇒ τ˙ −−→∗ eˆ ⇒ τ˙

α α¯ Γ˙ ` eˆ ⇒ τ˙ −−→ eˆ0 ⇒ τ˙ 0 Γ˙ ` eˆ0 ⇒ τ˙ 0 −−→∗ eˆ00 ⇒ τ˙ 00 (DOSYNTH) α;α¯ Γ˙ ` eˆ ⇒ τ˙ −−→∗ eˆ00 ⇒ τ˙ 00 α¯ Γ˙ ` eˆ −−→∗ eˆ0 ⇐ τ˙ · (DOREFL) Γ˙ ` eˆ −−→∗ eˆ ⇐ τ˙

α α¯ Γ˙ ` eˆ −−→ eˆ0 ⇐ τ˙ Γ˙ ` eˆ0 −−→∗ eˆ00 ⇐ τ˙ (DOANA) α;α¯ Γ˙ ` eˆ −−→∗ eˆ00 ⇐ τ˙ α¯ movements (AM[]) · movements

α¯ movements (AM::) move δ; α¯ movements