Download presentation

Presentation is loading. Please wait.

Published byAshley Padilla Modified over 5 years ago

1
Transposing F to C Transposing F to C Andrew Kennedy & Don Syme Microsoft Research Cambridge, U.K.

2
Transposing what? As musical keys, F and C are far apart As musical keys, F and C are far apart As programming languages, (System) F and (Generic) C are far apart As programming languages, (System) F and (Generic) C are far apart But (message of talk): But (message of talk): Polymorphism in Generic C is as expressive as polymorphism in System F

3
Polymorphic Programming Languages Standard ML OCaml Eiffel Ada (coming soon…) C (coming soon…) GJ C++ Mercury Clu

4
Polymorphic features Parameterized datatypes Parameterized classes Polymorphic functions For-all types Polymorphic methods Bounds on type parameters Constraints on type parameters Higher-order polymorphism & kinds Impredicative polymorphism Type classes Variance

5
System F and C System F and C System F (a.k.a. polymorphic lambda calculus) is very different from C System F (a.k.a. polymorphic lambda calculus) is very different from C System F Generic C Generic C Structural equivalence for types Name equivalence for types No subtyping Subtyping & inheritance First-class functions Virtual methods Quantified types (first-class polymorphism) Parameterized classes & polymorphic methods

6
System F into C System F into C Despite these differences, we can formalize a translation from System F into (Generic) C that Despite these differences, we can formalize a translation from System F into (Generic) C that is fully type-preserving (no loss of information) is fully type-preserving (no loss of information) is sound (preserves program behaviour) is sound (preserves program behaviour) (second message of talk) demonstrates that… (second message of talk) demonstrates that… polymorphic virtual methods express first-class polymorphism

7
ML-style polymorphism into C ML-style polymorphism into C Define a datatype: datatype a Tree = Leaf of a | Node of a Tree*a Tree Define a datatype: datatype a Tree = Leaf of a | Node of a Tree*a Tree Write a polymorphic function: fun reflect (t : a Tree) = case t of Leaf a => Leaf a | Node(l,r) => Node(reflect r,reflect l) Write a polymorphic function: fun reflect (t : a Tree) = case t of Leaf a => Leaf a | Node(l,r) => Node(reflect r,reflect l)

8
Compare: Define parameterized classes: abstract class Tree {... } class Leaf : Tree { A value;... } class Node : Tree { Tree left; Tree right;... } Define parameterized classes: abstract class Tree {... } class Leaf : Tree { A value;... } class Node : Tree { Tree left; Tree right;... } Add a method: abstract class Tree { virtual Tree reflect(); } class Leaf : Tree {... override Tree reflect() { return this; } } class Node : Tree {... override Tree reflect() { return new Node (right.reflect(), left.reflect()); } } Add a method: abstract class Tree { virtual Tree reflect(); } class Leaf : Tree {... override Tree reflect() { return this; } } class Node : Tree {... override Tree reflect() { return new Node (right.reflect(), left.reflect()); } }

