Slide 1

Slide 1 text

Getting Started with Haskell Munich Lambda - Paul Koerbitz January 20, 2014

Slide 2

Slide 2 text

Basic Functions Datatypes Higher Order Functions Additional Points Introduction to IO in Haskell (Heinrich) Hackathon

Slide 3

Slide 3 text

Getting started Clone: git clone [email protected]:defworkshop/haskell-workshop.git

Slide 4

Slide 4 text

Getting started Clone: git clone [email protected]:defworkshop/haskell-workshop.git Get dependencies: $ cabal install --dependencies-only

Slide 5

Slide 5 text

Getting started Clone: git clone [email protected]:defworkshop/haskell-workshop.git Get dependencies: $ cabal install --dependencies-only Build and test: $ cabal build && cabal test

Slide 6

Slide 6 text

Getting started Clone: git clone [email protected]:defworkshop/haskell-workshop.git Get dependencies: $ cabal install --dependencies-only Build and test: $ cabal build && cabal test use GHCi: $ cabal repl

Slide 7

Slide 7 text

Getting started Clone: git clone [email protected]:defworkshop/haskell-workshop.git Get dependencies: $ cabal install --dependencies-only Build and test: $ cabal build && cabal test use GHCi: $ cabal repl get help: ghci> :h

Slide 8

Slide 8 text

Getting started Clone: git clone [email protected]:defworkshop/haskell-workshop.git Get dependencies: $ cabal install --dependencies-only Build and test: $ cabal build && cabal test use GHCi: $ cabal repl get help: ghci> :h see a modules functions: ghci> :browse HaskellWorkshop.Worksheet01

Slide 9

Slide 9 text

Basic Functions

Slide 10

Slide 10 text

Functions abs :: Int -> Int abs x = if x < 0 then (-x) else x

Slide 11

Slide 11 text

Functions - Pattern Matching, Recursion, Precedence add :: Int -> Int -> Int add x 0 = x add x y = if y > 0 then add (succ x) (pred y) else add (pred x) (succ y)

Slide 12

Slide 12 text

where Bindings add :: Int -> Int -> Int add x 0 = x add x y = if y > 0 then add succ_x pred_y else add pred_x succ_y where pred_x = pred x succ_x = succ x pred_y = pred y succ_y = succ y

Slide 13

Slide 13 text

let Bindings add :: Int -> Int -> Int add x 0 = x add x y = if y > 0 then let succ_x = succ x pred_y = pred y in add succ_x pred_y else let pred_x = pred x succ_y = succ y in add pred_x succ_y

Slide 14

Slide 14 text

Datatypes

Slide 15

Slide 15 text

Datatypes - Basics Some datatypes are built in, for example Int, Integer, Char, Double, . . .

Slide 16

Slide 16 text

Datatypes - Basics Some datatypes are built in, for example Int, Integer, Char, Double, . . . Datatypes can be defined with the data keyword: -- This is like a ‘struct‘ in other languages data IntPair = IntPair Int Int -- This is like an ‘enum‘ in other languages data Color = Red | Green | Blue

Slide 17

Slide 17 text

Datatypes - Product Types and Records Product types are much like structs in C, C++, etc. data Car = Car String String Int Int

Slide 18

Slide 18 text

Datatypes - Product Types and Records Product types are much like structs in C, C++, etc. data Car = Car String String Int Int The fields of product types can also be named, such a definition is referred to as a record: data Car = Car { carMake :: String, carModel :: String, carYear :: Int, carHorsepower :: Int }

Slide 19

Slide 19 text

Datatypes - Product Types and Records Product types are much like structs in C, C++, etc. data Car = Car String String Int Int The fields of product types can also be named, such a definition is referred to as a record: data Car = Car { carMake :: String, carModel :: String, carYear :: Int, carHorsepower :: Int } Fieldnames live in the same namespace as other bindings, so they must be unique in a module.

Slide 20

Slide 20 text

Datatypes - Sum Types aka Disjoint Unions Sum types can have several representations: data MaybeInt = MIJust Int | MINothing

Slide 21

Slide 21 text

Datatypes - Sum Types aka Disjoint Unions Sum types can have several representations: data MaybeInt = MIJust Int | MINothing We can work with sum types by pattern matching their constructors: maybeAdd :: MaybeInt -> Int -> MaybeInt maybeAdd (MIJust x) y = MIJust (x+y) maybeAdd MINothing _ = MINothing

