Higher-Order Functions in Haskell
Higher-order functions are functions that take other functions as arguments or return functions as results. They are a fundamental concept in functional programming and enable powerful abstractions.
Functions as Arguments
Passing functions as arguments allows for flexible behavior:
-- Apply a function to a value twice
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
-- Example usage
square x = x * x
increment x = x + 1
-- applyTwice square 2 → 16
-- applyTwice increment 5 → 7
Common Higher-Order Functions
Haskell's standard library includes many useful higher-order functions:
-- Map applies a function to each element
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
-- Filter keeps elements that satisfy a predicate
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:xs)
| p x = x : filter p xs
| otherwise = filter p xs
-- Fold (reduce) a list
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ acc [] = acc
foldr f acc (x:xs) = f x (foldr f acc xs)
Function Composition
The (.) operator composes functions:
-- Function composition operator
(.) :: (b -> c) -> (a -> b) -> a -> c
(f . g) x = f (g x)
-- Example usage
squareAndIncrement :: Int -> Int
squareAndIncrement = (+1) . (^2)
-- Multiple compositions
processString :: String -> String
processString = reverse . map toUpper . filter (/= ' ')
Partial Application
Functions can be partially applied to create new functions:
-- Partial application
add :: Int -> Int -> Int
add x y = x + y
addFive :: Int -> Int
addFive = add 5
-- Using partial application with map
incrementAll :: [Int] -> [Int]
incrementAll = map (+1)
-- Partial application with infix operators
multiplyBy :: Int -> Int -> Int
multiplyBy = (*)
doubleAll :: [Int] -> [Int]
doubleAll = map (multiplyBy 2)
Lambda Functions
Anonymous functions can be created with lambda syntax:
-- Lambda function examples
squareAll :: [Int] -> [Int]
squareAll = map (\x -> x * x)
filterEvens :: [Int] -> [Int]
filterEvens = filter (\x -> x `mod` 2 == 0)
-- Using lambda with fold
sumSquares :: [Int] -> Int
sumSquares = foldr (\x acc -> x * x + acc) 0
Function Currying
All Haskell functions are curried by default:
-- Curried function
multiply :: Int -> Int -> Int
multiply x y = x * y
-- Equivalent to:
multiply' :: Int -> (Int -> Int)
multiply' x = \y -> x * y
-- Can be partially applied
double :: Int -> Int
double = multiply 2
-- Calling with all arguments
result = multiply 3 4 -- 12
Flip and Other Combinators
Useful higher-order functions for function manipulation:
-- Flip argument order
flip :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x
-- Example usage
subtract' = flip (-)
-- subtract' 5 3 → 2 (same as 3 - 5)
-- Const function
const :: a -> b -> a
const x _ = x
-- Identity function
id :: a -> a
id x = x
Point-free Style
Point-free style omits variable names where possible:
-- With explicit variables
sumSquares xs = sum (map (^2) xs)
-- Point-free version
sumSquares = sum . map (^2)
-- Another example
countWords = length . words
Folding Lists
Folds are powerful higher-order functions for reducing lists:
-- Left fold (tail-recursive)
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl _ acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs
-- Right fold
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ acc [] = acc
foldr f acc (x:xs) = f x (foldr f acc xs)
-- Examples
sumList = foldr (+) 0
productList = foldl (*) 1
concatStrings = foldr (++) ""
← Previous: Pattern Matching |
Next: Monads & IO →