Harvard School of Engineering and Applied Sciences Computer Science 152

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

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

Programming Languages Lecture 15: Recursive Types & Subtyping

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

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

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

Polymorphism. Lecture 19 CS 565 4/17/08

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

Programming Languages

CSE 505, Fall 2008, Final Examination 11 December Please do not turn the page until everyone is ready.

CSE 505, Fall 2008, Final Examination 11 December Please do not turn the page until everyone is ready.

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

The Polymorphic Blame Calculus and Parametricity

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

Programming Languages Assignment #7

Second-Order Type Systems

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

CSE505, Fall 2012, Midterm Examination October 30, 2012

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

Mutable References. Chapter 1

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

Types for References, Exceptions and Continuations. Review of Subtyping. Γ e:τ τ <:σ Γ e:σ. Annoucements. How s the midterm going?

Unifying Nominal and Structural Ad-Hoc Polymorphism

Lambda Calculi With Polymorphism

Simply-Typed Lambda Calculus

λ calculus is inconsistent

CSE 505, Fall 2007, Final Examination 10 December Please do not turn the page until everyone is ready.

CS-XXX: Graduate Programming Languages. Lecture 9 Simply Typed Lambda Calculus. Dan Grossman 2012

Subtyping. Lecture 13 CS 565 3/27/06

Lambda Calculi With Polymorphism

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

CSE-321 Programming Languages 2010 Final

Lecture 13: Subtyping

Advances in Programming Languages

COMP 4161 NICTA Advanced Course. Advanced Topics in Software Verification. Toby Murray, June Andronick, Gerwin Klein

1 Introduction. 3 Syntax

CSE 505, Fall 2009, Final Examination 14 December Please do not turn the page until everyone is ready.

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

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

Part III. Chapter 15: Subtyping

Programming Languages Lecture 14: Sum, Product, Recursive Types

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

CMSC 330: Organization of Programming Languages

Metaprogramming assignment 3

Abstract register machines Lecture 23 Tuesday, April 19, 2016

Official Survey. Cunning Plan: Focus On Objects. The Need for a Calculus. Object Calculi Summary. Why Not Use λ-calculus for OO?

Type Checking and Type Inference

Part III Chapter 15: Subtyping

Subsumption. Principle of safe substitution

Lecture #23: Conversion and Type Inference

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

CMSC 330: Organization of Programming Languages

Polymorphism and Type Inference

Typed Lambda Calculus and Exception Handling

COMP 1130 Lambda Calculus. based on slides by Jeff Foster, U Maryland

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

Tradeoffs. CSE 505: Programming Languages. Lecture 15 Subtyping. Where shall we add useful completeness? Where shall we add completeness?

CS558 Programming Languages

Subtyping and Objects

CS 4110 Programming Languages & Logics. Lecture 27 Recursive Types

Lecture 13 CIS 341: COMPILERS

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

Variables. Substitution

If a program is well-typed, then a type can be inferred. For example, consider the program

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

G Programming Languages Spring 2010 Lecture 6. Robert Grimm, New York University

The Untyped Lambda Calculus

One of a number of approaches to a mathematical challenge at the time (1930): Constructibility

Typing Data. Chapter Recursive Types Declaring Recursive Types

Recursive Types and Subtyping

CSE 505, Fall 2006, Final Examination 11 December Please do not turn the page until everyone is ready.

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

Intro to semantics; Small-step semantics Lecture 1 Tuesday, January 29, 2013

Types and Type Inference

CS 4110 Programming Languages & Logics. Lecture 28 Recursive Types

CMSC 330: Organization of Programming Languages

CSE-321 Programming Languages 2011 Final

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

Featherweight Java (FJ)

CSE-321: Assignment 8 (100 points)

Types-2. Polymorphism

Type Systems, Type Inference, and Polymorphism

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

CS131 Typed Lambda Calculus Worksheet Due Thursday, April 19th

Type Systems. Pierce Ch. 3, 8, 11, 15 CSE

Programming Language Concepts: Lecture 19

INF 212 ANALYSIS OF PROG. LANGS Type Systems. Instructors: Crista Lopes Copyright Instructors.

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.

CSE 505: Concepts of Programming Languages

Some instance messages and methods

Programming Language Features. CMSC 330: Organization of Programming Languages. Turing Completeness. Turing Machine.

CMSC 330: Organization of Programming Languages

Types. Type checking. Why Do We Need Type Systems? Types and Operations. What is a type? Consensus

CS558 Programming Languages

Flang typechecker Due: February 27, 2015

Resources: The slides of this lecture were derived from [Järvi], with permission of the original author, by copy & x = 1 let x = 1 in...

Part VI. Imperative Functional Programming

CSC312 Principles of Programming Languages : Functional Programming Language. Copyright 2006 The McGraw-Hill Companies, Inc.

Dependent Types. Announcements. Project Presentations. Recap. Dependent Types. Dependent Type Notation

