GADTs meet Subtyping

Similar documents
GADT meet subtyping. arxiv: v1 [cs.pl] 22 Oct 2012 RESEARCH REPORT N Gabriel Scherer, Didier Rémy. October Project-Team Gallium

Tracing Ambiguity in GADT Type Inference

Ornaments in ML. Thomas Williams, Didier Rémy. April 18, Inria - Gallium

Programming Languages Lecture 15: Recursive Types & Subtyping

Adding GADTs to OCaml the direct approach

CSCI-GA Scripting Languages

TYPE INFERENCE. François Pottier. The Programming Languages Mentoring ICFP August 30, 2015

Programming Languages Lecture 14: Sum, Product, Recursive Types

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

Subtyping. Lecture 13 CS 565 3/27/06

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

Search for Program Structure

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

Recursive Types and Subtyping

Where is ML type inference headed?

COS 320. Compiling Techniques

1 Introduction. 3 Syntax

Lecture #23: Conversion and Type Inference

Generic polymorphism on steroids

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

Lecture Notes on Aggregate Data Structures

Runtime Behavior of Conversion Interpretation of Subtyping

COSE212: Programming Languages. Lecture 3 Functional Programming in OCaml

L3 Programming September 19, OCaml Cheatsheet

Type Checking in COOL (II) Lecture 10

Programming Languages and Compilers (CS 421)

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

l e t print_name r = p r i n t _ e n d l i n e ( Name : ^ r. name)

Introduction to OCaml

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

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

Recursive Types and Subtyping

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

CS 4110 Programming Languages & Logics. Lecture 28 Recursive Types

Meeting14:Denotations

Coherent Coercion Abstraction with a step-indexed strong-reduction semantics

Relaxing the Value Restriction

CS558 Programming Languages

Programming Languages

MPRI course 2-4 Functional programming languages Exercises

Simple Unification-based Type Inference for GADTs

CSE-321: Assignment 8 (100 points)

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

Contractive Signatures with Recursive Types, Type Parameters, and Abstract Types

Hiding local state in direct style: a higher-order anti-frame rule

Part VI. Imperative Functional Programming

Static Checking and Type Systems

Relaxing the Value Restriction

The Worker/Wrapper Transformation

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

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

Agenda. CS301 Session 9. Abstract syntax: top level. Abstract syntax: expressions. The uscheme interpreter. Approaches to solving the homework problem

Types-2. Polymorphism

Programming Languages Assignment #7

Gradual Typing with Union and Intersection Types

The Worker/Wrapper Transformation

CSE-321 Programming Languages 2014 Final

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

CS558 Programming Languages

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

Intermediate Code Generation Part II

On the Logical Foundations of Staged Computation

CMSC 330: Organization of Programming Languages

Verifying Program Invariants with Refinement Types

Structural polymorphism in Generic Haskell

Scope and Introduction to Functional Languages. Review and Finish Scoping. Announcements. Assignment 3 due Thu at 11:55pm. Website has SML resources

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

CVO103: Programming Languages. Lecture 5 Design and Implementation of PLs (1) Expressions

Let Arguments Go First

Lecture 13: Subtyping

CSE-321 Programming Languages 2011 Final

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

F-ing Applicative Functors

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

A CRASH COURSE IN SEMANTICS

Principles of Programming Languages

Harvard School of Engineering and Applied Sciences Computer Science 152

Some instance messages and methods

Modular implicits for OCaml how to assert success. Gallium Seminar,

λ calculus is inconsistent

The design of a programming language for provably correct programs: success and failure

Combining Programming with Theorem Proving

Recap: Functions as first-class values

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

Dynamics in ML. 1 Introduction. Xavier Leroy Ecole Normale Supérieure. Michel Mauny INRIA Rocquencourt

A type directed translation of MLF to System F

Subtyping and Objects

Mutable References. Chapter 1

Static and User-Extensible Proof Checking. Antonis Stampoulis Zhong Shao Yale University POPL 2012

Gradual Typing with Inference

n Closed book n You are allowed 5 cheat pages n Practice problems available in Course Materials n Check grades in Rainbow grades

