Programming Languages (TC-2006)

56
Programming Languages (TC-2006) Higher-order functions and lazy evaluation in Haskell Jos´ e Carlos Ortiz Bayliss [email protected]

Transcript of Programming Languages (TC-2006)

Programming Languages(TC-2006)

Higher-order functions and lazy evaluation in Haskell

Jose Carlos Ortiz [email protected]

Contents

1 Lambda functions

2 Some useful higher-order functions

3 ‘Monads’

4 Lazy evaluation

2 / 23

Lambda functions

Lambda functions have no name.

Character ’\’ is used before the parameters to define a lambda function.

For example:

(\x -> x + 1) 10 ⇒ 11

(\x y -> x * y) 3 4 ⇒ 12

(\x -> x - 10) ((\x y -> x * y) 3 4) ⇒ 2

(\x -> fst x * snd x) (3, 5) ⇒ 15

3 / 23

Lambda functions

Lambda functions have no name.

Character ’\’ is used before the parameters to define a lambda function.

For example:

(\x -> x + 1) 10 ⇒ 11

(\x y -> x * y) 3 4 ⇒ 12

(\x -> x - 10) ((\x y -> x * y) 3 4) ⇒ 2

(\x -> fst x * snd x) (3, 5) ⇒ 15

3 / 23

Lambda functions

Lambda functions have no name.

Character ’\’ is used before the parameters to define a lambda function.

For example:

(\x -> x + 1) 10 ⇒ 11

(\x y -> x * y) 3 4 ⇒ 12

(\x -> x - 10) ((\x y -> x * y) 3 4) ⇒ 2

(\x -> fst x * snd x) (3, 5) ⇒ 15

3 / 23

Lambda functions

Lambda functions have no name.

Character ’\’ is used before the parameters to define a lambda function.

For example:

(\x -> x + 1) 10 ⇒ 11

(\x y -> x * y) 3 4 ⇒ 12

(\x -> x - 10) ((\x y -> x * y) 3 4) ⇒ 2

(\x -> fst x * snd x) (3, 5) ⇒ 15

3 / 23

Lambda functions

Lambda functions have no name.

Character ’\’ is used before the parameters to define a lambda function.

For example:

(\x -> x + 1) 10 ⇒ 11

(\x y -> x * y) 3 4 ⇒ 12

(\x -> x - 10) ((\x y -> x * y) 3 4) ⇒ 2

(\x -> fst x * snd x) (3, 5) ⇒ 15

3 / 23

Higher-order functions

Higher-order functions are functions that can be applied to other functions:

map.

all and any.

filter.

foldl and foldl1.

foldr and foldr1.

compose.

4 / 23

Applying a function to each element in a list: map

map function list

Function map applies a function to all the elements in a list and returnsthe result as a list.

For example:

map sqrt [4, 9, 16, 25] ⇒ [2.0, 3.0, 4.0, 5.0]

map (\x -> x * x) [1, 2, 3, 4, 5] ⇒ [1, 4, 9, 16, 25]

5 / 23

Applying a function to each element in a list: map

map function list

Function map applies a function to all the elements in a list and returnsthe result as a list.

For example:

map sqrt [4, 9, 16, 25] ⇒ [2.0, 3.0, 4.0, 5.0]

map (\x -> x * x) [1, 2, 3, 4, 5] ⇒ [1, 4, 9, 16, 25]

5 / 23

Applying a function to each element in a list: map

map function list

Function map applies a function to all the elements in a list and returnsthe result as a list.

For example:

map sqrt [4, 9, 16, 25] ⇒ [2.0, 3.0, 4.0, 5.0]

map (\x -> x * x) [1, 2, 3, 4, 5] ⇒ [1, 4, 9, 16, 25]

5 / 23

map in action: dot product

dotProduct :: [Int] -> [Int] -> IntdotProduct v w = sum (map (\(x, y) -> x * y) (zip v w))

> dotProduct [1, 2, 3] [10, 20, 30]140

6 / 23

map in action: dot product

dotProduct :: [Int] -> [Int] -> IntdotProduct v w = sum (map (\(x, y) -> x * y) (zip v w))

> dotProduct [1, 2, 3] [10, 20, 30]140

6 / 23

all and any

Function all applies a predicate to all the elements in a list and checksif all the elements fulfil this predicate.

all even [1, 2, 3, 4, 5] ⇒ False

Function all applies a predicate to all the elements in a list and checksif at least one of the elements fulfils this predicate.

any even [1, 2, 3, 4, 5] ⇒ True

7 / 23

all and any

Function all applies a predicate to all the elements in a list and checksif all the elements fulfil this predicate.

