Title: A Lightning Tour of Haskell
1A Lightning Tour of Haskell
- Lecture 1,
- Designing and Using Combinators
- John Hughes
2Using Haskell The Hugs Interpreter
3Using Haskell The Hugs Interpreter
A module is loaded.
4Using Haskell The Hugs Interpreter
A module is loaded.
Type an expression at the prompt.
5Using Haskell The Hugs Interpreter
A module is loaded.
Type an expression at the prompt.
The value is printed.
6Using Haskell The Hugs Interpreter
A function call with two arguments. No brackets!
Brackets are only for grouping e.g. f (g x)
7Using Haskell The Hugs Interpreter
A linked list
1
3
5
1 3 5
8Defining Functions
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
9Defining Functions
Type signature. Optional!
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
10Defining Functions
Type signature. Optional!
Ignore for now
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
11Defining Functions
Type signature. Optional!
Ignore for now
Type of first argument a
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
12Defining Functions
Type signature. Optional!
Ignore for now
Type of first argument a
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Type of second argument list of as
13Defining Functions
Type signature. Optional!
Ignore for now
Type of first argument a
Type of result
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Type of second argument list of as
14Defining Functions
Type signature. Optional!
Ignore for now
Type of first argument a
Type of result
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Type of second argument list of as
What is a?
A type variable which can stand for any
type. This function is polymorphic.
15Defining Functions
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Definition by pattern matching case analysis
on the form of the arguments.
16Defining Functions
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Definition by pattern matching case analysis
on the form of the arguments.
Guards define conditions for an equation to
apply.
17Defining Functions
We build a new structure as the
result purely functional.
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Definition by pattern matching case analysis
on the form of the arguments.
Guards define conditions for an equation to
apply.
18Defining Data Types
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
19Defining Data Types
Type name
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
20Defining Data Types
Type name
Type parameter
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
- Types may take parameters.
- Enables us to define polymorphic functions which
work on a tree with any type of labels.
21Defining Data Types
Type name
Type parameter
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
Constants start with upper case, variables with
lower
- Types may take parameters.
- Enables us to define polymorphic functions which
work on a tree with any type of labels.
22Defining Data Types
Node and Leaf are alternative forms of Tree.
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
23Defining Data Types
Node and Leaf are alternative forms of Tree.
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
Types of the components.
24Defining Data Types
Node and Leaf are alternative forms of Tree.
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
Types of the components.
Ignore for now.
25Defining Data Types
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
26Defining Data Types
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
Type Tree Integer
27Tree Insertion
insertTree Ord a a - Tree a - Tree
a insertTree x Leaf Node x Leaf Leaf insertTree
x (Node y l r) x l) r x y Node y l (insertTree x r)
xy Node y l r
Pattern matching works as for lists.
28Overloading
- Polymorphic functions use the same definition at
each type. - Overloaded functions may have a different
definition at each type.
Class name.
Read a is a type in class Eq, if it has the
following methods.
class Eq a where () a - a - Bool
(/) a - a - Bool x/y not (xy)
Class methods and types.
Default definition.
29The Class Hierarchy
Read Type a in class Eq is also in class Ord,
if it provides the following methods
class Eq a Ord a where ( a -
Bool
30Instance Declarations
instance Eq Integer where xy primitive
instance Eq a Eq a where
True xxs yys x y xs ys
Provided a is in class Eq, then a is in class
Eq, with the method definition given.
31Types of Overloaded Functions
a may be any type in class Ord.
insert Ord a a - a - a insert x
insert x (yxs) xy
yinsert x xs
Because insert uses a method from class Ord.
32Show and Read
class Show a where show a - String
class Read a where read String - a
These are simplifications there are more methods
in reality.
read . show id (usually)
33Derived Instances
data Tree a Node a (Tree a) (Tree a) Leaf
deriving Show
Constructs a default instance of class Show.
Works for many standard classes.
Main show (Node 1 Leaf (Node 2 Leaf Leaf)) "Node
1 Leaf (Node 2 Leaf Leaf)"
34Multi-Parameter Classes
Define relations between classes.
class Collection c a where empty c add
a - c - c member a - c - Bool
c is a collection with elements of type a.
instance Eq a Collection a a where
empty add () member elem
instance Ord a Collection (Tree a) a where
empty Leaf add insertTree member
elemTree
35Functional Dependencies
A functional dependency
class Collection c a c - a where empty
c add a - c - c member a - c -
Bool
- Declares that c determines a there can be only
one instance for each type c. - Helps the type-checker resolve ambiguities
(tremendously).
add x (add y empty) -- x and y must be the same
type.
36Side Effects in Haskell
- Suppose
- tick String - Integer
- reads an integer n from a file with given name,
- writes n1 back to the file
- returns n
Then tick tick might be False!
Cannot replace equals by equals. Not purely
functional!
37Haskells Solution
Performs I/O and delivers a String.
Side effects are recorded in the type!
readFile String - IO String writeFile
String - String - IO ()
So the type of tick is tick String - IO
Int and tick tick is ill-typed.
IO is a monad -- more later!
38The do notation
I/O actions may be combined in sequence.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
39The do notation
I/O actions may be combined in sequence.
Type IO String
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Type String
Scope of contents
40The do notation
I/O actions may be combined in sequence.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Local declaration
Scope
41The do notation
I/O actions may be combined in sequence.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Type IO ()
No need to bind a name to the result.
42The do notation
I/O actions may be combined in sequence.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Type IO Integer Defines result of tick.
return a - IO a
43IO a Action Yeilding an a
44IO a Action Yeilding an a
Action at the prompt is performed.
The action returned by tick has a side-effect.
Yields a different Integer each time it is
performed.
45IO a Action Yeilding an a
twice1 IO a - (IO a, IO a) twice1 c (c,c)
Result is not an action! Therefore not performed.
Next call reveals no side-effects occurred.
46IO a Action Yeilding an a
twice2 IO a - IO (a,a) twice2 a do x a return (x,x) twice3 IO a - IO
(a,a) twice3 a do x The same action can be performed many times.
47References
Variables in Haskell cannot be updated --
references can.
newIORef a - IO (IORef a) readIORef IORef
a - IO a writeIORef IORef a - a - IO ()
Reference operations have side-effects -- hence
IO type.
48Example Destructive List Insertion
Updateable tail.
data RList a Nil Cons a (IORef (RList
a)) insertRList Ord a a - IORef (RList a)
- IO () insertRList x xs do cell readIORef xs case cell of Nil - do
new (Cons x new) Cons y xs' x do
new (Cons x new) xy - insertRList x xs'
Must read the list cell.
Create new cell and update old.
case is inline pattern matching.
49Encapsulated Side Effects
- IORefs can only be updated at the top level.
- Can we use references internally to define a pure
function? - Example
- removeDuplicates Hashable a a - a
Array operations resemble reference ones.
Use a hash table internally to make comparison
fast.
No IO type no externally visible side-effects!
50Encapsulation The ST Monad
newSTRef a - ST s (STRef s a) readSTRef
STRef s a - ST s a writeSTRef STRef s a - a
- ST s ()
Similar family of operations.
51Encapsulation The ST Monad
newSTRef a - ST s (STRef s a) readSTRef
STRef s a - ST s a writeSTRef STRef s a - a
- ST s ()
s ties together the type of a reference and
the action which uses it.
52Encapsulation The ST Monad
newSTRef a - ST s (STRef s a) readSTRef
STRef s a - ST s a writeSTRef STRef s a - a
- ST s ()
The encapsulation function runST (forall s .
ST s a) - a
53Encapsulation The ST Monad
newSTRef a - ST s (STRef s a) readSTRef
STRef s a - ST s a writeSTRef STRef s a - a
- ST s ()
The encapsulation function runST (forall s .
ST s a) - a
Result type free from ST pure.
54Encapsulation The ST Monad
newSTRef a - ST s (STRef s a) readSTRef
STRef s a - ST s a writeSTRef STRef s a - a
- ST s ()
The encapsulation function runST (forall s .
ST s a) - a
Each use binds a fresh variable s labels
references created, guarantees used only here.
Result type free from ST pure.
55Encapsulation The ST Monad
newSTRef a - ST s (STRef s a) readSTRef
STRef s a - ST s a writeSTRef STRef s a - a
- ST s ()
The encapsulation function runST (forall s .
ST s a) - a
The argument of runST must be polymorphic in s.
This is a rank 2 type. Cannot be inferred
-- must be declared.
56Overloading Side-Effects
Why should we choose between IO and ST when we
want side-effects?
class Monad m RefMonad m r m - r where
newRef a - m (r a) readRef r a - m a
writeRef r a - a - m ()
instance RefMonad IO IORef
instance RefMonad (ST s) (STRef s)
57Overloading Side-Effects
Why should we choose between IO and ST when we
want side-effects?
class Monad m RefMonad m r m - r where
newRef a - m (r a) readRef r a - m a
writeRef r a - a - m ()
Partial type application. Plug in ST s and STRef
s for m and r in the types
instance RefMonad IO IORef
instance RefMonad (ST s) (STRef s)
58Overloading Side-Effects
Why should we choose between IO and ST when we
want side-effects?
class Monad m RefMonad m r m - r where
newRef a - ST s (STRef s a) readRef
STRef s a - ST s a writeRef STRef s a -
a - ST s ()
instance RefMonad IO IORef
instance RefMonad (ST s) (STRef s)
59Overloading Side-Effects
Why should we choose between IO and ST when we
want side-effects?
class Monad m RefMonad m r m - r where
newRef a - m (r a) readRef r a - m a
writeRef r a - a - m ()
Example
data RList r a Nil Cons a (r (RList r
a)) insertRList (Ord a, RefMonad m r) a
- r (RList r a) - m ()
60Higher-Order Functions
- Functions are values in Haskell.
- Program skeletons take functions as parameters.
takeWhile (a - Bool) - a - a takeWhile
p takeWhile p (xxs) p x
xtakeWhile p xs otherwise
Takes a prefix of a list, satisfying a predicate.
61Denoting Functions
62Denoting Functions
below a b b
63Denoting Functions
below a b b takeWhile (a - Bool) - a - a takeWhile
p takeWhile p (xxs) p x
xtakeWhile p xs otherwise
64Denoting Functions
below a b b takeWhile (a - Bool) - a - a takeWhile
p takeWhile p (xxs) below 10 x
xtakeWhile p xs otherwise
A partial function application.
65More Ways to Denote Functions
below a b b
takeWhile (below 10) 1,5,9,15,20 66More Ways to Denote Functions
below a b b
takeWhile (below 10) 1,5,9,15,20 takeWhile (\b - b
Lambda expression. Function definition in place.
67
More Ways to Denote Functions
below a b b takeWhile (below 10) 1,5,9,15,20 takeWhile (\b - b
Lambda expression. Function definition in place.
f b b
68
More Ways to Denote Functions
below a b b takeWhile (below 10) 1,5,9,15,20 takeWhile (\b - b takeWhile (
Lambda expression. Function definition in place.
f b b
Partial operator application -- argument replaces
missing operand.
69
Lazy Evaluation- Expressions are evaluated only when their value
is really needed! - Function arguments, data structure components,
are held unevaluated until their value is used.
from n n from (n1)
70
Lazy Recursive Definitions
nats 0 map (1) nats
71
A Confession
This program doesnt work!
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
72
A Confession
This program doesnt work!
The file is only opened here, it is read
when contents is needed.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
73
A Confession
This program doesnt work!
The file is only opened here, it is read
when contents is needed.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Not needed yet! n isnt needed
74
A Confession
This program doesnt work!
The file is only opened here, it is read
when contents is needed.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Not needed yet! n isnt needed
Not needed until after the file is opened for
writing!
75
A Confession
This program doesnt work!
The file is only opened here, it is read
when contents is needed.
tick String - IO Integer tick f
do contents contents writeFile f (show (n1)) return n
Not needed yet! n isnt needed
Not needed until after the file is opened for
writing!
So readFile sees an empty file!
76
A Confession
This program doesnt work!
tick String - IO Integer tick f
do contents contents n seq writeFile f (show
(n1)) return n
77
A Confession
This program doesnt work!
tick String - IO Integer tick f
do contents contents n seq writeFile f (show
(n1)) return n
seq evaluates its first argument, then returns
its second.
78
A Confession
This program doesnt work!
tick String - IO Integer tick f
do contents contents n seq writeFile f (show
(n1)) return n
seq evaluates its first argument, then returns
its second.
Backquotes turn a function name into
an operator.
79
Time for a Demo
80
Course Home Page
www.cs.chalmers.se/rjmh/Combinators Begin with
some finger exercises in Haskell.