First-Class Type Classes

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

Project 6 Due 11:59:59pm Thu, Dec 10, 2015

Shared Subtypes. Subtyping Recursive Parameterized Algebraic Data Types

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

Static analysis and all that

CS421 Spring 2014 Midterm 1

Static semantics. Lecture 3-6: Semantics. Attribute grammars (2) Attribute grammars. Attribute grammars example. Dynamic semantics

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

Transcription:

GADTs meet Subtyping Gabriel Scherer, Didier Rémy Gallium INRIA 2014 Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 1 / 21

A reminder on GADTs GADTs are algebraic data types that may carry type equalities. Think of the following simple type: type expr = Int of int Bool of bool Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 2 / 21

A reminder on GADTs GADTs are algebraic data types that may carry type equalities. Think of the following simple type: type expr = Int of int Bool of bool It can be turned into the more finely typed: type α expr = Int of int with α = int Bool of bool with α = bool type α expr = Int : int -> int expr Bool : bool -> bool expr Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 2 / 21

A reminder on GADTs GADTs are algebraic data types that may carry type equalities. Think of the following simple type: type expr = Int of int Bool of bool It can be turned into the more finely typed: type α expr = Int of int with α = int Bool of bool with α = bool We can now write the following: let eval : α. α expr α = function Int n -> n (* α = int *) Bool b -> b (* α = bool *) type α expr = Int : int -> int expr Bool : bool -> bool expr Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 2 / 21

Motivating variance Subtyping: σ τ means all values of σ are also values of τ. Checked by set of decidable and incomplete inference rules. σ 1 σ 1 σ 2 σ 2 (σ 1 σ 2 ) (σ 1 σ 2) Variance annotations lift subtyping to type parameters. type (-α, =β, +γ) t = (α β) (β γ) α α β = β γ γ (α, β, γ) t (α, β, γ ) t For simple types, this is easy to check. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 3 / 21

Variance for GADT: harder than it seems Ok? type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 4 / 21

Variance for GADT: harder than it seems Ok? type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr And this one? type file_descr = private int (* file descr int *) val stdin : file_descr type +α t = File : file_descr -> file_descr t let o = File stdin in let o = (o : file_descr t :> int t) Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 4 / 21

Variance for GADT: harder than it seems Ok? type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr And this one? type file_descr = private int (* file descr int *) val stdin : file_descr type +α t = File : file_descr -> file_descr t let o = File stdin in let o = (o : file_descr t :> int t) Breaks abstraction! let project : α. α t (α file descr) = function File _ -> (fun x -> x) project o : int -> file_descr Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 4 / 21

Proving an example correct type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr When σ σ, I know it s safe to assume σ expr σ expr. Because I could almost write that conversion myself. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 5 / 21

Proving an example correct type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr When σ σ, I know it s safe to assume σ expr σ expr. Because I could almost write that conversion myself. let coerce (α α ) : α expr α expr = function Val (v : α) -> Val (v :> α ) Prod β γ ((b, c) : β expr γ expr) -> (* α = (β γ), α α ; Prod? *) Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 5 / 21

Proving an example correct type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr When σ σ, I know it s safe to assume σ expr σ expr. Because I could almost write that conversion myself. let coerce (α α ) : α expr α expr = function Val (v : α) -> Val (v :> α ) Prod β γ ((b, c) : β expr γ expr) -> (* α = (β γ), α α ; Prod? *) (* if β γ α, then α is of the form β γ with β β and γ γ *) Prod β γ ((b :> β expr), (c :> γ expr)) Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 5 / 21

Proving an example correct type +α expr = Val : α. α α expr Prod : βγ. β expr γ expr (β γ) expr When σ σ, I know it s safe to assume σ expr σ expr. Because I could almost write that conversion myself. let coerce (α α ) : α expr α expr = function Val (v : α) -> Val (v :> α ) Prod β γ ((b, c) : β expr γ expr) -> (* α = (β γ), α α ; Prod? *) (* if β γ α, then α is of the form β γ with β β and γ γ *) Prod β γ ((b :> β expr), (c :> γ expr)) Upward closure for τ[α]: If τ[σ] τ, then τ is also of the form τ[σ ] for some σ. Holds for α β, but fails for file descr = private int. abriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 5 / 21