all even [1, 2, 3, 4, 5] ⇒ False

Function all applies a predicate to all the elements in a list and checksif at least one of the elements fulfils this predicate.

any even [1, 2, 3, 4, 5] ⇒ True

7 / 23

all and any

Function all applies a predicate to all the elements in a list and checksif all the elements fulfil this predicate.

all even [1, 2, 3, 4, 5] ⇒ False

Function all applies a predicate to all the elements in a list and checksif at least one of the elements fulfils this predicate.

any even [1, 2, 3, 4, 5] ⇒ True

7 / 23

all and any

Function all applies a predicate to all the elements in a list and checksif all the elements fulfil this predicate.

all even [1, 2, 3, 4, 5] ⇒ False

Function all applies a predicate to all the elements in a list and checksif at least one of the elements fulfils this predicate.

any even [1, 2, 3, 4, 5] ⇒ True

7 / 23

Filtering a list: filter

filter predicate list

Function filter produces a list with all the elements in a list thatfulfil a given predicate.

For example:

filter even [1, 2, 3, 4, 5] ⇒ [2, 4]

filter odd [1, 2, 3, 4, 5] ⇒ [1, 3, 5]

filter (> 3) [1, 2, 3, 4, 5] ⇒ [4, 5]

filter (\x -> odd x && x < 10) [3, 6, 9, 12, 15] ⇒ [3, 9]

8 / 23

Filtering a list: filter

filter predicate list

Function filter produces a list with all the elements in a list thatfulfil a given predicate.

For example:

filter even [1, 2, 3, 4, 5] ⇒ [2, 4]

filter odd [1, 2, 3, 4, 5] ⇒ [1, 3, 5]

filter (> 3) [1, 2, 3, 4, 5] ⇒ [4, 5]

filter (\x -> odd x && x < 10) [3, 6, 9, 12, 15] ⇒ [3, 9]

8 / 23

Filtering a list: filter

filter predicate list

Function filter produces a list with all the elements in a list thatfulfil a given predicate.

For example:

filter even [1, 2, 3, 4, 5] ⇒ [2, 4]

filter odd [1, 2, 3, 4, 5] ⇒ [1, 3, 5]

filter (> 3) [1, 2, 3, 4, 5] ⇒ [4, 5]

filter (\x -> odd x && x < 10) [3, 6, 9, 12, 15] ⇒ [3, 9]

8 / 23

Filtering a list: filter

filter predicate list

Function filter produces a list with all the elements in a list thatfulfil a given predicate.

For example:

filter even [1, 2, 3, 4, 5] ⇒ [2, 4]

filter odd [1, 2, 3, 4, 5] ⇒ [1, 3, 5]

filter (> 3) [1, 2, 3, 4, 5] ⇒ [4, 5]

filter (\x -> odd x && x < 10) [3, 6, 9, 12, 15] ⇒ [3, 9]

8 / 23

Filtering a list: filter

filter predicate list

Function filter produces a list with all the elements in a list thatfulfil a given predicate.

For example:

filter even [1, 2, 3, 4, 5] ⇒ [2, 4]

filter odd [1, 2, 3, 4, 5] ⇒ [1, 3, 5]

filter (> 3) [1, 2, 3, 4, 5] ⇒ [4, 5]

filter (\x -> odd x && x < 10) [3, 6, 9, 12, 15] ⇒ [3, 9]

8 / 23

Sorting a list: quicksort (using let)

quicksort :: [Int] -> [Int]quicksort [] = []quicksort (first:rest) = let

leftList = filter (< first) restrightList = filter (>= first) restin(quicksort leftList) ++ [first] ++ (quicksort rightList)

> quicksort [5, -2, 9, 8, 10, 3, 14][-2,3,5,8,9,10,14]

9 / 23

Sorting a list: quicksort (using let)

quicksort :: [Int] -> [Int]quicksort [] = []quicksort (first:rest) = let

leftList = filter (< first) restrightList = filter (>= first) restin(quicksort leftList) ++ [first] ++ (quicksort rightList)

> quicksort [5, -2, 9, 8, 10, 3, 14][-2,3,5,8,9,10,14]

9 / 23

Folding a list: foldl and foldl1

Function foldl reduces a list by applying a binary operator (firstargument) from left to right and using the second argument as initialvalue for the calculation.

foldl (-) 1 [2, 3, 4, 5] ⇒ -13

foldl (\x y -> x - y) 1 [2, 3, 4, 5] ⇒ -13

Function foldl1 does the same than foldl does but without initialvalue.

foldl1 (-) [1, 2, 3, 4, 5] ⇒ -13

10 / 23

Folding a list: foldr and foldr1

