Supplementary Notes on Recursive Types

Similar documents
CS 4110 Programming Languages & Logics. Lecture 28 Recursive Types

Lecture Notes on Data Representation

Recursive Types and Subtyping

CS 4110 Programming Languages & Logics. Lecture 27 Recursive Types

Second-Order Type Systems

Lecture Notes on Aggregate Data Structures

Programming Languages Lecture 15: Recursive Types & Subtyping

Pattern Matching and Abstract Data Types

Polymorphism. Lecture 19 CS 565 4/17/08

4.5 Pure Linear Functional Programming

We defined congruence rules that determine the order of evaluation, using the following evaluation

CS-XXX: Graduate Programming Languages. Lecture 17 Recursive Types. Dan Grossman 2012

Introduction to System F. Lecture 18 CS 565 4/20/09

Structural polymorphism in Generic Haskell

CIS 500 Software Foundations Midterm I Answer key October 8, 2003

CSE505, Fall 2012, Midterm Examination October 30, 2012

Inductive Definitions, continued

Lecture Notes on Program Equivalence

λ calculus is inconsistent

CSE-505: Programming Languages. Lecture 20.5 Recursive Types. Zach Tatlock 2016

Introduction to Lambda Calculus. Lecture 7 CS /08/09

Type Systems. Parametric Polymorphism. 1. Recall Let-Polymorphism. 1. Recall Let-Polymorphism. Lecture 9 Dec. 15th, 2004 Sebastian Maneth

CIS 500 Software Foundations Fall September 25

CIS 500 Software Foundations Fall December 6

Administrivia. Existential Types. CIS 500 Software Foundations Fall December 6. Administrivia. Motivation. Motivation

CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011

Exercise 1 ( = 18 points)

1 Introduction. 3 Syntax

The Typed λ Calculus and Type Inferencing in ML

Supplementary Notes on Abstract Syntax

Goal. CS152: Programming Languages. Lecture 15 Parametric Polymorphism. What the Library Likes. What The Client Likes. Start simpler.

From Types to Sets in Isabelle/HOL

The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS

MLW. Henk Barendregt and Freek Wiedijk assisted by Andrew Polonsky. March 26, Radboud University Nijmegen

Fundamental Concepts. Chapter 1

Lambda Calculus and Type Inference

CMSC 336: Type Systems for Programming Languages Lecture 5: Simply Typed Lambda Calculus Acar & Ahmed January 24, 2008

Recursive Types and Subtyping

Type Inference; Parametric Polymorphism; Records and Subtyping Section and Practice Problems Mar 20-23, 2018

Lambda Calculus. Type Systems, Lectures 3. Jevgeni Kabanov Tartu,

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Calculus of Inductive Constructions

CSE-321 Programming Languages 2010 Midterm

Introduction to Lambda Calculus. Lecture 5 CS 565 1/24/08

The Lambda Calculus. 27 September. Fall Software Foundations CIS 500. The lambda-calculus. Announcements

CSE-321 Programming Languages 2010 Final

CSE-321 Programming Languages 2011 Final

Polymorphic lambda calculus Princ. of Progr. Languages (and Extended ) The University of Birmingham. c Uday Reddy

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

Lecture 8: Summary of Haskell course + Type Level Programming

Simple Unification-based Type Inference for GADTs

15 212: Principles of Programming. Some Notes on Continuations

Generic Programming With Dependent Types: II

Lecture #13: Type Inference and Unification. Typing In the Language ML. Type Inference. Doing Type Inference

Lecture Notes: Control Flow Analysis for Functional Languages

Theorem Proving Principles, Techniques, Applications Recursion

CS611 Lecture 33 Equirecursive types & Recursive domain equations November 19, 2001

λ calculus Function application Untyped λ-calculus - Basic Idea Terms, Variables, Syntax β reduction Advanced Formal Methods

CIS 500 Software Foundations Midterm I

Programming in Omega Part 1. Tim Sheard Portland State University

Types and Programming Languages. Lecture 6. Normalization, references, and exceptions

Recitation 6: System F and Existential Types : Foundations of Programming Languages

Concepts of programming languages

Exercise 1 ( = 24 points)

