04. haskell handling

22
Handling Sebastian Rettig “Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it.” ([1]) “Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it.” ([1])

Upload: sebastian-rettig

Post on 11-May-2015

206 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 04. haskell handling

Handling

Sebastian Rettig

“Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it.” ([1])

“Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it.” ([1])

Page 2: 04. haskell handling

Functional Programming

● No Variables● Functions only, eventually stored in

Modules– Behavior do not change, once defined

– → Function called with same parameter calculates always the same result

● Function definitions (Match Cases)● Recursion (Memory)

Page 3: 04. haskell handling

Haskell Features

● Pure Functional Programming Language● Lazy Evaluation ● Pattern Matching and Guards● List Comprehension● Type Polymorphism

Page 4: 04. haskell handling

How to write Functions?

● eventually think about imperative function● and translate into recursive function● → generally the same schema to go for:

– 1. define simple cases (recursion anchor)

– 2. define the recursion call

● lets start with imperative functions

Page 5: 04. haskell handling

How to implement the Factorial?

● Remember:

“Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it.” ([1])

● Okay, then look at the definition:

– Imperative definition

– Recursive definition

Page 6: 04. haskell handling

Let's look at the imperative way...

● Imperative

function factorial(n) { int result = 1; if (n == 0) return result; } for (int i=1; i<n; i++) { result *= i; } return result;}

● Recursive

Page 7: 04. haskell handling

…and translate to the functional way

● Imperative

function fact(n) { int result = 1; if (n == 0) return result; } for (int i=1; i<n; i++) { result *= i; } return result;}

● Recursive

fact 0 = 1fact n = n * fact (n-1)

● and in comparison with the definition:

● BUT imperative also possible:

fact' 0 = 1fact' n = product [1..n]

● compared with the definition:

Page 8: 04. haskell handling

Recursion (1)

● we have no loops → use Recursion:myMap :: Int -> [Int] -> [Int]

myMap v [] = [] -- � Recursion Anchor!

myMap v (x:xs) = [v*x] ++ myMap v xs

● Recursion Anchor contains the break rule– endless loop = anchorless recursionisTrue :: Bool � Bool

isTrue b = b && isTrue b

Page 9: 04. haskell handling

Recursion (2)● Recursion vs. Final Recursion:

● Hugs> countX 3 [1,4,3,5,3]2

● use accumulator to reduce stack usage

● Hugs> countXFinal 3 [1,4,3,5,3] 0 2

countX :: Int -> [Int] -> IntcountX x [] = 0countX x (y:ys) | x==y = 1 + countX x ys | otherwise = countX x ys

countXFinal :: Int -> [Int] -> Int -> IntcountXFinal x [] accu = accucountXFinal x (y:ys) accu | x==y = countXFinal x ys accu+1 | otherwise = countXFinal x ys accu

Page 10: 04. haskell handling

Where & let .. in

● additional definitions● let .. in defines scope of usage

– let = definition

– in = scope of definition

– e.g.: add x = let a=9 in a + x

● where has scope in whole function– e.g.: add x = a + x

where a=9

Page 11: 04. haskell handling

The maximum value of a List?

● Remember:

“Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it.” ([1])

● Okay, then look at the definition:

Page 12: 04. haskell handling

Let's look at the imperative way...

● Imperative

function max(array list) { if (empty(list)) { throw new Exception(); } max = list[0] for (int i=0; i<length(list);

i++) { if (list[i] > max) { max = list[i]; } } return max;}

● Recursive

Page 13: 04. haskell handling

…and translate to the functional way ● Imperative

function max(array list) { if (empty(list)) { throw new Exception(); } max = list[0] for (int i=0; i<length(list);

i++) { if (list[i] > max) { max = list[i]; } } return max;}

● Recursive

maxList [] = error “empty”maxList [x] = xmaxList (x:xs) | x > maxTail = x | otherwise = maxTail where maxTail = maxList xs

● or simpler:maxList [] = error “empty”maxList [x] = xmaxList (x:xs) = max x (maxList xs)

● and in comparison with the definition:

Page 14: 04. haskell handling

Final Recursion

● Get maximum element of list in final recursionmaxFinal :: [Int] -> Int -> Int

maxFinal [] accu = accu

maxFinal (x:xs) accu

| x > accu = maxFinal xs x

| otherwise = maxFinal xs accu

● often the same Schema to program

● → there exist functions in haskell to simplify the all day work :)

Page 15: 04. haskell handling

Simple Recursion Helper

● map

● foldl, foldr, foldl1, foldr1

● scanl, scanr, scanl1, scanr1

● etc...

Page 16: 04. haskell handling

Lambda Functions

● often called as Inline Functions in other languages

● Syntax:– \<param> <param> → <operation>

– e.g.:\a b -> a+b

– map (\x -> x+3) [2,3,4]

● returns [5,6,7]

Page 17: 04. haskell handling

Folding, Scanning (1)

● e.g.: How to get the max of an array?– imperative:

int max = 0;

foreach (entry in list) {

max = (entry > max) ? entry : max;

}

– functional: let list = [8,6,4,1,7,3,5]

foldl (\acc x -> if x > acc then x else acc) 0 list

Page 18: 04. haskell handling

Folding, Scanning (2)

● scan shows the accumulator state on every recursion step:

scanl (\acc x -> if x > acc then x else acc) 0 list

– returns:[0,8,8,8,8,8,8,8]

– good for debugging

– good to understand recursion

Page 19: 04. haskell handling

Folding, Scanning (3)

● foldl versus foldr: – first we look at the Header of the functions:

Prelude> :t foldl

foldl :: (a -> b -> a) -> a -> [b] -> a

Prelude> :t foldr

foldr :: (a -> b -> b) -> b -> [a] -> b

– What is the difference?

Page 20: 04. haskell handling

Folding, Scanning (4)

● foldl versus foldr: – first we look at the Header of the functions:

Prelude> :t foldl

foldl :: (a -> b -> a) -> a -> [b] -> a

Prelude> :t foldr

foldr :: (a -> b -> b) -> b -> [a] -> b

– What is the difference?● accumulator and parameter are

switched!!!

Page 21: 04. haskell handling

Infix, Prefix, Postfix

● Infix (usable in Haskell):– 2 + 3

– 2 `mod` 3

● Prefix (usable in Haskell):– (+) 2 3

– mod 2 3

● Postfix (used in stack machines):– 3 2 +

Page 22: 04. haskell handling

Sources

[1] Haskell-Tutorial: Learn you a Haskell (http://learnyouahaskell.com/, 2012/03/15)

[2] The Hugs User-Manual (http://cvs.haskell.org/Hugs/pages/hugsman/index.html, 2012/03/15)

[3] The Haskellwiki (http://www.haskell.org/haskellwiki, 2012/03/15)