Subtyping (cont) Lecture 15 CS 565 4/3/08

Transcription:

Harvard School of Engineering and Applied Sciences Computer Science 152 Lecture 17 Tuesday, March 30, 2010 1 Polymorph means many forms. Polymorphism is the ability of code to be used on values of different types. For example, a polymorphic function is one that can be invoked with arguments of different types. A polymorphic datatype is one that can contain elements of different types. Several kinds of polymorphism are commonly used in modern languages. Subtype polymorphism gives a single term many types using the subsumption rule. For example, a function with argument τ can operate on any value with a type that is a subtype of τ. Ad-hoc polymorphism usually refers to code that appears to be polymorphic to the programmer, but the actual implementation is not. A typical example is overloading: using the same function name for functions with different kinds of parameters. Although it looks like a polymorphic function to the code that uses it, there are actually multiple function implementations (none being polymorphic) and the compiler invokes the appropriate one. Ad-hoc polymorphism is a dispatch mechanism: the type of the arguments is used to determine (either at compile time or run time) which code to invoke. refers to code that is written without knowledge of the actual type of the arguments; the code is parametric in the type of the parameters. Examples include polymorphic functions in ML, or generics in Java 5. We consider parametric polymorphism in more detail. Suppose we are working in the simply-typed lambda calculus, and consider a doubling function for integers that takes a function f, and an integer x, applies f to x, and then applies f to the result. doubleint λf :int int. λx:int. f (f x) We could also write a double function for booleans. Or for functions over integers. Or for any other type... doublebool λf :bool bool. λx:bool. f (f x) doublef n λf :(int int) (int int). λx:int int. f (f x). In the simply typed lambda calculus, if we want to apply the doubling operation to different types of arguments in the same program, we need to write a new function for each type. This violates the abstraction principle of software engineering: Each significant piece of functionality in a program should be implemented in just one place in the source code. When similar functions are carried out by distinct pieces of code, it is generally beneficial to combine them into one by abstracting out the varying parts. In the doubling functions above, the varying parts are the types. We need a way to abstract out the type of the doubling operation, and later instantiate this abstract type with different concrete types. We extend the simply-typed lambda calculus with abstraction over types, giving the polymorphic lambda calculus, also called System F. A type abstraction is a new expression, written ΛX. e, where Λ is the upper-case form of the Greek letter lambda, and X is a type variable. We also introduce a new form of application, called type application, or instantiation, written e 1 [τ].

