Ynot : Reasoning with the Awkward Squad Aleksandar Nanevski Microsoft Research aleksn@microsoft.com Greg Morrisett Avi Shinnar Paul Govereau Harvard University {greg, shinnar, govereau}@eecs.harvard.edu Lars Birkedal IT University of Copenhagen birkedal@itu.dk Abstract We describe an axiomatic extension to the Coq proof assistant, that supports writing, reasoning about, and extracting higher-order, dependently-typed programs with side-effects. Coq already in- cludes a powerful functional language that supports dependent types, but that language is limited to pure, total functions. The key contribution of our extension, which we call Ynot, is the added support for computations that may have effects such as non-termination, accessing a mutable store, and throwing/catch- ing exceptions. The axioms of Ynot form a small trusted computing base which has been formally justified in our previous work on Hoare Type Theory (HTT). We show how these axioms can be combined with the powerful type and abstraction mechanisms of Coq to build higher-level reasoning mechanisms which in turn can be used to build realistic, verified software components. To substantiate this claim, we describe here a representative series of modules that implement imperative finite maps, including support for a higher- order (effectful) iterator. The implementations range from simple (e.g., association lists) to complex (e.g., hash tables) but share a common interface which abstracts the implementation details and ensures that the modules properly implement the finite map abstraction. Categories and Subject Descriptors F.3.1 [Logics and Meanings of Programs]: Specifying and Verifying and Reasoning about Pro- grams General Terms Languages, Verification Keywords Type Theory, Hoare Logic, Separation Logic, Monads 1. Introduction Two main properties make type systems an effective and scalable formal method. First, important classes of programming errors are eliminated by statically enforcing the correct use of values. Second, types facilitate modular software development by serving as spec- ifications of program components, while hiding the component’s actual implementation. Implementations with the same type can be Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. XXXX XXXX Copyright c 2008 ACM XXXX. . . $5.00 interchanged, improving software development, reuse and evolu- tion. Mainstream type systems focus on relatively simple properties that admit type inference and checking with little or no input from the programmer. Unfortunately, this leaves a number of properties, including data structure invariants, and API protocols, outside of their reach, and also restricts the practical programming features that can be safely supported. For example, most simply-typed lan- guages cannot safely allow low-level operations such as pointer arithmetic or explicit memory management. Static verification can be somewhat extended by refining types with annotations from more expressive logics, as implemented in ESC [25], JML [7], Spec# [2], Cyclone [20], Sage [14], DML [50], Deputy [8] and Liquid types [39]. However, because of the unde- cidability of the annotation logics, these systems still have trouble automatically discharging all but the most shallow specifications, and do not provide alternatives to the programmer when the au- tomation fails, beyond run-time checks. On the other hand, dependent type theories such as the Calcu- lus of Inductive Constructions (implemented in the Coq proof as- sistant), can provide very strong correctness assurances, ranging from simple type safety to full functional correctness, and if some property cannot be discharged automatically, the programmer can provide the proof by hand. Unfortunately, dependent type theories such as Coq, where proofs are represented as language terms, make it difficult to incor- porate computational effects. For example, a diverging term, which can be assigned any type, could be presented as a “proof” of False, which renders the theory inconsistent. As a result, most type theo- ries limit computations to total, pure functions with absolutely no side effects. For example, Coq excludes general recursion, mutable state, exceptions, I/O and concurrency. While some programming tasks, such as a compiler or a decision procedure, can be formu- lated as a pure, terminating function, most important tasks cannot. Furthermore, even computations that can be cast as pure functions need to use asymptotically efficient algorithms and mutable data structures (e.g., hash tables) to be practical. In this paper, we present the system Ynot, which is our proposal for addressing the above shortcomings. Ynot starts with the type theory of Coq, which already has good support for functional pro- gramming, inductive definitions, specifications, proofs, and tactics, and extends it with a new type ST pAq and the associated pro- gramming constructors. Intuitively, ST classifies delayed, possibly effectful computations, much the way that the IO-monad classifies effectful computations in Haskell. The monadic separation facil- itates a clean interaction between effects and pure Coq, preserv- ing the logical soundness of the combined system. Unlike Haskell, our monad is indexed not only by the return type of the compu-