Slide 22

Slide 22 text

Datatypes - Recursive Datatypes Datatype definitions can refer to themselves: data IntList = ILNil | ILCons Int IntList

Slide 23

Slide 23 text

Datatypes - Recursive Datatypes Datatype definitions can refer to themselves: data IntList = ILNil | ILCons Int IntList . . . and can be processed by recursion length :: IntList -> Int length ILNil = 0 length (ILCons _ xs) = length xs + 1

Slide 24

Slide 24 text

Type Parameters We don’t want to define lists for every single datatype! Type parameters allow this: data List a = Nil | Cons a (List a)

Slide 25

Slide 25 text

Type Parameters We don’t want to define lists for every single datatype! Type parameters allow this: data List a = Nil | Cons a (List a) Type parameters can also be used in functions: length :: List a -> Int length Nil = 0 length (Cons _ xs) = length xs + 1

Slide 26

Slide 26 text

Type Parameters We don’t want to define lists for every single datatype! Type parameters allow this: data List a = Nil | Cons a (List a) Type parameters can also be used in functions: length :: List a -> Int length Nil = 0 length (Cons _ xs) = length xs + 1 Haskell has syntactic sugar for lists: [] is Nil, x:xs is Cons x xs and [a] is List a: length :: [a] -> Int length [] = 0 length (_:xs) = length xs + 1

Slide 27

Slide 27 text

Typeclasses 101 Many operations should work for values of many, but not all types. This can be achieved with typeclasses in Haskell. qsort :: Ord a => [a] -> [a] qsort [] = [] qsort (x:xs) = lessOrEqual ++ [x] ++ greater where lessOrEqual = qsort (filter (<= x) xs) greater = qsort (filter (> x) xs)

Slide 28

Slide 28 text

Typeclasses 101 Many operations should work for values of many, but not all types. This can be achieved with typeclasses in Haskell. qsort :: Ord a => [a] -> [a] qsort [] = [] qsort (x:xs) = lessOrEqual ++ [x] ++ greater where lessOrEqual = qsort (filter (<= x) xs) greater = qsort (filter (> x) xs) Useful typeclasses include Eq, Ord, Show, Num, Enum

Slide 29

Slide 29 text

Typeclasses 101 Many operations should work for values of many, but not all types. This can be achieved with typeclasses in Haskell. qsort :: Ord a => [a] -> [a] qsort [] = [] qsort (x:xs) = lessOrEqual ++ [x] ++ greater where lessOrEqual = qsort (filter (<= x) xs) greater = qsort (filter (> x) xs) Useful typeclasses include Eq, Ord, Show, Num, Enum New datatypes can sometimes be given instances in typeclasses with the deriving keyword: data Pair a b = Pair a b deriving (Eq, Ord, Show)

Slide 30

Slide 30 text

Higher Order Functions

Slide 31

Slide 31 text

Higher Order Functions Higher order functions take functions as arguments.

Slide 32

Slide 32 text

Higher Order Functions Higher order functions take functions as arguments. Example: Apply a function to every element in a list: map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs

Slide 33

Slide 33 text

Higher Order Functions Higher order functions take functions as arguments. Example: Apply a function to every element in a list: map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs Example: Fold a list to a singe element: foldl :: (a -> b -> a) -> a -> [b] -> a foldl _ acc [] = acc foldl f acc (x:xs) = foldl f (f acc x) xs

Slide 34

Slide 34 text

Where is my for loop? There are no for, while, or similar loops in Haskell.

Slide 35

Slide 35 text

Where is my for loop? There are no for, while, or similar loops in Haskell. Many specific iteration patterns are factored into higher-order-functions such as map and foldl.

Slide 36

Slide 36 text

Where is my for loop? There are no for, while, or similar loops in Haskell. Many specific iteration patterns are factored into higher-order-functions such as map and foldl. You can write your own loops via recursion: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = go 0 p xs where go cnt _ [] = cnt go cnt p (x:xs) = if p x then go (cnt+1) p xs else go cnt p xs

Slide 37

Slide 37 text

Where is my for loop? There are no for, while, or similar loops in Haskell. Many specific iteration patterns are factored into higher-order-functions such as map and foldl. You can write your own loops via recursion: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = go 0 p xs where go cnt _ [] = cnt go cnt p (x:xs) = if p x then go (cnt+1) p xs else go cnt p xs It is usually a good idea to use existing HOFs: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = length (filter p xs)

