Presentation is loading. Please wait.

Presentation is loading. Please wait.

A Lightning Tour of Haskell Lecture 1, Designing and Using Combinators John Hughes.

Similar presentations


Presentation on theme: "A Lightning Tour of Haskell Lecture 1, Designing and Using Combinators John Hughes."— Presentation transcript:

1 A Lightning Tour of Haskell Lecture 1, Designing and Using Combinators John Hughes

2 Using Haskell: The Hugs Interpreter

3 A module is loaded.

4 Using Haskell: The Hugs Interpreter A module is loaded. Type an expression at the prompt.

5 Using Haskell: The Hugs Interpreter A module is loaded. Type an expression at the prompt. The value is printed.

6 Using Haskell: The Hugs Interpreter A function call with two arguments. No brackets! Brackets are only for grouping e.g. f (g x)

7 Using Haskell: The Hugs Interpreter A linked list 1 3 5 1 : 3 : 5 : []

8 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs

9 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Type signature. Optional!

10 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Type signature. Optional! Ignore for now

11 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Type signature. Optional! Ignore for now Type of first argument: “a”

12 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Type signature. Optional! Ignore for now Type of first argument: “a” Type of second argument: list of “a”s

13 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Type signature. Optional! Ignore for now Type of first argument: “a” Type of second argument: list of “a”s Type of result

14 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Type signature. Optional! Ignore for now Type of first argument: “a” Type of second argument: list of “a”s Type of result What is “a”? A type variable which can stand for any type. This function is polymorphic.

15 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Definition by “pattern matching”: case analysis on the form of the arguments.

16 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Definition by “pattern matching”: case analysis on the form of the arguments. “Guards” define conditions for an equation to apply.

17 Defining Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs Definition by “pattern matching”: case analysis on the form of the arguments. “Guards” define conditions for an equation to apply. We build a new structure as the result: “purely functional”.

18 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show

19 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Type name

20 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Type nameType parameter Types may take parameters. Enables us to define polymorphic functions which work on a tree with any type of labels.

21 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Type nameType parameter Types may take parameters. Enables us to define polymorphic functions which work on a tree with any type of labels. Constants start with upper case, variables with lower

22 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Node and Leaf are alternative forms of Tree.

23 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Node and Leaf are alternative forms of Tree. Types of the components.

24 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Node and Leaf are alternative forms of Tree. Types of the components. Ignore for now.

25 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show

26 Defining Data Types data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Type: Tree Integer

27 Tree Insertion insertTree :: Ord a => a -> Tree a -> Tree a insertTree x Leaf = Node x Leaf Leaf insertTree x (Node y l r) | x < y = Node y (insertTree x l) r | x > y = Node y l (insertTree x r) | x==y = Node y l r Pattern matching works as for lists.

28 Overloading Polymorphic functions use the same definition at each type. Overloaded functions may have a different definition at each type. class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x/=y = not (x==y) Class name. Class methods and types. Default definition. Read: “a is a type in class Eq, if it has the following methods”.

29 The Class Hierarchy class Eq a => Ord a where ( a -> Bool … Read: “Type a in class Eq is also in class Ord, if it provides the following methods…”

30 Instance Declarations instance Eq Integer where x==y = …primitive… instance Eq a => Eq [a] where [] == [] = True x:xs == y:ys = x == y && xs == ys Provided a is in class Eq, then [a] is in class Eq, with the method definition given.

31 Types of Overloaded Functions insert :: Ord a => a -> [a] -> [a] insert x [] = [] insert x (y:xs) | x<=y = x:y:xs | x>y = y:insert x xs “a” may be any type in class Ord. Because insert uses a method from class Ord.

32 Show 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)

33 Derived Instances data Tree a = Node a (Tree a) (Tree a) | Leaf deriving Show Constructs a “default instance” of class Show. Main> show (Node 1 Leaf (Node 2 Leaf Leaf)) "Node 1 Leaf (Node 2 Leaf Leaf)" Works for many standard classes.

34 Multi-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

35 Functional Dependencies class Collection c a | c -> a where empty :: c add :: a -> c -> c member :: a -> c -> Bool A functional dependency 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.

36 “Side Effects” in Haskell Suppose tick :: String -> Integer reads an integer n from a file with given name, writes n+1 back to the file returns n Then tick == tick might be False! Cannot replace equals by equals. Not “purely functional”!

37 Haskell’s Solution 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. Performs I/O and delivers a String. IO is a monad -- more later!

38 The do notation I/O actions may be combined in sequence. tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n

