0% found this document useful (0 votes)
30 views

Oopsla - Introduction

This document summarizes four parts of an article about the evolution of programming languages and type systems: Part I discusses the origins of typed deduction in the work of Gerhard Gentzen and Alonzo Church, who developed natural deduction and the simply typed lambda calculus. Part II covers Haskell's type classes and how they allow defining types like Ord that can be instantiated for different types like Int and Char. Part III compares how generics were added to Java between versions 4.0 and 5.0, allowing the definition of lists with specific element types like List<Integer>. Part IV discusses how Links aims to reconcile static and dynamic typing through its type system that allows both static verification and dynamic updates.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views

Oopsla - Introduction

This document summarizes four parts of an article about the evolution of programming languages and type systems: Part I discusses the origins of typed deduction in the work of Gerhard Gentzen and Alonzo Church, who developed natural deduction and the simply typed lambda calculus. Part II covers Haskell's type classes and how they allow defining types like Ord that can be instantiated for different types like Int and Char. Part III compares how generics were added to Java between versions 4.0 and 5.0, allowing the definition of lists with specific element types like List<Integer>. Part IV discusses how Links aims to reconcile static and dynamic typing through its type system that allows both static verification and dynamic updates.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 54

Faith, Evolution, and Programming

Languages
Philip Wadler
University of Edinburgh
Evolution
Multiculturalism
Static vs. Dynamic Typing
Part I. Church: The origins of faith

Part II. Haskell: Type Classes

Part III. Java: Generics

Part IV. Links: Reconciliation


Part I

Church: The origins of faith


Gerhard Gentzen (1909–1945)
Gerhard Gentzen (1935) — Natural Deduction
Gerhard Gentzen (1935) — Natural Deduction
[A]x
·· A⊃B A
· ⊃-E
B B
⊃-Ix
A⊃B

A B A&B A&B
&-I &-E0 &-E1
A&B A B
Simplifying a proof
[B & A]z [B & A]z
&-E1 &-E0
A B
&-I
A&B [B]y [A]x
⊃-Iz &-I
(B & A) ⊃ (A & B) B&A
⊃-E
A&B
Simplifying a proof
[B & A]z [B & A]z
&-E1 &-E0
A B
&-I y x
A&B [B] [A]
⊃-Iz &-I
(B & A) ⊃ (A & B) B&A
⊃-E
A&B

[B]y [A]x [B]y [A]x
&-I &-I
B&A B&A
&-E1 &-E0
A B
&-I
A&B
Simplifying a proof
[B & A]z [B & A]z
&-E1 &-E0
A B
&-I y x
A&B [B] [A]
⊃-Iz &-I
(B & A) ⊃ (A & B) B&A
⊃-E
A&B

[B]y [A]x [B]y [A]x
&-I &-I
B&A B&A
&-E1 &-E0
A B
&-I
A&B

[A]x [B]y
&-I
A&B
Alonzo Church (1903–1995)
Alonzo Church (1932) — Lambda calculus
Alonzo Church (1940) — Typed λ-calculus
[x : A]x
·· s:A⊃B t:A
· ⊃-E
u:B st : B
⊃-Ix
λx. u : A ⊃ B

t:A u:B s:A&B s:A&B


&-I &-E0 &-E1
ht, ui : A & B s0 : A s1 : B
Simplifying a program
[z : B & A]z [z : B & A]z
&-E1 &-E0
z1 : A z0 : B
&-I y x
hz1 , z0 i : A & B [y : B] [x : A]
⊃-Iz &-I
λz. hz1 , z0 i : (B & A) ⊃ (A & B) hy, xi : B & A
⊃-E
(λz. hz1 , z0 i) hy, xi : A & B
Simplifying a program
[z : B & A]z [z : B & A]z
&-E1 &-E0
z1 : A z0 : B
&-I y x
hz1 , z0 i : A & B [y : B] [x : A]
⊃-Iz &-I
λz. hz1 , z0 i : (B & A) ⊃ (A & B) hy, xi : B & A
⊃-E
(λz. hz1 , z0 i) hy, xi : A & B

[y : B]y [x : A]x [y : B]y [x : A]x
&-I &-I
hy, xi : B & A hy, xi : B & A
&-E1 &-E0
hy, xi1 : A hy, xi0 : B
&-I
hhy, xi1 , hy, xi0 i : A & B
Simplifying a program
[z : B & A]z [z : B & A]z
&-E1 &-E0
z1 : A z0 : B
&-I y x
hz1 , z0 i : A & B [y : B] [x : A]
⊃-Iz &-I
λz. hz1 , z0 i : (B & A) ⊃ (A & B) hy, xi : B & A
⊃-E
(λz. hz1 , z0 i) hy, xi : A & B