4.8 Dependent Types 97

CS 4110 Programming Languages & Logics. Lecture 17 Programming in the λ-calculus

Inductive datatypes in HOL. lessons learned in Formal-Logic Engineering

Calculus INT. Value Types A, B ::= types of the low-level language Interactive Types X, Y ::= [A] A X X Y A X

An Introduction to Programming and Proving in Agda (incomplete draft)

Type assignment for intersections and unions in call-by-value languages

(Refer Slide Time: 4:00)

CIS 500 Software Foundations Fall October 2

Lambda Calculus and Extensions as Foundation of Functional Programming

Programming Languages

15 212: Principles of Programming. Some Notes on Induction

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals

Supplementary Notes on Exceptions

CITS3211 FUNCTIONAL PROGRAMMING. 10. Programming in the pure λ calculus

Types and Programming Languages. Lecture 5. Extensions of simple types

Lecture #23: Conversion and Type Inference

CS 320: Concepts of Programming Languages

Conversion vs. Subtyping. Lecture #23: Conversion and Type Inference. Integer Conversions. Conversions: Implicit vs. Explicit. Object x = "Hello";

λ-calculus Lecture 1 Venanzio Capretta MGS Nottingham

Haskell 98 in short! CPSC 449 Principles of Programming Languages

CMSC 336: Type Systems for Programming Languages Lecture 4: Programming in the Lambda Calculus Acar & Ahmed 22 January 2008.

Harvard School of Engineering and Applied Sciences Computer Science 152

CMSC 330: Organization of Programming Languages

4.6 Recursive Types. 4.6 Recursive Types 105

Type-directed Syntax Transformations for ATS-style Programs with Proofs

CMSC 330: Organization of Programming Languages

Type-indexed functions in Generic Haskell

Advances in Programming Languages

Type Systems Winter Semester 2006

M. Snyder, George Mason University LAMBDA CALCULUS. (untyped)

Type families and data kinds

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

Formal Systems and their Applications

Exercise 1 (2+2+2 points)

Programming Language Concepts: Lecture 19

Lecture Notes on Session Types

Transcription:

Supplementary Notes on Recursive Types 15-312: Foundations of Programming Languages Frank Pfenning Lecture 13 October 8, 2002 In the last two lectures we have seen two critical concepts of programming languages: parametric polymorphism (modeled by universal types) and data abstraction (modeled by existential types). These provide quantification over types, but they do not allow us to define types recursively. Clearly, this is needed in a practical language. Common data structures such as lists or trees are defined inductively, which is a restricted case of general recursion in the definition of types [Ch. 19.3]. So far, we have considered how to add a particular recursive type, namely lists, to our language as a primitive by giving constructors (nil and cons), a discriminating destructor (listcase). For a realistic language, this approach is unsatisfactory because we would have to extend the language itself every time we needed a new data type. Instead we would like to have a uniform construct to define new recursive types as we need them. In ML, this is accomplished with the datatype construct. Here we use a somewhat lower-level primitive we return to the question how this is related to ML at the end of this lecture. As a first, simple non-recursive example, consider how we might implement a three-element type. datatype Color = Red Green Blue;

