=Paper=
{{Paper
|id=Vol-1186/paper-20
|storemode=property
|title=Certified Proofs in Programs Involving Exceptions
|pdfUrl=https://ceur-ws.org/Vol-1186/paper-20.pdf
|volume=Vol-1186
|dblpUrl=https://dblp.org/rec/conf/mkm/DumasDER14
}}
==Certified Proofs in Programs Involving Exceptions==
Certified proofs in programs involving exceptions Jean-Guillaume Dumas1 , Dominique Duval1 , Burak Ekici1 , and Jean-Claude Reynaud2 1 Laboratoire J. Kuntzmann, Université de Grenoble. 51, rue des Mathématiques, umr CNRS 5224, bp 53X, F38041 Grenoble, France, {Jean-Guillaume.Dumas,Dominique.Duval,Burak.Ekici}@imag.fr. 2 Reynaud Consulting (RC), Jean-Claude.Reynaud@imag.fr. Abstract. Exception handling is provided by most modern program- ming languages. It allows to deal with anomalous or exceptional events which require special processing. In computer algebra, exception han- dling is an efficient way to implement the dynamic evaluation paradigm: for instance, in linear algebra, dynamic evaluation can be used for ap- plying programs which have been written for matrices with coefficients in a field to matrices with coefficients in a ring. Thus, a proof system for computer algebra should include a treatement of exceptions, which must rely on a careful description of a semantics of exceptions. The categorical notion of monad can be used for formalizing the raising of exceptions: this has been proposed by Moggi and implemented in Haskell. In this pa- per, we provide a proof system for exceptions which involves both raising and handling, by extending Moggi’s approach. Moreover, the core part of this proof system is dual to a proof system for side effects in imperative languages, which relies on the categorical notion of comonad. Both proof systems are implemented in the Coq proof assistant. 1 Introduction Using exceptions is an efficient way to simultaneously compute with dynamic evaluation in exact linear algebra. For instance, for computing the rank of a matrix, a program written for matrices with coefficients in a field can easily be modified by adding an exception treatment in order to be applied to a matrix with coefficients in a ring: the exception mechanism provides an automatic case distinction whenever it is required. The question that arises then is how to prove correctness of the new algorithm. It would be nice to design proofs with two levels, as we designed the algorithms: a first level without exceptions, then a second level taking the exceptions into account. In this paper, we propose a proof system following this principle. Exceptions form a computational effect, in the sense that a syntactic expres- sion f : X → Y is not always interpreted as a function Jf K : JXK → JY K (where, as usual, the sets JXK and JY K denote the interpretations of the types X and Y ). For instance a function which raises an exception can be interpreted as a function Jf K : JXK → JY K + Exc where Exc is the set of exceptions and “+” denotes the disjoint union. In a programming language, exceptions usually differ from errors in the sense that it is possible to recover from an exception while this is impossible for an error; thus, exceptions have to be both raised and handled. The fundamental computational effect is the evolution of states in an im- perative language, when seen from a functional point of view. There are several frameworks for combining functional and imperative programming: the effect systems classify the expressions according to the way they interact with the store [11], while the Kleisli category of the monad of states (X × St)St (where St is the set of states) also provides a classification of expressions [14]; indeed, both approaches are related [20]. Lawvere theories were proposed for dealing with the operations and equations related to computational effects [16,12]. An- other related approach, based on the fact that the state is observed, relies on the classification of expressions provided by the coKleisli category of the comonad of states X × St and its associated Kleisli-on-coKleisli category [4]. The treatment of exceptions is another fundamental computational effect. It can be studied from the point of view of the monad of exceptions X + Exc (where Exc is the set of exceptions), or with a Lawvere theory, however in these settings it is difficult to handle exceptions because this operation does not have the required algebraicity property [17,18], in contrast with raising exceptions, looking up and updating states. This makes exceptions much more difficult to formalize than other effects in the Lawvere theory framework. This issue has been circumvented in [19] in order to get a Hoare logic for exceptions, in [13] by using both algebras and coalgebras and in [18] by introducing handlers. The for- malization of exceptions can also be made from a coalgebraic point of view [10]. In this paper we extend Moggi’s original approach: we use the classification of expressions provided by the Kleisli category of the monad of exceptions and its associated coKleisli-on-Kleisli category; moreover, we use the duality between states and exceptions discovered in [3]. However, it is not necessary to know about monads or comonads for reading this paper: the definitions and results are presented in an elementary way, in terms of equational theories. In Section 2 we give a motivating example for the use of exceptions as an efficient way to compute with dynamic evaluation in exact linear algebra. Then in Section 3 we define the syntax of a simple language for dealing with exceptions. The intended denotational semantics is described in Section 4: we dissociate the core operations for switching between exceptions and non-exceptional values, on one side, from their encapsulation in the raising and handling operations, on the other side. In Section 5 we add decorations to the syntax, in order to classify the expressions of the language according to their interaction with the exceptions. Decorations extend the syntax much like compiler qualifiers or specifiers (e.g., like the throw annotation in C++ functions’ signatures). In addition, we also decorate the equations, which provides a proof system for dealing with this decorated syntax. The main result of the paper is that this proof system is sound with respect to the semantics of exceptions (Theorem 1). A major property of this new proof system is that we can separate the verification of the proofs in two steps: a first step checks properties of the programs whenever there is no effect, while a second step takes the effects into account via the decorations. 2 Several properties of exceptions have been proven using this proof system, and these proofs have been verified in the Coq proof assistant. 2 Rank computations modulo composite numbers Rank algorithms play a fundamental role in computer algebra. For instance, computing homology groups of simplicial complexes reduces to computing ranks and integer Smith normal forms of the associated boundary matrices [6]. One of the most efficient method for computing the Smith normal form of such boundary matrices also reduces to computing ranks but modulo the valence, a product of the primes involved in the Smith form [7]. Now rank algorithms (mostly Gaussian elimination and Krylov based methods) work well over fields (note that Gaussian elimination can be adapted modulo powers of primes [7, §5.1]). Modulo composite numbers, zero divisors arise. Gauss-Bareiss method could be used but would require to know the determinant in advance, with is more difficult than the valence. The strategy used in [7] is to factor the valence, but only partially (factoring is still not polynomial). The large remaining composite factors will have very few zero divisors and thus Gaussian elimination or Krylov methods will have very few risks of falling upon them. Thus one can use dynamic evaluation: try to launch the rank algorithm modulo this composite number with large prime factors and “pretend” to be working over a field [8]. In any case, if a zero divisor is encoutered, then the valence has been further factored (in polynomial time!) and the algorithm can split its computation independently modulo both factors. An effective algorithm design, here in C++, enabling this dynamic evaluation with very little code modification, uses exceptions: 1. Add one exception at the arithmetic level, for signaling a tentative division by a zero divisor, see Fig. 1. inline Integer invmod(const Integer& a, const Integer& m) { Integer gcd,u,v; ExtendedEuclideanAlgorithm(gcd,u,v,a,m); if (gcd != 1) throw ZmzInvByZero(gcd); return u>0?u:u+=m; } Fig. 1. Throwing an exception upon division by a non unit 2. Catch this exception inside the rank algorithm and throw a new exception with the state of the rank iteration, see Fig. 2 (in our implementation the class zmz wraps integers modulo m, the latter modulus being a static global variable). 3. Then it is sufficient to wrap the rank algorithm with a dynamic evaluation, splitting the continuation modulo both factors, see Fig. 3. 3 try { invpiv = zmz(1) / A[k][k]; } catch (ZmzInvByZero e) { throw GaussNonInvPivot(e.getGcd(), k, currentrank); } Fig. 2. Re-throwing an exception to forward rank and iteration number information void DynEvalRank(RankPairs& vectranks, size t addedrank, ZmzMatrix& A) { try { long rank = gaussrank(A); // in place modifications of A vectranks.push back(RankPair(rank+addedrank, zmz::getModulus()) ); } catch (GaussNonInvPivot e) { // Split long mymodulus1 = zmz::getModulus()/e.getGcd(); long mymodulus2 = zmz::getModulus()/mymodulus1; // Homomorphism on the (n-k)×(m-k) remaining block zmz::setModulus( mymodulus1 ); ZmzMatrix M1(A,e.getIndex(),e.getIndex()); DynEvalRank(vectranks, e.getCurrentRank(), M1); // Homomorphism on the (n-k)×(m-k) remaining block zmz::setModulus( mymodulus2 ); ZmzMatrix M2(A,e.getIndex(),e.getIndex()); DynEvalRank(vectranks, e.getCurrentRank(), M2); }} Fig. 3. Recursive splitting wrapper around classical Gaussian elimination, packing a list of pairs of rank and associated modulus. The advantage of using exceptions over other software design is twofold: first, throwing an exception at the arithmetic level and not only on the inverse call in the rank algorithm allows to prevent that other unexpected divisions by zero divisors go unnoticed; second, re-throwing a new exception in the rank algorithm allows to keep its specifications unchanged. It also enables to keep the modifica- tions of rank algorithms to a minimum and to clearly separate normal behavior with primes from the exceptional handling of splitting composite moduli. In the following, we propose a proof system with decorations, so that proofs can easily be made in two steps: a first step without exceptions, that is, just preserving an initial proof of the rank algorithm; then a second level taking the exceptions into account. 4 3 Syntax for exceptions The syntax for exceptions in computer languages depends on the language: the keywords for raising exceptions may be either raise or throw, and for handling exceptions they may be either handle, try-with, try-except or try-catch, for instance. In this paper we rather use throw and try-catch. The syntax for dealing with exceptions may be described in two parts: a basic part which deals with the basic data types and an exceptional part for raising and handling exceptions. The language we develop is quite close to the Ynot language [15]. Like Ynot, our approach is ”a generalization of the well-known ideas from type-and-effect systems and their monadic counterparts”. However, we can use comonads as well as monads, and we offer more modularity: in Ynot there is a single monad encompassing all effects, while we are able to compose effects, thus enabling to prove programs in several simpler stages. The basic part of our syntax is a signature Sig base , made of types (or sorts) and operations. The exceptional types form a subset T of the set of types of Sig base . For instance in C++ any type (basic type or class) is an exceptional type, while in Java there is a base class for exceptional types, such that the exceptional types are precisely the subtypes of this base class. Now, we assume that some basic signature Sig base and some set of exceptional types T have been chosen. The signature Sig exc for exceptions is made of Sig base together with the operations for raising and handling exceptions, as follows. Definition 1. The signature for exceptions Sig exc is made of Sig base with the following operations: a raising operation for each exceptional type T and each type Y : throwT ,Y : T → Y , and a handling operation for each Sig exc -term f : X → Y , each non-empty list of exceptional types (Ti )1≤i≤n and each family of Sig exc -terms (gi : Ti → Y )1≤i≤n : try{f } catch {Ti ⇒ gi }1≤i≤n : X → Y . An important, and somewhat surprising, feature of a language with excep- tions is that all expressions in the language, including the try-catch expressions, propagate exceptions. Indeed, if an exception is raised before some try-catch ex- pression is evaluated, this exception is propagated. In fact, the catch block in a try-catch expression may recover from exceptions which are raised inside the try block, but the catch block alone is not an expression of the language. This means that the operations for catching exceptions are private operations: they are not part of the signature for exceptions. More precisely, the operations for raising and handling exceptions can be expressed in terms of a private empty type and two families of private operations: the tagging operations for creating exceptions and the untagging operations for catching them (inside the catch block of any try-catch expression). The tagging and untagging operations are called the core 5 operations for exceptions. They are not part of Sig exc , but the interpretations of the operations for raising and handling exceptions, which are part of Sig exc , are defined in terms of the interpretations of the core operations. The meaning of the core operations is given in Section 4. Definition 2. Let Sig exc be the signature for exceptions. The core of Sig exc is the signature Sig core made of Sig base with a type 0 called the empty type and two operations for each exceptional type T : tagT : T → 0 and untagT : 0 → T where tagT is called the exception constructor or the tagging operation and untagT is called the exception recovery or the untagging operation. 4 Denotational semantics for exceptions In this Section we define a denotational semantics for exceptions which relies on the common semantics of exceptions in various languages, for instance in C++ [1, Ch. 15], Java [9, Ch. 14] or ML. The basic part of the syntax is interpreted in the usual way: each type X is interpreted as a set JXK and each operation f : X → Y of Sig base as a function Jf K : JXK → JY K. But, when f : X → Y in Sig exc is a raising or handling operation, or when f : X → Y in Sig core is a tagging or untagging operation, it is not interpreted as a function Jf K : JXK → JY K: this corresponds to the fact that the exceptions form a computational effect. The distinction between ordinary and exceptional values is discussed in Subsection 4.1. Then, denotational semantics of raising and handling exceptions are considered in Subsections 4.2 and 4.3, respectively. We assume that some interpretation of Sig base has been chosen. 4.1 Ordinary values and exceptional values In order to express the denotational semantics of exceptions, a fundamental point is to distinguish between two kinds of values: the ordinary (or non-exceptional) values and the exceptions. It follows that the operations may be classified ac- cording to the way they may, or may not, interchange these two kinds of values: an ordinary value may be tagged for constructing an exception, and later on the tag may be cleared in order to recover the value; then we say that the exception gets untagged. Let Exc be a set, called the set of exceptions. For each set A, the set A + Exc is the disjoint union of A and Exc and the canonical inclusions are denoted normal A : A → A + Exc and abrupt A : Exc → A + Exc. For each functions f : A → B and g : Exc → B, we denote by [f |g] : A + Exc → B the unique function such that [f |g] ◦ normal A = f and [f |g] ◦ abrupt A = g. Definition 3. An element of A + Exc is an ordinary value if it is in A and an exceptional value if it is in Exc. A function ϕ : A + Exc → B + Exc: – raises an exception if there is some x ∈ A such that ϕ(x) ∈ Exc. 6 – recovers from an exception if there is some e ∈ Exc such that ϕ(e) ∈ B. – propagates exceptions if ϕ(e) = e for every e ∈ Exc. Clearly, a function ϕ : A + Exc → B + Exc which propagates exceptions may raise an exception, but cannot recover from an exception. Such a function ϕ is characterized by its restriction ϕ|A : A → B + Exc, since its restriction on exceptions ϕ|Exc : Exc → B + Exc is the inclusion abrupt B of Exc in B + Exc. In the denotational semantics for exceptions, we will see that a term f : X → Y of Sig exc or Sig core may be interpreted either as a function Jf K : JXK → JY K or as a function Jf K : JXK → JY K+Exc or as a function Jf K : JXK+Exc → JY K+Exc. However, in all cases, it is possible to convert Jf K to a function from JXK + Exc to JY K + Exc, as follows. Definition 4. The upcasting conversions are the following transformations: – every function ϕ : A → B gives rise to ϕ = normal B ◦ ϕ : A → B + Exc, – every function ψ : A → B + Exc gives rise to Ţψ = [ψ|abrupt B ] : A + Exc → B + Exc, which is equal to ψ on A and which propagates exceptions; – it follows that every function ϕ : A → B gives rise to ϕ = Ţ( ϕ) = [normal B ◦ ϕ|abrupt B ] = ϕ + id Exc : A + Exc → B + Exc, which is equal to ϕ on A and which propagates exceptions. Since the upcasting conversions are safe (i.e., injective), when there is no ambi- guity the symbols , Ţ and may be omitted. In this way, for each f : X → Y and g : Y → Z, whatever their effects, we get Jf K : JXK + Exc → JY K + Exc and JgK : JY K+Exc → JZK+Exc, which can be composed. Thus, every term of Sig exc and Sig core can be interpreted by first converting the interpretation of each of its components f : X → Y to a function Jf K : JXK + Exc → JY K + Exc. For Sig exc , this coincides with the Kleisli composition associated to the exception monad A + Exc [14]. We will also use the following conversion. Definition 5. The downcasting conversion is the following transformation: – every function θ : A + Exc → B + Exc gives rise to Ťθ = θ ◦ normal A : A → B + Exc which is equal to θ on A and which propagates exceptions. This conversion is unsafe: different θ’s may give rise to the same Ťθ. 4.2 Tagging and raising exceptions Raising exceptions relies on the interpretation of the tagging operations. The interpretation of the empty type 0 is the empty set ∅; thus, for each type X the interpretation of 0 + X can be identified with JXK. Definition 6. Let Exc be the disjoint union of the sets JT K for all the exceptional types T . Then, for each exceptional type T , the interpretation of the tagging operation tagT : T → 0 is the coprojection function JtagT K : JT K → Exc . 7 Thus, the tagging function JtagT K : JT K → Exc maps a non-exceptional value (or parameter ) a ∈ JT K to an exception JtagT K(a) ∈ Exc. We can now define the raising of exceptions in a programming language. Definition 7. For each exceptional type T and each type Y , the interpretation of the raising operation throwT ,Y is the tagging function JtagT K followed by the inclusion of Exc in JY K + Exc: JthrowT ,Y K = abrupt JY K ◦ JtagT K : JT K → JY K + Exc . 4.3 Untagging and handling exceptions Handling exceptions relies on the interpretation of the untagging operations for clearing the exception tags. Definition 8. For each exceptional type T , the interpretation of the untagging operation untagT : 0 → T is the function JuntagT K : Exc → JT K + Exc , which satisfies for each exceptional type R: ( normal JT K when R = T JuntagT K ◦ JtagR K = : JRK → JT K + Exc. abrupt JT K ◦ JtagR K when R 6= T Thus, the untagging function JuntagT K, when applied to any exception e, first tests whether e is in JT K; if this is the case, then it returns the parameter a ∈ JT K such that e = JtagT K(a), otherwise it propagates the exception e. Since the do- main of JuntagT K is Exc, JuntagT K is uniquely determined by its restrictions to all the exceptional types, and therefore by the equalities in Definition 8. For handling exceptions of types T1 , . . . Tn , raised by the interpretation of some term f : X → Y of Sig exc , one provides for each i in {1, . . . , n} a term gi : Ti → Y of Sig exc (thus, the interpretation of gi may itself raise exceptions). Then the handling process builds a function which first executes f , and if f returns an ex- ception then maybe catches this exception. The catching part encapsulates some untagging functions, but the resulting function always propagates exceptions. Definition 9. For each term f : X → Y of Sig exc , and each non-empty lists (Ti )1≤i≤n of exceptional types and (gi : Ti → Y )1≤i≤n of terms of Sig exc , let (recover i )1≤i≤n denote the family of functions defined recursively by: ( [ Jgn K | abrupt Y ] ◦ untagTn when i = n recover i = : Exc → Y + Exc [ Jgi K | recover i+1 ] ◦ untagTi when i < n Then the interpretation of the handling operation is: Jtry{f } catch {Ti ⇒ gi }1≤i≤n K = [ normal Y | recover 1 ] ◦ Jf K. 8 It should be noted that Jf K : JXK → JY K + Exc and that similarly Jtry{f } catch {Ti ⇒ gi }1≤i≤n K : JXK → JY K + Exc. When n = 1 we get: Jtry{f } catch {T ⇒ g}K = [ normal Y | [ JgK | abrupt Y ] ◦ untagT ] ◦ Jf K . This definition matches that of Java exceptions [9, Ch. 14] or C++ excep- tions [1, §15]. In particular, in the interpretation of try{f } catch {Ti ⇒ gi }1≤i≤n , each function Jgi K may itself raise exceptions; and the types T1 , . . . , Tn need not be pairwise distinct, but if Ti = Tj for some i < j then gj is never executed. 5 A decorated equational proof system for exceptions In Sections 3 and 4 we have formalized the signature for exceptions Sig exc , its associated core signature Sig core , and we have described their denotational semantics. However the soundness property is not satisfied, in the sense that the denotational semantics is not a model of the signature, in the usual sense: indeed, a term f : X → Y is not always interpreted as a function Jf K : JXK → JY K; it may be interpreted as Jf K : JXK → JY K + Exc, or as Jf K : JXK + Exc → JY K + Exc. In order to get soundness, in this Section we add decorations to the signature for exceptions by classifying the operations and equations according to the interaction of their interpretations with the mechanism of exceptions. Signature decoration / Decorated signature interpretation / (sound) Semantics (Section 3) (Section 5) (Section 4) 5.1 Decorations for exceptions By looking at the interpretation (in Section 4) of the syntax for exceptions (from Section 3), we get a classification of the operations and terms in three parts, depending on their interaction with the exceptions mechanism. The terms are decorated by (0), (1) and (2) used as superscripts, they are called respectively pure terms, propagators and catchers, according to their interpretations: (0) the interpretation of a pure term may neither raise exceptions nor recover from exceptions, (1) the interpretation of a propagator may raise exceptions but is not allowed to recover from exceptions, (2) the interpretation of a catcher may raise exceptions and recover from excep- tions. For instance, the decoration (0) corresponds to the decoration noexcept in C++ (replacement of the deprecated throw()) and the decoration (1) corresponds to throw(...), still in C++. The decoration (2) is usually not encountered in the language, since catching is the prerogative of the core untagging function, which is private. Similarly, we introduce two kinds of equations between terms. This is done by using two distinct relational symbols which correspond to two distinct interpretations: 9 (≡) a strong equation is an equality of functions both on ordinary values and on exceptions (∼) a weak equation is an equality of functions only on ordinary values, but maybe not on exceptions. The interpretation of these three kinds of terms and two kinds of equations is summarized in Fig. 4. It has been shown in Section 4.1 that any propagator can be seen as a catcher and that any pure term can be seen as a propagator and thus also as a catcher. This allows to compose terms of different nature, so that it is not a restriction to give the interpretation of the decorated equations only when both members are catchers. Syntax Decorated syntax Interpretation type type X X JXK term pure term f (0) X f /Y X /Y JXK Jf K / JY K term propagator f (1) X f /Y X /Y JXK Jf K / JY K + Exc term catcher f (2) X f /Y X /Y JXK + Exc Jf K / JY K + Exc equation strong equation f = g : X → Y f (2) ≡ g (2) : X → Y Jf K = JgK equation weak equation f = g : X → Y f (2) ∼ g (2) : X → Y Jf K ◦ normal JXK = JgK ◦ normal JXK Fig. 4. Interpretation of the decorated syntax. Now we can add decorations to the signature for exceptions Sig exc and its associated core signature Sig core , from Definitions 1 and 2. Definition 10. The decorated signature for exceptions Sig deco exc and its asso- ciated decorated core signature Sig deco core are made of Sig exc and Sig core , respec- tively, decorated as follows: the basic operations are pure, the tagging, raising and handling operations are propagators, and the untagging operations are catchers. 5.2 Decorated rules for exceptions In this Section we define an equational proof system for exceptions. This proof system is made of the rules in Fig. 5. It can be used for proving properties of 10 exceptions, for instance in the Coq proof assistant. In Fig. 5, the decoration properties are often grouped with other properties: for instance, “f (1) ∼ g (1) ” means “f (1) and g (1) and f ∼ g”; in addition, the decoration (2) is usually dropped, since the rules assert that every term can be seen as a catcher; and several rules with the same premisses may be grouped together: H 1 ...Hn C1 ...Cp stands for H1C...H 1 n ,. . . , H1C...H p n . Rules (a) are the usual rules for the monadic equational logic; they are valid for all decorated terms and for strong equations. Rules (b) provide more infor- mation on the decorated monadic equational logic for exceptions; in particular, the substitution of f in a weak equation g1 ∼ g2 holds only when f is pure, which is quite restrictive. Rules (c) ensure that the empty type is a kind of ini- tial type with respect to weak equations. Rules (d) are used for case distinctions between exceptional arguments (on the “0” side of X + 0) and non-exceptional arguments (on the “X” side of X + 0). The symbol Ť in rules (e) is interpreted as the downcast conversion, see Definition 5. Rules in (f) mean that the tagging operations are interpreted as the canonical inclusions of the exceptional types in the set Exc, see Definition 6. The rules in (g) determine the untagging operations up to strong equations: an untagging operation recovers the exception param- eter whenever the exception type is matched, and it propagates the exception otherwise see Definition 8. Remark 1. It has been shown in [3] that the denotational semantics of the core language for exceptions is dual to the denotational semantics for states: the tagging and untagging operations are respectively dual to the lookup and update operations. In fact, this duality is also valid for the decorated equational logics. This decorated proof system is used now (in Definition 12) for construct- ing the raising and handling operations from the core tagging and untagging operations. It has to be noted that the term catch {Ti ⇒ gi }1≤i≤n ◦ f may catch exceptions, while the handling operation, which coincides with catch {Ti ⇒ gi }1≤i≤n ◦ f on non-exceptional values, must propagate exceptions; this is why the downcast operator Ť is used. Definition 11. For each exceptional type T and each type Y , the raising oper- (1) ation throwT ,Y : T → Y is the propagator defined as: (1) throwT ,Y = [ ]Y ◦ tagT . Definition 12. For each propagator f (1) : X → Y , each non-empty lists of types (1) (2) (Ti )1≤i≤n and propagators (gi : Ti → Y )1≤i≤n , let catch {Ti ⇒ gi }1≤i≤n : Y → Y denote the catcher defined by: (2) catch {Ti ⇒ gi }1≤i≤n = [ id Y | recover 1 ] 11 (a) Monadic equational rules for exceptions (first part): f :X→Y g:Y →Z X f f ≡g f ≡g g≡h g◦f :X →Z id X : X → X f ≡f g≡f f ≡h f : X → Y g1 ≡ g2 : Y → Z f1 ≡ f2 : X → Y g : Y → Z g1 ◦ f ≡ g2 ◦ f : X → Z g ◦ f1 ≡ g ◦ f2 : X → Z f :X→Y g:Y →Z h:Z→W f :X→Y f :X→Y h ◦ (g ◦ f ) ≡ (h ◦ g) ◦ f f ◦ id X ≡ f id Y ◦ f ≡ f (b) Monadic equational rules for exceptions (second part): f (0) f (1) X f (0) g (0) f (1) g (1) f (1) ∼ g (1) f ≡g f (1) f (2) (0) id X (g ◦ f )(0) (g ◦ f )(1) f ≡g f ∼g f f ∼g f ∼g g∼h f ∼f g∼f f ∼h f (0) : X → Y g1 ∼ g2 : Y → Z f1 ∼ f2 : X → Y g : Y → Z g1 ◦ f ∼ g2 ◦ f g ◦ f1 ∼ g ◦ f2 X f, g : 0 → Y (c) Rules for the empty type 0: (0) [ ]X : 0 → X f ∼g (d) Case distinction with respect to X + 0: g (1) : X → Y k(2) : 0 → Y [g | k](2) : X → Y [g | k] ∼ g [g | k] ◦ [ ]X ≡ k f, g : X → Y f ∼ g f ◦ [ ] X ≡ g ◦ [ ]X f ≡g k(2) : X → Y (e) Propagating exceptions: (Ťk)(1) : X → Y Ťk ∼ k (f) Tagging: (1) T ∈T (fT : T → Y )T ∈T (1) (2) tagT : T → 0 [fT ]T ∈T : 0 → Y [fT ]T ∈T ◦ tagT ∼ fT f, g : 0 → Y f ◦ tagT ∼ g ◦ tagT for all T ∈ T f ≡g (g) Untagging: T ∈T R, T ∈ T R 6= T (2) untagT : 0 → T untagT ◦ tagT ∼ id T untagT ◦ tagR ∼ [ ]T ◦ tagR Fig. 5. Decorated rules for exceptions 12 (2) where (recover i : 0 → Y )1≤i≤n denotes the family of catchers defined recur- sively by: ( (2) gn ◦ untagTn when i = n, recover i = [gi | recover i+1 ] ◦ untagTi when i < n. Then, the handling operation (try{f } catch {Ti ⇒ gi }1≤i≤n )(1) : X → Y is the propagator defined by: try{f } catch {Ti ⇒ gi }1≤i≤n = Ť (catch {Ti ⇒ gi }1≤i≤n ◦ f ) When n = 1 we get: try{f } catch {T ⇒ g} = Ť (catch {T ⇒ g} ◦ f ) = Ť ([ id Y | g ◦ untagT ] ◦ f ). Now Theorem 1 derives easily, by induction, from Fig. 5 and 4 and from Definitions 11 and 12. Theorem 1. The decorated rules for exceptions and the raising and handling constructions are sound with respect to the denotational semantics of exceptions. 5.3 A decorated proof: a propagator propagates With these tools, it is now possible to prove properties of programs involving exceptions and to check these proofs in Coq. For instance, let us prove that given an exception, a propagator will do nothing apart from propagating it. Recall that the interpretation of [ ]Z (or, more precisely, of [ ]Z ) is abrupt JZK : Exc → JZK + Exc. Lemma 1. For each propagator g (1) : X → Y we have g ◦ [ ]X ≡ [ ]Y . Proof. This lemma can be proved as follows; the labels refer to Fig. 5, and their subscripts to the proof in Coq of Fig. 6. (c)3 X (c)1 X (0) [ ]X : 0 → X g:X→Y [ ]X Y (a) (b)1 (c)4 (0) (1) g ◦ [ ]X : 0 → Y g (1) [ ]X [ ]Y (c)2 (b)2 (b)3 (1) g ◦ [ ]X ∼ [ ]Y (g ◦ [ ]X )(1) [ ]Y (b)4 g ◦ [ ]X ≡ [ ]Y The proof in Coq follows the same line as the mathematical proof above. It goes as in Figure 6. The Coq library for exceptions, EXCEPTIONS-0.1.tar.gz, can be found online: http://coqeffects.forge.imag.fr (in file Proofs.v) with proofs of many other properties of programs involving exceptions. It should be recalled that any Coq proof is read from bottom up. The application of the from empty is weakly unique rule certifies that the term g o (@empty X), because its domain is the empty type, is weakly equal to the term (@empty Y). Thus, we have the left side sub-proof: g o (@empty X) ∼ (@empty Y). There, weak equality is converted into strong: apply- ing propagator weakeq is strongeq resolves the goal: g o (@empty X) == (@empty Y) and produces as sub-goals that there is no catcher involved in both hand sides (middle and right side sub-proofs). 13 Lemma propagator propagates 1: forall X Y (g: term Y X), is propagator g -> g o (@empty X) == (@empty Y). Proof. intros. (* (b)4 *) apply propagator weakeq is strongeq. (* (b)2 *) apply is comp. assumption. (* (b)1 *) apply is pure propagator. (* (c)3 *) apply is empty. (* (b)3 *) apply is pure propagator. (* (c)4 *) apply is empty. (* (c)2 *) apply from empty is weakly unique. Qed. Fig. 6. Proof in Coq that “a propagator propagates exceptions” 5.4 A hierarchy of exceptional types In object-oriented languages, exceptions are usually the objects of classes which are related by a hierarchy of subclasses. Our framework can be extended in this direction by introducing a hierarchy of exceptional types: the set T is endowed with a partial order _ called the subtyping relation, and the sig- nature Sig base is extended with a cast operation castR,T : R → T whenever R _ T . The interpretation of castR,T is a pure function JcastR,T K : JRK → JT K, such that JcastT ,T K is the identity on JT K and when S _ R _ T then JcastS ,T K = JcastR,T K ◦ JcastS ,R K. Definition 8 has to be modified as follows: the function JuntagT K : Exc → JT K + Exc satisfies for each exceptional type R: ( normal JT K ◦ JcastR,T K when R _ T JuntagT K◦JtagR K = : JRK → JT K+Exc. abrupt JT K ◦ JtagR K otherwise 6 Conclusion Exceptions are part of most modern programming languages and they are useful in computer algebra, typically for implementing dynamic evaluation. We have presented a new framework for formalizing the treatment of exceptions. These decorations form a bridge between the syntax and the denotational semantics by turning the syntax sound with respect to the semantics, without adding any explicit “type of exceptions” as a possible return type for the operations. The salient features of our approach are: – We provide rules for equational proofs on programs involving exceptions (Fig. 5) and an automatic process for interpreting these proofs (Fig. 4). – Decorating the equations allows to separate properties that are true only up to effects (weak equations) from properties that are true even when effects are considered (strong equations). 14 – Moreover, the verification of the proofs can be done in two steps: in a first step, decorations are dropped and the proof is checked syntactically; in a sec- ond step, the decorations are taken into account in order to prove properties involving computational effects. – The distinction between the language for exceptions and its associated pri- vate core language (Definitions 1 and 2) allows to split the proofs in two successive parts; in addition, the private part can be directly dualized from the proofs on global states (relying on [3] and [4]). – A proof assistant can be used for checking the decorated proofs on ex- ceptions. Indeed the decorated proof system for states, as described in [4] has been implemented in Coq [2] and dualized for exceptions (see http: //coqeffects.forge.imag.fr). We have used the approach of decorated logic, which provides rules for com- putational effects by adding decorations to usual rules for “pure” programs. This approach can be extended in order to deal with multivariate operations [5], conditionals, loops, and high-order functions. References 1. Working Draft, Standard for Programming Language C++. ISO/IEC JTC1/SC22/WG21 standard 14882:2011. 2. Jean-Guillaume Dumas, Dominique Duval, Burak Ekici, Damien Pous. Formal verification in Coq of program properties involving the global state effect. JFLA’13, Fréjus, France, 2013. arXiv:1310.0794. 3. Jean-Guillaume Dumas, Dominique Duval, Laurent Fousse, Jean-Claude Reynaud. A duality between exceptions and states. Mathematical Structures in Computer Science 22, p. 719-722 (2012). 4. Jean-Guillaume Dumas, Dominique Duval, Laurent Fousse, Jean-Claude Reynaud. Decorated proofs for computational effects: States. ACCAT 2012. Electronic Pro- ceedings in Theoretical Computer Science 93, p. 45-59 (2012). 5. Jean-Guillaume Dumas, Dominique Duval, Jean-Claude Reynaud. Cartesian effect categories are Freyd-categories. Journal of Symbolic Computation 46, p. 272-293 (2011). 6. Jean-Guillaume Dumas, Frank Heckenbach, B. David Saunders, and Volkmar Welker. Computing simplicial homology based on efficient Smith normal form algorithms. In Michael Joswig and Nobuki Takayama, editors, Algebra, Geometry and Software Systems, pages 177–206. Springer, March 2003. 7. Jean-Guillaume Dumas, B. David Saunders, and Gilles Villard. On efficient sparse integer matrix Smith normal form computations. Journal of Symbolic Computa- tion, 32(1/2):71–99, July–August 2001. 8. Dominique Duval. Simultaneous computations in fields of different characteristics. In Erich Kaltofen and Stephen M. Watt, editors, Computers and Mathematics, pages 321–326. Springer US, 1989. 9. James Gosling, Bill Joy, Guy Steele, Gilad Bracha. The Java Language Specifica- tion, Third Edition. Addison-Wesley Longman (2005). 10. Bart Jacobs. A Formalisation of Java’s Exception Mechanism. ESOP 2001. Springer Lecture Notes in Computer Science 2028. p. 284-301 (2001). 15 11. John M. Lucassen, David K. Gifford. Polymorphic effect systems. POPL 1988. ACM Press, p. 47-57. 12. Martin Hyland, John Power. The Category Theoretic Understanding of Universal Algebra: Lawvere Theories and Monads. Electronic Notes in Theoretical Computer Science 172, p. 437-458 (2007). 13. Paul Blain Levy. Monads and adjunctions for global exceptions. MFPS 2006. Elec- tronic Notes in Theoretical Computer Science 158, p. 261-287 (2006). 14. Eugenio Moggi. Notions of Computation and Monads. Information and Computa- tion 93(1), p. 55-92 (1991). 15. Aleksandar Nanevski, Greg Morrisett, Avraham Shinnar, Paul Govereau, Lars Birkedal. Ynot: Dependent Types for Imperative Programs. Proceedings of the 13th ACM SIGPLAN International Conference on Functional Programming (ICFP ’08), p. 229-240 (2008). 16. Gordon D. Plotkin, John Power. Notions of Computation Determine Monads. FoS- SaCS 2002. Springer-Verlag Lecture Notes in Computer Science 2303, p. 342-356 (2002). 17. Gordon D. Plotkin, John Power. Algebraic Operations and Generic Effects. Applied Categorical Structures 11(1), p. 69-94 (2003). 18. Gordon D. Plotkin, Matija Pretnar. Handlers of Algebraic Effects. ESOP 2009. Springer-Verlag Lecture Notes in Computer Science 5502, p. 80-94 (2009). 19. Lutz Schröder, Till Mossakowski. Generic Exception Handling and the Java Monad. AMAST 2004. Springer-Verlag Lecture Notes in Computer Science 3116, p. 443-459 (2004). 20. Philip Wadler. The Marriage of Effects and Monads. ICFP 1998. ACM Press, p. 63-74 (1998). 16