When a type abstraction meets a type application during evaluation, we substitute the free occurrences of the type variable with the type. Note that instantiation does not require the program to keep run-time type information, or to perform type checks at run-time; it is just used as a way to statically check type safety in the presence of polymorphism. 1.1 Syntax and operational semantics The new syntax of the language is given by the following grammar. e ::= n x λx:τ. e e 1 e 2 ΛX. e e [τ] v ::= n λx:τ. e ΛX. e The evaluation rules for the polymorphic lambda calculus are the same as for the simply-typed lambda calculus, augmented with new rules for evaluating type application. E ::= [ ] E e v E E [τ] e e E[e] E[e ] β-reduction (λx:τ. e) v e{v/x TYPE-REDUCTION (ΛX. e) [τ] e{τ/x Let s consider an example. In this language, the polymorphic identity function is written as ID ΛX. λx:x. x We can apply the polymorphic identity function to int, producing the identity function on integers. (ΛX. λx:x. x) [int] λx:int. x We can apply ID to other types as easily: (ΛX. λx:x. x) [int int] λx:int int. x 1.2 Type system We also need to provide a type for the new type abstraction. The type of ΛX. e is X. τ, where τ is the type of e, and may contain the type variable X. Intuitively, we use this notation because we can instantiate the type expression with any type for X: for any type X, expression e can have the type τ (which may mention X). τ ::= int τ 1 τ 2 X X. τ Type checking expressions is slightly different than before. Besides the type environment Γ (which maps variables to types), we also need to keep track of the set of type variables. This is to ensure that a type variable X is only used in the scope of an enclosing type abstraction ΛX. e. Thus, typing judgments are now of the form, Γ e : τ, where is a set of type variables, and Γ is a typing context. We also use an additional judgment τ ok to ensure that type τ uses only type variables from the set., Γ n:int τ ok, Γ x:τ Γ(x) = τ, Γ, x:τ e:τ τ ok, Γ λx:τ. e:τ τ Page 2 of 5

, Γ e 1 :τ τ, Γ e 2 :τ, Γ e 1 e 2 :τ {X, Γ e:τ, Γ ΛX. e: X. τ, Γ e: X. τ τ ok, Γ e [τ]:τ {τ/x X ok X int ok τ 1 ok τ 2 ok τ 1 τ 2 ok τ 1 ok {X τ ok X. τ ok 1.3 Examples Let s consider the doubling operation again. We can write a polymorphic doubling operation as double ΛX. λf :X X. λx:x. f (f x). The type of this expression is X. (X X) X X We can instantiate this on a type, and provide arguments. For example, double [int] (λn:int. n + 1) 7 (λf :int int. λx:int. f (f x)) (λn:int. n + 1) 7 9 Recall that in the simply-typed lambda calculus, we had no way of typing the expression λx. x x. In the polymorphic lambda calculus, however, we can type this expression if we give it a polymorphic type and instantiate it appropriately. λx: X. X X. x [ X. X X] x : ( X. X X) ( X. X X) 1.4 Polymorphism in ML and Java In real languages such as ML, programmers don t have to annotate their programs with X. τ or e [τ]. Both are automatically inferred by the compiler (although the programmer can specify the former if he wishes). For example, we can write let double f x = f (f x);; and Ocaml will figure out that the type is ( a -> a) -> a -> a (which is roughly equivalent to A. (A A) A A). We can also write double (fun x -> x+1) 7;;, and Ocaml will infer that the polymorphic function double is instantiated on the type int. The polymorphism in ML is not, however, exactly like the polymorphism in System F. ML restricts what types a type variable may be instantiated with. Specifically, type variables can not be instantiated with polymorphic types. Also, polymorphic types are not allowed to appear on the left-hand side of arrows (i.e., a polymorphic type cannot be the type of a function argument). This form of polymorphism is known as let-polymorphism (due to the special role played by let in ML), or prenex polymorphism. These restrictions ensure that type inference is possible. An example of a term that is typable in System F but not typable in ML is the self-application expression λx. x x. (Try typing fun x -> x x;; in the top-level loop of Ocaml, and see what happens...) Java, as of version 1.5, provides generics, a form of parametric polymorphism. For instance, we can write a class that is parameterized on an unknown reference type T: Page 3 of 5

class Pair T { T x, y; Pair(T x, T y) { this.x = x; this.y = y; T fst(pair T p) { this.x = p.x; return p.x; This is a class that contains a pair of two elements of some unknown type T. The parameterization T is implicit around the class declaration. Since Java does not support type inference, type instantiations are required. Type instantiations are done by writing the actual type in angle brackets: Pair Boolean p; p = new Pair Boolean (Boolean.TRUE, Boolean.FALSE); Boolean x = p.fst(p); 1.5 Bounded polymorphism Polymorphism and subtyping can be combined. That is, we can change type abstraction to include an upper bound on the types that can be used to instantiate the type variable: X τ 1. τ 2. This means that X can only be instantiated with a subtype of τ 1. Note that if there is a top type (i.e., every type τ is a subtype of ), then X. τ is equivalent to X. τ. Subtyping and parametric polymorphism are largely orthogonal. We need to change the type variable context so that it contains the bounds on type variables, so is now a sequence of elements of the form X τ. The syntax of expressions, values and types is now as follows. e ::= n x λx:τ. e e 1 e 2 ΛX τ. e e [τ] v ::= n λx:τ. e ΛX τ. e τ ::= int τ 1 τ 2 X X. τ The operational semantics are the same (modulo the minor changes to syntax). Most of the typing rules remain the same. We present the rules for type abstraction, type application, and subsumption. Note that type application requires that the instantiating type is a subtype of the declared bound on the type variable. Note also that the subtyping relation now uses the type variable context., X τ 1, Γ e:τ 2, Γ e: X τ 1. τ 2 τ τ 1, Γ ΛX τ 1. e: X τ 1. τ 2, Γ e [τ]:τ 2 {τ/x, Γ e:τ τ τ, Γ e:τ The rule for subtyping a type variable simply uses the type variable context. X τ X τ The subtyping rule for polymorphic types is the most interesting. Going back to the subtyping principle, X τ 1. τ 2 is a subtype of X τ 1. τ 2 if whenever a value of type X τ 1. τ 2 is expected, a value of type X τ 1. τ 2 can be used instead. Intuitively, an expression of polymorphic type X τ 1. τ 2 can be thought of as a function from types to terms. That is, it takes a type as an argument, and returns an expression. Page 4 of 5

(By contrast, functions (also known as term abstractions) that we have seen previously are functions from terms to terms.) A term of type X τ 1. τ 2 may be instantiated with any type that is a subtype of τ 1; for X τ 1. τ 2 to be a subtype, it must also be able to be instantiated with any type that is a subtype of τ 1, so we want τ 1 to be a subtype of τ 1. That is, we are contravariant in the bound on the type variable. Also, when instantiated on any type X that satisfies both constraints (i.e., X τ 1 and X τ 1), a value produced by an expression of type τ 2 should be usable at type τ 2. So we want, X τ 1 τ 2 τ 2. The inference rule for subtyping on polymorphic types is thus the following. τ 1 τ 1, X τ 1 τ 2 τ 2 X τ 1. τ 2 X τ 1. τ 2 Page 5 of 5