-- Partial application is awesome, since haskell functions are curried: compareWithHundred :: (Num a, Ord a) => a -> Ordering compareWithHundred x = compare 100 x -- this is equivalent to: compareWithHundred :: (Num a, Ord a) => a -> Ordering compareWithHundred = compare 100 -- Infix functions can also be partially-applied: divideByTen :: (Floating a) => a -> a divideByTen = (/10) -- (/10) 200 == 200 / 10 isUpperAlphanum :: Char -> Bool isUpperAlphanum = (`elem` ['A'..'Z']) -- Functions can take functions as params: applyTwice :: (a -> a) -> a -> a applyTwice f x = f (f x) -- Example implementation of zipWith: zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] zipWith _ [] _ = [] zipWith _ _ [] = [] zipWith f (x:xs) (y:ys) = (f x y):(zipWith f xs ys) flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x -- map built-in: map (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = (f x):(map f xs) -- filter built-in: filter (a -> Bool) -> [a] -> [a] filter _ [] = [] filter f (x:xs) | f x = x:(filter xs) | otherwise = filter xs -- Largest # under 100000 divisible by 3829: -- (this stops after finding the first matching value, because of lazy evaluation) largestDivisible :: (Integral a) => a largestDivisible = head (filter p [100000,99999,..]) where p x = x `mod` 3829 == 0 takeWhile :: (a -> Bool) -> [a] -> [a] takeWhile _ [] = [] takeWhile p (x:xs) | p x = x:(takeWhile p xs) | otherwise = [] -- Collatz sequence builder chain :: (Integral a) => a -> [a] chain 1 = [1] chain n | even n = n:(chain (n `div` 2)) | odd n = n:(chain (n*3 + 1)) numLongChains :: Int numLongChains = length (filter isLong (map chain [1..100])) where isLong xs = length xs > 15 -- Instead, with lambdas! numLongChains :: Int numLongChains = length (filter (\xs -> length xs > 15) (map chain [1..100])) -- You can pattern-match in lambdas, but only on one case. If a value doesn't match the pattern, -- you get a runtime error. So, make sure your pattern is exhaustive. -- Folds - foldl - left fold sum :: (Num a) => [a] -> a sum xs = foldl (\acc x -> acc + x) 0 xs -- Or, more succinctly with currying: sum xs = foldl (+) 0 xs -- Generally, because of currying, a function `foo a = bar b a` can be written as `foo = bar b` -- Another fold example: elem :: (Eq a) => a -> [a] -> Bool elem y ys = foldl (\acc x -> if x == y then True else acc) False ys -- Right folds `foldr` work similarly, but from the right side, and the acc x are reversed. e.g. map :: (a -> b) -> [a] -> [b] map f xs = foldr (\x acc -> (f x):acc) [] xs -- We could have done this with `foldl` and `++`, but cons is much cheaper than `++`, so we generally -- use `foldr` when building lists from lists. -- `foldl1` and `foldr1` work the same as `foldl` and `foldr`, but they use the starting element in -- the list as the initial accumulator (the left-most or right-most, respectively) -- `scanl` and `scanr` are like their fold* counterparts, but return an array of all the states of the accumulator: scanl1Test = scanl1 (\acc x -> if x > acc then x else acc) [3,4,5,3] -- == [3,4,5,5] -- These have a `scanl1` and `scanr1` equivalent. The final result of `scanl*` is the last element, and the head -- element for `scanr1` -- Function application -- Take: ($) :: (a -> b) -> a -> b f $ x = f x -- Right-associative function application! sum (map sqrt (1 + 2 + 3)) == sum $ map $ sqrt $ 1 + 2 + 3 -- This also means we can use function application... as a function: mapTest1 = map ($ 3) [(4+), (^2)] -- == [4 + 3, 3 ^ 2] -- Also, function composition: (.) :: (b -> c) -> (a -> b) -> a -> c f . g = \x -> f (g x) -- This means more concise code! TFAE mapTest2 = map (\x -> negate $ abs x) [1..3] mapTest3 = map (negate . abs) [1..3] -- If we want to compose functions with multiple parameters, we need to partially apply them first.