Slide 38

Slide 38 text

Making functions tail recursive When using recursion there is a danger of blowing the stack: length :: [a] -> Int length [] = 0 length (x:xs) = length xs + 1

Slide 39

Slide 39 text

Making functions tail recursive When using recursion there is a danger of blowing the stack: length :: [a] -> Int length [] = 0 length (x:xs) = length xs + 1 Haskell provides tail call optimization (TCO), but for this two work functions must be tail recursive.

Slide 40

Slide 40 text

Making functions tail recursive When using recursion there is a danger of blowing the stack: length :: [a] -> Int length [] = 0 length (x:xs) = length xs + 1 Haskell provides tail call optimization (TCO), but for this two work functions must be tail recursive. Usual trick: transfer results in an ‘accumulator’ length :: [a] -> Int length xs = len 0 xs where len acc [] = acc len acc (x:xs) = len (acc+1) xs

Slide 41

Slide 41 text

Lambdas Higher order functions are even more convenient to use if we can create functions in place.

Slide 42

Slide 42 text

Lambdas Higher order functions are even more convenient to use if we can create functions in place. Lambdas can be created with the \ -> syntax: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = foldl (\cnt x -> if p x then (cnt+1) else cnt) 0 xs

Slide 43

Slide 43 text

Lambdas Higher order functions are even more convenient to use if we can create functions in place. Lambdas can be created with the \ -> syntax: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = foldl (\cnt x -> if p x then (cnt+1) else cnt) 0 xs Long lambdas can be a bit awkward. Remember that you can also define functions in let and where expressions: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = foldl counter 0 xs where counter cnt x = if p x then (cnt+1) else cnt

Slide 44

Slide 44 text

Additional Points

Slide 45

Slide 45 text

Laziness Lazy evaluation is the default in Haskell, so arguments are not evaluated until they have to be.

Slide 46

Slide 46 text

Laziness Lazy evaluation is the default in Haskell, so arguments are not evaluated until they have to be. You can see this in ghci: ghci> let a = sum [1..10*1000*1000] -- This is very fast ghci> show a -- This takes some time "50000005000000"

Slide 47

Slide 47 text

Laziness Lazy evaluation is the default in Haskell, so arguments are not evaluated until they have to be. You can see this in ghci: ghci> let a = sum [1..10*1000*1000] -- This is very fast ghci> show a -- This takes some time "50000005000000" The great thing about laziness is that it decouples production from consumption.

Slide 48

Slide 48 text

When Laziness bites Unfortunately laziness can sometimes have unexpected consequences: length :: Int -> [a] -> Int length acc [] = acc length acc (x:xs) = length (1+acc) xs This uses a huge amount of memory, blows the stack if in a compiled program: ghci> length [1..10*1000*1000]

Slide 49

Slide 49 text

When Laziness bites Unfortunately laziness can sometimes have unexpected consequences: length :: Int -> [a] -> Int length acc [] = acc length acc (x:xs) = length (1+acc) xs This uses a huge amount of memory, blows the stack if in a compiled program: ghci> length [1..10*1000*1000] The problem is that (+) is lazy, so we build up a huge thunk (1+(1+(1+(1+(1+ ...)))))

Slide 50

Slide 50 text

When Laziness bites We can avoid this by forcing the evaluation of acc with seq: len :: Int -> [a] -> Int len acc [] = acc len acc (x:xs) = let z = acc+1 in z ‘seq‘ len z xs

Slide 51

Slide 51 text

When Laziness bites We can avoid this by forcing the evaluation of acc with seq: len :: Int -> [a] -> Int len acc [] = acc len acc (x:xs) = let z = acc+1 in z ‘seq‘ len z xs Instead of rolling our own, we can also use existing combinators such as foldl’ from Data.List.

Slide 52

Slide 52 text

Currying and Partial Function Application Currying: Take a function of n parameters into a function of n-k parameters which returns a function of k parameters.

Slide 53

Slide 53 text

Currying and Partial Function Application Currying: Take a function of n parameters into a function of n-k parameters which returns a function of k parameters. Currying is the default modus operandi in Haskell: add :: Int -> Int -> Int add x y = x + y add is a function that takes an Int and returns a function of type Int -> Int.