Function foldr reduces a list by applying a binary operator (firstargument) from right to left and using the second argument as initialvalue for the calculation.

foldr (-) 1 [2, 3, 4, 5] ⇒ -1

Function foldr1 does the same than foldr does but without initialvalue.

foldr1 (-) [2, 3, 4, 5, 1] ⇒ -1

foldr1 (-) [1, 2, 3, 4, 5] ⇒ 3

11 / 23

“Chaining” functions: compose

Function compose takes two functions and ‘chains’ them.

Using (f . g . h) x is equivalent to f (g (h x)).

For example:

(sqrt . sum) [4, 9, 16, 25] ⇒ 7.3484

(sum . map sqrt) [4, 9, 16, 25] ⇒ 14

(foldl1 (*) . map abs) [1, -2, 3] ⇒ 6

12 / 23

“Chaining” functions: compose

Function compose takes two functions and ‘chains’ them.

Using (f . g . h) x is equivalent to f (g (h x)).

For example:

(sqrt . sum) [4, 9, 16, 25] ⇒ 7.3484

(sum . map sqrt) [4, 9, 16, 25] ⇒ 14

(foldl1 (*) . map abs) [1, -2, 3] ⇒ 6

12 / 23

“Chaining” functions: compose

Function compose takes two functions and ‘chains’ them.

Using (f . g . h) x is equivalent to f (g (h x)).

For example:

(sqrt . sum) [4, 9, 16, 25] ⇒ 7.3484

(sum . map sqrt) [4, 9, 16, 25] ⇒ 14

(foldl1 (*) . map abs) [1, -2, 3] ⇒ 6

12 / 23

“Chaining” functions: compose

Function compose takes two functions and ‘chains’ them.

Using (f . g . h) x is equivalent to f (g (h x)).

For example:

(sqrt . sum) [4, 9, 16, 25] ⇒ 7.3484

(sum . map sqrt) [4, 9, 16, 25] ⇒ 14

(foldl1 (*) . map abs) [1, -2, 3] ⇒ 6

12 / 23

Guards

‘Guards’ are used for cases definition.

They make the code simpler to read.

13 / 23

The factorial

factorial :: Int -> Intfactorial n

| n == 0 = 1| n > 0 = n * factorial (n - 1)

> factorial 5120

14 / 23

The factorial

factorial :: Int -> Intfactorial n

| n == 0 = 1| n > 0 = n * factorial (n - 1)

> factorial 5120

14 / 23

Selecting even elements from a list

getEven :: [Int] -> [Int]getEven [] = []getEven (first:rest)

| even first = first : getEven rest| otherwise = getEven rest

> getEven [4, 10, 3, 1, 8, 9][4,10,8]

15 / 23

Selecting even elements from a list

getEven :: [Int] -> [Int]getEven [] = []getEven (first:rest)

| even first = first : getEven rest| otherwise = getEven rest

> getEven [4, 10, 3, 1, 8, 9][4,10,8]

15 / 23

Generators

[xi | xi <- x, xi > 0] means: “create a list with every xi ∈ xwhere xi > 0”.

xi <- x is usually referred to as a generator.

positives :: [Int] -> [Int]positives x = [xi | xi <- x, xi > 0]

> positives [2, 3, -1, 10, -6][2,3,10]

16 / 23

Generators

[xi | xi <- x, xi > 0] means: “create a list with every xi ∈ xwhere xi > 0”.

xi <- x is usually referred to as a generator.

positives :: [Int] -> [Int]positives x = [xi | xi <- x, xi > 0]

> positives [2, 3, -1, 10, -6][2,3,10]

16 / 23

Generators

[xi | xi <- x, xi > 0] means: “create a list with every xi ∈ xwhere xi > 0”.

xi <- x is usually referred to as a generator.

positives :: [Int] -> [Int]positives x = [xi | xi <- x, xi > 0]

> positives [2, 3, -1, 10, -6][2,3,10]

16 / 23

Cartesian product

cartesian :: [t] -> [t] -> [(t, t)]cartesian x y = [(xi, yi) | xi <- x, yi <- y]

> cartesian [1, 2] [3, 4][(1,3),(1,4),(2,3),(2,4)]

17 / 23

Cartesian product

cartesian :: [t] -> [t] -> [(t, t)]cartesian x y = [(xi, yi) | xi <- x, yi <- y]

> cartesian [1, 2] [3, 4][(1,3),(1,4),(2,3),(2,4)]

17 / 23

Cartesian product (with an additional constraint)

cartesianSum :: [Int] -> [Int] -> [(Int, Int)]cartesianSum x y = [(xi, yi) | xi <- x, yi <- y, (xi + yi) >= 5]

