
Termination Checking with Types Strong Normalization for Mendler-Style Course-Of-Value Recursion Andreas Abel ? Department of Computer Science University of Munich Oettingenstr. 67 80538 M¨unchen, Germany [email protected] Abstract. Gim´enez’type system for structural recursion in the Calcu- lus of Constructions is adapted to typed functional programming. As core language, the λ-calculus with inductive types, subtyping and bounded quantification is introduced. Decorated type variables, which represent approximations of inductive types, enable the type system to track the size of arguments to recursive functions and the size of the result of func- tion calls. Novel are an algorithm for type checking and proofs of type preservation and strong normalization. 1 Introduction The process of verifying a program can be separated into two parts: As the first step, partial correctness is established by verifying that a program matches its specification; then, termination is shown to obtain full correctness. For practical purposes, a complete verification is too tedious in most cases since it requires a huge amount of interactive theorem proving. But verification of certain program properties slowly makes its way into professional software development. Modern programming languages allow the specification of invariants which are verified statically and fully automatically by the compiler. These invariants effectively help uncover programming errors at compile-time. One very basic invariant is typing and type preservation which has been incor- porated into many modern programming languages, e.g. the widely used JAVA, as Nipkow and von Oheimb proved for a considerable subset [26]. Other interest- ing invariants are termination, and, even stronger, termination independent of the internal evaluation strategy, i.e. strong normalization. We aim at developing fully automatic, verified termination checking. For now, we restrict to declarative programming. To be suitable for practical programming, we claim that termination check- ing has to obey the following principles: First, the criteria on which the checker ? Research supported by the Graduiertenkolleg Logik in der Informatik (PhD Program Logic in Computer Science) of the Deutsche Forschungsgemeinschaft (DFG) decides acceptance must be simple enough for the user to comprehend. He should be able to obtain a model of which program is accepted and which is rejected without much difficulty. A good example here is again typing: In typed func- tional languages, e.g., SML [25], it is easy to write well-typed programs and to comprehend type errors. Secondly—this is strongly connected with the first principle—it must be possible for the compiler to give a good error message and point to the expression which makes the program fail the termination check. Otherwise, termination checking will most probably result in a loss rather than a gain of productivity. Traditionally, termination has been investigated in the context of term rewrit- ing systems. Research has focused on developing more and more powerful algo- rithms which accepted more and more programs as terminating. To this end, increasingly strong term orderings have been described (cf. Dershowitz [16], Steinbach [32], Giesl and Arts [7]). The methods of term rewriting are transferable to functional and logic pro- gramming as follows: The given (untyped) program is translated into a term rewriting system which then is checked for termination. The advantage of this procedure is that the full arsenal of methods developed for term rewriting sys- tems is available. However, due to the translation, termination checking will appear obscure to the user. We believe that, in general, it will be very hard to produce helpful error messages and expose the program location which fails ter- mination. Consequently, we focus on methods which directly deal with functional or logic programs. In the area of functional and logic programming, most termination checkers follow methods from term rewriting and rely on term orderings. Some examples: In previous work [1], we used the subterm ordering extended to higher-order functions to capture the class of structurally recursive functions over strictly positive inductive datatypes. For polynomial inductive types, a greater class of functions is accepted in Telford & Turner’s ESFP [34]. Their termination checker also incorporates a limited form of size-change and dataflow analysis which recognizes certain functions as reducers or preservers. Functions in these classes—first described by Walther [35]—have the property that the size of their output is bound by the size of some input argument (strictly smaller in the case of reducers). Finally, Pientka [29] has implemented termination and reduction checking for higher-order logic programs based on the subterm ordering. Unfortunately, the subterm ordering has some drawbacks. As we will see in an example (Sect. 3), it does not capture the notion of size well enough. Furthermore, as Gim´enezpointed out [18], the usual formulations make it hard to prove strong normalization. To my knowledge, no proof has been published so far. An alternative to subterm calculi is the introduction of type variables to keep track of the relation of the input argument of a function with the argument in the recursive call. This technique was first introduced by Mendler [24] for the restricted case of primitive recursion. His ideas were refined by Gim´enez [18], who proposed an extension of the Calculus of Constructions by a notion of subtyping and bounded quantification to type recursive functions over inductive 2 and coinductive datatypes. So far however, he has not shown that his system is sound, that is, proven of type preservation1 and strong normalization. We adopt Gim´enez’ idea for typed functional programming and propose a method of termination checking by type checking. In this paper, we present a core functional programming language Mini-MLµ≤ with higher-order functions and (non-strictly) positive inductive types. The types come with a lean and decidable subtyping calculus. Recursive functions can be written in a natural way as it is common practice in functional languages. Termination and size information are encoded in the types in a natural way and can be checked fully automated. Our main contribution are proofs of type preservation and strong normalization of our language. 1.1 Comparison with Xi’s Work Recently, Hongwei Xi has presented a method of termination verification which relies on dependent types. His approach seems powerful, practical and rather general, which raises the question whether it encompasses our system. This is not the case, for the following reason: To maintain decidability of type-checking, Xi’s types may only be indexed by integer expressions. In his system, we can construct a type list(n) of lists of length n. Then, we can write a recursive function on list(n) which only calls itself with arguments in list(n−1). Xi’s type system recognizes such a function as terminating. However, for some higher-order datatypes like infinitely branching trees, the height of a structure can no longer be described by a natural number; ordinals are required. Thus, recursive functions on such data structures cannot be shown terminating only with integer constraints. We see another potential problem in Xi’s setting, regarding error messages. To check dependent types, constraints have to be solved. If the constraint solver fails, a given expression is not of the ascribed type. In this case it is hard to ex- plain to the user exactly what caused the problem. In the simply typed setting however, type checking is rather straight-forward and type errors are compre- hensible. 1.2 Overview Besides specification of the language and type-checking (in Sect. 4), the proof of type preservation (Sect. 5) and strong normalization (Sect. 6), this paper contains an introduction to inductive types (Sect. 2), an informal description of our method with examples (Sect. 3), possible applications (Sect. 7) and a discussion of related and further work (Sect. 8). 2 Inductive Types We consider termination in the setting of simply-typed functional programming with inductive datatypes. Table 1 shows the core language Mini-MLµ most con- 1 alternative term: subject reduction 3 Types: ρ, σ, τ ::= X | 1 | σ + τ | σ × τ | σ → τ | µX.ρ (where X appears only positively in ρ) Terms: M, N ::= x | λx.M | M1 M2 | inl M | inr M | (case M of inl x1 ⇒ M1 | inr x2 ⇒ M2) | () | (M1,M2) | fst M | snd M | fold M | unfold M | fix g(x).M Contexts (all variables distinct): Γ ::= · | Γ, x: τ Typing (τ and all types in Γ closed): Γ ` M : τ Lambda-calculus: x: τ ∈ Γ Γ, x: σ ` M : τ Γ ` M1 : σ → τ Γ ` M2 : σ Γ ` x : τ Γ ` λx.M : σ → τ Γ ` M1 M2 : τ Sum types: Γ ` M : σ Γ ` M : τ Γ ` M : σ + τ Γ, x1 : σ ` M1 : ρ Γ, x2 : τ ` M2 : ρ Γ ` inl M : σ + τ Γ ` inr M : σ + τ Γ ` case M of inl x1 ⇒ M1 | inr x2 ⇒ M2 : ρ Product types: Γ ` M1 : σ Γ ` M2 : τ Γ ` M : σ × τ Γ ` M : σ × τ Γ ` () : 1 Γ ` (M1,M2): σ × τ Γ ` fst M : σ Γ ` snd M : τ Inductive types and recursion: Γ ` M : σ(µX.σ) Γ ` M : µX.σ Γ, g : σ → τ, x : σ ` M : τ Γ ` fold M : µX.σ Γ ` unfold M : σ(µX.σ) Γ ` fix g(x).M : σ → τ Notational definitions: 0 ≡ µX.X abort ≡ fix g(x).g(unfold x) : 0 → τ Table 1. The core functional language Mini-MLµ. structs of which are well-known. Note that fix g(x).M bind the two variables g and x in M. Some significant subset of a functional language like SML can be translated to Mini-MLµ. For example, consider the following SML program: datatype Nat = Zero | Succ of Nat datatype ListN = Nil | Cons of Nat * ListN fun sum (Nil) = Zero | sum (Cons (n, l)) = sum’ (n, l) and sum’ (Zero, l) = sum l | sum’ (Succ n, l) = Succ (sum’ (n, l)) 4 In Mini-MLµ, the defined datatypes are represented by the type expressions Nat := µX.1 + X and ListN := µY.1 + Nat × Y .
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages24 Page
-
File Size-