haskell n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Haskell PowerPoint Presentation
Download Presentation
Haskell

Loading in 2 Seconds...

play fullscreen
1 / 29

Haskell - PowerPoint PPT Presentation


  • 154 Views
  • Uploaded on

Haskell. Chapter 5, Part II. Topics. Review/More Higher Order Functions Lambda functions Folds. Higher Order Functions. Higher-Order functions. applyTwice :: (a -> a) -> a -> a applyTwice f x = f (f x) (a -> a) is a function parentheses are needed.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Haskell' - duane


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
haskell

Haskell

Chapter 5, Part II

topics
Topics
  • Review/More Higher Order Functions
  • Lambda functions
  • Folds
higher order functions1
Higher-Order functions

applyTwice :: (a -> a) -> a -> a

applyTwice f x = f (f x)

  • (a -> a) is a function
  • parentheses are needed.
  • a is (of course) a type parameter, maybe Int, String, etc.
  • BUT, parameter and result must have the same type
  • Try:
    • applyTwice(+3) 10
    • applyTwice (++ " woot") "say"
    • applyTwice (3:) [1]
  • Note that we are passing partially applied functions (e.g., 3:, +3, etc.)
example zipwith
Example: zipWith

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]

zipWith' _ [] _ = []

zipWith' _ _ [] = []

zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xsys

  • joins two lists by applying function to corresponding elements
  • must handle cases where lists are not equal length
  • lists don’t need to have same type
  • Try
    • zipWith' (+) [4,2,5] [2,6,2]
    • zipWith' (max) [4,2,5, 3] [2,6,2]
    • zipWith' (++) ["foo ", "bar "] ["fighters", "bells"]
    • zipWith' (*) (replicate 5 2) [1..] // replicates 2 5x
    • zipWith' (zipWith' (*)) [[2,3],[4,6]] [[10,20],[100, 200]]
example flip
Example: flip

flip' :: (a->b->c) -> (b -> a -> c)

flip' f = g

where g x y = f y x

  • Try:
    • zip [1,2,3,4,5] "hello"
    • flip' zip [1,2,3,4,5] "hello"
lambda l
Lambda - l
  • Anonymous function we use when that function is only needed once
  • Typically use to pass to a higher-order function
  • Syntax:
    • \ (kind of like l)
    • function parameters
    • ->
    • function body
  • Example:

numLongChains :: Int

numLongChains = length (filter (\xs -> length xs > 15) (map chain [1..100]))

  • compare to:

numLongChains :: Int

numLongChains = length (filter isLong (map chain [1..100]))

where isLongxs = length xs > 15

when not to use lambda
When not to use lambda
  • Don’t use lambda when currying and partial application work… those are more readable
  • Example, use:
    • map (+3) [1,6,3,2]
  • Not
    • map (\x -> x + 3) [1,6,3,2]
  • Both work... but which would you rather read??
more on lambda functions
More on lambda functions
  • They can take multiple parameters

zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]

  • Can include pattern matching
  • BUT, only one pattern (can’t fall through as in normal functions)
  • map (\(a, b) -> a + b) [(1,2),(3,4)]
folds1
Folds
  • A programming language can make it quicker to write code if it includes language constructs that capture common patterns
  • Think about common recursive pattern:
    • Base case: empty list
    • Pattern match x:xs
    • Perform some action on x and (recursively) on xs
  • In Haskell, this is what a fold does!
  • Can be used whenever you want to traverse a list once and return something.
more details
More details
  • A fold takes:
    • A binary function (e.g., +, div, etc.)
    • A starting value (accumulator)
    • A list to fold up

sum' :: (Num a) => [a] -> a

sum' xs = foldl (\acc x -> acc + x) 0 xs

  • sum’ [2,4,5]
    • 0 + 2
      • 2 + 4
        • 6 + 5
          • 11

[2,4,5]

acc

0

fold

[4,5]

acc

2

fold

[5]

acc

6

fold

[]

acc

11

fold

can use currying
Can use currying

sum'' :: (Num a) => [a] -> a

sum'' = foldl (+) 0

  • *Main> sum'' [3,5]
  • 8
  • What happened to xs? The above returns a partially applied function that takes a list.
  • In general, if have fn foo a = bar b a
    • can rewrite as foo = bar b
    • then call foo a
  • Note that the definition is more concise without the lambda
quick exercise
Quick Exercise

sum could be done as a fold at the command line, e.g.,

  • *Main>foldl (+) 0 [3,4,5]
  • 12

EXERCISE

  • Use a fold1 to create the product of the numbers in a list (just do this at the GHCi prompt, no function definition)
  • Use a foldl to append strings stored in a list to an initial string of “Hello ”
  • Use a foldl to subtract a list of numbers from an initial value (could be subtracting purchases from your wallet, for example)
right folds1
Right folds
  • foldr is like foldl, except it “eats up” the values starting from the right.
  • In some cases, the result is the same.
  • *Main>foldl (+) 0 [3,4,5]
  • 12
  • *Main>foldr (+) 0 [3,4,5]
  • 12

[2,4,5]

acc

0

fold

[2, 4]

acc

5

fold

[2]

acc

9

fold

[]

acc

