Jan 4, 2016 - example the asynchronous edition of proofs [17], interaction with other ..... The set of free variables of a term FVptq is defined inductively: .... This calculus has only one syntactic category for types and terms12: ..... There is a package developed by Thomas Schilling with the ...... publications/verimltr.pdf.
Incrementality and effect simulation in the simply typed lambda calculus Lourdes del Carmen Gonzalez Huesca
To cite this version: Lourdes del Carmen Gonzalez Huesca. Incrementality and effect simulation in the simply typed lambda calculus. Computer Science [cs]. Universite Paris Diderot-Paris VII, 2015. English.
HAL Id: tel-01248531 https://hal.inria.fr/tel-01248531 Submitted on 4 Jan 2016
HAL is a multi-disciplinary open access archive for the deposit and dissemination of scientific research documents, whether they are published or not. The documents may come from teaching and research institutions in France or abroad, or from public or private research centers.
L’archive ouverte pluridisciplinaire HAL, est destin´ee au d´epˆot et `a la diffusion de documents scientifiques de niveau recherche, publi´es ou non, ´emanant des ´etablissements d’enseignement et de recherche fran¸cais ou ´etrangers, des laboratoires publics ou priv´es.
U NIVERSITÉ PARIS D IDEROT – PARIS 7 S ORBONNE PARIS C ITÉ
É COLE D OCTORALE S CIENCES M ATHÉMATIQUES DE PARIS C ENTRE L ABORATOIRE P REUVES , P ROGRAMMES ET S YSTÈMES – É QUIPE πr 2
T HÈSE
DE
D OCTORAT
EN I NFORMATIQUE
Présentée et soutenue par
Lourdes del Carmen G ONZÁLEZ H UESCA le 27 novembre 2015
I NCREMENTALITY AND EFFECT SIMULATION IN THE S IMPLY T YPED L AMBDA C ALCULUS I NCRÉMENTALITÉ ET SIMULATION D ’ EFFETS DANS LE LAMBDA CALCUL SIMPLEMENT TYPÉ
devant le jury composé de Mme. M. M. Mme. M. M. Mme.
Delia K ESNER Hugo H ERBELIN Yann R ÉGIS -G IANAS Catherine D UBOIS Sylvain C ONCHON Daniele VARACCA Sandrine B LAZY
: : : : : : :
Présidente Directeur Directeur Rapporteuse Rapporteur Examinateur Examinatrice
ii
Abstract Certified programming is a framework in which any program is correct by construction. Proof assistants and dependently typed programming languages are the representatives of this paradigm where the proof and implementation of a program are done at the same time. However, it has some limitations: a program in Type Theory is built only with pure and total functions. Our objective is to write efficient and certified programs. The contributions of this work are the formalization, in the Simply Typed Lambda Calculus, of two mechanisms to achieve efficiency: to validate impure computations and to optimize computations by incrementality. An impure computation, that is a program with effects, and its validation in a functional and total language is done through a posteriori simulation. The simulation is performed afterwards on a monadic procedure and is guided by a prophecy. An efficient oracle is responsible for producing prophecies which is actually, the monadic procedure itself translated into an effectful programming language. The second contribution is an optimization to perform incremental computations. Incrementality as a way to propagate an input change into a corresponding output change is guided by formal change descriptions over terms and dynamic differentiation of functions. Displaceable types represent data-changes while an extension of the simply typed lambda calculus with differentials and partial derivatives offers a language to reason about incrementality.
iii
iv
Résumé La programmation certifiée offre un cadre dans lequel tout programme est correct par construction. Les assistants de preuve et les langages de programmation avec types dépendents sont les représentants de ce paradigme, où la prévue et l’implementation d’un programme sont faites au m˜eme temps. Toutefois, il existe certaines limitations : un programme écrit en théorie des types est construit seulement avec des fonctions pures et totales. Notre objectif est d’écrire des programmes efficaces et certifiés. Les contributions de cette thèse sont la formalisation, dans le lambda calcul simplement typé, de deux mécanismes pour améliorer l’efficacité : la validation des calculs impurs et l’optimisation des calculs incrémentaux. Un calcul impur, c’est-à-dire un programme avec effets, et sa validation dans un langage fonctionnel et total est fait á l’aide d’une simulation a posteriori. La simulation est effectuée après, par une procédure monadique et elle est guidée par une prophétie. Un oracle efficace est responsable de la production des prophéties et lui est en fait, la procédure monadique traduite dans un language de programmation généraliste. La deuxième contribution est une optimisation pour les calculs incrémentaux. L’incrémentalité consiste à propager des changements des entrées en changements des sorties, elle est guidée par les descriptions formelles du changement des termes et une différenciation dynamique des fonctions. La représentation des changements de données est pris en charge par les types déplaçables et une extension du lambda calcul simplement typé avec dérivées et dérivées partielles offre un language pour raisonner sur l’incrementalité.
v
vi
Remerciements – Agradecimientos Mon aventure appelée doctorat a été marquée par des rencontres avec plusieurs personnes. Ces remerciments sont dédiés à toutes ces personnes, que je vais essayer de toutes nommer 1 . En premier lieu, je veux remercier Delia Kesner pour ses efforts en faveur des liens academiques. Sans son conseil, je ne serais jamais m’engagée dans le doctorat au sein de l’équipe πr2 . Aussi, dans ce premier merci, je suis très reconnaissant du travail d’encadrement et d’encouragement de Yann Régis-Gianas. Dès le premier jour, il a été un soutien académique et aussi dans les affaires administratives françaises. Merci pour me rappeler toujours le sens pédagogique et pour me montrer un autre regard de mon travail. Merci à Hugo Herbelin pour être une figure constante dans l’équipe, pour nous faire confiance à Yann et moi dans cette aventure. Un grand merci aux rapporteurs qui ont accepté la responsabilité de lire et comprendre mon travail. À Catherine Dubois pour les (nombreuses) remarques et commentaires qui ont amelioré ce manuscrit. À Sylvain Conchon pour ses commentaires très précis. Et un deuxième grand merci aux examinateurs, Sandrine Blazy et Daniele Varacca, pour prendre part au jury. Cette aventure a eu que de grandes contributions académiques: toute l’équipe πr2 et surtout le laboratoire PPS ont été d’excellents fournisseurs de savoir avec les membres permanents et les personnes invitées, aussi avec les nombreux séminaires et groupes de travail. Cette première année à Place d’Italie a facilité le développement de mon premier ‘noyau dur’, lie à l’apprentissage de la langue et culture française et au côté fraternité C OQ: Pierre, Pierre-Marie, Matthias et Guillaume. Je vous remercie énormément de l’encouragement et de la gentillesse de tous ces jours avec votre patience et soutien. Pendant les célèbres journées PPS à Trouville 2012, j’ai découvert le vrai laboratoire et quelques mois plus tard nous nous sommes tous rencontrés dans notre nouveau bâtiment. Depuis cela, le groupe de thésards est devenu plus qu’une bande des potes au labo, mais une bande de gens qui n’a cessé d’ajouter plus de membres. C’est ici que mon deuxième ‘noyau dur’ a été crée : Ioana, Kuba, Shahin qui m’ont adopté et m’ont surtout encouragé pendant la rédaction de cette thèse. Merci Ioana d’être une des mamacitas les plus fortes et cools du monde. Merci Shahin pour mettre en perspective mes origines et de vivre sans avoir peur. Merci Kuba pour toujours ajouter des images et phrases et parce que ‘eres un hombre muy honrado que le gusta lo mejor...’ 1. Si jamais vous n’êtes pas présent dans cette partie, je tiens à vos présenter mes excuses les plus sincères car mon cerveau est devenu inútil ces dernières semaines, mais certainement vous êtes présente dans mon coeur.
vii
viii Je tiens à remercier aux thésards qui m’ont toujours fait sourire: Étienne 2 , Matthieu, Flavien, Giulio, Ludovic, Jovana, Hadrien, Thibaut, Marie. Et tous les thésards dont la présence a contribué aux journées très agréables au labo. Merci aussi aux thésards Liafa, en particulier à Bruno et Jehanne qui ont toujours descendu les escaliers pour venir nous visiter et surtout pour partager les soirées. Samy, Rafa, Luis, Shadi, merci pour les soirées, cafés et discussions très variées. Les couloirs de PPS bien silencieux m’ont fait aussi sourire, merci à Juliusz pour toujours avoir une histoire à raconter, merci à Paul-André pour les samedis avec le son du violon et plus récemment, merci pour les bonjours de Daniel. Merci aux stagiaires avec lesquels on a partagé un e´té au labo et qui sont restés plus dans le coin: Philipp, Kenji et Béa. Le boulot administratif a toujours été un succés grâce à deux super responsables administratives, merci Lindsay, merci Odile. Un côté académique international a influencié ces années, merci à Tim Griffin pour me montrer les origins du C OQ, à Beta pour ses nombreuses visites et discussions sur n’importe quel sujet, à Daniel pour le sourire brésilien, à Pablo et Elisa. No puedo dejar de dar las gracias al lugar donde viví por más de la mitad de este tiempo acá y en donde conocí otra parte de mi país: la Maison du Mexique en citéU. Ahí tuve el privilegio de conocer a muchas personas, las cuales han sido mi apoyo más grande todo este tiempo. Gracias por las fêtes, les pique-niques, les dimanches culturels, les petits week-ends, las vacaciones y por la isla. Merci Denis por ser la primera en recibirme con una sonrisa aquel 31 de diciembre. Merci Alberto por las pláticas deportivas y las no tan deportivas... Merci Juan Carlos por las discussions sobre la vida y la música. Merci a todos los que compartimos más que una ciudad de estudiantes: Fer, José, Vero, Ale, Dama, Arturo, Nuria, Daniel, Braulio, Alejandro, Xiomara, Ale, Laura... También las visitas fueron un gran apoyo: Edgar, Mini, Liliana, Emilio, Daniela, Noé, Merari, Arturo, Nancy, Adriana, Selene, Moni, Ame. Gracias por los juegos, los ‘chats’ y por las visitas turísticas que me ayudaron a conocer más. El apoyo a la distancia ha sido constante: Favio, Liliana y Rafa, siempre al pendiente, mil gracias. Gracias Felipe por soñar(me) y contestar siempre, sin importar mis crisis y locuras. Finalmente, las gracias infinitas van hacia mi familia: a mi mamá por siempre estar ahi, y a Criss y a Carlos, los tres que son todo junto con los dos pilares de mi vida. No puedo dejar de agradecer a quien me inició en la computación. Y a pesar de todo, ‘por hacerme el paro’ en cualquier circunstancia y por el apoyo incondicional, gracias Joel. Un dia nos pidieron, como ejercicio, que describieramos el doctorado en tres palabras. A mi mente vinieron las palabras: desafío, introspección, constancia, resistencia y aprendizaje. Mi decisión de iniciar un doctorado fue motivado por la idea de aprender, de dar un paso más en el camino profesional, por la necesidad de compartir el conocimiento, pero no comprendí que este camino está hecho para convertirse en maestro de uno mismo. Después de estos cuatro años, definidos por autoaprendizaje y por ponerse a prueba constantemente, he aprendido más que sólo lo académico, la capacidad de asombro por cosas nuevas y por lo desconocido, pero sobre todo he aprendido el sentido de la amistad. 2. Gracias por corregir mi francés!
Contents 1 Introduction 1.1 λ-Calculus and Proof Assistants . . . . . . . . . . . . . . . . . . . . . . . . 1.2 This thesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Preliminaries and Notations . . . . . . . . . . . . . . . . . . . . . . . . . .
1 2 7 10
Lightweight proof by reflection
21
2 Proof by reflection 2.1 Reflection . . . . . . . . . . . . . . . . . . . . . . 2.2 Proof by computation . . . . . . . . . . . . . . . 2.3 Certifying proof by Reflection . . . . . . . . . . . 2.4 Discussion . . . . . . . . . . . . . . . . . . . . . . 2.5 Towards another approach to proof-by-reflection
. . . . .
21 24 25 26 27 28
. . . . . . .
31 33 35 36 46 50 52 55
3 Reflection by simulation 3.1 λM a purely functional monadic language . . . 3.1.1 Simulation . . . . . . . . . . . . . . . . 3.1.2 Meta-theory . . . . . . . . . . . . . . . . 3.2 λv,K a call-by-value impure functional language 3.3 A posteriori simulation of effects . . . . . . . . . 3.4 Examples of simulable monads . . . . . . . . . 3.5 Chapter conclusions . . . . . . . . . . . . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
. . . . .
. . . . . . .
Incrementality
61
4 Optimization via data-differences 4.1 Incremental computation . . 4.2 Incrementality . . . . . . . . . 4.3 Change description . . . . . . 4.4 Towards Incrementality . . .
61 61 67 68 74
. . . .
. . . .
. . . .
. . . .
ix
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
x 5 A deterministic differential lambda calculus 5.1 The λ´diff calculus . . . . . . . . . . . . . 5.2 Displaceable types . . . . . . . . . . . . . 5.3 Meta-theory . . . . . . . . . . . . . . . . . 5.3.1 Equivalence . . . . . . . . . . . . . 5.4 Soundness . . . . . . . . . . . . . . . . . .
CONTENTS
. . . . .
. . . . .
. . . . .
. . . . .
77 77 81 83 88 89
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
6 Recursion and Data-Types in λ´diff 6.1 Differentiation of multiple-argument functions . . . 6.2 Fixed-Points . . . . . . . . . . . . . . . . . . . . . . 6.3 Structural displacements over algebraic data-types 6.4 Examples . . . . . . . . . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
99 . 99 . 100 . 101 . 106
. . . . .
111 111 111 113 113 114
7 Closing remarks 7.1 λ´diff Related work . . . . . . . . . . . . . . . . . . . . 7.1.1 A theory of changes for Higher-Order Languages 7.1.2 Discussion . . . . . . . . . . . . . . . . . . . . . . 7.2 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . 7.3 Future work . . . . . . . . . . . . . . . . . . . . . . . . . Bibliography
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
117
Note: British English is used along this document, but some established nouns in literature come from American English.
Chapter 1 Introduction One of the principal and practical aspects of Computer Science is to give solutions to problems by computations through algorithms or programs. The computer scientist may see in the solution of abstract problems an opportunity for creativity, where once a solution is found the curious scientist takes the challenge further and seeks to improve it. Ideally, problem solving should obey a cycle of development and program improvement more or less as the following schema: a specification of the problem to be solved, a sketch of the solution, an implementation and finally, some optimisations to the solution or to the implementation in order to improve the performance. The optimisations may vary depending on the user and the desired behaviour. We are confident that they should not belong to an isolated phase at the end of the process, they must be included at different levels and stages of program design and implementation. Also, the development process should be directed by techniques and standards dedicated to obtain better solutions and to ensure that the final program indeed satisfy the specification, that it actually solves the problem. Furthermore, the design and implementation phases are guided not only by the specification but they are commonly influenced by the programming paradigm in which the solution will be carried out. A higher demand of software within a short developing time and the necessity of trustworthy programs with respect to their specification become more and more ubiquitous. In addition to this, the errors or program failures due to specification mismatch or encoding flaws should not be present in the implementation. We can argue that the above remarks can be alleviated by adding a phase of program verification to the development cycle, where a formal validation of the implementation should be carried out. In practice, the verification is substituted by a merely code test and is occasionally totally skipped from the development cycle. In order to ease the program verification, to amend the errors or even prevent them, we claim that any program development must be done in an environment which ensures the correctness of programs from the very process of design and creation. However, there exist a large number of computing paradigms, many different, some of them share certain qualities while other contrast the abstraction and understanding of programming. The user must choose the best among them, which offers convenient tools in order to perform reliable software developments.
1
2
CHAPTER 1. INTRODUCTION
To restrict the possible failures the programmer can make, some researchers and users support the functional paradigm as a safe development environment [53]. The confidence in functional programming languages has been largely considered, they offer a modular and high-level environment to create well-structured programs. They are closer to mathematics, and hence the program specifications can be verified rigorously and almost in a direct way. Furthermore, there is an increasing interest in providing a rigorous verification of programs, i.e., to validate that a program meets a specification through a formal and mechanised proof. This draws the attention to the recently called certified programming paradigm, a new concept of programming where the programs are correct by construction [29]. As functional programming, certified programming is a strict and elegant framework for abstraction, verification and coding, based on type theory. Through this introductory chapter, the reader will be immersed into the universe of theoretical aspects of programming languages leading to the certified programming paradigm which is the inspiration of the work and research done during my PhD. We give a brief reminder of the λ-Calculus and its relation with proof assistants, our contributions and some initial notations.
1.1
λ-Calculus and Proof Assistants
λ-Calculus is a model of computation, a formalism where functions are the central object of study. The original theory defined by Church in 1932, is a language to manipulate functions in its most pure and abstract form. Curry includes the notion of type for any lambda-expression in 1934, thus initiating the second most studied functional formalism. While the two models of calculus, Church and Curry, are sufficient for reasoning about functions in a general setting, there is a practical side where computability becomes a tangible task thanks to (abstract) machines. λ-Calculus inspired the first machines and their programming languages. Since then, there is a double encouragement between formal and practical aspects of the calculus, leading to more and more complex developments which raise to expressive theories and moreover, specialise a variety of programming languages [57, 91]. During the second half of the 20th century, the development of (typed) theories as formal frameworks to model many classes of programming languages, inspired more theories and promote implementations to realise the concept of computation. In particular, λ-Calculus is considered as the basis of functional programming [106]. This paradigm of computing is a theory also characterised as ‘pure and elegant’, in the sense that is considered as a high-level language where reasoning is clear and programs are easier to verify given the closeness to mathematics. As said before, the necessity of programs with fewer errors, developed in less time and with a high level of reliability, demands complex and specialised frameworks for software development. The more a program development is based and constructed following an accurate design, the more we will trust its reliance to the specification.
1.1. λ-CALCULUS AND PROOF ASSISTANTS
3
Thus, the formal approach of type theory in functional programming makes this paradigm a perfect environment to develop correct programs by construction. As a computational model, per se, the typed theories enable to reason about languages and their properties, bringing closer a formal verification. The Curry-Howard correspondence enables a direct construction of programs from a mathematical specification, it considers Type Theory as a language of proofs where solutions to problems are given through demonstrations of logical formulae. It is founded on two notions: a formula describes a calculation that is, a specification is given through a logical statement, and given a formula a proof of it can be decorated resulting in a program. Then, the correspondence between formulae and types, between proofs and programs, ensures that demonstrating a formula or finding an inhabitant of a type will deliver a program that satisfies its specification. This correspondence inspires many programming languages and also theorem provers or proof assistants. The latter are computer programs to help the verification of proofs. For an historical and accurate presentation of the propositions as types principle we refer the reader to the work of Wadler [112].
Foundations of Theorem Provers Scott presented in 1969 a formal language which served as an approach to denotational semantics for programming languages, this model was named Logic of Computable Functions (LCF). After this, Milner was inspired and proposed in 1972 a Logic for Computable Functions (also abbreviated as LCF), a theorem prover. This logic was refined and later in 1979 Milner together with Gordon and Wadsworth presented the Edinburgh LCF 1 , an interactive theorem prover along with its meta-language ML. The latter was conceived as a language to develop proof tactics in the theorem prover. While it was a functional and polymorphic language of the initial proposal, it evolved as a prominent programming language with imperative and sophisticated features. Two major implementations of the meta-language are SML and OC AML 2 . This was the beginning of the interactive theorem provers era, those systems that help users to make proofs while ensuring the correctness of them. Nowadays, they are just called theorem provers or proof assistants, while a more general name is proof management systems 3 . The original implementation of LCF included data-types to prove logic formulae: a type to denote a theorem (thm) which is a pair of conclusion and hypotheses, a validation which is a function from a list of theorems that implies the theorem to be demonstrated and a tactic is a function to transform goals. They are related as follows: 1. We will always make reference to Edinburgh LCF just as LCF. 2. The current implementations can be found in http://www.smlnj.org/ and http://ocaml.org/. 3. Inside the community of proof assistants, there is an indistinct use of proof assistants and theorem provers to refer to the same computational frameworks. The interactive adjective was added to denote an implicit feature of these systems which is nowadays essential. We continue to use them interchangeably.
4
CHAPTER 1. INTRODUCTION thm = form * form list goal = form * simplset * form list tactic = goal -> (goal list * validation) validation = thm list -> thm Figure 1.1 – LCF data-types
A tactic is a tool, a heuristic to transform a goal into a sequence of simpler goals using the information available in the context of the proof. It includes a validation which is a rule that mimics an hypothetical judgement, using the schema of premises and conclusion. When a tactic is applied to a goal, it replaces the current goal with the premises of the rule, to generate a list of new sub-goals to be proven together with a validation. The validation or witness of the tactic is maintained, is usually the name of the tactic. In this way, at the end of the proof, the witnesses and the order they were applied form a proofscript which will be checked. This process describes a user interaction with the theorem prover to direct the construction of a proof. A useful feature of the system is provided by a mechanism to combine and compose tactics, named then tacticals. Since tactics are functions, their composition through a tactical gives a higher-order tactic to ease the construction of complex proofs. It is also used to control how the current list of goals can be focused and merged. In the LCF theorem prover, a tactic can only be applied to the focused goal, this means that the global state of the system all along the proof is not tracked but used in each step of the proof. Despite the validations, an interpretation of a proof-script, outside the proofdevelopment is meaningless. Meanwhile, the spread of the above theories and the influence of the ideas in LCF together with a (philosophical) foundation of Martin-Löf in 1971 4 , as a system for intuitionistic or constructive proofs, inspired the modern theorem provers. The Martin-Löf Type Theory is an expressive typed λ-calculus, with a predicative type system, an infinite sequence of type universes and equality for types. Later, more expressive extensions of λ-calculus as the System F by Girard and Reynolds in the mid 1970’s formalised the polymorphism of ML. Then, in the beginning of 1980’s the work of Huet and Coquand set the foundations of a theory of dependent types called The Calculus of Constructions. Later, in 1985, the first implementation of the Calculus of Constructions appeared as a type-checker for lambda expressions. Together with this theory, other efforts of many researchers started pushing on the realisation of systems and languages to program efficient decision procedures and more ambitiously, to contribute to the first versions of a theorem prover based on the Calculus 4. Notes and transcriptions of lectures given by Martin-Löf are classical references: ‘On the meanings of the logical constants and the justifications of the logical laws’ and Intuitionistic Type Theory.
1.1. λ-CALCULUS AND PROOF ASSISTANTS
5
of Constructions 5 . In particular, the work of Paulin-Mohring, added some automation to the tactics. Later, she also extended the formal and practical way to describe data-types with inductive constructions and principles in the Calculus of Constructions. This gave the theoretical base of the modern C OQ, the The Calculus of Inductive Constructions.
Proof management systems A theorem prover based on Type Theory is an interactive system for symbolic manipulation guided by the user. Its central activity is to build proofs of theorems and to verify formal developments or what we call theories. Any theorem prover has a specification language and is usually composed of two independent parts: 1. a proof-development environment, to construct proofs interactively controlled by the user, and 2. a proof-checker, to verify the proof-term obtained at the end of a proof. The user gives definitions and properties, all the information needed by the system in order to support and develop a theory. As described before, while trying to demonstrate a statement or theorem, the proof assistant considers the statement as a goal. Then, a tactic breaks the goal into simpler sub-goals which in their turn have to be demonstrated. This process continues until the goals are facts easy to proof and finishes when there are no more goals to prove. Up to here, the proof construction process is managed by the first component of the theorem prover, the so-called proof engine. Finally, a composition of tactics gives a proof-script describing the construction of the proof. The proof-checker or type-checker is the implementation of the type theory in which is inspired the theorem prover, it is called the kernel. Then, constructing a proof is comparable with the inhabitant problem, where given a context and a type, then a proof or term is searched. Therefore, a final proof verification by the kernel is needed to ensure that the proof-term obtained is a well-typed term in the type theory. Any proof is type-checked when it is finished. The process generates a proof-term corresponding to the proof-script. We highlight the following facts of the LCF, as ancestor of the modern proof management or development systems like C OQ, I SABELLE, HOL, N UPRL, etc. They are also the result of deep analysis and implementation experiences of several authors [116, 9]: • Tactics are (deduction) rules associating premises to a conclusion. Some systems implement a backward reasoning, others use the forward reasoning. • The proof-scripts are just a sequence of tactics and system instructions: they are unstructured, sometimes heavy (depending on the user experience) and at the same time fragile since outside the proof, there is no current information to keep track of the proof and the context where a tactic was applied. This makes the proof sensitive to small changes. 5. A detailed history is available in the Notes on the prehistory of Coq http://github.com/coq/coq/ blob/beedccef9ddc8633c705d7c5ee2f1bbbb3ec8a47/dev/doc/README-V1-V5.
6
CHAPTER 1. INTRODUCTION • The Poincaré principle states that the proofs carried out in a proof assistant must be verified. A verification of a proof is done until it is completed, by the proof-checker. • The kernel must be reliable, since the proof verification depends on it. Hence the it is usually a small, isolated and human-certified program. This is called the de Bruijn criterion. • Some proof management systems allow that parts of proofs are achieved by computations. Then, there is no need of verification of those calculations. This is related with the computational power of the type theory on which is based the theorem prover offering great benefits.
Coq The C OQ proof assistant, defined nowadays as a formal proof management system, is a well-established interactive system for developing and checking proofs. It is based on a formal language: the Calculus of Inductive Constructions, a powerful type theory. It provides a framework where the user defines and elaborates theories, offering a safe, strict and formal environment to reason about them. The system helps the user through proofs while it can also generate automatic proofs because of its features to do proof-automation. The proof-terms obtained after the demonstration process are certified by the kernel of C OQ. The kernel is essentially a type checker which is the implementation of the Calculus of Inductive Constructions, it takes a term or proof which is treated as an inhabitant candidate for a type or formula. Thanks to the Curry-Howard correspondence, C OQ is also considered as a functional programming language since the proofs are lambda-terms. Moreover, as we said earlier, the type theory behind C OQ is highly expressive and there is always a way to perform computations at any level, that is, the convertibility of terms and types is ensured by the conversion rule which characterises the computation or reduction of them. Many contributors since then, have consolidated this influential framework for defining and formalising theories including a part of mathematics itself. For more historical details and implementation description of C OQ, the online documentation 6 can be consulted as well as the Coq’Art book [20]. Proofs in C OQ Theorem provers give confidence in the formalisation and the proofs carried out while developing a theory. Their evolution responds to user demands and each system must incorporate user creativity as (permanent) features. Therefore, expanding the mechanisms for proof development like extensions for tactics, facilities for programming or deduction reasoning are desirable. All the tools or techniques for alleviating the process of proof construction must be all sound. 6. http://coq.inria.fr/documentation/
1.2. THIS THESIS
7
The focus on providing an efficient environment while constructing and checking proofs has been largely explored. There are several parts that can be improved by the system developers, in order to get a better overall performance on proof management. As proposed by Milner, there should be a language support for writing new tactics in theorem provers that is, achieving efficiency of development by means of improving the tactic language. In C OQ we would like to build interactively proofs with more complex constructions and techniques for proof automation. To achieve this, there is a language for tactics named Ltac , proposed by Delahaye [36] to enrich the current tactic combinators. Formally, Ltac is a higher order language to design domain specific tactics. Nowadays, most of the provided tactics are definitions of such combinations of primitive tactics. However, one of the shortcomings of Ltac is that tactics used to construct proofs are unsafe 7 . This language can be improved by means of types for tactics as is suggested by Delahaye. Efficiency in theorem provers can also be gained by improving the machinery to guide and verify proofs, by means of improvements in the interaction with the kernel and the tactic engine. Improvements for system development have many contributions: libraries for specialised theories (see the list of users’ contributions 8 ), tactic languages to enhance the mechanisation of proofs [36, 118], improvements to the user back-end framework for example the asynchronous edition of proofs [17], interaction with other theorem provers to cooperate in a large developments, etc. All of this turns C OQ into a sophisticated programming language where the program development arises naturally, for instance the R USSELL extension [101] to develop programs with dependent types.
1.2
This thesis
We have highlighted that the functional paradigm provides a formal approach to programming and ensure correct programs. Unfortunately, it disregards to be used while solving low level problems or when incorporating imperative techniques to obtain efficient solutions. Besides, the effects offered by a low-level language, unavoidable when reaching the innermost practical aspects of computing, need to be studied and therefore incorporated in the models of pure lambda calculus to represent and to reason about programming mechanisms. The focus of this work is on formal techniques that extend the models of the simply typed lambda calculus, inspired by some practical motivations taken from the everyday programming, and with the aim to be applied in a system for formal proof assistance. Our goal is to reason about two improvements to be carried out in a total functional programming language: to verify the simulations of effects a posteriori and the optimization by incrementality through data-change description. 7. As pointed out in various works, there are disadvantages with the treatment of tactics inherited form LCF, for example the exhaustive comparison made by Harrison [47]. 8. https://coq.inria.fr/contribs/
8
CHAPTER 1. INTRODUCTION
The Paral-ITP project This work was supported mainly by the ANR project Pervasive Paralellism in Highly-Trustable Interactive Theorem Proving Systems. The project involves the interactive theorem provers I SABELLE and C OQ and its main goal is to overcome the sequential model of both proof assistants to make the resources of multi-core hardware available in large proof developments 9 . The project proposal stated a PhD student to work towards the conception and study of a formal repository based on Logical Frameworks (LF) [46]. The formal repository, also named the prover repository, was planned as an entity which must be highly sensitive to handle the dependencies between different versions of terms. All actions performed over the repository must be logically sound: history management and operations like finegrained requests and the propagation of (non-sequential) changes must ensure a sound control of formal content. The above ideas originate the research reported in this thesis where its concrete and future goal is to obtain a certified type-checker for C OQ. This is a bigger project which can be divided in two parts, the first to improve or make a new proposal for a tactic language and the second to achieve the formalization of a prover repository. The idea of a formal repository depends on the design of a typed language for tactics, which will provide safe proof-scripts in order to facilitate their use and control within the repository. A dependent type theory, as LF or the Calculus of Inductive Constructions, could serve as a robust theory for a formalization of the repository and its operations as suggested by the project proposal. While the rigorous frameworks of LF and VeriML [102] can be the basis for the formal repository, we chose another line of investigation where research was conducted in the direction to define a typed language to improve the tactic language of C OQ. This results in a proposal of an effectful language to write decision procedures whose formalization will be elaborated in the first part of this thesis. One of the project’s main goals described above seeks to improve C OQ by giving a new way of certification of proof-terms to be used in the repository. We chose to start the research towards the improvement of proof-development by setting an incremental framework, which one future application will allow the incremental construction and certification of proofs. The incremental flavour is inspired by a new model of computation where programs automatically respond to changes in their data. A recent paradigm supporting incrementality is the so-called self-adjusting computation which uses several techniques to write self-adjusting programs as normal programs. The second part of this thesis introduces a language where incremental computations are part of the evaluation process. The ideas of changeable data and incrementality could lead a formal repository, in where fragments or complete proof-terms, which are already certified, are stored in order to improve the type-checking process. As we said, this work is pretended to be done in collaboration of a typed language for C OQ’s tactics to construct safe proof-terms throughout the proof development process. The contribution of this thesis states an initial theoretic support to the formal repository, a long term goal to be elaborated in the future. In the following, we briefly describe 9. For more information visit http://www.lri.fr/~wolff/projects/ANR-Paral-ITP/.
1.2. THIS THESIS
9
the contributions which are focused on providing methods for reasoning within effect simulation and incrementality in the simply typed lambda calculus.
Cybele: lightweight proof by reflection This work conciliates imperative features in the pure and total theory of C OQ by adding effects through monads like in purely functional approaches. This enhancement allows the user to write efficient and trustworthy programs in a certifying environment. Moreover, since in theorem provers the construction of proofs (or programs) can be simplified by performing computations at type level, the enhancement is used in proof development using the reflection technique. The joint work with Yann Régis-Gianas, Guillaume Claret and Beta Ziliani states a way to describe effectful decision procedures. The main idea is to use an untrusted compiled version of a monadic decision procedure written in Type Theory within an effectful language as an efficient oracle for itself. The evaluation of decision procedures is executed with the help of what we call a prophecy, acquired by the execution of an instrumented code in an impure programming language (OC AML). The prophecy is a small piece of information to efficiently simulate a converging reduction in Type Theory. This work is the Cybele project 10 which results in a new style of proof by reflection characterised by a lightweight simulation of effectful programs. The contribution described in this thesis, is to analyse and state the requirements of simulation by studying the relation between two languages, one representing Type Theory without effects and the other representing a general purpose effectful language. The notion of a posteriori simulation is the main support on which rests a new style of proof-by-reflection. A formalisation of the lightweight approach to proof by reflection enables an extension of the lambda calculus with monads and an operator to simulate computations.
Incrementality Among the computational optimizations, an intuitive technique is to avoid repeated computations by data re-use. Incremental computation as a programming paradigm, takes advantage of similar computations in order to reduce the costs. The incrementality can be achieved in several ways and can be present in explicit program transformations or in implicit features of some program developments. An analysis of many efforts to add incrementality in computations leaded to propose a functional approach by a differential treatment of data and programs, that is a combination of a change theory for data dissection and a formal language for program differentiation. The contribution to incremental computation is achieved by dynamic differentiation of functions to take advantage of computed results from old program inputs and function differentials. It is inspired in the differential lambda calculus [38] and in a typedirected change description. A new system meeting these ideas, λ-diff, is defined and of10. Visit http://cybele.gforge.inria.fr/.
10
CHAPTER 1. INTRODUCTION
fers to the user the ability to reason about fine-grained input changes which are reflected into efficient computed results. The computation by means of a gradual and steady subcomputations, led by smooth input transformations. The language λ-diff, exposed in this thesis, is a framework for analysis and reasoning about incremental computation and is not intended to be an optimal implementation of incrementality.
Thesis Organisation Following the above topics, the thesis is organised in two main parts, one for reflection by simulation (Chapters 2 and 3) and one for incrementality (Chapters 4 to 7). Each part is self-contained, however the foundations of both are commented in the next section for preliminary theoretical concepts.
1.3
Preliminaries and General Notations
In this section, we present some basic notions to level the knowledge of the reader with the concepts used through this work. Other concepts are more common to be included as background, such as the formal system which is the base for the languages in this work, the simply typed λ-calculus 11 . Nevertheless, the chapters in this work are selfcontained and in what follows, we restrict ourselves to present a brief description where some statements of properties are given without their proofs.
Relations Given a set S, a binary relation R is a collection of pairs of elements in S, we use an infix notation for relations. Given a relation R we say that R˚ is the reflexive and transitive closure of R. The notation e is used to denote a finite sequence or a vector of elements e0 e1 . . . en where n ě 0. The length of a vector is the number of its elements. If a function F is defined over e then we abusively write F peq for the pointwise extension of F to a sequence of elements.
Simply typed lambda calculus λ-calculus as an abstract system to represent and perform computations is a model which was first formulated as a pure theory, now distinguished as the untyped lambda calculus. It is composed by variables, abstractions or functions, and applications of terms. There are no constants nor any other primitives. The terms created under these three basic elements are infinitely many and some of them are not adequate for characterising the solution to a given problem, for instance consider an application of a function with the wrong type of arguments. 11. The conventional references are: H. Barendregt [12, 13, 14], B. Pierce [92], R. Harper [45], among others [11] who traditionally recall the pillars of the programming language theory.
1.3. PRELIMINARIES AND NOTATIONS
11
We want to get rid of those terms in order to prevent misbehaviours while encoding programs. Therefore, imposing syntactical restrictions to the terms in order to reduce the non-sense terms or wrong constructions, gives an accurate system where simple types limit the terms to those which make sense to compute. This idea was coined by Milner in the famous phrase ‘Well typed programs do not go wrong’. Simply typed λ-Calculus, à la Church, is the language generated by the constructions in the grammar of Figure 1.2 whose principal syntactic classes distinguish terms and types. The terms are built up from typed variables, lambda abstractions binding a single variable to a body sub-term and applications of a left sub-term to a right sub-term. The types include abstract basic types denoted by ι and the functional-type with hypothesis σ and conclusion τ types. The third syntactic class encompasses the class of typing contexts which are collections of all distinct typed variables. Syntax t, r, s ::“ x | λxσ . s | r s τ, σ ::“ ι | σ Ñ τ
Γ ::“
∅
| Γ, xτ Static Semantics
xτ P Γ VAR Γ$x:τ
Γ, xσ $ s : τ A BS Γ $ λxσ . s : σ Ñ τ
Γ$r:σÑτ Γ$s:σ A PP Γ $ rs : τ
Figure 1.2 – Simply Typed Lambda Calculus
Static semantics We choose to present first the static semantics, that is the rules for type assignation, to give to the reader an attachment to a notion that will be implicit in this work, the treatment of well-typed terms. The static semantics are typing judgements relating terms to types under typing contexts. The judgement Γ $ t : τ is read as ‘the term t has type τ under the context Γ’ and the rules are defined inductively on the form of terms. A variable carries her own type and a lambda abstraction has a function-type constructed with the type of the linked variable and the type of the body sub-term. The type of an application results from the types of its sub-terms: if the left sub-term has a function-type and the right sub-term agrees with the type of the hypothesis then, the type of the application is the conclusion type of the function-type. Notation A lambda abstraction is generalised to multiple binding: λx0 . λx1 . . . . λxn . t “ λx0 , . . . , xn . t “ λx. t. The syntactic equality between elements is denoted by “. A multi-argument function is represented in a curried form if its arguments are expected one by one that is, the function is a chain of λ-abstractions. The uncurried version of the multi-argument function expects all the arguments in a tuple.
12
CHAPTER 1. INTRODUCTION
Operations Operations over terms are essential for reasoning, here we present the operations used in this work. Each of these definitions can be extended according to the new elements of the corresponding system extensions addressed in later chapters. Definition 1.1 (Free and Bound variables) The set of free variables of a term FV ptq is defined inductively: FV pxτ q FV pλxσ . sq FV pr sq
def
“ txτ u def “ FV psq ztxσ u Ť def “ FV prq FV psq
Bound variables are those which are not free. Definition 1.2 (α-equivalent terms) Any two terms are α-equivalent if they are syntactically equal up to the renaming of their bound variables. Definition 1.3 (Substitution) The substitution of a variable by a given term in another term is defined inductively, a renaming of bound variables in λ-abstractions is considered before the substitution. x rx y rx σ pλy . sq rx pr sq rx
:“ :“ :“ :“
ts ts ts ts
“ “ “ “
t y λy σ . s rx :“ ts where x ‰ y r rx :“ ts s rx :“ ts
Dynamic semantics The concept of computation is realised by means of input processing by applying functions. There are two main ways to describe the process of obtaining outputs: by a precise description of every computation made until an irreducible expression is reached, named a reduction relation between two terms; or a description of the values obtained at the end of the process, named an evaluation of a term. A value is an object which cannot be reduced any more, it is impossible to apply at least one more reduction step. The collection of values is a syntactic class, distinguishing those objects form the rest of terms in the grammar defining the language. In the case of the simply typed lambda calculus, the values are the abstractions, but for instance in a calculus including the natural numbers as primitives, the numbers and constant functions are also values. A normal form is also a term on which it is not possible to make progress, that is, there does not exist a term t1 from which a given t is reduced by a stepping rule. The collection of normal forms is a semantic distinction between terms, it is defined by a proposition and not directly in the syntax as the definition of values. The two notions of dynamic semantics, for a call-by-value strategy, are formalised by small-step semantics and big-step semantics whose respective rules appear in Figure 1.3.
1.3. PRELIMINARIES AND NOTATIONS
13 Small-step semantics
v ::“ λxσ . s β- RED
R ED
pλxσ . sq v ÝÑ s rx :“ vs T RANS
E ::“ r s | v E | E t t ÝÑ t1 Erts ÝÑ Ert1 s
R EFL
t ÝÑ˚ t
t1 ÝÑ t2 t2 ÝÑ˚ t3 t1 ÝÑ˚ t3 Big-step semantics
v ::“ pλxσ . sq rηs
η ::“
η $ r ó pλxσ . tq rη 1 s η $ λxσ . s ó pλxσ . sq rηs
‚
| η ; x ÞÑ v
η$sóu η $ rs ó v
η 1 ; x ÞÑ u $ t ó v
Figure 1.3 – Dynamic Semantics for a call-by-value strategy.
The small-step semantics reduces a term by making explicit each computation. The use of evaluation contexts η, emphasizes the reduced expression or redex in the term. The contexts and reduction rules define the call-by-value strategy of reduction, where each term has a left-to-right order of reduction and the β-reduction makes progress simplifying a function: introduces an input value in the body-term of the function by using the substitution operation. A full reduction of a term is obtained after applying exhaustively the reduction rules and it is defined by the reflexive and transitive closure of reduction (ÝÑ). The big-step operational semantics makes use of an environment η, a partial function from variables to values. The values in this calculus are functions that depend on the context that is, they are λ-abstractions all along with its current environment of evaluation rηs, called closures. We write η $ t ó v where ó relates a term t and a value v under a given environment η whose domain is the set of free variables in t. The relation is defined inductively over terms: a variable is evaluated to its corresponding value in the environment, a lambdaabstraction is evaluated to a closure and the evaluation of an application rests in the evaluation of the function-body of its left sub-term under an extended environment with the value of the right sub-term evaluation. It is possible to recover from small-step semantics the big-step semantics, and vice versa, that is they are equivalent by means of value-ending chains of reductions using ÝÑ˚ in the former semantics and the ó relation in the latter.
14
CHAPTER 1. INTRODUCTION
Properties Simply typed λ-calculus enjoys many properties derived from the semantic relations. From type assignation, the traditional lemmas of inversion of typing and uniqueness of types to ensure well-typed terms. Together with small-step semantics we have the properties of determinism and subject reduction also known as type preservation. Each extension of λ-calculus used in this work contains the corresponding statements and proofs for these properties, they are stated and proved in the appropriate places in future sections. Logical Relations Logical relations can be defined as predicates to describe properties of terms. We follow the notation of logical relations used by Ahmed [8] and we make some recalls to conduct the reader toward the work of Reddy et al. [49] who stress the closer relation between logical relations and Reynolds work on parametricity. The last authors consider the logical relations and parametricity as a more general form of abstraction which enables information hiding through the structure over which the relation is defined. One of the applications of logical relations is the proof of meta-level theorems [97]. Most of the applications are adopted to prove theorems of type theory where the (traditional) method of proving by induction over one syntactical structure as terms, types or judgements do not give strong enough induction hypotheses. There are different choices between languages on which interpret a type theory, referred also as the object language. One useful choice is to take the same type theory as meta-language. Other choices consider the set interpretation of types or a domain interpretation. The case of set theory as meta-theory interprets the type theory as: JιK “ X
for each basic type and a given set X
Jσ Ñ τ K “ JσK ùñ Jτ K
In order to have more logical relations than just a set and Śfunction Řspaces ùñ, we add some relation operators like the set operators: product , sum , power set P, p predicates Q, among others. On the one hand, logical relations do not require to compose, but in the other hand they could have a mapping operation known as parametric transformation [49]. The logical relation approach to proofs is a two step procedure. The first step is to define a logical relation adapted to the target type theory and to the property to demonstrate. This is done inductively by defining a type-indexed family of relations. In the case of a theory of the simple typed lambda calculus, we consider that any logical relation at least must detail and extend the following definition: Definition 1.4 (Logical Relation) A logical relation is a family of type-indexed n-ary relations R “ tRτ u such that the terms of a n-tuple have the same type and • if τ is a basic type ι, then Rι Ď JιKn
• if τ is a function type, then RσÑτ pr1 , . . . , rn q if and only if for all n-tuples ps1 , . . . , sn q, if Rσ ps1 , . . . , sn q then Rτ pr1 s1 , . . . , rn sn q.
1.3. PRELIMINARIES AND NOTATIONS
15
Logical relations are defined strictly following the structure of types and this structure is reflected and preserved in the relation. In other words, the above definition and extensions of it comprises the well-typing of a term, a condition for a term to has the property of interest and a condition to ensure that the logical relation is preserved by evaluation of elimination forms. The second step is to show the completeness and soundness of the logical relation: that any well-typed term of the theory belongs to the relation and that any element which belongs to the relation has the desired property. Lemma 1.1 (Completeness of a Logical Relation) Consider a well-typed term, Γ $ t : τ , then Rτ ptq. Lemma 1.2 (Soundness of a Logical Relation) Any term such that Rτ ptq has the property characterised by the relation.
Coq As commented before, the Curry-Howard correspondence is a principal paradigm on which C OQ is based. The constructive logic which used by C OQ is the Calculus of Inductive Constructions. This calculus has only one syntactic category for types and terms 12 : t, r ::“ s |x|c|C|I | @xt .t | λxt . r | let x “ r in t | t r | case t of r0 . . . rn | fix x txr : y :“ tu
sort identifiers elimination recursion
There are three sorts in the calculus: Prop, Set and Type, which represent the propositional or logical level of the language and the hierarchical universes of types, respectively. The sort Type has an enumeration according to the type level needed in the theory. The identifiers give the global definitions of the language and are included in contexts when doing proofs. The identifiers are variables and names for constants, constructors and types. Together with the third syntactic category built the terms of the language. The computational terms include the product @ which is an upper-level abstraction for function definition while the other terms are the usual constructions for abstraction, term application and local definitions (let). The elimination form case, goes together with the inductive definitions introduced by constants I. Finally, another elimination form is recursion and is performed by a fix-point term. A context, while constructing a proof, includes hypotheses as variables x : t, definitions of constants c :“ t : r and inductive declarations I pΓI :“ Γc q where the context ΓI contains the inductive types and Γc the corresponding constructors. Any term in this calculus has a type and the evaluation always terminates. This condition is continuously verified syntactically by the system through the positive requirement 12. We follow the presentation used by Letouzey [61] and the CIC language description in the reference manual: http://coq.inria.fr/distrib/current/refman/.
16
CHAPTER 1. INTRODUCTION
for types and by well-founded definitions for elimination forms. The recursive calls must show a clear use of the function over a sub-component of the parameter. The dynamics of the calculus, the reduction of terms, is done mainly by a strong callby-value strategy. This kind of reduction differs from the one described previously in our presentation of λ-Calculus, since in the Calculus of Inductive Constructions the reductions are carried out pervasively. This means that the body-terms of λ-abstractions are likely to be reduced. The system provides other reductions as the ι, δ, ζ or η reduction rules, each one to reduce respectively: inductive terms, definitions, let-terms and to permorm the η-expansion of the λ-calculus. The whole combination of these rules defines the conversion rule stating that two expressions are equivalent t ” s. The relation t ” s is read as t is convertible with s and is a reflexive, symmetric and transitive relation over the above strong reduction rules. Then, two terms are convertible or equivalent if they are reduced to identical terms or are convertible up to η-expansion: C ONV
Γ$U:σ
Γ$t:T Γ $ T ”βδιζη U Γ$t:U
where the relation ”βδιζη represents the set of reduction rules in the language.
Monads The purely functional approach reviewed up to this point does not allow a representation of computational effects as memory location, perform input/output, error handling or exceptions, non-determinism, etc. The monadic approach to functional programming proposed by Moggi [76] offers an extension and interpretation of a λ-Calculus to represent computations by abstracting a program logic inside a structure. The data-type constructor M τ represents computations that will produce a value of type τ . It consists of two operations, one named the unit operation to encapsulate an expression as a trivial computation and another operation to perform and compose computations named bind . These operations allow to explicitly describe sequential computations. A single effect is an instance of a monad which needs a specific definition for the two operations of unit and bind . Any monad holds the three monadic laws characterising the equivalences between computations. In Figure 1.4 is depicted the extension of λ-Calculus with the terms for monads. The dynamic semantics uses the strong reduction where the values include unit terms. References in the literature of monads include the work of Wadler [111, 113]. The success of this theoretical approach is used in practice in several (functional) programming languages to ease a structured programming, such as in H ASKELL [65, 81]. In this language, the operations unit t and bind r s are written return t and r >>= s respectively. Using the type-class abstraction for polymorphism, to regroup types and manage overloading of functions, the Monad class describes four monadic operations:
1.3. PRELIMINARIES AND NOTATIONS
17 Syntax E ::“ ¨ ¨ ¨ | unit E | bind E s | bind v E
t, r, s ::“ ¨ ¨ ¨ | unit t | bind r s v ::“ ¨ ¨ ¨ | unit v τ, σ ::“ ¨ ¨ ¨ | M τ
Static Semantics Γ$t:τ U NIT Γ $ unit t : M τ unit
Γ $ r : Mσ Γ $ s : σ Ñ Mτ B IND Γ $ bind r s : M τ Dynamic Semantics
C OMP
bind punit vq pλxσ . sq ÝÑ s rx :“ vs Monadic Laws bind punit tq r “ r t bind t pλxσ . unit xq “ t bind pbind t sq r “ bind t pλxσ . bind ps xq rq Figure 1.4 – Monads
class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a Any instantiation must declare the definition of the >== operation. Also, the popular do-notation is used to give structure to monadic programs. This is a syntactic sugar to hide the details of bind-applications and to make clear the compositions. For instance the term bind t1 (\x -> bind (f x) (\y -> return y)) can be rephrased as: do x = k Nothing >>= _ return fail _
CHAPTER 1. INTRODUCTION where = k x = Nothing = Just = Nothing
The one-effect representation by one monadic type can be generalised into a multipleeffect monad by the combination of effects using monad transformers. It is a type constructor that takes a monad and returns a new monad by ‘lifting’ the monad, it is defined in H ASKELL also as a type-class: class MonadTrans t where lift :: (Monad m) => m a -> t m a This generalisation is done by taking an existing monad m, and encapsulating the type into another monad t. For the Maybe type, the monad transformer is defined by encapsulating the optional value inside the monadic argument m: newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } instance Monad m => Monad (MaybeT m) where return = MaybeT . return . Just x >>= f = MaybeT (do maybe_value return Nothing Just value -> runMaybeT (f value)) instance MonadTrans MaybeT where lift m = MaybeT (liftM Just m)
Lightweight proof by reflection using a posteriori simulation of effectful computation
19
Chapter 2 Proof by reflection Among the problems a computer scientist faces to, there are those whose solution is achieved by deciding if an object has a property or not, that is where the computations are focused to produce a ‘yes’ or ‘no’ answer for a given statement 1 . For instance, consider the following problem: Congruence problem Given a set S of equivalent terms si „ sj , determine whether or not two given elements s and s1 are equivalent from set S. The word equivalent refers to the fact that a pair of objects are considered as equals because they share the same properties or have the same behaviour under a specific scenario, not only because they could have the same form or syntax. This problem does not examine the properties of the objects but just the fact that they are related, in order to decide if a given equivalence follows from a set of equivalences. The meaning of equality between elements arises when we can relate them directly by definition, that is when s „ s1 belongs to S, or because we can go from s to s1 by passing through some equivalences in S. This is better known as the Leibniz equality, the ability of substituting equals by equals. Then, we say that the equivalence s „ s1 follows from S when a path between the elements s and s1 is found. The notion of paths is derived from considering the relation „ as an equivalence relation: any element is equal to itself (reflexivity), if two elements are equal s1 „ s2 , then they are also related the other way around s2 „ s1 (symmetry) and given two equal elements and one of them is equal to a third one, then the first element is equivalent to the third element: s1 „ s2 and s2 „ s3 then s1 „ s3 (transitivity). A popular and efficient solution to this problem is achieved by computing the equivalence closure of the set of equivalences using the union-find algorithm due to Tarjan et al. [37, 105, 104]. This method computes the equivalence classes of the set S and then decide if the representatives of the classes of terms s and s1 are the same. It is based on two principal operations: one to merge two equivalence classes, by unifying the representatives of the classes named the union operation, and a second operation named find, to search for the representative of the class of a given element. Hence, this algorithm is called the union-find algorithm. 1. We are not considering decision problems like the Halting Problem, nor even problems in the spirit of Logic Programming.
21
22
CHAPTER 2. PROOF BY REFLECTION
There are many variations, abstractions and applications inspired on the couple unionfind leading to efficient implementations. A range of problems get better run time when solved by computing a closure, and also the so called disjoint-set data structures, to maintain a structure for the elements and their representatives, lead to better data handling ([78] and [35], chapters 22 and 24). Let us analyse some possible implementations of the intuitive solution of path finding for the equivalence problem. The following is a first and very naive pseudo-code approximation of the algorithm described above. is_equivalent(S, ) : Bool C := singleton(S) while C != S do A := C for in S do union(C,si,sj) S := A return (find(C,s) == find(C,s’)) The function is_equivalent expects two arguments, the set of equivalences together with the pair of elements to be tested, and it returns a boolean value. We start by creating an initial closure where each element is its own representative, this is achieved by the function singleton 2 . Then we have a while-loop to compute the closure of S, guarded by the comparison between the actual closure C and the previous one S. The union function computes the representatives and we use it to create a new closure at each iteration. The loop stops when the closure does not change after the union operation. Then, the closure is C and we can verify if the representatives of the elements s and s’ are the same or not by comparing the results of the find function. To implement this pseudo-code, the programmer may expect a comfortable way to bring an optimal implementation where coexist all the benefits and components of effectful and imperative languages. For instance features as control-flow operators and a global state, where a specialised data-structure is available to maintain the elements of S together with their representatives. A ‘more elegant’ implementation is possible by means of functional program with effects, a development admissible using a monadic extension of the language, as H ASKELL offers. Here is another pseudo-code, similar to the one given above: is_equivalent :: Monad m => a -> a -> UnFndST a m Bool is_equivalent S (s, s’) = do x \y -> union x y) S u