What Are Higher-Order Functions?

A higher-order function is a function that takes one or more functions as arguments, or returns a function as its result (or both). This is possible because in functional languages, functions are first-class values — they can be passed around just like numbers or strings.

Three higher-order functions appear everywhere in functional code: map, filter, and reduce. Learning them well eliminates the need for most loops and dramatically clarifies intent.

map: Transform Every Element

map applies a function to every element of a collection and returns a new collection of the results. The original collection is not modified.

In Clojure:

(map inc [1 2 3 4 5])
;; => (2 3 4 5 6)

(map #(* % %) [1 2 3 4 5])
;; => (1 4 9 16 25)

In Haskell:

map (+1) [1,2,3,4,5]
-- [2,3,4,5,6]

map (^2) [1,2,3,4,5]
-- [1,4,9,16,25]

Think of map as answering: "What does each element become?"

filter: Keep What You Want

filter takes a predicate function (one that returns true or false) and returns only the elements for which the predicate returns true.

In Clojure:

(filter even? [1 2 3 4 5 6])
;; => (2 4 6)

(filter #(> % 3) [1 2 3 4 5])
;; => (4 5)

In Haskell:

filter even [1,2,3,4,5,6]
-- [2,4,6]

filter (> 3) [1,2,3,4,5]
-- [4,5]

Think of filter as answering: "Which elements satisfy this condition?"

reduce: Collapse a Collection to a Value

reduce (also called fold in Haskell) takes a combining function, an initial value (accumulator), and a collection — and repeatedly applies the function to accumulate a single result.

In Clojure:

(reduce + 0 [1 2 3 4 5])
;; => 15

(reduce (fn [acc x] (conj acc (* x x))) [] [1 2 3])
;; => [1 4 9]

In Haskell:

foldl (+) 0 [1,2,3,4,5]
-- 15

foldl (\acc x -> acc ++ [x^2]) [] [1,2,3]
-- [1,4,9]

Think of reduce as answering: "How do all these elements combine into one result?"

Chaining Them Together

The real power emerges when you chain these functions. In Clojure, the threading macro ->> makes pipelines readable:

(->> (range 1 11)          ; (1 2 3 4 5 6 7 8 9 10)
     (filter odd?)         ; (1 3 5 7 9)
     (map #(* % %))        ; (1 9 25 49 81)
     (reduce +))           ; => 165

This reads naturally from top to bottom: generate a range, keep the odd numbers, square them, then sum the results. Compare this to an equivalent imperative loop — the functional version expresses intent far more clearly.

When to Use Each

FunctionUse When You Want To…
mapTransform every element; output same size as input
filterSelect a subset; output is same type, smaller or equal size
reduceAggregate, summarize, or restructure a collection into one value

Once map, filter, and reduce become second nature, you'll find yourself writing less boilerplate, making fewer bugs, and expressing complex data transformations in just a few elegant lines.