39 The do notation I/O actions may be combined in sequence. tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n Type: IO String Type: String Scope of contents

40 The do notation I/O actions may be combined in sequence. tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n Local declaration Scope

41 The do notation I/O actions may be combined in sequence. tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n Type: IO () No need to bind a name to the result.

42 The do notation I/O actions may be combined in sequence. tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n Type: IO Integer Defines result of tick. return :: a -> IO a

43 IO a = Action Yeilding an a

44 Action at the prompt is performed. The action returned by tick has a side-effect. Yields a different Integer each time it is performed.

45 IO 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.

46 IO a = Action Yeilding an a twice2 :: IO a -> IO (a,a) twice2 a = dox <- a return (x,x) twice3 :: IO a -> IO (a,a) twice3 a = dox <- a y <- a return (x,y) The same action can be performed many times.

47 References 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.

48 Example: Destructive List Insertion 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 <- newIORef Nil writeIORef xs (Cons x new) Cons y xs' | x do new <- newIORef cell writeIORef xs (Cons x new) | x>y -> insertRList x xs' Updateable tail. Must read the list cell. case is inline pattern matching. Create new cell and update old.

49 Encapsulated 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] Use a hash table internally to make comparison fast. No IO type: no externally visible side-effects! Array operations resemble reference ones.

50 Encapsulation: 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.

51 Encapsulation: 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.

52 Encapsulation: 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

53 Encapsulation: 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”.

54 Encapsulation: 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”. Each use binds a fresh variable s: labels references created, guarantees used only here.

55 Encapsulation: 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.

56 Overloading 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) …

57 Overloading 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) … Partial type application. Plug in ST s and STRef s for m and r in the types…

58 Overloading 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) …

59 Overloading 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 ()

60 Higher-Order Functions Functions are values in Haskell. “Program skeletons” take functions as parameters. takeWhile :: (a -> Bool) -> [a] -> [a] takeWhile p [] = [] takeWhile p (x:xs) | p x= x:takeWhile p xs | otherwise = [] Takes a prefix of a list, satisfying a predicate.

61 Denoting Functions

62 below a b = b < a

63 Denoting Functions below a b = b < a takeWhile :: (a -> Bool) -> [a] -> [a] takeWhile p [] = [] takeWhile p (x:xs) | p x= x:takeWhile p xs | otherwise = []

64 Denoting Functions below a b = b < a takeWhile :: (a -> Bool) -> [a] -> [a] takeWhile p [] = [] takeWhile p (x:xs) | below 10 x= x:takeWhile p xs | otherwise = [] A partial function application.

65 More Ways to Denote Functions takeWhile (below 10) [1,5,9,15,20] below a b = b < a

66 More Ways to Denote Functions takeWhile (below 10) [1,5,9,15,20] takeWhile (\b -> b < 10) [1,5,9,15,20] below a b = b < a “Lambda” expression. Function definition in place.

67 More Ways to Denote Functions takeWhile (below 10) [1,5,9,15,20] takeWhile (\b -> b < 10) [1,5,9,15,20] below a b = b < a “Lambda” expression. Function definition in place. f b = b < 10

68 More Ways to Denote Functions takeWhile (below 10) [1,5,9,15,20] takeWhile (\b -> b < 10) [1,5,9,15,20] takeWhile (<10) [1,5,9,15,20] below a b = b < a “Lambda” expression. Function definition in place. f b = b < 10 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 (n+1)

70 Lazy Recursive Definitions nats = 0 : map (+1) nats

71 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n

72 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n The file is only opened here, it is read when contents is needed.

73 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n The file is only opened here, it is read when contents is needed. Not needed yet! n isn’t needed…

74 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n The file is only opened here, it is read when contents is needed. Not needed yet! n isn’t needed… Not needed until after the file is opened for writing!

75 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents writeFile f (show (n+1)) return n The file is only opened here, it is read when contents is needed. Not needed yet! n isn’t needed… Not needed until after the file is opened for writing! So readFile sees an empty file!

76 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents n `seq` writeFile f (show (n+1)) return n

77 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents n `seq` writeFile f (show (n+1)) return n `seq` evaluates its first argument, then returns its second.

78 A Confession This program doesn’t work! tick :: String -> IO Integer tick f = docontents <- readFile f let n = read contents n `seq` writeFile f (show (n+1)) 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.


Download ppt "A Lightning Tour of Haskell Lecture 1, Designing and Using Combinators John Hughes."

Similar presentations


Ads by Google