You A Haskell Chapter 6
Haskell functions can take functions as parameters and return functions as values. A function that does so is called a higher order function.
Functions in haskell only take one parameter – any functions that take more are actually curried functions.
For example, taking the max of two numbers:
max 4 5
is just like this:
max 4) 5 (
remember the type of max is this:
max :: Ord a => a -> a -> a
For this example:
multThree :: (Num a) => a -> a -> a -> a
= x * y * z multThree x y z
we can compose this function with some other ones like so:
> let multTwoWithNine = multThree 9
ghci> multTwoWithNine 2 3
ghci54
> let multWithEighteen = multTwoWithNine 2
ghci> multWithEighteen 10
ghci180
We can compare any number with 100 like so:
compareWithHundred :: (Num a, Ord a) => a -> Ordering
= compare 100 x compareWithHundred x
Infix functions can be partially applied using sections.
divideByTen :: (Floating a) => a -> a
= (/10) divideByTen
What about a function that checks if a character supplied to it is uppercase?
isUpperAlphanum :: Char -> Bool
= (`elem` ['A'..'Z']) isUpperAlpanum
Let’s create a function that applies a function twice
applyTwice :: (a -> a) -> a -> a
= f (f x) applyTwice f x
and let’s use it
> applyTwice (+3) 10
ghci16
> applyTwice (++ "HEY"
ghci"HEY HAHA HAHA"
> applyTwice ("HAHA " ++) "HEY"
ghci"HAHA HAHA HEY"
> applyTwice (multThree 2 2) 9
ghci144
> applyTwice (3:) [1]
ghci3,3,1] [
Let’s make zipWith, which takes a function and two lists. it applies the function to both of the lists and returns a new list.
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
= []
zipWith' _ [] _ = []
zipWith' _ _ [] :xs) (y:ys) = f x y : zipWith' f xs ys zipWith' f (x
> zipWith' (+) [4,2,5,6] [2,6,2,3]
ghci6,8,7,9]
[> zipWith' max [6,3,2,1] [7,3,1,5]
ghci7,3,2,5]
[> zipWith' (++) ["foo ", "bar ", "baz "] ["fighters", "hoppers", "aldrin"]
ghci"foo fighters","bar hoppers","baz aldrin"]
[> zipWith' (*) (replicate 5 2) [1..]
ghci2,4,6,8,10]
[> zipWith' (zipWith' (*)) [1,2,3],[3,5,6],[2,3,4]] [3,2,2],[3,4,5],[5,4,3]]
ghci3,4,6],[9,20,30],[10,12,12]] [
we can also implement flip
, which takes a function and
returns a function that is like the function provided, just with the two
arguments flipped.
flip' :: (a -> b -> c) -> (b -> a -> c)
= g
flip' f where g x y = f y x
We can simplify this by noticing that functions are curried:
flip' :: (a -> b -> c) -> b -> a -> c
= f x y flip' f y x
> flip' zip [1,2,3,4,5] "hello"
ghci'h',1),('e',2),('l',3),('l',4),('o',5)]
[(> zipWith (flip' div) [2,2..] [10,8,6,4,2]
ghci5,4,3,2,1] [
map
takes a function and a list and applies that
function to every element in the list.
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
> map (+3) [1,5,3,1,6]
ghci4,8,6,4,9]
[> map (++ ["BIFF", "BANG", "POW"]
ghci"BIFF!","BANG!","POW!"]
[> map (replicate 3) [3..6]
ghci3,3,3],[4,4,4],[5,5,5],[6,6,6]]
[> map (map (^2)) [1,2],[3,4,5,6],[7,8]]
ghci1,4],[9,16,25,36],[49,64]]
[> map fst [(1,2),(3,5),(6,3),(2,6),(2,5)]
ghci1,3,6,2,2] [
filter
takes a predicate function and if the function
evaluates to true, keeps that element.
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:xs)
| p x = x : filter p xs
| _ = filter p xs
> filter (>3) [1,5,3,2,1,6,4,3,2,1]
ghci5,6,4]
[> filter (==3) [1,2,3,4,5]
ghci3]
[> filter even [1..10]
ghci2,4,6,8,10]
[> let notNull x = not (null x) in filter notNull [1,2,3],[],[3,4,5],[2,2],[],[],[]]
ghci1,2,3],[3,4,5],[2,2]]
[> filter (`elem` ['a'..'z']) "u LaUgH aT mE BeCaUsE I aM diFfeRent"
ghci"uagameasadifeent"
> filter (`elem` ['A'..'Z']) "i lauGh At You BecAuse u r aLL the Same"
ghci"GAYBALLS"
Here’s the previous chapter’s quicksort with Filters
quicksort :: (Ord a) => [a] -> a
= []
quicksort [] :xs) =
quicksort (xlet smaller = quicksort (filter (<= x) xs)
= quicksort (filter (>x) xs)
larger in smaller ++ [x] ++ larger
Finding the largest number under 100,000 that’s divisible by 3829.
largestDivisible :: (Integral a) => a
= head (filter p [100000,99999..])
largestDivisible where p x = x `mod` 3829 == 0
find the sum of all odd squares that are smaller than 10,000.
> sum (takeWhile (<10000) (filter odd (map (^2) [1..])))
ghci166650
Lambdas are expressions that can take any number of arguments and be passed to any function. When applied, they return a value.
This map sums up the pairs here and returns a list:
map ((a,b) -> a + b) [(1,2),(3,5),(6,3),(2,6),(2,5)]
Let’s implement sum using a fold:
sum' :: (Num a) => [a] -> a
= foldl (acc x -> acc + x) 0 xs sum' xs
> sum' [3,5,2,1]
ghci11
If we apply the addition function to all arguments however, we can do this more succinctly:
sum' :: (Num a) => [a] -> a
= foldl (+) 0 sum'
foldr
works the same way, except it approaches from the
right hand side:
map' :: (a -> b) -> [a] -> [b]
= foldr (x acc -> f x : acc) [] xs map' f xs
One caveat why foldr
exists is that it works on infinite
lists, but foldl
will never terminate.
foldl1
uses the first element as the accumulator:
foldr1
uses the last element as the accumulator:
sum' :: (Num a) => [a] -> a
= foldl1 (+) sum'
Here are some library functions using folds
maximum' :: (Ord a) => [a] -> a
= foldr1 (x acc -> if x > acc then x else acc)
maximum'
reverse' :: [a] -> [a]
= foldl (acc x -> x : acc) []
reverse'
product' :: (Num a) => [a] -> a
= foldr1 (*)
product'
filter' :: (a -> Bool) -> [a] -> [a]
= foldr (x acc -> if p x then x : acc else acc) []
filter' p
head' :: [a] -> a
= foldr1 (x _ -> x)
head'
last' :: [a] -> a
= foldl1 (_ x -> x) last'
scanl
and scanr
are similar to
foldl
and foldr
, but they report their
intermediate states:
> scanl (+) 0 [3,5,2,1]
ghci0,3,8,10,11]
[> scanr (+) 0 [3,5,2,1]
ghci11,8,3,1,0]
[> scanl1 (acc x -> if x > acc then x else acc) [3,4,5,3,7,9,2,1]
ghci3,4,5,5,7,9,9,9]
[> scanl (flip (:)) [] [3,2,1]
ghci3],[2,3],[1,2,3]] [],[
Function application can be done with $
, which evaluates
the right hand side of the equation before the left.
Instead of sqrt (3 + 4 + 9)
we can write
sqrt $ 3 + 4 + 9
.
Function composition can be done with the .
operator:
Instead of:
> map (x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]
ghci-5,-3,-6,-7,-3,-2,-19,-24] [
We can do this:
> map (negate . abs) [5,-3,-6,7,-3,2,-19,24]
ghci-5,-3,-6,-7,-3,-2,-19,-24] [
Prev: learn-you-a-haskell-chapter-5 Next: learn-you-a-haskell-chapter-7