0% found this document useful (0 votes)
98 views60 pages

History of Haskell - Slides

This document provides a history of the development of the Haskell programming language from the late 1970s through the 2000s. It describes the early work on lazy functional programming and the many experimental languages that were developed. It then summarizes the formation of the Haskell community in 1987 which aimed to standardize a common language specification. This led to successive Haskell reports through version 1.4 in 1997 and the Haskell 98 standard in 1999. The document notes that Haskell 98 provided stability for teaching and books while active development continued beyond the standard. It highlights some of the key aspects of Haskell like purity, laziness, type classes, and its enduring community process.

Uploaded by

sensei
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
98 views60 pages

History of Haskell - Slides

This document provides a history of the development of the Haskell programming language from the late 1970s through the 2000s. It describes the early work on lazy functional programming and the many experimental languages that were developed. It then summarizes the formation of the Haskell community in 1987 which aimed to standardize a common language specification. This led to successive Haskell reports through version 1.4 in 1997 and the Haskell 98 standard in 1999. The document notes that Haskell 98 provided stability for teaching and books while active development continued beyond the standard. It highlights some of the key aspects of Haskell like purity, laziness, type classes, and its enduring community process.

Uploaded by

sensei
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 60

Being lazy with class

A history of Haskell
Paul Hudak, Yale University
John Hughes, Chalmers University,
Simon Peyton Jones, Microsoft Research
Phil Wadler, University of Edinburgh
The late 1979s, early 1980s
Pure functional programming: Lazy functional
recursion, pattern matching, programming
comprehensions etc etc (Friedman, Wise,
(ML, SASL, KRC, Hope, Id) Henderson, Morris, Turner)

Lisp machines Lambda the Ultimate


SK combinators,
(Symbolics, LMI) (Steele, Sussman)
graph reduction
(Turner)
Dataflow architectures
(Dennis, Arvind et al)
e.g. (\x. x+x) 5
= S (S (K +) I) I 5
The late 1979s, early 1980s
Pure functional programming: Lazy functional
recursion, pattern matching, programming
comprehensions etc etc (Friedman, Wise,
(ML, SASL, KRC, Hope, Id) Henderson, Morris, Turner)

Lisp machines Lambda the Ultimate


SK combinators,
(Symbolics, LMI) (Steele, Sussman)
graph reduction
(Turner)
Dataflow architectures
(Dennis, Arvind et al)

Backus 1978
Can programming be
liberated from the von
Neumann style?

John Backus Dec 1924 – Mar 2007


The 1980s
Functional programming: Lazy functional
recursion, pattern matching,
FP is respectable
comprehensions etc etc
(ML, SASL, KRC, Hope, Id)
programming
(Friedman, Wise,
Henderson, Morris, Turner)
(as well as cool)
SK combinators,
Dataflow architectures graph reduction

Go forth and design


(Arvind et al) (Turner)

new languages
Backus
and new computers
Can programming be
liberated from the von

and rule the world


Neumann style?
Result

Chaos
Many, many bright young things
Many conferences
(birth of FPCA, LFP)

Many languages
(Miranda, LML, Orwell, Ponder, Alfl, Clean)

Many compilers
Many architectures
(mostly doomed)
Crystalisation
FPCA, Sept 1987: initial meeting.
A dozen lazy functional programmers, wanting to agree
on a common language.
 Suitable for teaching, research, and application
 Formally-described syntax and semantics
 Freely available
 Embody the apparent consensus of ideas
 Reduce unnecessary diversity
Absolutely no clue how much work we were taking on
Led to...a succession of face-to-face meetings

April 1990 (2½ yrs later): Haskell 1.0 report


Haskell Curry
1900-1982

Timeline
Sept 87: kick off; choose name

Apr 90: Haskell 1.0


Aug 91: Haskell 1.1 (153pp)
May 92: Haskell 1.2 (SIGPLAN Notices) (164pp)

May 96: Haskell 1.3. Monadic I/O,


separate library report
Apr 97: Haskell 1.4 (213pp)

Feb 99: Haskell 98 (240pp)

Dec 02: Haskell 98 revised (260pp)

2003-2007 Growth spurt


WG2.8 June 1992
WG2.8 June 1992
Phil John
Paul
WG2.8 June 1992

Dorothy

Sarah
Haskell the cat (b. 2002)
Timeline
Sept 87: kick off

Apr 90: Haskell 1.0


Aug 91: Haskell 1.1 (153pp)
May 92: Haskell 1.2 (SIGPLAN Notices) (164pp)
(thank you Richard Wexelblat)

