
Types and Programming Languages Lecture 8. Recursive type Xiaojuan Cai [email protected] BASICS Lab, Shanghai Jiao Tong University Fall, 2016 List[T] I List[T] is a type constructor whose elements are lists with elements of type T. I A list is either null or else a pair (cons cell) of an element and another list. I Similar structures include: queues, binary trees, etc. I We need a general mechanism with which they can be defined from simpler elements. This mechanism is called recursive types. The system studied in this lecture is simply typed λ-calculus with recursive types. And we will only focus on NatList. Another mechanism for List[T] is type operator (Chapter 29). Outline Recursive types Formalities Metatheory of recursive types Induction and coinduction Finite and infinite types Subtyping Membership checking Regular trees µ-types Recursive types I How to define the type NatList? I It's a variant type: NatList =< nil : Unit; cons : fNat; :::g > I The ::: is another list of number! NatList =< nil : Unit; cons : fNat; NatListg > I Above definition will introduce divergence. Like recursive functions, we introduce an explicit recursion operator µ for types: NatList = µX: < nil : Unit; cons : fNat; Xg > NatList operations Recall in Figure 11-13, we define lots of operations for List[T] as built-in. Here we will define them as functions. I nil = <nil = unit> as NatList; I cons = λn:Nat.λl:NatList.<cons = fn,lg> as NatList; I isnil = λl : NatList: case l of < nil = u > ) true j < cons = p > ) false I hd = λl : NatList: case l of < nil = u > ) 0 j < cons = p > ) p:1 I tl = λl : NatList: case l of < nil = u > ) 0 j < cons = p > ) p:2 NatList functions I sumlist = fix (λs : NatList ! Nat: λl : NatList: case l of < nil = u > ) 0 j < cons = p > ) plus p:1 (s p:2)) I mylist = cons 2 (cons 3 (cons 5 nil)) I sumlist mylist returns 10. Hungry functions I Hungry = µA.Nat-> A I f = fix (λf:Hungry.λn:Nat.f) I f 0 1 2 3 4 5; Streams I Stream is the type of functions that can produce an arbitrary number of numbers (or other types). I Stream = µA. Unit->fNat,Ag I hd = λs:Stream.(s unit).1; I tl = λs:Stream.(s unit).2; I But how to define a stream? I upfrom0 = fix (λf:Nat->Stream.λn:Nat.λ :Unit.fn,f (succ n)g) 0; I hd upfrom0 returns 0. I hd (tl (tl (tl upfrom0))) returns 3. Quiz. Define a stream that yields all the elements to be 1. ones = fix (λs:Stream.λ :Unit.f1,sg) Processes I Processes are functions that accept a number and return a number and a new process. I Process = µA. Nat->fNat,Ag I p = fix (λf:Nat->Process.λacc.λn:Nat. let newacc = plus acc n in fnewacc,f newaccg) 0; I curr = λs:Process.(s 0).1 I send = λn:Nat.λs:Process.(s n).2 I curr (send 20 (send 3 (send 5 p))) returns 28. Objects I Processes are similar to objects which interacting with data. I Counter = µC.fget:Nat, inc:Unit->Cg I c = let create = fix (λf:fx:Natg->Counter.λs:fx:Natg. fget = s.x, inc = λ :Unit.f fx=succ(s.x)g) in create fx=0g I c1 = c.inc unit; c2 = c1.inc unit; c2.get; Recursive values from recursive types I A more surprising use of recursive types is a well-typed implementation of the fixed-point combinator. Quiz. Please rewrite the fix-point operator into simply typed λ-term with recursive type. fix = λf:(λx:f(x x))(λx:f(x x)) I fixT = λf : T ! T:(λx :(µA:A ! T):f (x x)) (λx :(µA:A ! T):f (x x); I Recursive types break the strong normalization property: divergeT = λ : Unit:fixT (λx : T:x) I This reveals the expressive power of recursive types. Untyped λ-calculus I Moreover, we can embed the whole untyped λ-calculus into a statically typed language with recursive types. I D = µX.X->X I lam = λf:D->D.f as D I ap = λf:D.λa:D.f a I Here comes the encoding from untyped λ-calculus into a well-typed one: kxk = x kλx:Mk = lam (λx : D:kMk) kMNk = ap kMk kNk Untyped λ-calculus with other features I If we extend untyped λ-calculus with numbers, then the whole datatype is extended to be a variant type. I D = µX.<nat:Nat, fn:X->X> I ap = λf:D.λa:D.case f of <nat=n>) divergeD unit j <fn = f> ) f a Outline Recursive types Formalities Metatheory of recursive types Induction and coinduction Finite and infinite types Subtyping Membership checking Regular trees µ-types Formalities I There are two basic approaches to recursive types. I The essential difference is their reponse to the question: What is the relation between the type µX.T and its one-step unfolding? For example, NatList and <nil:Unit, cons:fNat,NatListg>. I The equi-recursive approach takes these two expressions definitionally equal { interchangeable in any context. I The iso-recursive approach takes these two expression different, but isomorphic. Equi-recursive I Pros: I More intuitive; I Match with all the previous presentations. Definitions, safety theorems and even proofs remains unchanged. I Cons: I The implementation requires some work, Since type checking can not work directly with infinite structures. (Chapter 21) I Interactions with other advanced features, such as quantification, lead to theoretical difficulties, even undecidability. Iso-recursive I The unfolding of µX.T is using the standard notation for substitution: NatList = µX: < nil : Unit; cons : fNat; Xg > unfolds to < nil : Unit; cons : fNat; µX: < nil : Unit; cons : fNat; Xg >g > I We need to introduce fold[µX.T] and unfold[µX.T] explicitly into syntax. Iso-recursive: pros and cons I Pros: I Less work for type systems. I Easy to interact with other features. I Cons: I Heavier: requiring programs to be decorated with fold and unfold. I Iso-recursive is quite palatable in practice. Since the fold and unfold notations can be hidden by coalescing them with other annotations. I Each use of constructors is to build a value with implicitly include a fold; I Each use of case implicitly forces an unfold. Subtyping I Assume Even is a subtype of Nat. What the relation between these two types? µX:Nat ! (Even × X) and µX:Even ! (Nat × X) Outline Recursive types Formalities Metatheory of recursive types Induction and coinduction Finite and infinite types Subtyping Membership checking Regular trees µ-types Coming soon I We will develop the theoretical foundations of typecheckers for equi-recursive types. I We will deal with a system including both recursive types and subtyping. I We will use coinduction to make equi-recursive types precise. Induction and coinduction Let's fix some universal set U, which denotes \everything in the world". Definition. A function F 2 P(U) !P(U) is monotone if X ⊆ Y implies F (X ) ⊆ F (Y ), where P(U) is the powerset of U. In the following, F is always monotone, also called as generating function. Definition. Let X be a subset of U. I X is F -closed if F (X ) ⊆ X . I X is F -consistent if X ⊆ F (X ). I X is a fixed point if X = F (X ). Example Consider the three-element universe U = fa; b; cg: E1(;) = fcg E1(fa; bg) = fcg E1(fag) = fcg E1(fa; cg) = fb; cg E1(fbg) = fcg E1(fb; cg) = fa; b; cg E1(fcg) = fb; cg E1(fa; b; cg) = fa; b; cg I fa; b; cg is E1-closed; I ;; fcg; fb; cg and fa; b; cg are E1-consistent; I fa; b; cg is a fixed point of E1. Actually, E1 can be represented as a set of inference rules: c b c c b a Knaster-Tarski theorem Theorem [Knaster-Tarski]. I The intersection of all F -closed sets is the least fixed point of F , denoted µF ; I The union of all F -consistent sets is the greatest fixed point of F , denoted νF . Example. (continued) µE1 = νE1 = fa; b; cg. Corollary. I Principle of induction: If X is F -closed, then µF ⊆ X ; I Principle of coinduction: If X is F -consistent, then X ⊆ νF ; Outline Recursive types Formalities Metatheory of recursive types Induction and coinduction Finite and infinite types Subtyping Membership checking Regular trees µ-types Finite and infinite types Definition. A tree type is a partial function T 2 f1; 2g∗ ! f!; ×; Topg satisfying: I T (•) is defined; I if T (π; σ) is defined then T (π) is defined; I if T (π) =! or T (π) = ×, then T (π; 1) and T (π; 2) are defined; I if T (π) = Top, then T (π; 1) and T (π; 2) are undefined; An alternative definition for finite tree types A tree type T is finite if dom(T ) is finite. The set of finite tree types can be defined more compactly by a grammar: T ::= Top j T × T j T ! T I The set of all finite tree types is the least fixed point of the generating function described by the grammar. I The set of all tree types is the greatest fixed point of the generating function described by the grammar. Outline Recursive types Formalities Metatheory of recursive types Induction and coinduction Finite and infinite types Subtyping Membership checking Regular trees µ-types Subtyping for finite types Definition 21.3.1. Two finite tree types S and T are in the subtype relation if (S; T ) 2 µSf , where the monotone function Sf 2 P(Tf × Tf ) !P(Tf × Tf ) is defined by Sf (R) = f(T ; Top) j T 2 Tf g [ f(S1 × S2; T1 × T2) j (S1; T1); (S2; T2) 2 Rg [ f(S1 ! S2; T1 ! T2) j (T1; S1); (S2; T2) 2 Rg: Quiz.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages49 Page
-
File Size-