Making Uniqueness Typing Less Unique Thesis Submitted for the Degree of Doctor in Philosophy
Total Page:16
File Type:pdf, Size:1020Kb
Making Uniqueness Typing Less Unique Thesis submitted for the degree of Doctor in Philosophy December 14, 2008 Edsko Jacob Jelle de Vries Declaration This thesis has not been submitted as an exercise for a degree at this or any other university. It is entirely the candidate’s own work. The candidate agrees that the Library may lend or copy the thesis upon request. This permission covers only single copies made for study purposes, subject to normal conditions of acknowledgement. Edsko de Vries i ii Voor mijn ouders Voor het helpen met de GW-Basic programma’s uit de Weet-Ik!, en het herstellen van autoexec.bat. iii iv Summary Computer science distinguishes between two major programming paradigms: imperative and Chapter 1, p. 11 functional programming. Central to imperative programming is the notion of some form of state (or memory) together with a list of instructions that inspect and modify that state. The canonical example of this paradigm is the Turing machine. Functional programming on the other hand is centred around a mathematical language with a notion of evaluation of expressions in this language. The notion of state—the core concept in imperative programming—is completely absent. The canonical example of the functional paradigm is the lambda calculus. Although neither Turing machines nor the lambda calculus support a notion of interaction, it is not difficult to see how interaction can be added to a Turing machine: it suffices to allow external entities to modify the machine state. Adding interaction to the lambda calculus is a much more difficult problem, and there are many solutions proposed in the literature. One option is to regard an interactive program as a function from the world state to a new world state. For example, we might have a function getChar that, given a world object, reads a character from the console and produces a new world object; and a function putChar that, given a character and a world object, echos the character to the console and produces a new world object. We can then define a program that reads a character from the console and echoes it back to the user as follows: lworld. putChar (getChar world) The main problem with this approach is the potential duplication of the world state. For example, we can easily define a function that returns a pair of world states, one in which the character ’a’ has been printed and one in which the character ’b’ has been printed: lworld. (putChar (’a’, world), putChar (’b’, world)) Since such a program has no semantic interpretation, we have two options: we can dismiss this approach, or we can impose a type system which analyses the programs written by the user and rejects those without a semantic interpretation. Uniqueness typing is such a type system: it can be used to ensure that objects such as the world state are used in a single-threaded manner. Uniqueness typing was developed for a language based on graph rewriting rather than the lambda calculus. This is unfortunate as it means that recent advances in type systems in the wider functional programming community cannot readily be incorporated in uniqueness typing. The main thesis we will defend in this dissertation is that the graph rewriting background is inessential to uniqueness typing. We claim that it is possible to define a uniqueness type system that is sufficiently similar to conventional type systems for lambda calculus based functional programming languages that techniques developed for such languages can be applied without major difficulties. In short, we propose to make uniqueness typing less unique. v Two main themes have been interwoven in this thesis. In the first, we show how to define a uniqueness type system for the lambda calculus. This system is initially strongly based on the original uniqueness type system, but through a series of simplifications we show how to make it simpler and more like a conventional lambda calculus type system. In the second theme we offer evidence of the effectiveness of these simplifications by taking advantage of them to incorporate type system extensions originally developed for languages without uniqueness typing. Chapter 4, p. 115 The original uniqueness type system distinguishes between objects that are non-unique (may freely be duplicated), unique now (have not been duplicated) but that may become non-unique later, and objects that are necessarily unique (unique now and must forever remain unique). The first simplification we propose is that it is sufficient to distinguish only between non-unique and unique objects (without a notion of “necessarily unique”), and we develop a lambda calculus type system based on this idea. We then show how to extend this type system with arbitrary rank types, based on work by Peyton Jones, Vytiniotis, Weirich, and Shields(2007). Chapter 5, p. 129 Uniqueness types often involve inequality constraints between uniqueness attributes (“this object must be unique if that other object is”). The second simplification we propose is to remove these constraints by supporting arbitrary boolean expressions as uniqueness attributes, sim- plifying both the type system and its implementation. We show again how to incorporate higher rank types, and briefly discuss how to support generalized algebraic data types based on work by Peyton Jones, Vytiniotis, Weirich, and Washburn(2006). Chapter 6, p. 143 As mentioned, the original uniqueness type system distinguishes between non-unique, unique and necessarily unique objects. We suggested that this may be simplified by distinguishing only between non-unique and unique objects, but a disadvantage of this approach is that it relies on a form of closure typing. This makes types difficult to read and understand, and so in the final system we suggest that it may be better to distinguish only between non-unique and necessarily unique objects (and no longer support a notion of “unique now, but may become non-unique later). This removes the need for closure typing, without sacrificing expressiveness provided that we are careful in the types we assign to library functions and take advantage of polymorphism. As a further simplification, we propose to regard uniqueness attributes and types as one syntactic category (and distinguish using a kind system). This makes the presentation and formalization of the type system more uniform, and gives us additional expressive power for free. We show how to support higher rank types, impredicativity and records and variants based on work by Leijen (2008a) and Gaster and Jones(1996). Chapter 7, p. 159 We then give a formalization of this (core) type system using the proof assistant Coq. After proving numerous technical lemmas, we provide a number of lemmas about the type system such as well-kindedness, weakening and exchange, followed by the main soundness theorem (progress and type preservation or subject reduction) based on the call-by-need lambda calculus. Chapter 8, p. 199 Finally, we discuss some of the design choices we have made, potential alternatives, and the relation between our work and related work, and identity future work. We conclude that indeed we have made uniqueness typing less unique: the system we have developed is simple, easy to understand and recent type system extensions are readily incorporated. The only exception appears to be that our system allows less impredicative instantiation than the type system on which it is based. We explain why and discuss some ways in which we might solve this problem. vi Acknowledgements Choosing a PhD thesis topic is a difficult and time consuming task (Cham, 1998), and when I eventually settled on one I wanted to make sure that an expert in the field thought the project worthwhile. At the time, our university was organizing IFL05 and one of the participants was Prof. Rinus Plasmeijer, head of the Software Technology Research Group in Nijmegen—the team that develops the language Clean; I took advantage and asked him for his opinion. He thought that it was a good proposal, but told me that another PhD student in Hungary was working on the exact same problem. This was a bit of a set-back, but Rinus and I got talking—first during a lovely walk in Glendalough, Wicklow and later in a small Italian restaurant just off O’Connell Street in the heart of Dublin—and it turned out that Rinus had a huge list of open problems and would only be too happy if I started working on one of them. A few days later this was followed up with an email listing some of these projects. Many of them were detailed funding proposals for PhD positions, but somewhere in the middle was a throw-away remark that the relation between uniqueness typing and polytypic programming needed clarification. This sounded like an interesting problem and it was not too far off from my original thesis topic, so I suggested that I begin work on this. It soon emerged that to be able to fully answer the question, we needed a uniqueness type system with support for higher rank types and the result is the thesis that you are currently reading. As well as suggesting the original research problem, Rinus has been very helpful throughout my PhD: he gave feedback on my papers, was enthusiastic about my ideas and provided encouragement when needed. Rinus, your involvement was greatly appreciated! Further motivation and feedback was given by my colleagues in the Foundations and Methods Group, especially Arthur Hughes, Andrew Butterfield, Hugh Gibbons, Glenn Strong and Shane Ó Conchúir. I am indebted to David Gregg, who got me an invitation for the Verifying Optimizing Compilers seminar in Dagstuhl. A huge thank-you also to my office mate of four years and fellow student of eight, John Gilbert.