
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 fcomar, iev, [email protected] [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. syntax highlighting [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 (lLMx. ) : (. / ! ) construct num (12b) static meaning to expressions and types with holes, which 3 (lx.LM) : (.numLM / !LM ) move parent (6c) we call H-expressions and H-types. Hazelnut’s formal action 4 (lx.LM) : .(num ! L)M/ move child 2 (6b) semantics maintains the invariant that every edit state is a 5 (lx.LM) : (num ! .LM/) construct num (12b) statically meaningful (i.e. well-H-typed) H-expression with 6 (lx.LM) : (num ! .numLM /) move parent (6d) a single superimposed cursor. We call H-expressions and H- 7 (lx.LM) : .(num ! num)/ move parent (8d) types with a cursor Z-expressions and Z-types (so prefixed 8 .(lxL.M ) : (num ! num)/ move child 1 (8a) because our encoding follows Huet’s zipper pattern [25].) 9 .(lx.LM)/ : (num ! num) move child 1 (8e) Na¨ıvely, enforcing an injunction on ill-H-typed edit states 10 (lx..LM/) : (num ! num) construct var x (13c) would force programmers to construct programs in a rigid 11 (lx..LxM/) : (num ! num) construct plus (13l) “outside-in” manner. For example, the programmer would 12 (lx.(x + . /)) : (num ! num) construct lit 1 (13j) often need to construct the outer function application form 13 (lx.(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 .t˙ /, 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.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages20 Page
-
File Size-