[y : B]y [x : A]x [y : B]y [x : A]x
&-I &-I
hy, xi : B & A hy, xi : B & A
&-E1 &-E0
hy, xi1 : A hy, xi0 : B
&-I
hhy, xi1 , hy, xi0 i : A & B

[x : A]x [y : B]y
&-I
hx, yi : A & B
William Howard (1980) — Curry-Howard Isomorphism
Curry-Howard

Hindley-Milner

Girard-Reynolds
Part II

Haskell: Type Classes


Type classes
class Ord a where
(<) :: a -> a -> Bool

instance Ord Int where


(<) = primitiveLessInt

instance Ord Char where


(<) = primitiveLessChar

max :: (Ord a) => a -> a -> a


max x y = if x < y then y else x

maximum :: (Ord a) => [a] -> a


maximum [x] = x
maximum (x:xs) = max x (maximum xs)

test :: Bool
test = maximum [0,1,2] == 2 &&
maximum "abc" == ’c’
Translation
data Ord a = Ord { less :: a -> a -> Bool }

ordInt :: Ord Int


ordInt = Ord { less = primitiveLessInt }

ordChar :: Ord Char


ordChar = Ord { less = primitiveLessChar }

max :: Ord a -> a -> a -> a


max d x y = if less d x y then y else x

maximum :: Ord a -> [a] -> a


maximum d [x] = x
maximum d (x:xs) = max d x (maximum d xs)

test :: Bool
test = maximum ordInt [0,1,2] == 2 &&
maximum ordChar "abc" == ’c’
Type classes, continued
instance Ord a => Ord [a] where
[] < [] = False
[] < y:ys = True
x:xs < [] = False
x:xs < y:ys | x < y = True
| y < x = False
| otherwise = xs < ys

test’ :: Bool
test’ = maximum ["zero","one","two"] == "zero" &&
maximum [[[0],[1]],[[0,1]]] == [[0,1]]
Translation, continued
ordList :: Ord a -> Ord [a]
ordList d = Ord { less = lt }
where
lt d [] [] = False
lt d [] (y:ys) = True
lt d (x:xs) [] = False
lt d (x:xs) (y:ys) | x < y = True
| y < x = False
| otherwise = lt d xs ys

test’ :: Bool
test’ = maximum d0 ["zero","one","two"] == "zero" &&
maximum d1 [[[0],[1]],[[0,1]]] == [[0,1]]
where
d0 = ordList ordChar
d1 = ordList (ordList ordInt)
Part III

Java: Generics
Java generics
Lists in Java 4.0 and Java 5.0

in Java 4.0 in Java 5.0

integer list List List<Integer>

string list List List<String>

string list list List List<List<String>>


Lists in Java 4.0 and Java 5.0

in Java 4.0 in Java 5.0

integer list List List<Integer>

string list List List<String>

string list list List List<List<String>>


Lists in Java 4.0 and Java 5.0

in Java 4.0 in Java 5.0

integer list List List<Integer>

string list List List<String>

string list list List List<List<String>>


Lists in Java 4.0 and Java 5.0

in Java 4.0 in Java 5.0

integer list List List<Integer>

string list List List<String>

string list list List List<List<String>>


Lists in Java 4.0 and Java 5.0

in Java 4.0 in Java 5.0

integer list List List<Integer>

string list List List<String>

string list list List List<List<String>>


Legacy library with legacy client
class Stack {
private List list;
public Stack() { list = new ArrayList(); }
public boolean empty() { return list.size() == 0; }
public void push(Object elt) { list.add(elt); }
public Object pop() {
Object elt = list.remove(list.size()-1);
return elt;
}
}

class Client {
public static void main(String[] args) {
Stack stack = new Stack();
stack.push(new Integer(42));
int top = ((Integer)stack.pop()).intValue();
assert top == 42;
}
}
Generic library with generic client
class Stack<E> {
private List<E> list;
public Stack() { list = new ArrayList<E>(); }
public boolean empty() { return list.size() == 0; }
public void push(E elt) { list.add(elt); }
public E pop() {
E elt = list.remove(list.size()-1);
return elt;
}
}

class Client {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(42);
int top = stack.pop();
assert top == 42;
}
}
Generic library with legacy client
class Stack<E> {
private List<E> list;
public Stack() { list = new ArrayList<E>(); }
public boolean empty() { return list.size() == 0; }
public void push(E elt) { list.add(elt); }
public E pop() {
E elt = list.remove(list.size()-1);
return elt;
}
}