In the general case Consider a GADT α t with a constructor of the form K of β[α = T [β]]. τ[β] Imagine I have a value v of type σ t, and I know σ σ. Can I convert this σ t into a σ t? Let s write the coercion code again: match v : σ t with... K arg -> (arg : τ[ρ] :> τ[?]) We can type-check this coercion term when σ σ if and only if ρ, σ = T [ρ] = ρ, σ = T [ρ ] τ[ρ] τ[ρ ] This extends both upward-closure and the usual variance check on τ. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 6 / 21

The semantic criterion A GADT declaration for vα t is correct if, for each constructor K of type β[d[α, β]].τ[β], we have σσ ρ, σ t σ t D[σ, ρ] = ρ, D[σ, ρ ] τ[ρ] τ[ρ ] How can we check this? What does it even mean? Our job: get something syntactic out of this semantic criterion, that compilers and humans can understand and use. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 7 / 21

The plan We will first explain how to check variance of type variables by a judgment Γ τ : v. Resembles previous work with a twist. We will then extend it to a judgment Γ τ : v v to check closure properties. From there it s not too hard (but not too easy either) to derive the final syntactic formulation of the correctness criterion. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 8 / 21

Variances + : only positive occurences : only negative occurences = : both positive and negative : no occurence at all + = σ + τ := σ τ σ τ := σ τ σ = τ := σ = τ Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 9 / 21

Variances + : only positive occurences : only negative occurences = : both positive and negative : no occurence at all + = σ + τ := σ τ σ τ := σ τ σ = τ := σ = τ σ τ := true Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 9 / 21

Variances + : only positive occurences : only negative occurences = : both positive and negative : no occurence at all + = σ + τ := σ τ σ τ := σ τ σ = τ := σ = τ σ τ := true If α has variance v in (α t), and β variance w in (β u), what is the variance of α in ((α t) u)? v.w = + w = = = = + = + = + v Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 9 / 21

Γ τ : v We manipulate contexts Γ of variables with variances: ( α, =β, +γ). Γ τ : v means that if the variables vary according to their variance, τ varies along v. α, =β, +γ (α β) (β γ) : (+) =α, =β, =γ (α β) (β γ) : (=) Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 10 / 21

Γ τ : v We manipulate contexts Γ of variables with variances: ( α, =β, +γ). Γ τ : v means that if the variables vary according to their variance, τ varies along v. α, =β, +γ (α β) (β γ) : (+) =α, =β, =γ (α β) (β γ) : (=) wα Γ Γ α : v w v Γ wα t i, Γ σ i : v.w i Γ σ t : v For instance, in the arrow case: Γ σ 1 : v. Γ σ 2 : v.+ Γ (σ 1 σ 2 ) : v Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 10 / 21

Closure properties in depth In our system, α β is upward-closed. This is because the head type constructor, ( ), is closed. For α t (β γ) to be upward-closed, α t must be downward-closed. In the general case, we recursively check closure, according to variance. What about variables? Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 11 / 21

What about variables? [Reminder] Upward closure: If τ[σ] τ, then τ = τ[σ ] for some σ. β β is not closed : (file descr file descr) (file descr int). Repeating a variable twice is dangerous. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 12 / 21

What about variables? [Reminder] Upward closure: If τ[σ] τ, then τ = τ[σ ] for some σ. β β is not closed : (file descr file descr) (file descr int). Repeating a variable twice is dangerous. Yet, (β ref) (β ref) is closed... because all occurences are invariant. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 12 / 21

What about variables? [Reminder] Upward closure: If τ[σ] τ, then τ = τ[σ ] for some σ. β β is not closed : (file descr file descr) (file descr int). Repeating a variable twice is dangerous. Yet, (β ref) (β ref) is closed... because all occurences are invariant. We capture those subtleties through a partial variance operation v 1 v 2. Defined only when two occurences at variances v 1 and v 2 can be soundly combined. v w = + w = = = + + = + v Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 12 / 21

