#RTIMG# mjd.jpg
Atypical Types
==============
v 1.0
+++++
Mark Jason Dominus
==================
23 October 2008
+++++++++++++++
Slides online at:
#HTML#
http://pic.blog.plover.com/OOPSLA/
----------------------------------------------------------------
#RTIMG# mjd.jpg
Good [[AFTERNOON]].
I am Mark Dominus.
Thank you for inviting me to [[NASHVILLE]].
It is a real honor to be speaking here at [[OOPSLA]].
----------------------------------------------------------------
Shameful confession
*******************
----------------------------------------------------------------
In the programming community, we see a lot of holy wars.
Some of these are merely matters of personal preference.
They go on forever.
For example, should one use [[vi]] or [[emacs]]?
It can be easy to forget that other arguments are eventually resolved.
----------------------------------------------------------------
For example, structured programming, or [[goto]]?
This one is finished now.
================================================================
The bodies of the [[goto]] supporters are buried pretty deep.
#IMG# goto.jpg
----------------------------------------------------------------
#RTIMG# soldering_iron.jpg
Before that, there was a holy war about high-level languages vs. assembly language.
I caught the tail end of it when I began programming in the 1970's.
"High-level languages are inefficient," said the assembly language proponents.
And they were right.
They lost anyway.
----------------------------------------------------------------
#RTIMG# garbage_truck.jpg
Manual memory allocation vs. automatic garbage collection.
I didn't expect to see this resolved as soon as it was.
But the advent of Java ended _that_ discussison.
Right or wrong, garbage collection has won.
----------------------------------------------------------------
#RTIMG# Bele-Lokai.jpg
One of these discussions that is still going on concerns strong vs. weak type systems.
C and Pascal programmers used to argue a lot about this in the 1980's.
Which is kind of funny, since C and Pascal have almost exactly the same type system.
----------------------------------------------------------------
#RTIMG# noose
In 1999 ago I gave a talk on this topic.
1999 title: "Strong Typing Doesn't Have to Suck."
(It was an audience of Perl programmers.)
================================================================
For Perl programmers, any kind of automatic check is a hard sell.
Perl's motto is "Enough rope".
----------------------------------------------------------------
I said the question was still open.
In 1999, there was no well-known static type system that did not suck.
(I discussed SML, an academic research language.)
At the time, Java's type system was a craptastic throwback to the 1970's.
#IMG# 1977.jpg
In 2008, I think Java 5.0 is a persuasive argument in favor of static typing.
Let's look at the history a bit.
----------------------------------------------------------------
#RTIMG# Peabody.jpg
Why Types?
**********
Sherman, set the WABAC machine for 1955!
----------------------------------------------------------------
#IMG# 1955calendar.jpg
----------------------------------------------------------------SKIP
#RTIMG# eels.jpg
1955
****
Imagine an assembly language program
Stores a string [[More yummy eels, please]] into memory at locations 2001-2024
Later on, a mistake occurs
Locations 2012-2015 are loaded into a floating-point register and used as a floating-point number
What do you get when you interpret [[eels]] as a floating point number?
1.87292264408661e+31
[R[Whoops]R]
----------------------------------------------------------------SKIP
Why Types?
**********
eels [E[equiv]E] 1.87292264408661e+31 [E[equiv]E] 1,936,483,685
We'd like to prevent this error from occurring.
Idea:
o Variables have _types_ (integer, character, float, etc.)
o Operations have _types_
o Compiler / assembler can check that types match
================================================================
#RTIMG# garbage_truck_small.jpg
o I think this idea first appeared in COBOL
o It's a pretty good idea anyway
----------------------------------------------------------------
Early Type Systems: FORTRAN
***************************
(This is Fortran 77, but early Fortran was similar.)
o [[INTEGER]]
o [[INTEGER*2]], [[INTEGER*4]], [[INTEGER*8]]
o [[LOGICAL]] (Fortran jargon for [E[lsquo]E]boolean[E[rsquo]E])
o [[LOGICAL*1]] (synonym: [[BYTE]]), [[LOGICAL*2]], [[LOGICAL*4]], [[LOGICAL*8]]
o [[REAL]]
o [[REAL*4]], [[REAL*8]] (synonym: [[DOUBLE PRECISION]]), [[REAL*16]]
o [[COMPLEX]]
o [[COMPLEX*8]], [[COMPLEX*16]] (synonym: [[DOUBLE COMPLEX]]), [[COMPLEX*32]]
Now if you write:
INTEGER I
REAL R,S
R = I + S
then the compiler can automatically generate the correct instructions
o *Static* type checking
----------------------------------------------------------------
Early Type Systems: FORTRAN
***************************
o Side note: Declaration is optional, defaults to:
o [[INTEGER]] for variables that begin with [[I]], [[J]], [[K]], [[L]], [[M]], [[N]]
o [[REAL]] for other variables
o Array types also:
INTEGER A(10)
o Functions have types:
FUNCTION F(X)
INTEGER F, X
F = X+1
RETURN
N = F(37)
o *Static* type checking
o _Expressions_ have types, determined at _compile time_
----------------------------------------------------------------
Early Type Systems: Lisp
************************
o *Dynamic* type checking
o _Values_, not expressions, are tagged with types
o Operations generate type errors at _run time_
(+ 1 2)
3
(+ 1 2.0)
3.0
(+ 1 "eels")
Error in +: "eels" is not a number.
----------------------------------------------------------------
Static Typing in ALGOL-based languages
**************************************
o ALGOL (1960), Pascal (1968), C (1971)
o These are all very similar
o Attempt to extend type system beyond scalars
o [[array of]] _type_
o [[pointer to]] _type_ ([E[lsquo]E]reference[E[rsquo]E] in ALGOL)
o [[set of]] _type_ (Pascal only)
o [[record of]] _types_ ([[struct]] in C)
o [[function returning]] _type_
o And arbitrary compositions of these operations:
/* This is why we love C */
int *((*murgatroyd[17])(void *));
----------------------------------------------------------------
Typing: Hard to Get Right
*************************
o Goal: Compile-time checking of program soundness
o Pitfalls
o False negative: Ignore real errors
o False positive: Report spurious errors
Pascal Examples
var s : array [1..10] of character;
s := 'hello'; { [C[You wish]C] }
{----Thank you sir and may I have another! ----------}
type string = array [1..40] of character;
procedure error (c: string)
begin
write('ERROR: ');
write(c);
writeln('');
end;
error('File not found'); { [C[In your dreams]C] }
error('File not found '); { [C[You have to do this]C] }
error('Please just kill me Mr. Wirth ');
Wirth agrees that this was a bad move.
And almost every commercial implementation of Pascal fixed this problem.
Not all these fixes were mututally compatible.
### Add `index' example here?
### index('The quick brown fox', 'q') { In your dreams }
----------------------------------------------------------------
Typing: Hard to Get Right
*************************
Pascal is pretty much dead, so let's have a...
C Example
=========
#include
int main(void)
{
unsigned char *c;
float f = 10;
for (c = (char *)&f;
#* c < sizeof(float) + (char *)&f;
c++) {
printf("%u ", *c);
}
putchar('\n');
return 0;
}
float.c: In function `main':
#* float.c:9: warning: comparison of distinct pointer types lacks a cast
o The warning is spurious
----------------------------------------------------------------
C Example
=========
o The whole program was one giant type violation
o But the compiler didn't care
----------------------------------------------------------------
Typing in Pascal and C is a Failure
***********************************
*Many* spurious errors
* So programmers ignore them
Proliferation of type-defeating features:
* Casts (C) [[ (char *)(&f) ]]
* Automatic conversions (C)
int i;
i = 1.42857; /* Silently truncated to 1 */
* Variadic functions (C)
* Union types (C and Pascal both)
var u: case tag: integer of
0: (intval: integer);
1: (realval: real);
2: (stringval: array [1..20] of character);
3: (boolval: boolean);
end;
r : real;
u.intval = 1428457;
r = u.realval; { Gack }
* Abuse of the separate compilation facility (Pascal)
This proliferation is a sure sign of failure
----------------------------------------------------------------
Coping With Failure
*******************
o Static typing, as implemented in C and Pascal, was not very technically successful
o Solution 1: Give up
o Lisp
o APL
o AWK
o Perl ( _really_ give up: [[+(8/2).".".0.0.0]])
Hey, that worked pretty well!
o Solution 2: Try to do better
o Haskell (and its precursors ISWIM, Miranda, ML, etc.)
o Closely related: Java 5
This has _also_ worked pretty well.
----------------------------------------------------------------
1999 vs. Today
**************
* In 1999, the Haskell type system was a hard sell
* Haskell was worked on by a bunch of funny-looking ivory-tower types:
#HTML#
#HTML#
#HTML#
Philip Wadler
Martin Odersky
#HTML#
(University of Edinburgh)
(EPFL)
#HTML#
----------------------------------------------------------------
1999 vs. Today
**************
#HTML#
#HTML#
#HTML#
Philip Wadler
Martin Odersky
#HTML#
* But these guys designed the Java 5 "generics" feature
* Which is directly derived from their experience with Haskell and related languages
* Which they also designed
* The rest of this talk is about Haskell
----------------------------------------------------------------
Static Typing that Works
************************
We saw that typing in Pascal and C failed for several reasons:
* Too fine-grained ([[character[12] ]] vs. [[character[13] ]])
* Spurious warnings [E[rArr]E] ignored warnings
* Too easy to violate (unions, casts)
* Too coarse-grained ([[structs]])
* Inconvenient to use (explicit types everywhere)
These problems are surmountable!
----------------------------------------------------------------
The Haskell Programming Language
********************************
* Extremely expressive and fine-grained type system
* Many fascinating and powerful features that I will not discuss today
* Originally a research language
* Solves the type problems of C and Pascal
----------------------------------------------------------------
Types in Haskell
****************
Scalars
+++++++
17 Integer
17.3 Float
'x' Char
True Bool
----------------------------------------------------------------
Types in Haskell
****************
Tuples
++++++
(17, 'x') (Integer, Char)
(12.5, 13.5, 9) (Float, Float, Int)
(True, False, True) (Bool, Bool, Bool)
----------------------------------------------------------------
Types in Haskell
****************
Lists
+++++
[True, False, True] [Bool]
[True, False, True, False] [Bool]
[1,2,3,4,5] [Integer]
['O', 'O', 'P', 'S', 'L', 'A'] [Char]
"OOPSLA" [Char]
* [[String]] is accepted as a synonym for [[??![Char]??!]]
* Types like [[??![Integer]??!]] this should remind you of Java types like [[List]] etc.
* Just as Java has [[List>]], Haskell has [[??![??![Integer]??!]??!]]
[ [1,2,3], [4,6], [0,233] ] [??![Integer]??!]
[ "I", "like", "pie" ] [??![Char]??!]
[17, "foo"] [R[Error]R]
----------------------------------------------------------------
Types in Haskell
****************
Polymorphism
++++++++++++
[] [_a_]
[ [1,2,3], [], [] ] [??![Integer]??!]
[ ['p', 'i', 'e'], [], [] ] [??![Char]??!]
([], []) ([_a_], [_b_])
(Better examples coming up shortly.)
### Move this slide later?
----------------------------------------------------------------
Types in Haskell
****************
Type composition
++++++++++++++++
[ (True, [1, 2, 3]),
(False, []),
(False, [4, 5])
] [ (Bool, [Integer]) ]
----------------------------------------------------------------
Types in Haskell
****************
Function types
++++++++++++++
not Bool -> Bool
words String -> [String]
unwords [String] -> String
length [_a_] -> Int
reverse [_a_] -> [_a_]
head [_a_] -> _a_
tail [_a_] -> [_a_]
: _a_ -> [_a_] -> [_a_]
* [[:]] is the "cons" operation
* [[??![1,2,3]??!]] is shorthand for [[??!1:2:3:[]??!]]
----------------------------------------------------------------
Overloading
***********
* _Type classes_ are something like object classes in Java
* Several different types might be instances of the same class
* This means they must support some basic set of operations
* For example, any type [[_t_]] might be an instance of the [[Show]] class
* If so, there must be a function [[show]] of type [[_t_]] -> [[String]]
* The Haskell standard library makes all the standard types instances of [[Show]]
* So for example:
show 137 yields "137"
show True yields "True"
show "Foo" yields "\"Foo\""
* If you define your own type, you can define a [[show]] method
* And you can declare your type to be an instance of [[Show]]
* Notation:
Show Integer ("Integer is an instance of Show")
Show Bool ("Bool is an instance of Show")
Show [Char] ("[Char] is an instance of Show")
----------------------------------------------------------------
Overloading
***********
* The [[show]] function itself has this type:
(Show _a_) => _a_ -> String
* That is, it takes an argument of type [[_a_]] and returns a [[String]]
* But only if [[_a_]] is an instance of [[Show]]
* The [[(Show _a_)]] is called a _context_
* The [[show]] function for [[Bool]] has type [[Bool -> String]]
----------------------------------------------------------------
Overloading
***********
* Numeric operations are similarly overloaded
* The type of [[+]] is
(Num _a_) => _a_ -> _a_ -> _a_
* So you can add two [[Integer]] arguments and get another [[Integer]]
* Add two [[Float]] arguments and get another [[Float]]
* Define your own [[Vector]] type
* Declare that it's an instance of [[Num]]
* Define [[+]] (and [[*]], etc.) operations on it
* And then add two [[Vector]] arguments and get another [[Vector]]
* But if you mess up and add a [[Vector]] to an [[Integer]] you'll get a compile-time error
----------------------------------------------------------------
Overloaded constants
********************
* Constants like 163 are taken to be shorthand for
fromInteger 163
* Where [[fromInteger]] has type
(Num _a_) => Integer -> _a_
* So you can use "[[163]]" as a constant of any numeric type
* As long as that type defines an appropriate [[fromInteger]] function
----------------------------------------------------------------
Overloaded constants
********************
* In particular, this works:
163 + 13.5
* 163 gets the same type as 13.5 here
* An appropriate value is manufactured by an appropriate version of [[fromInteger]]
* No nonsense like this:
double fahrenheit = 98.6;
double celsius1 = 5/9 * (fahrenheit - 32);
double celsius2 = (fahrenheit - 32) * 5/9;
printf("%.1f\n%.1f\n", celsius1, celsius2);
/* This is why we love C */
0.0
37.0
* A constant like [[163]] actually has this type:
(Num _a_) => _a_
* "Any type [[_a_]], as long as it's an instance of [[Num]]."
----------------------------------------------------------------
Overloading
***********
* Early versions of this type system had problems with equality
* What's the type of [[==]]?
* Something like [[_a_ -> _a_ -> Bool]]
* _Except_ that [[_a_]] must not be a function type
* Haskell solves this problem:
* [[(Eq a) => _a_ -> _a_ -> Bool]]
* And function types are not instances of [[Eq]]
* Similarly, ordered types should be declared instances of [[Ord]]
* Values can be compared with <, >, etc.
----------------------------------------------------------------
Big Deal?
*********
One big deal is that you do _not_ need to declare types!
Let's consider everyone's favorite example:
int fact(int n) {
if (n == 0) return 1;
else return n * fact(n-1);
}
In Haskell, that looks almost the same:
fact 0 = 1
fact n = n * fact(n-1)
Hey, where did the [[int]]s go?
----------------------------------------------------------------
Type inference
**************
The compiler says to itself:
fact [C[0]C] = 1
fact n = n * fact(n-1)
"[[0]] has type [[(Num _a_) => _a_]]."
----------------------------------------------------------------
Type inference
**************
#HTML#
#HTML#
fact ::
(Num a) => a -> b
#HTML#
"[[0]] has type [[(Num _a_) => _a_]]."
fact 0 = 1
fact [C[n]C] = n * fact(n-1)
"So [[_n_]] must have that type too."
----------------------------------------------------------------
Type inference
**************
#HTML#
#HTML#
fact ::
(Num a) => a -> b
#HTML#
n ::
(Num a) => a
#HTML#
"[[0]] has type [[(Num _a_) => _a_]]."
"So [[_n_]] must have that type too."
fact 0 = 1
fact n = n * fact([C[n-1]C])
"[[_n_-1]] checks out okay."
----------------------------------------------------------------
Type inference
**************
#HTML#
#HTML#
fact ::
(Num a) => a -> b
#HTML#
n ::
(Num a) => a
#HTML#
"[[_n_]] has type [[(Num _a_) => _a_]]."
fact 0 = 1
fact n = [C[n * fact(n-1)]C]
"[[*]] requires two arguments of the same type, both instances of [[Num]]."
"So [[fact]] must return [[(Num _a_) => _a_]] also."
----------------------------------------------------------------
Type inference
**************
#HTML#
#HTML#
fact ::
(Num a) => a -> a
#HTML#
n ::
(Num a) => a
#HTML#
"[[fact]] must return [[(Num _a_) => _a_]] also."
fact 0 = [C[1]C]
fact n = n * fact(n-1)
"The return value of [[1]] is consistent with that."
----------------------------------------------------------------
Type inference
**************
#HTML#
#HTML#
fact ::
(Num a) => a -> a
#HTML#
n ::
(Num a) => a
#HTML#
fact 0 = 1
fact n = n * fact(n-1)
"Okay, everything checks out!"
o And if you ask it, it will _tell you_ the type of [[fact]]:
fact :: (Num _a_) => _a_ -> _a_
o If you ask for the factorial of an [[Integer]], you get back an [[Integer]]
o If you ask for the factorial of a [[Float]], you get back a [[Float]]
o If you ask for the factorial of a [[String]], you get a compile-time error
o Because [[String]] is not an instance of [[Num]]
----------------------------------------------------------------
Haskell types are always correct
********************************
fact :: (Num _a_) => _a_ -> _a_
o Ask the compiler to tell you the type of some function
o Is it what you expect?
o Yes? Okay then!
o If not, your program almost certainly has a bug.
o A _real_ bug, not a nonsense string-the-wrong-length bug
----------------------------------------------------------------
Haskell types are always correct
********************************
#IMG# cast.jpg
o When there's a type error, you do not have to groan and pull out a bunch of casts
o Or figure out to trick the compiler into accepting it anyway
o Instead, you stop and ask yourself "What did I screw up this time?"
o And when you figure it out, you say "Whew! Good thing I caught that."
----------------------------------------------------------------
Type Inference Example 2
************************
sumof [] = 0
sumof (h:t) = h + sumof t
----------------------------------------------------------------
Type Inference
**************
sumof [C[??![]??!]C] = 0
sumof (h:t) = h + sumof t
"The argument is [[??![]??!]]."
"That's some kind of list, say [[??![_a_]??!]]."
"And let's say that the return type is [[_b_]] for now."
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
sumof ::
[a] -> b
#HTML#
"The argument has type [[??![_a_]??!]]."
sumof [] = 0
sumof ([C[h:t]C]) = h + sumof t
"[[h:t]] is also a list, so that's okay."
"[[h]] must have type [[_a_]] and [[t]] must have type [[??![_a_]??!]]."
h :: _a_
t :: [[??![_a_]??!]]
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
sumof ::
[a] -> b
#HTML#
h ::
a
#HTML#
t ::
[a]
#HTML#
"[[h]] must have type [[_a_]] and [[t]] must have type [[??![_a_]??!]]."
sumof [] = 0
sumof (h:t) = [C[h + sumof t]C]
"We're adding [[h]] to the return value of [[sumof]]."
"So the return value must be [[_a_]] also."
"And [[+]] is only defined for instances of [[Num]], so [[_a_]] is such an instance
"So the return value is really of type (Num _a_) => _a_."
sumof :: (Num [[_a_]]) => [[??![_a_]??!]] -> [[_a_]]
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
sumof ::
(Num a) => [a] -> a
#HTML#
h ::
(Num a) => a
#HTML#
t ::
(Num a) => [a]
#HTML#
"So the return value is really (Num _a_) => _a_."
sumof [] = [C[0]C]
sumof (h:t) = h + sumof t
"That fits with the other return value of 0."
"And everything else checks out okay."
o If you ask, it will say that the type is:
sumof :: (Num _a_) => [_a_] -> _a_
o If we had put [[0.0]] instead of 0, it would have deduced:
sumof :: (Fractional _a_) => [_a_] -> _a_
o ([[Fractional]] is a subclass of [[Num]])
o Among other things, it supports division
o If we had put [["Fred"]] we would have gotten a type error
o Because [[String]] is not an instance of [[Num]]
----------------------------------------------------------------
Type Inference Example 3
************************
map(f, []) = []
map(f, h:t) = f(h) : map(f, t)
----------------------------------------------------------------
Type Inference
**************
map([C[f, []??!]C]) = []
map(f, h:t) = f(h) : map(f, t)
"[[f]] has some type, say [[_p_]], and [[??![]??!]] has some list type, say [[??![_a_]??!]]."
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
map ::
(p, [a]) -> q
#HTML#
f ::
p
#HTML#
"[[??![]??!]] has some list type, say [[??![_a_]??!]]."
map(f, []) = []
map(f, [C[h:t]C]) = f(h) : map(f, t)
"[[h]] must have type [[_a_]] and [[t]] must have type [[??![_a_]??!]]."
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
map ::
(p, [a]) -> q
#HTML#
f ::
p
#HTML#
h ::
a
#HTML#
t ::
[a]
#HTML#
"[[h]] must have type [[_a_]]."
map(f, []) = []
map(f, h:t) = [C[f(h)]C] : map(f, t)
"[[f]] is used as a function applied to [[h]]."
"So [[f]] must have type [[_a_ -> _b_]] for some [[_b_]]."
"[[f]] must take an argument of type [[_a_]] and return a result of type [[_b_]]."
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
map ::
(a -> b, [a]) -> q
#HTML#
f ::
a -> b
#HTML#
h ::
a
#HTML#
t ::
[a]
#HTML#
"[[f]] must take an argument of type [[_a_]] and return a result of type [[_b_]]."
map(f, []) = []
map(f, h:t) = f(h) : [C[map(f, t)]C]
"The result of [[f]] is consed to the result of [[map]]."
"So [[map]] must return [[??![_b_]??!]]."
----------------------------------------------------------------
Type Inference
**************
#HTML#
#HTML#
map ::
(a -> b, [a]) -> [b]
#HTML#
f ::
a -> b
#HTML#
h ::
a
#HTML#
t ::
[a]
#HTML#
"[[map]] must return [[??![_b_]??!]]."
map(f, []) = [C[ [] ]C]
map(f, h:t) = f(h) : [map(f, t)
"That fits with the return value in the other clause."
"Everything else checks out okay."
o If you ask the compiler, it will say that the type is:
map :: (_a_ -> _b_, [_a_]) -> [_b_]
----------------------------------------------------------------
Type Inference Example 3 Continued
**********************************
map :: (_a_ -> _b_, [_a_]) -> [_b_]
Normally [[map]] is defined as a _curried_ function
Instead of this:
map(f, []) = []
map(f, h:t) = f(h) : map(f, t)
We write this:
map f [] = []
map f (h:t) = f(h) : map f t
And the type is:
map :: (_a_ -> _b_) -> [_a_] -> [_b_]
Then for example:
length :: [a] -> Integer
map length ["I", "like", "pie"]
[C[??![1, 4, 3]??!]C]
length_all = map length
length_all :: [??![a]??!] -> [Integer]
length_all ["I", "like", "pie"]
[C[??![1, 4, 3]??!]C]
----------------------------------------------------------------
Life with Haskell
*****************
The Haskell type system has a lot of unspectacular successes.
Programming in Haskell is pleasant
o No type declarations[E[mdash]E]everything is automatic
o You get quite a few type errors (darn!)
o But _every error_ indicates a real, _serious_ problem
o Not like [[lint]] or C or Pascal.
----------------------------------------------------------------
A Spectacular Example
*********************
Here's a _spectacular_ example, due to Andrew R. Koenig.
We will write a merge sort function.
Strategy:
o Split list into two lists
o Sort each list separately
o Merge sorted lists together
We expect the type of this function to be
(Ord _a_) => [_a_] -> [_a_]
----------------------------------------------------------------
Splitting
*********
split [] = ([], [])
split [a] = ([a], [])
split (a:b:rest) = (a:a', b:b')
where (a', b') = split rest
split :: [_t_] -> ([_t_], [_t_])
----------------------------------------------------------------
Merging
*******
merge [] ls = ls
merge ls [] = ls
merge (a:as) (b:bs) =
if a <= b then a : merge as (b:bs)
else b : merge (a:as) bs
merge :: (Ord _t_) => [_t_] -> [_t_] -> [_t_]
----------------------------------------------
Merge Sort
**********
sort [] = []
sort ls = merge (sort p) (sort q)
where (p, q) = split ls
* If we ask Haskell for the type of [[sort]], it says:
sort :: (Ord _a_) => [_t_] -> [_a_]
#HTML#
sort :: (Ord _a_) => [_t_] -> [_a_]
* This says that we could put in _any_ kind of list [[??![_t_]??!]]
* It does not even have to be ordered
* And what we get out has nothing to do with what we put in
* We could put in a list of [[Integer]] and get out a list of [[String]]
* Which is impossible
----------------------------------------------
#HTML#
Huh??
sort :: (Ord _a_) => [_t_] -> [_a_]
* But this is _impossible_
One way the impossible can occur is if it never can occur
----------------------------------------------------------------
#LTIMG# gagme.jpg
[E[ldquo]E]Go out with you? Sure, when [L[Arnold Schwarzenegger]L] is elected [L[president]L].[E[rdquo]E]
[E[ldquo]E]But he isn't an American citizen.[E[rdquo]E]
[E[ldquo]E]Right![E[rdquo]E]
----------------------------------------------
Huh???
******
sort :: (Ord _a_) => [_t_] -> [_a_]
[E[ldquo]E]Given a list of numbers, it could return a list of strings.[E[rdquo]E]
[E[ldquo]E]But it can't possibly return a list of strings.[E[rdquo]E]
[E[ldquo]E]Right![E[rdquo]E]
----------------------------------------------------------------
sort [] = []
sort ls = merge (sort p) (sort q)
where (p, q) = split ls
In fact, this function has a bug.
* It never returns
* (Except when the input is empty.)
* (In which case it _does_ return a list of type [[??![_a_]??!]])
* _Type checking_ found an infinite loop bug!
================================================================
* At compile time!!
================================================================
* !!!!!!!!!!
----------------------------------------------------------------
Where's the Bug?
****************
sort [] = []
sort ls = merge (sort p) (sort q)
where (p, q) = split ls
#LTIMG# bug2.jpg
Suppose the function is trying to sort a one-element list [[??![x]??!]]
It calls [[split]] and gets [[([x], [])]]
Then it tries to recursively sort the two parts
Sorting [[??![]??!]] is okay.
Sorting [[??![x]??!]] puts it into an infinite loop
----------------------------------------------------------------
Solution: Add a clause
sort [] = []
#* sort [x] = [x]
sort ls = merge (sort p) (sort q)
where (p, q) = split ls
The type is now:
sort :: (Ord _a_) => [_a_] -> [_a_]
as we expected it should be.
----------------------------------------------------------------
Summary
*******
#HTML#
#HTML#
#HTML#
Ten years ago, this evolution seemed very unlikely to almost everyone
But those dweeby guys have some very good ideas
Also, they are the guys writing the compilers
So pay attention, because I think the trend will continue
----------------------------------------------------------------
#RTIMG# sen.jpg
Thank you!
**********
They say to allot 3[E[ndash]E]5 minutes per slide
So I won't pretend that there will be time for questions
(sorry)
Please email me or catch me in the hallway
#HTML#