11

fold

right folds2
Right folds

The accumulator value of a fold can be any type – including a list.

  • *Main>foldr (\x acc -> (^2) x:acc) [] [2,3,4]
  • [4,9,16]
  • Note that the order of the arguments is reversed from the order of the parameters (x accparameters, [] [2,3,4] arguments)

If arguments not reversed:

  • *Main>foldr (\x acc -> (^2) x:acc) [2,3,4] []
  • [2,3,4]
  • (nothing to “eat up” so result=acc)

[2,3, 4]

acc

[]

fold

[2, 3]

acc

[16]

fold

[2]

acc

[9, 16]

fold

[]

acc

[4,9,16]

fold

can i trace this
Can I trace this?
  • scanl and scanr (and scanl1, scanr1) are like foldl and foldr, except they report intermediate accumulator states.
  • Used to monitor the progress of a function that can be implemented as a fold.
  • *Main>foldl (+) 0 [3,5,2,1]
  • 11
  • *Main> scanl (+) 0 [3,5,2,1]
  • [0,3,8,10,11]
  • *Main>scanr (\x acc -> (^2) x:acc) [] [2,3,4]
  • [[4,9,16],[9,16],[16],[]]
  • *Main>scanr (\x acc -> (^2) x:acc) [2,3,4] []
  • [[2,3,4]]
right folds to implement map
Right folds – to implement map
  • Like what we just did
    • foldr(\x acc -> (^2) x:acc) [] [2,3,4]
  • BUTuse function passed as argument rather than ^2

map' :: (a -> b) -> [a] -> [b]

map' fxs = foldr (\x acc -> f x : acc) [] xs

  • map' (+3) [1,2,3]
    • 3 : [ ]
      • 2 : [3]
        • 1 : [2,3]
          • [1,2,3]
which to use
Which to use?
  • Could have done map with left fold:

map'' :: (a -> b) -> [a] -> [b]

map'' f xs = foldl (\acc x -> acc ++ [f x]) [] xs

  • Note that ++ is slower than :
    • (why would that make sense?)
  • SO, map' will be faster than map''
another example with bool acc
Another example – with Bool acc

elem' :: (Eq a) => a -> [a] -> Bool

elem' y ys = foldr (\x acc -> if x == y then True else acc) False ys

  • Note that accumulator starts with False
  • This code will work with an empty list

Trace with your partner

(we’ll do another one in a minute)

two more folds
Two more folds
  • foldr1 and foldl1
  • Like foldr and foldl, but first (or last) element of the list is the starting value
  • Can’t be called with empty list
  • *Main> foldl1 (+) [2,3,4]
  • 9

maximum' :: (Ord a) => [a] -> a

maximum' = foldl1 max

more fold examples
More fold examples

reverse' :: [a] -> [a]

reverse' = foldl (\acc x -> x : acc) []

  • OR

reverse'' :: [a] -> [a]

reverse'' = foldl (flip (:)) []

  • Quick exercise:
    • Trace reverse'' [1,2,3]
    • Remember: flip f x y = f y x
more fold examples1
More fold examples

filter' :: (a -> Bool) -> [a] -> [a]

filter' p = foldr (\x acc -> if p x then x : acc else acc) []

last' :: [a] -> a

last' = foldl1 (\_ x -> x)

another look at folds
Another look at folds
  • Can view as successive applications of some function to elements in a list
  • Assume right fold, binary function f, starting acc z
  • do foldron [3,4,5,6]
  • this is essentially
    • f 3 (f 4 (f 5 ( f 6 z)))
  • If f is + and starting value is 0, this is:
    • 3 + (4 + (5 + (6 + 0)))
folds and infinite lists
Folds and infinite lists
  • && returns True if all elements are True, False if any element is False
  • So as soon as a False is encountered, the result is False

and' :: [Bool] -> Bool

and' xs = foldr (&&) True xs

  • and [True, False, True]
    • True && (False && (True && True))
using and with infinite list
Using and with infinite list
  • repeat False
    • False && (False && (False && (False ….
  • Haskell is lazy. Only generates items as needed.
  • && returns False if one of its parameters is False.

(&&) :: Bool -> Bool -> Bool

True && x = x

False && _ = False

  • *Main> and' (repeat False)
  • False
  • Foldr works with infinite lists IF binary function doesn’t always evaluate its second parameter (as in &&). Will not work with infinite lists if second parameter is always needed.
play and share higher order functions
Play and Share – higher order functions
  • Write a function divisibleBy such that: divisibleBy 2 4 returns True, divisibleBy 2 5 returns False
  • Try: map (divisibleBy 2) [2,3,4]
  • Write a function divisibleByFive that returns a partially applied divisibleBy function
  • Try: map divisibleByFive [2,4,5]
  • Write isDivisibleByFive that uses a lambda function with map to achieve the same result (e.g., returns [False, False, True] for [2,4,5])

Suggested by a former student:

  • Create a higher-order function named integrate that takes a function, range, and step size and computes approximate numerical integration by evaluating the function at each step.
  • *Main> integrate square 2 4 0.001
  • 18.66066700000209
  • *Main> integrate cube 2 4 0.001
  • 59.97200299999252