L13.2 Recursive Types Using the singleton type 1 (unit, in ML), we can define Color = 1 + (1 + 1) Red : Color = inl ( ) Green : Color = inr(inl ( )) Blue : Color = inr(inr ( )) ccase : s.color (1 s) (1 s) (1 s) s = Λs.λc.λy 1.λy 2.λy 3. case c of inl(c 1 ) y 1 c 1 inr(c 2 ) case c 2 of inl(z 2 ) y 2 z 2 inr(z 3 ) y 3 z 3 Recall the notation λx.e for a non-recursive function and Λt.e for a type abstraction. The ccase constructs invokes one of its arguments y 1, y 2, or y 3, depending on whether the argument c represents red, green, or blue. If we try to apply the technique, for example, to represent natural numbers as they would be given in ML by datatype Nat = Zero Succ of Nat; we would have Nat = 1 + (1 + (1 + )) where n : Nat = inr(... (inr( inl ( )))) }{{} n times In order to make this definition recursive instead of infinitary we would write Nat 1 + Nat where we leave the mathematical status of purposely vague, but one should read τ σ as τ is isomorphic to σ. Just as with the recursion at the level of expressions, it is more convenient to write this out as an explicit definition using a recursion operator. Nat = µt.1 + t We can unwind a recursive type µt.σ to {µt.σ/t}σ to obtain an isomorphic type. Nat = µt.1 + t {µt.1 + t/t}1 + t = 1 + µt.1 + t = 1 + Nat

Recursive Types L13.3 In order to obtain a reasonable system for type-checking, we have constructors and destructors for recursive types. They can be considered witnesses for the unrolling of a recursive type. Γ e : {µt.τ/t}τ Γ µt.τ type Γ roll(e) : µt.τ Γ e : µt.τ Γ unroll(e) : {µt.τ/t}τ The operational semantics and values are straightforward; the difficulty of recursive types lies entirely in the complexity of the substitution that takes place during the unrolling of a recursive type. e e roll(e) roll(e ) e e unroll(e) unroll(e ) v value roll(v) value v value unroll(roll(v)) v Now we can go back to the definition of specific recursive types, using natural numbers built from zero and successor as the first example. Nat = µt.1 + t Zero : Nat = roll(inl ( )) Succ : Nat Nat = λx.roll(inr x) ncase : s.nat (1 s) (nat s) s = Λs.λn.λy 1.λy 2. case unroll(n) of inl(z 1 ) y 1 z 1 inr(z 2 ) y 2 z 2 In the definition of ncase we see that z 1 : 1 and z 2 : Nat, so that y 2 is really applies to the predecessor of n, while y 1 is just applied to the unit element. Polymorphic recursive types can be defined in a similar manner. As an example, we consider lists with elements of type r. r List = µt.1 + r t Nil : r.r List = Λr.roll(inl ( )) Cons : r.r r List r List = Λs.λp.roll(inr p) lcase : s. r.r List (1 s) (r r List s) s = Λs.Λr.λl.λy 1.λy 2. case unroll(l) of inl(z 1 ) y 1 z 1 inr(z 2 ) y 2 z 2

L13.4 Recursive Types If we go back to the first example, it is easy to see that representation of data types does not quite match their use in ML. This is because we can see the complete implementation of the type, for example, Color = 1 + (1 + 1). This leads to a loss of data abstraction and confusion between different data types. Consider another ML data type Answer = Yes No Maybe; This would also be represented by Answer = 1 + (1 + 1) which is the same as Color. Perhaps this does not seem problematic until we realize that Yes = Red! This is obviously meaningless and create incompatibilities, for example, if we decide to change the order of definition of the elements of the data types. Fortunately, we already have the tool of data abstraction to avoid this kind of confusion. We therefore combine recursive types with existential types to model the datatype construct of ML. Using the first example, datatype Color = Red Green Blue; we would represent this c.c c c s.c (1 s) (1 s) (1 s) s The implementation will have the form pack(1 + (1 + 1), pair(inl ( ), pair(inr(inl ( )),...))) Upon opening an implementation of this type we can give its components the usual names. With this strategy, Color and Answer can no longer be confused. We close this section with a curiosity regarding recursive types. We can use them to type a simple, non-terminating expression that does not employ recursive functions! The pure λ-calculus version of this function is (λx.x x) (λx.x x). Our example is just slight more complicated because of the need to roll and unroll recursive types.

Recursive Types L13.5 We define ω = µt.t t x:ω unroll(x) : ω ω x:ω unroll(x) x : ω λx.unroll(x) x : ω ω roll(λx.unroll(x) x) : ω (λx.unroll(x) x) roll(λx.unroll(x) x) : ω When we execute this term we obtain (λx.unroll(x) x) roll(λx.unroll(x) x) unroll(roll(λx.unroll(x) x)) (roll(λx.unroll(x) x)) (λx.unroll(x) x) (roll(λx.unroll(x) x)) so it reduces to itself in two steps. While we will probably not prove this in this course, recursive types are necessary for such an example. For any other (pure) type construct we have introduced so far, all functions are terminating if we do not use recursion at the level of expressions.