Slide 54

Slide 54 text

Currying and Partial Function Application Currying: Take a function of n parameters into a function of n-k parameters which returns a function of k parameters. Currying is the default modus operandi in Haskell: add :: Int -> Int -> Int add x y = x + y add is a function that takes an Int and returns a function of type Int -> Int. Since functions are curried by default, partial function application is very natural in Haskell: add3 :: Int -> Int add3 = add 3 map add3 [1..5] -- [4, 5, 6, 7, 8]

Slide 55

Slide 55 text

Operators are just functions Haskell may seem like it is full of operators, but operators are just functions: (!?) :: [a] -> Int -> Maybe a (!?) [] _ = Nothing (!?) (x:xs) 0 = Just x (x:xs) !? n = xs !? (n-1)

Slide 56

Slide 56 text

Operators are just functions Haskell may seem like it is full of operators, but operators are just functions: (!?) :: [a] -> Int -> Maybe a (!?) [] _ = Nothing (!?) (x:xs) 0 = Just x (x:xs) !? n = xs !? (n-1) Operators are written inline by default, but don’t have to be: ghci> [0,1,2,3,4] !? 3 Just 3 ghci> (!?) [0,1,2,3,4] 3 Just 3

Slide 57

Slide 57 text

Operators are just functions Haskell may seem like it is full of operators, but operators are just functions: (!?) :: [a] -> Int -> Maybe a (!?) [] _ = Nothing (!?) (x:xs) 0 = Just x (x:xs) !? n = xs !? (n-1) Operators are written inline by default, but don’t have to be: ghci> [0,1,2,3,4] !? 3 Just 3 ghci> (!?) [0,1,2,3,4] 3 Just 3 We can write regular functions inline by surrounding them with backticks: ghci> 6 ‘mod‘ 3 0

Slide 58

Slide 58 text

($) and (.) The ($) operator is function application, but has very low precedence and binds to the right. This can be convenient to avoid writing to many parenthesis: concat $ map show $ take 10 [1..]

Slide 59

Slide 59 text

($) and (.) The ($) operator is function application, but has very low precedence and binds to the right. This can be convenient to avoid writing to many parenthesis: concat $ map show $ take 10 [1..] Functions can be composed with the function composition operator (.): (.) :: (b -> c) -> (a -> b) -> a -> c (.) f g x = f (g x)

Slide 60

Slide 60 text

Pointfree vs. Pointful Style So far we have written our Haskell in what is called pointful style: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = length (filter p xs)

Slide 61

Slide 61 text

Pointfree vs. Pointful Style So far we have written our Haskell in what is called pointful style: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = length (filter p xs) An alternative is pointfree style: countIf :: (a -> Bool) -> [a] -> Int countIf p = length . filter p

Slide 62

Slide 62 text

Pointfree vs. Pointful Style So far we have written our Haskell in what is called pointful style: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = length (filter p xs) An alternative is pointfree style: countIf :: (a -> Bool) -> [a] -> Int countIf p = length . filter p Pointfree style focuses on how functions can be defined in terms of other functions.

Slide 63

Slide 63 text

Pointfree vs. Pointful Style So far we have written our Haskell in what is called pointful style: countIf :: (a -> Bool) -> [a] -> Int countIf p xs = length (filter p xs) An alternative is pointfree style: countIf :: (a -> Bool) -> [a] -> Int countIf p = length . filter p Pointfree style focuses on how functions can be defined in terms of other functions. Ironically ‘pointfree’ style has more (.)!

Slide 64

Slide 64 text

Introduction to IO in Haskell (Heinrich)

Slide 65

Slide 65 text

Hackathon

Slide 66

Slide 66 text

Happy hacking Need a project? Write a Sudoku solver

Slide 67

Slide 67 text

Happy hacking Need a project? Write a Sudoku solver Auf wie viele Arten kann man das ‘Haus-vom-Nikolaus’ zeichnen? http://de.wikipedia.org/wiki/Haus_vom_Nikolaus

Slide 68

Slide 68 text

Happy hacking Need a project? Write a Sudoku solver Auf wie viele Arten kann man das ‘Haus-vom-Nikolaus’ zeichnen? http://de.wikipedia.org/wiki/Haus_vom_Nikolaus Hashlife: http://www.drdobbs.com/jvm/ an-algorithm-for-compressing-space-and-t/ 184406478