class Client {
public static void main(String[] args) {
Stack stack = new Stack(); // raw type
stack.push(new Integer(42));
int top = ((Integer)stack.pop()).intValue();
assert top == 42;
}
}
Legacy library with generic client—minimal changes
class Stack<E> {
private List list; // raw type
public Stack() { list = new ArrayList(); }
public boolean empty() { return list.size() == 0; }
public void push(E elt) { list.add(elt); }
public E pop() {
Object elt = list.remove(list.size()-1);
return (E)elt; // unchecked cast
}
}

class Client {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(42);
int top = stack.pop();
assert top == 42;
}
}
Legacy library with generic client—stubs
class Stack<E> {
public Stack() { throw new StubException(); }
public boolean empty() { throw new StubException(); }
public void push(E elt) { throw new StubException(); }
public E pop() { throw new StubException(); }
}

class Client {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(42);
int top = stack.pop();
assert top == 42;
}
}

// compile with stub library, execute with legacy library


% javac -classpath stubs Client.java
% java -ea -classpath legacy Client
Comparison
interface Comparable<T> {
public int compareTo(T o);
}

Integer int0 = 0;
Integer int1 = 1;
assert int0.compareTo(int1) < 0;

String str0 = "zero";


String str1 = "one";
assert str0.compareTo(str1) > 0;

Number num0 = 0;
Number num1 = 1.0;
assert num0.compareTo(num1) < 0; // compile-time error
Maximum of a list
public static <T extends Comparable<T>>
T max(List<T> elts)
{
T candidate = elts.get(0);
for (T elt : elts) {
if (candidate.compareTo(elt) < 0) candidate = elt;
}
return candidate;
}

List<Integer> ints = Arrays.asList(0,1,2);


assert max(ints) == 2;

List<String> strs = Arrays.asList("zero","one","two");


assert max(strs).equals("zero");

List<Number> nums = Arrays.asList(0,1,2,3.14);


assert max(nums) == 3.14; // compile-time error
A fruity example
Permit comparison of apples with oranges
class Fruit implements Comparable<Fruit> {
... }
class Apple extends Fruit {
... }
class Orange extends Fruit {
... }

Prohibit comparison of apples with oranges


class Fruit {
... }
class Apple extends Fruit implements Comparable<Apple> {
... }
class Orange extends Fruit implements Comparable<Orange> {
... }
Comparing lists
class ComparableList<E extends Comparable<E>>
extends ArrayList<E> implements Comparable<List<E>>
{
public ComparableList(Iterable<E> list) {super(list)}
public int compareTo(List<E> that) {
int n1 = this.size();
int n2 = that.size();
for (int i = 0; i < Math.min(n1,n2); i++) {
int k = list1.get(i).compareTo(list2.get(i));
if (k != 0) return k;
}
return (n1 < n2) ? -1 : (n1 == n2) ? 0 : 1;
}
}

Cumbersome to use—probably better to use comparators


Maximum of a list of lists of lists of integers
ComparableList<ComparableList<Integer>> xss =
new ComparableList<ComparableList<Integer>>{{
add(new ComparableList<Integer>{{add(0)}});
add(new ComparableList<Integer>{{add(1)}});}};
ComparableList<ComparableList<Integer>> yss =
new ComparableList<ComparableList<Integer>>{{
add(new ComparableList<Integer>{{add(0);add(1);}})}};
List<ComparableList<ComparableList<Integer>>> xsss =
new List<ComparableList<ComparableList<Integer>>>{{
add(xss); add(yss);}};
assert max(xsss).equals(yss);
Part IV

Links: Reconciliation
Links: Web Programming without Tiers

Browser
(HTML,XML,JavaScript)
6
form response
?
Server
(Java,Perl,PHP,Python)
6
query response
?
Database
(SQL,XQuery)
Links: Web Programming without Tiers

Browser
(Links)
6
call return
?
Server
(Links)
6
call return
?
Database
(Links)
Hope — Burstall, MacQueen, and Sannella (1980)

Links — Cooper, Lindley, Wadler, and Yallop (2007)


Type classes, revisited
(+) :: Num a => a -> a -> a
1 :: Num a => a
2 :: Num a => a

1 + 1 == 2 :: Num a => Bool


-- ambiguous!

read :: Read a => String -> a


show :: Show a => a -> String

show . read :: (Read a, Show a) => String -> String


-- ambiguous!
Type classes, revisited
(+) :: Num a => a -> a -> a
1 :: Int
2 :: Int

1 + 1 == 2 :: Bool
-- unambiguous!

readInt :: String -> Int


show :: Show a => a -> String

show . readInt :: String -> String


-- unambiguous!
Static vs. Dynamic Typing
Multiculturalism
Evolution
Faith, Evolution, and Programming
Languages
Philip Wadler
University of Edinburgh

You might also like