> cartesianSum [1, 2, 3] [1, 2, 3][(2,3),(3,2),(3,3)]

18 / 23

Cartesian product (with an additional constraint)

cartesianSum :: [Int] -> [Int] -> [(Int, Int)]cartesianSum x y = [(xi, yi) | xi <- x, yi <- y, (xi + yi) >= 5]

> cartesianSum [1, 2, 3] [1, 2, 3][(2,3),(3,2),(3,3)]

18 / 23

Counting the occurrences of a number

occurrences :: Int -> [Int] -> Intoccurrences n x = length [xi | xi <- x, n == xi]

> occurrences 1 [1, 2, 3, 4, 1, 1, 5, 6]3

19 / 23

Counting the occurrences of a number

occurrences :: Int -> [Int] -> Intoccurrences n x = length [xi | xi <- x, n == xi]

> occurrences 1 [1, 2, 3, 4, 1, 1, 5, 6]3

19 / 23

Sorting a list: quicksort (using where)

qSort :: [Int] -> [Int]qSort [] = []qSort (first:rest) =

(qSort leftList) ++ [first] ++ (qSort rightList)where

leftList = [lefti | lefti <- rest, lefti < first]rightList = [righti | righti <- rest, righti >= first]

> qSort [5, -2, 9, 8, 10, 3, 14][-2,3,5,8,9,10,14]

20 / 23

Sorting a list: quicksort (using where)

qSort :: [Int] -> [Int]qSort [] = []qSort (first:rest) =

(qSort leftList) ++ [first] ++ (qSort rightList)where

leftList = [lefti | lefti <- rest, lefti < first]rightList = [righti | righti <- rest, righti >= first]

> qSort [5, -2, 9, 8, 10, 3, 14][-2,3,5,8,9,10,14]

20 / 23

‘Infinite’ data structures

ones :: [Int]ones = 1:ones

> take 5 ones[1,1,1,1,1]

numbersFrom :: Int -> [Int]numbersFrom n = n:numbersFrom (n + 1)

> take 3 (numbersFrom 1000)[1000,1001,1002]

21 / 23

‘Infinite’ data structures

ones :: [Int]ones = 1:ones

> take 5 ones[1,1,1,1,1]

numbersFrom :: Int -> [Int]numbersFrom n = n:numbersFrom (n + 1)

> take 3 (numbersFrom 1000)[1000,1001,1002]

21 / 23

‘Infinite’ data structures

ones :: [Int]ones = 1:ones

> take 5 ones[1,1,1,1,1]

numbersFrom :: Int -> [Int]numbersFrom n = n:numbersFrom (n + 1)

> take 3 (numbersFrom 1000)[1000,1001,1002]

21 / 23

‘Infinite’ data structures

ones :: [Int]ones = 1:ones

> take 5 ones[1,1,1,1,1]

numbersFrom :: Int -> [Int]numbersFrom n = n:numbersFrom (n + 1)

> take 3 (numbersFrom 1000)[1000,1001,1002]

21 / 23

‘Infinite’ data structures

factorialInf :: Int -> IntfactorialInf n = product (take n [1..])

> factorialInf 5120

22 / 23

‘Infinite’ data structures

factorialInf :: Int -> IntfactorialInf n = product (take n [1..])

> factorialInf 5120

22 / 23

Lazy evaluation

Lazy evaluation evaluates expressions only when they are needed!

Once it has been evaluated, the result is saved for further computation,or discarded if it is not needed in any other running code.

Pros: only the minimal amount of computation is performed duringprogram execution.Cons: all the suspended expressions that have not yet been evaluatedmust be saved in memory.

23 / 23

Lazy evaluation

Lazy evaluation evaluates expressions only when they are needed!

Once it has been evaluated, the result is saved for further computation,or discarded if it is not needed in any other running code.

Pros: only the minimal amount of computation is performed duringprogram execution.Cons: all the suspended expressions that have not yet been evaluatedmust be saved in memory.

23 / 23

Lazy evaluation

Lazy evaluation evaluates expressions only when they are needed!

Once it has been evaluated, the result is saved for further computation,or discarded if it is not needed in any other running code.

Pros: only the minimal amount of computation is performed duringprogram execution.

Cons: all the suspended expressions that have not yet been evaluatedmust be saved in memory.

23 / 23

Lazy evaluation

Lazy evaluation evaluates expressions only when they are needed!

Once it has been evaluated, the result is saved for further computation,or discarded if it is not needed in any other running code.

Pros: only the minimal amount of computation is performed duringprogram execution.Cons: all the suspended expressions that have not yet been evaluatedmust be saved in memory.

23 / 23