May 96: Haskell 1.3. Monadic I/O,


separate library report
Apr 97: Haskell 1.4 (213pp)

Feb 99: Haskell 98 (240pp)

Dec 02: Haskell 98 revised (260pp)

2003-2007 Growth spurt


Haskell 98
Haskell 98
• Stable
• Documented
• Consistent across
implementations
• Useful for teaching,
books

Haskell
Haskell + extensions
development • Dynamic, exciting
• Unstable,
undocumented,
implementations vary...
Timeline
Sept 87: kick off

Apr 90: Haskell 1.0


Aug 91: Haskell 1.1 (153pp)
May 92: Haskell 1.2 (SIGPLAN Notices) (164pp)

May 96: Haskell 1.3. Monadic I/O,


separate library report
Apr 97: Haskell 1.4 (213pp)

Feb 99: Haskell 98 (240pp)


The Book!
(thank you CUP)
Dec 02: Haskell 98 revised (260pp)

2003-2007 Growth spurt


History of most research
languages
Practitioners

1,000,000

10,000

100

The quick death


Geeks

1yr 5yr 10yr 15yr


Practitioners
Successful research languages

1,000,000

10,000

100
The slow death
Geeks

1yr 5yr 10yr 15yr


C++, Java, Perl, Ruby
Threshold of immortality
Practitioners

1,000,000

10,000
The complete
100 absence of death
Geeks

1yr 5yr 10yr 15yr


Haskell “Learning Haskell is a great way of
“I'm already looking at training yourself to think functionally
coding problems and my so you are ready to take full
mental perspective is now advantage of C# 3.0 when it comes
Practitioners

shifting back and forth out” (blog Apr 2007)


1,000,000 between purely OO and
more FP styled solutions”
(blog Mar 2007)

10,000

100
The second life?
Geeks

1yr 5yr 10yr 15yr


2003-7: growth spurt

Haskell Cafe (2000)


Haskell Communities
Report (2001)
IRC #Haskell (2001)
Haskell Weekly News
(2005)
Google Summer of
Code (2006)
GHC bug count climbs
When Haskell is dust,
what will it be
remembered for?

1. Purity and laziness


2. Type classes
3. Process and community
Purity
and
laziness
Laziness
 Laziness was Haskell’s initial rallying cry
 John Hughes’s famous paper “Why
functional programming matters”
– Modular programming needs powerful glue
– Lazy evaluation enables new forms of
modularity; in particular, separating generation
from selection.
– Non-strict semantics means that unrestricted
beta substitution is OK.
But...
 Laziness makes it much, much harder to reason
about performance, especially space. Tricky uses
of seq for effect seq :: a -> b -> b
 Laziness has a real implementation cost
 Laziness can be added to a strict language
(although not as easily as you might think)
 And it’s not so bad only having bV instead of b

So why wear the hair shirt of laziness?


Laziness keeps you pure
 Every call-by-value language has given into
the siren call of side effects
 But in Haskell
(print “yes”) + (print “no”)
just does not make sense. Even worse is
[print “yes”, print “no”]
 So effects (I/O, references, exceptions)
are just not an option.
 Result: prolonged embarrassment.
Stream-based I/O, continuation I/O...
but NO DEALS WIH THE DEVIL
Salvation through monads
A value of type (IO t) is an “action”
that, when performed, may do
some input/output before
delivering a result of type t.

eg.
getChar :: IO Char
putChar :: Char -> IO ()
Connecting I/O operations

(>>=) :: IO a -> (a -> IO b) -> IO b


return :: a -> IO a

eg.
getChar >>= (\a ->
getChar >>= (\b ->
putChar b >>= (\() ->
return (a,b))))
The do-notation

do {
getChar >>= \a -> a <- getChar;

==
getChar >>= \b -> b <- getChar;
putchar b >>= \()-> putchar b;
return (a,b) return (a,b)
}

 Syntactic sugar only


 Easy translation into (>>=), return
 Deliberately imperative “look and feel”
Control structures
Values of type (IO t) are first class
So we can define our own “control structures”
forever :: IO () -> IO ()
forever a = do { a; forever a }

repeatN :: Int -> IO () -> IO ()


repeatN 0 a = return ()
repeatN n a = do { a; repeatN (n-1) a }

e.g. repeatN 10 (putChar „x‟)


What have we achieved?
 The ability to mix imperative and purely-
functional programming, without ruining
either
 All laws of pure functional programming
remain unconditionally true, even of actions
e.g.
let x=e in ...x....x...
=
....e....e.....
Fine grain control
 reverse :: String -> String
