Mechanized Reasoning During Compilation in the Glasgow Haskell Compiler
Total Page:16
File Type:pdf, Size:1020Kb
HERMIT: Mechanized Reasoning during Compilation in the Glasgow Haskell Compiler By Andrew Farmer Submitted to the graduate degree program in Electrical Engineering and Computer Science and the Graduate Faculty of the University of Kansas in partial fulfillment of the requirements for the degree of Doctor of Philosophy. Chairperson Dr. Andy Gill Dr. Perry Alexander Dr. Prasad Kulkarni Dr. James Miller Dr. Christopher Depcik Date Defended: April 30, 2015 The Dissertation Committee for Andrew Farmer certifies that this is the approved version of the following dissertation: HERMIT: Mechanized Reasoning during Compilation in the Glasgow Haskell Compiler Chairperson Dr. Andy Gill Date approved: ii Abstract It is difficult to write programs which are both correct and fast. A promising approach, functional programming, is based on the idea of using pure, mathematical functions to construct programs. With effort, it is possible to establish a connection between a specification written in a functional language, which has been proven correct, and a fast implementation, via program transformation. When practiced in the functional programming community, this style of reasoning is still typ- ically performed by hand, by either modifying the source code or using pen-and-paper. Unfortu- nately, performing such semi-formal reasoning by directly modifying the source code often obfus- cates the program, and pen-and-paper reasoning becomes outdated as the program changes over time. Even so, this semi-formal reasoning prevails because formal reasoning is time-consuming, and requires considerable expertise. Formal reasoning tools often only work for a subset of the target language, or require programs to be implemented in a custom language for reasoning. This dissertation investigates a solution, called HERMIT, which mechanizes reasoning during compilation. HERMIT can be used to prove properties about programs written in the Haskell functional programming language, or transform them to improve their performance. Reasoning in HERMIT proceeds in a style familiar to practitioners of pen-and-paper reasoning, and mech- anization allows these techniques to be applied to real-world programs with greater confidence. HERMIT can also re-check recorded reasoning steps on subsequent compilations, enforcing a connection with the program as the program is developed. HERMIT is the first system capable of directly reasoning about the full Haskell language. The design and implementation of HERMIT, motivated both by typical reasoning tasks and HERMIT’s place in the Haskell ecosystem, is presented in detail. Three case studies investigate HERMIT’s capability to reason in practice. These case studies demonstrate that semi-formal reasoning with HERMIT lowers the barrier to writing programs which are both correct and fast. iii Acknowledgements I read somewhere, once, that a dissertation takes a village. That is certainly true in my experience. I am indebted to a great many people, both professionally and personally, over the last six(!) years. Foremost, I would like to thank my advisor, Andy Gill, for providing me many opportunities I did not even realize existed, and for tolerating my occasional divergences. I have learned an incredible amount in my time as his student, and have always valued his guidance and support. I definitely owe him a non-trivial amount of beer. I was fortunate to have Neil Sculthorpe as a collaborator for much of HERMIT’s development. I learned a lot from Neil, especially in regards to writing about research. Without his excellent work, both on KURE and HERMIT itself, HERMIT would not exist as it does. Thanks also to HERMIT’s first users: Michael Adams, Conal Elliott, and Paul Liu. Their feedback was invaluable, and they were kind enough to put up with HERMIT’s ever-changing APIs breaking their code. Thanks to Jim Hook for hosting me for a semester at Portland State and enabling my collaboration with Michael Adams. To my peers and mentors, past and present, in the CSDL lab (and elsewhere): Perry, Prasad, Garrin, Ed, Nick, Mark, Evan, Wes, Megan, Brigid, Mike J, Nathan, Pedro, Laurence, Brent, Richard, Kevin, Tristan, Mike S, Justin, Jason, Ryan, Bowe, and Brad. I learned something from each of you, and appreciate having been able to work with you all at some point. Also thanks to the National Science Foundation, which partially supported HERMIT under grants CCF-1117569 and DGE-0742523. I could not have accomplished a great many things in life without the support of my parents, who are some of the most selfless people I know. Thanks Mom and Dad, for everything. Thanks also to my brother, Ben, who is someone I look up to, both literally and figuratively. To some great friends: Austin, Bob, Michael, John, Derick, Amy, Jys, Jess, Beth, and a great many others. To Larryville, for all the shenanigans, punctuated with the occasional running. Finally, to Karen, for putting up with my absentmindness, for making sure I ate something besides fast food, and for cheering me up when I was stressed out. I love you. iv Contents 1 Introduction 1 1.1 Reasoning . .3 1.1.1 Proving Properties . .4 1.1.2 Domain-Specific Optimizations . .6 1.1.3 Calculational Programming . .8 1.2 Contributions . .9 1.3 Organization . 11 2 Technical Background 14 2.1 GHC Plugins . 14 2.2 GHC Core . 16 2.2.1 Names . 17 2.2.1.1 OccName . 17 2.2.1.2 RdrName . 17 2.2.1.3 Name . 18 2.2.1.4 Var . 19 2.2.2 Dictionaries . 19 2.2.3 RULES . 20 2.3 KURE . 22 2.3.1 Transformations . 22 v 2.3.2 Monad . 23 2.3.3 MonadCatch . 24 2.3.4 Traversal . 24 2.3.4.1 Context . 25 2.3.4.2 Congruence Combinators . 27 2.3.5 Summary . 27 3 HERMIT Architecture 32 3.1 Plugin . 34 3.2 Kernel . 36 3.3 Plugin DSL . 37 3.3.1 Example Plugin . 39 3.3.2 Pretty Printer . 39 3.4 Shell . 41 3.4.1 Interpreted Command Language . 42 3.4.2 Scripts . 44 3.4.3 Extending HERMIT . 45 3.4.4 Proving in the Shell . 45 3.5 Invoking HERMIT . 46 4 Transformation 50 4.1 Example . 51 4.2 KURE . 58 4.2.1 Universes . 59 4.2.2 Crumbs . 60 4.2.3 The HERMIT Context . 63 4.2.3.1 Recording Bindings . 63 4.2.3.2 Accessing Bindings . 66 vi 4.2.3.3 In-scope RULES . 67 4.2.3.4 Paths . 67 4.2.4 Congruence Combinators . 68 4.2.5 The HERMIT Monad . 71 4.2.6 Conventions . 71 4.3 Names . 72 4.4 Folds . 73 4.4.1 Definition . 74 4.4.2 Implementation . 75 4.4.2.1 Tries . 75 4.4.2.2 TrieMaps . 76 4.4.2.3 α-equivalence . 78 4.4.2.4 Adding Holes . 79 4.4.2.5 Implementing Folds . 82 4.4.3 Applications . 82 4.5 Dictionary . 83 4.5.1 Fold/Unfold . 84 4.5.2 Local Transformations . 84 4.5.3 Creating and Finding Variables . 85 4.5.4 Constructing Expressions . 86 4.5.5 Navigation . 86 4.5.6 Debugging . 87 4.5.7 Composite Transformations . 88 4.5.7.1 Simplify . 89 4.5.7.2 Smash and Bash . 89 5 Proof 90 5.1 Example . 91 vii 5.2 Lemmas . 96 5.3 Equivalence . 97 5.4 Creating Lemmas . 98 5.5 Primitive Operations . 100 5.5.1 Redundant Binder Elimination . 100 5.5.2 Instantiation . 101 5.6 Lemma Universes . ..