Skip to content

Chapter 2 of 8

Functions and Higher-Order Programming

Functional programming treats functions as first-class values: they can be assigned to variables, passed as arguments, returned from other functions, and stored in data structures. A function that takes one or more functions as arguments, or that returns a function as its result, is called a higher-order function. The familiar array methods \( \text{map} \), \( \text{filter} \), and \( \text{reduce} \) are all higher-order functions, and they form the backbone of functional data processing. Closures and lexical scoping are intimately connected with this style: a closure is a function that captures and remembers variables from its enclosing lexical scope, even after that scope has finished executing, and lexical scoping means a variable's scope is determined by its position in the source code rather than by the runtime call stack.

Currying and partial application are two related techniques for working with multi-argument functions. Currying transforms a function of \( n \) arguments into a sequence of \( n \) single-argument functions, so that \( \text{add}(a, b) \) becomes \( a \mapsto b \mapsto a + b \); in Haskell every function is automatically curried. Partial application, by contrast, fixes some arguments of a function to produce a new function with fewer parameters, and it can fix multiple arguments at once. Currying enables partial application, but the two are distinct: currying is a structural transformation of a function's shape, while partial application is about pre-filling specific values.

Closely related are function composition, which combines functions so the output of one becomes the input of the next, and piping, which provides a more readable left-to-right data flow. Elixir and F# use the pipe operator \( \rvert \), while Haskell composes functions right-to-left with the dot operator. Together with point-free style — defining functions without explicitly naming their arguments, so that \( s \mapsto s.\text{toUpperCase}() \) becomes \( \text{map}(\text{prop}('\text{name}')) \) — these techniques let programmers build expressive transformation pipelines out of small, reusable pieces. Eta reduction is the corresponding simplification that removes redundant parameter passing when a function merely forwards its argument to another function, while eta expansion is its inverse, wrapping a function to make its type explicit.

All chapters
  1. 1Foundations of Functional Programming
  2. 2Functions and Higher-Order Programming
  3. 3Data Structures and Types
  4. 4Recursion, Folds, and Evaluation
  5. 5Functors, Applicatives, and Monads
  6. 6Type System Concepts
  7. 7Lambda Calculus and Category Theory
  8. 8Real-World Functional Programming and Concurrency

Drill it

Reading is not remembering. These come from the Functional Programming deck:

Q

What is functional programming?

Functional programming is a declarative programming paradigm that treats computation as the evaluation of mathematical functions. It emphasizes immutability, pu...

Q

What is a pure function?

A pure function is a function that: Always returns the same output for the same input (deterministic)Has no side effects — it doesn't modify external state, per...

Q

What are side effects in functional programming?

Side effects are any observable changes a function makes beyond returning a value. Examples include: Modifying a global or external variableWriting to a file or...

Q

What is immutability?

Immutability means that once a data structure is created, it cannot be changed. Instead of modifying data, you create new copies with the desired changes. Benef...