o pure: no side effects

 launchMissiles :: String -> IO [String]


o impure: international side effects

 transfer :: Acc -> Acc -> Int -> STM ()


o transactional: limited effects (reading and
writing transactional variables

There are lots of useful monads,


not only I/O
The central challenge

Useful Arbitrary effects

No effects
Useless

Dangerous Safe
The challenge of effects
Plan A
(everyone else)

Useful Arbitrary effects Nirvana

“A good language should change the


way people think about software” Plan B
(Stroustrup, HOPL 2007) (Haskell)

No effects
Useless

Dangerous Safe
Two basic approaches: Plan A
Default = Any effect
Arbitrary effects Plan = Add restrictions

• Types play a major role


• Types blur into analyses
Examples
 Regions
 Ownership types
 Vault, Spec#,
Cyclone, etc etc
Two basic approaches: Plan B
Default = No effects
Plan = Selectively permit effects

Again, types play


Two main approaches: a major role
 Domain specific languages
(SQL, XQuery, MDX,
Google map/reduce)
 Wide-spectrum functional Value oriented
languages + controlled programming
effects (e.g. Haskell)
Lots of cross-over
Plan A
(everyone else)

Useful Arbitrary effects Nirvana

Envy
Plan B
(Haskell)

No effects
Useless

Dangerous Safe
Lots of cross-over
Plan A
(everyone else)

Useful Arbitrary effects Nirvana

Ideas; e.g. Software


Transactional Memory Plan B
(retry, orElse) (Haskell)

No effects
Useless

Dangerous Safe
SLPJ conclusions
 One of Haskell’s most significant
contributions is to take purity seriously,
and relentlessly pursue Plan B

 The next ML will be pure, with effects


only via monads. The next Haskell will be
strict, but still pure.

 Imperative languages will embody growing


(and checkable) pure subsets
Type classes
Type classes
Initially, just a neat
class Eq a where way to get systematic
(==) :: a -> a -> Bool
overloading of (==),
instance Eq Int where read, show.
i1 == i2 = eqInt i1 i2

instance (Eq a) => Eq [a] where


[] == [] = True
(x:xs) == (y:ys) = (x == y) && (xs == ys)

member :: Eq a => a -> [a] -> Bool


member x [] = False
member x (y:ys) | x==y = True
| otherwise = member x ys
Implementing type classes
data Eq a = MkEq (a->a->Bool)
eq (MkEq e) = e Class witnessed
by a “dictionary”
Instance of methods
dEqInt :: Eq Int declarations create
dictionaries
dEqInt = MkEq eqInt

dEqList :: Eq a -> Eq [a]


dEqList (MkEq e) = MkEq el
where el [] [] = True
el (x:xs) (y:ys) = x `e` y && xs `el` ys
Overloaded
functions
take extra
member :: Eq a -> a -> [a] -> Bool dictionary
member d x [] = False parameter(s)
member d x (y:ys) | eq d x y = True
| otherwise = member d x ys
Type classes over time
 Type classes are the most unusual
feature of Haskell’s type system

Hey, what’s
Wild enthusiasm the big
deal?

Despair Hack,
Incomprehension hack,
hack

1987 1989 1993 1997


Implementation begins
Type classes have proved
extraordinarily convenient in practice

 Equality, ordering, serialisation


 Numerical operations. Even numeric In Haskell,
my 17 can
constants are overloaded definitely
be your 23
 Monadic operations
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b

 And on and on....time-varying


Note the
values, pretty-printing, collections, higher-kinded
reflection, generic programming, type variable, m

marshalling, monad transformers....


Quickcheck
propRev :: [Int] -> Bool
propRev xs = reverse (reverse xs) == xs

propRevApp :: [Int] -> [Int] -> Bool


propRevApp xs ys = reverse (xs++ys) ==
reverse ys ++ reverse xs

ghci> quickCheck propRev


OK: passed 100 tests

ghci> quickCheck propRevApp


OK: passed 100 tests
Quickcheck (which is just a Haskell 98 library)
 Works out how many arguments
 Generates suitable test data
 Runs tests
Quickcheck
quickCheck :: Test a => a -> IO ()

class Test a where


test :: a -> Rand -> Bool

class Arby a where


arby :: Rand -> a

instance (Arby a, Test b) => Test (a->b) where


test f r = test (f (arby r1)) r2
where (r1,r2) = split r

instance Test Bool where


test b r = b
Type-class fertility
Higher kinded
Implicit
type variables
parameters (2000)
(1995)

Wadler/ Extensible
Multi- records (1996) Computation
Blott
parameter at the type
type
type classes level
classes
(1989) (1991) Functional
dependencies
(2000) Generic
Overlapping programming
instances

“newtype
deriving” Associated Testing
types (2005)
Derivable
type classes
Applications

Variations
Type classes summary
 A much more far-reaching idea than we
first realised: the automatic, type-driven
generation of executable “evidence”
 Many interesting generalisations, still
being explored
 Variants adopted in Isabel, Clean,
Mercury, Hal, Escher
 Danger of Heat Death
 Long term impact yet to become clear
Process
and
community
A committee language
 No Supreme Leader
 A powerfully motivated design group who
trusted each other
 The Editor and the Syntax Tzar
 Committee explicitly disbanded 1999
Language complexity
 “Languages are too complex,
fraught with dispensable features
and facilities.” (Wirth, HOPL 2007)
 Much superficial complexity (e.g.
redundant syntactic forms),
 No formal semantics
 Nevertheless, underpinned by
Deeply Held Principles
“Deeply held principles”
 System F is GHC’s intermediate language
(Well, something very like System F.)

data Expr
= Var Var
| Lit Literal
| App Expr Expr
| Lam Var Expr
| Let Bind Expr
| Case Expr Var Type [(AltCon, [Var], Expr)]
| Cast Expr Coercion
| Note Note Expr
| Type Type
type Coercion = Type
data Bind = NonRec Var Expr | Rec [(Var,Expr)]
data AltCon = DEFAULT | LitAlt Lit | DataAlt DataCon
Sanity check on wilder excesses

The Haskell
Gorilla

System FC

Rest of GHC
Haskell users
 A smallish,
tolerant,
rather pointy-headed, and
extremely friendly
user-base makes Haskell nimble.
Haskell has evolved rapidly and
continues to do so.
 Haskell users react to new features
like hyenas react to red meat
Lesson: avoid success at all costs
The price of usefulness
 Libraries increasingly important:
– 1996: Separate libraries Report
– 2001: Hierarchical library naming structure, increasingly
populated
– 2006: Cabal and Hackage: packaging and distribution
infrastructure
 Foreign-function interface increasingly important
– 1993 onwards: a variety of experiments
– 2001: successful effort to standardise a FFI across
implementations
 Lightweight concurrency, asynchronous
exceptions, bound threads, transactional memory,
data parallelism...
Any language large enough to be
useful becomes dauntingly complex
Conclusion
 Haskell does not meet Bjarne’s
criterion (be good enough on all axes)
 Instead, like Self, it aspires to take
a few beautiful ideas (esp: purity and
polymorphism), pursue them single-
mindedly, and see how far they can
take us.
 In the end, we want to infect your
brain, not your hard drive
Luck
 Technical excellence helps, but is neither
necessary nor sufficient for a language
to succeed
 Luck, on the other hand, is definitely
necessary
 We were certainly lucky: the conditions
that led to Haskell are hard to
reproduce (witness Haskell’)
Fun
 Haskell is rich enough to be useful
 But above all, Haskell is a language in which
people play
– Programming as an art form
– Embedded domain-specific languages
– Type system hacks
 Play leads to new discoveries
Encapsulating it all
data ST s a -- Abstract
newRef :: a -> ST s (STRef s a)
read :: STRef s a -> ST s a
write :: STRef s a -> a -> ST s ()

runST :: (forall s. ST s a) -> a

Stateful
computation Pure result

sort :: Ord a => [a] -> [a]


sort xs = runST (do { ..in-place sort.. })
Encapsulating it all
runST :: (forall s. ST s a) -> a

Higher rank type

Security of Monads
encapsulation
depends on
parametricity And that depends on type classes
to make non-parametric
operations explicit
(e.g. f :: Ord a => a -> a)
Parametricity depends on there
being few polymorphic functions
(e.g.. f:: a->a means f is the And it also depends
identity function or bottom) on purity (no side
effects)
The Haskell committee
Arvind Thomas Johnsson
Lennart Augustsson Mark Jones
Dave Barton Dick Kieburtz
Brian Boutel John Launchbury
Warren Burton Erik Meijer
Jon Fairbairn Rishiyur Nikhil
Joseph Fasel John Peterson
Andy Gordon Simon Peyton Jones [editor]
Maria Guzman Mike Reeve
Kevin Hammond Alastair Reid
Ralf Hinze Colin Runciman
Paul Hudak [editor] Philip Wadler [editor]
John Hughes [editor] David Wise
Jonathan Young

You might also like