9
In general ML-style datatypes can be translated into parameterized classes ML-style datatypes can be translated into parameterized classes Polymorphic functions can be translated into methods inside a parameterized class e.g. class Mapper { List Map(Function f, List xs) {... } List li =...; List ls = new Mapper ().Map(myFun, li); Polymorphic functions can be translated into methods inside a parameterized class e.g. class Mapper { List Map(Function f, List xs) {... } List li =...; List ls = new Mapper ().Map(myFun, li);

10
So: Core ML polymorphism can be encoded using parameterized classes alone

11
Polymorphic virtual methods Define an interface or abstract class: interface Sorter { void Sort (T[] a, IComparer c); } Define an interface or abstract class: interface Sorter { void Sort (T[] a, IComparer c); } Implement the interface: class QuickSort : Sorter {... } class MergeSort : Sorter {... } Implement the interface: class QuickSort : Sorter {... } class MergeSort : Sorter {... } Use instances at many type instantiations: void TestSorter(Sorter s, int[] ia, string[] sa) { s.Sort (ia, IntComparer); s.Sort (sa, StringComparer); } TestSorter(new QuickSort(),...); TestSorter(new MergeSort(),...); Use instances at many type instantiations: void TestSorter(Sorter s, int[] ia, string[] sa) { s.Sort (ia, IntComparer); s.Sort (sa, StringComparer); } TestSorter(new QuickSort(),...); TestSorter(new MergeSort(),...);

12
Compare: Define an SML signature: signature Sorter = sig val Sort : a array * (a*a->order) –> unit end Define an SML signature: signature Sorter = sig val Sort : a array * (a*a->order) –> unit end Define structures that match the signature: structure QuickSort :> Sorter =... structure MergeSort :> Sorter =... Define structures that match the signature: structure QuickSort :> Sorter =... structure MergeSort :> Sorter =... Use structures at many type instantiations: functor TestSorter(S : Sorter) = struct fun test (ia, sa) = (S.Sort(ia, Int.compare); S.Sort(sa, String.compare) end structure TestQuickSort = TestSorter(QuickSort); TestQuickSort.test(...); structure TestMergeSort = TestSorter(MergeSort); TestMergeSort.test(...); Use structures at many type instantiations: functor TestSorter(S : Sorter) = struct fun test (ia, sa) = (S.Sort(ia, Int.compare); S.Sort(sa, String.compare) end structure TestQuickSort = TestSorter(QuickSort); TestQuickSort.test(...); structure TestMergeSort = TestSorter(MergeSort); TestMergeSort.test(...);

13
Or (Russo first-class modules): Define an SML signature: signature Sorter = sig val Sort : a array * (a*a->order) –> unit end Define an SML signature: signature Sorter = sig val Sort : a array * (a*a->order) –> unit end Define structures that match the signature: structure QuickSort :> Sorter =... structure MergeSort :> Sorter =... Define structures that match the signature: structure QuickSort :> Sorter =... structure MergeSort :> Sorter =... Use a function to test the structures: fun TestSorter (s, ia, sa) = let structure S as Sorter = s in (S.Sort(ia, Int.compare); S.Sort(sa, String.compare)) end TestSorter ([structure QuickSort as Sorter],...); TestSorter ([structure MergeSort as Sorter],...); Use a function to test the structures: fun TestSorter (s, ia, sa) = let structure S as Sorter = s in (S.Sort(ia, Int.compare); S.Sort(sa, String.compare)) end TestSorter ([structure QuickSort as Sorter],...); TestSorter ([structure MergeSort as Sorter],...);

14
Question: Can System F first-class polymorphism be encoded using polymorphic virtual methods ?

15
To answer the question... Take System F + recursion + call-by-value evaluation order Take System F + recursion + call-by-value evaluation order Formalize a type-preserving translation into Generic C# Formalize a type-preserving translation into Generic C# Prove that it works Prove that it works

16
In more detail Source is System F + CBV recursion: (Types) A,B ::= X | A -> B | forall X.A (Terms) M,N ::= x | M N | rec y(x:A):B.M | M A | ΛX.V (Values) V ::= rec y(x:A):B.M | ΛX.V Source is System F + CBV recursion: (Types) A,B ::= X | A -> B | forall X.A (Terms) M,N ::= x | M N | rec y(x:A):B.M | M A | ΛX.V (Values) V ::= rec y(x:A):B.M | ΛX.V Target is C# minor Target is C# minor a tiny, purely functional subset of Generic C# a tiny, purely functional subset of Generic C# very similar to Featherweight Java (Pierce, Igarashi, Wadler) very similar to Featherweight Java (Pierce, Igarashi, Wadler) includes just enough for our translation plus a bit more (run-time types) includes just enough for our translation plus a bit more (run-time types)

17
Translation: functions Represent function types using a parameterized class: class Arrow { public virtual Y app(X x); } Represent function types using a parameterized class: class Arrow { public virtual Y app(X x); } Function application is just invocation of app method Function application is just invocation of app method Represent function values by instances of closure classes implementing Arrow e.g. λx:X->Y.x y translates to new C (y) with class C : Arrow,Y> { X y; public override Y app(Arrow x) { return x.app(this.y); } } Represent function values by instances of closure classes implementing Arrow e.g. λx:X->Y.x y translates to new C (y) with class C : Arrow,Y> { X y; public override Y app(Arrow x) { return x.app(this.y); } } Note: Note: fields store free variables of function fields store free variables of function class is parameterized over free type variables of function class is parameterized over free type variables of function

18
Translation: recursion Translate recursion into self-reference through this Translate recursion into self-reference through this For example, rec y(x:X):X. y(x) translates to new C () with class C : Arrow { public override X app(X x) { return this.app(x); } } For example, rec y(x:X):X. y(x) translates to new C () with class C : Arrow { public override X app(X x) { return this.app(x); } }

19
Translation: polymorphism We cant use a single class definition for forall types We cant use a single class definition for forall types Instead use different class for each such type e.g. forall X. X->Y is class ForAll_X_XtoY { public virtual Arrow tyapp (); } Instead use different class for each such type e.g. forall X. X->Y is class ForAll_X_XtoY { public virtual Arrow tyapp (); } Type application is just invocation of tyapp method Type application is just invocation of tyapp method Represent polymorphic values by instances of closure classes implementing appropriate ForAll class Represent polymorphic values by instances of closure classes implementing appropriate ForAll class close over free variables and free type variables just as with functions close over free variables and free type variables just as with functions

20
Translation: polymorphism, cont. Problem: translation of types doesnt commute with substitution i.e. ([A/X]B)* [A*/X]B* Problem: translation of types doesnt commute with substitution i.e. ([A/X]B)* [A*/X]B* Example: Example: forall X.X->Y translates to All_X_XtoY forall X.X->Y translates to All_X_XtoY Now substitute forall Z.Z for Y Now substitute forall Z.Z for Y We get forall X.(X->forall Z.Z) which translates to All_X_XtoAll_Z_Z We get forall X.(X->forall Z.Z) which translates to All_X_XtoAll_Z_Z Solution (Läufer & Odersky): use a single class to represent a whole family of related polymorphic types Solution (Läufer & Odersky): use a single class to represent a whole family of related polymorphic types

21
Properties of translation Fully type-preserving: A* = B* iff A=B Fully type-preserving: A* = B* iff A=B Translation preserves types of terms: If M:A translates to e then e:A* Translation preserves types of terms: If M:A translates to e then e:A* Translation preserves convergence behaviour of closed terms (i.e. the translation is adequate): If M:A translates to e then M converges iff e converges Translation preserves convergence behaviour of closed terms (i.e. the translation is adequate): If M:A translates to e then M converges iff e converges

22
Observations Strictly speaking the translation is not compositional (global generation of names for forall types) Strictly speaking the translation is not compositional (global generation of names for forall types) The translation is harnessing the power of polymorphic virtual methods The translation is harnessing the power of polymorphic virtual methods Generic C#, GJ, NextGen permit polymorphic methods to be virtual Generic C#, GJ, NextGen permit polymorphic methods to be virtual Eiffel, C++ do not Eiffel, C++ do not Distinctiveness of polymorphic virtual methods shows up in (type-preserving) implementations Distinctiveness of polymorphic virtual methods shows up in (type-preserving) implementations requires execution-time type application requires execution-time type application

23
Future work Proof of semantic correctness (adequacy) of translation Proof of semantic correctness (adequacy) of translation use method of logical relations use method of logical relations Harper, Morrisett, Minamide use similar technique to prove correctness of typed closure conversion Harper, Morrisett, Minamide use similar technique to prove correctness of typed closure conversion But: we have impredicative polymorphism and recursion; this makes things tricky But: we have impredicative polymorphism and recursion; this makes things tricky Compositional, partial type-preserving translations Compositional, partial type-preserving translations F ω F ω Dynamic types Dynamic types Power of nominal vs structural equivalence of types Power of nominal vs structural equivalence of types

24
Questions?

Similar presentations

OK

Object-Oriented Programming Python. OO Paradigm - Review Three Characteristics of OO Languages –Inheritance It isn’t necessary to build every class from.

Object-Oriented Programming Python. OO Paradigm - Review Three Characteristics of OO Languages –Inheritance It isn’t necessary to build every class from.

© 2018 SlidePlayer.com Inc.

All rights reserved.

Ads by Google