Γ τ : v v We can finally extend the judgment Γ τ : v to capture closure properties. We want to say that Γ τ is v-closed if: We need a generalization: τ, σ, τ[σ] v τ = σ, τ[σ ] = τ τ, σ, τ[σ] v τ = σ, τ[σ ] v τ This is our Γ τ : v v judgment. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 13 / 21

Inference rules for the show They rely on closure information for type constructors, and to merge contexts of subterms. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 14 / 21

Inference rules for the show They rely on closure information for type constructors, and to merge contexts of subterms. Triv v v Γ τ : v Γ τ : v v Var wα Γ w = v Γ α : v v Constr Γ wα t : v-closed Γ = i Γ i i, Γ i σ i : v.w i v.w i Γ σ t : v v Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 14 / 21

How do you check those rules? Theorem Γ τ : v holds if and only if σ, σ, σ Γ σ = τ[σ] v τ[σ ] Simple. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 15 / 21

How do you check those rules? Theorem Γ τ : v holds if and only if σ, σ, σ Γ σ = τ[σ] v τ[σ ] Simple. Theorem Γ τ : v (=) holds if and only if Γ τ : v and ρ, τ, τ[ρ] v τ = ρ, τ[ρ ] = τ Soundness (syntactic = semantic): routine. Completeness (semantic = syntactic): surprisingly hard. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 15 / 21

Back to the check From these primitives, we can devise a syntactic check for our initial semantic criterion. Assume we have the variances v α and a constructor declaration of the form ( β [ i I α i = T i [β] ]. τ[β]). Remember the sophisticated semantic criterion: σ, σ, ρ, σ t σ t (σ i = T i [ρ]) i I = ρ, (σ i = T i [ρ ]) i I τ[ρ] τ[ρ ] Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 16 / 21

Back to the check From these primitives, we can devise a syntactic check for our initial semantic criterion. Assume we have the variances v α and a constructor declaration of the form ( β [ i I α i = T i [β] ]. τ[β]). Remember the sophisticated semantic criterion: σ, σ, ρ, σ t σ t (σ i = T i [ρ]) i I = ρ, (σ i = T i [ρ ]) i I τ[ρ] τ[ρ ] Theorem (Algorithmic criterion) The soundness criterion above is equivalent to Γ, (Γ i ) i I, Γ τ : (+) Γ = Γ i i I, Γ i T i : v i (=) i I (Oral explanation) Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 16 / 21

Phew! That was the formal side of things. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 17 / 21

Phew! That was the formal side of things. This criterion raises interesting design issues: private definitions make all OCaml types non-downward-closed. Should we restrict those? The opposite of OOP s final keyword. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 17 / 21

Another solution We showed, through hard work, how to check that equality constraints are upward-closed. With subtyping in constructor types, variance is easy to check type +α expr = Val : β α. β α expr Prod : βγ [α (β γ)]. β expr γ expr α expr Now pattern-matching only knows a subtyping relation: let eval : α. α expr α = function Int n -> (n :> α) (* α int *) Bool b -> (b :> α) (* α bool *) Less convenient: use of subtyping must be annotated explicitly, while equations where implicit. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 18 / 21

Future work: Completeness of the S&P criterion: type inhabitation. Verify behavior through type abstraction. Does this also happen with inductive dependent types? Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 19 / 21

Conclusion GADT variance checking: suprisingly less obvious than we thought. Not anecdotal: raises deeper design questions. We have a sound criterion that can be implemented easily in a type checker. Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 20 / 21

Bonus Slide: Variance and the value restriction type (= a) ref = { mutable contents : a } In a language with mutable data, generalizing any expression is unsafe (because you may generalize data locations): # let test = ref [];; val test : _a list ref Solution (Wright, 1992): only generalize values (fun () -> ref [], or []). Painful when manipulating polymorphic data structures: let test = id [] (* not generalized? *) OCaml relies on variance for the relaxed value restriction covariant data is immutable, so covariant type variables may be safely generalized. Very useful in practice. # let test = id [];; val test : a list = [] Gabriel Scherer, Didier Rémy (Gallium INRIA) GADTs meet Subtyping 2014 21 / 21