Functional Programming Vocabulary: 25 FP Terms for Developers

Pure function, immutability, higher-order functions, monads, currying, and functional programming vocabulary.

Functional programming has moved from academic curiosity to mainstream practice. Whether you are working in TypeScript, Scala, Haskell, or even writing React hooks, you will encounter FP concepts daily. The challenge for many developers — especially those working in international teams — is that functional programming has its own dense vocabulary. Misunderstanding a single term like “monad” or “referential transparency” can make a code review feel like a foreign language exam. This guide covers 15 essential FP terms with plain-English definitions and real conversation examples so you can participate confidently in technical discussions.


Core Terms: The Foundation of Functional Thinking

These terms appear in almost every FP discussion. If you learn nothing else, learn these.

Pure function — a function that always returns the same output for the same input and causes no observable changes outside itself. No network calls, no file writes, no mutations.

“We need to refactor this service layer. Most of these functions aren’t pure — they’re reading from a global config object, which makes them impossible to test in isolation.”

“I rewrote the price calculation as a pure function. Now the unit tests run in milliseconds and we don’t need to mock anything.”

Side effect — any observable interaction a function has with the outside world: writing to a database, logging to the console, modifying a variable outside its scope, or making an HTTP request.

“The bug was caused by a side effect in the mapper — it was silently mutating the input array instead of returning a new one.”

“In our FP layer we try to push all side effects to the edges of the application. The core business logic stays pure.”

Immutability — the principle that once a data structure is created, it cannot be changed. Instead of modifying an object, you create a new one with the updated values.

“We switched to immutable data structures for our Redux store. Debugging became so much easier — we could replay every state transition.”

“TypeScript’s readonly modifier enforces immutability at compile time, which is a good start, but it doesn’t deep-freeze nested objects.”

Referential transparency — an expression is referentially transparent if it can be replaced by its evaluated result without changing the programme’s behaviour. A pure function call is referentially transparent; a function that reads the current time is not.

“If a function is referentially transparent, you can memoise it safely. The result is always the same for the same arguments.”

“That function isn’t referentially transparent — it depends on Date.now(), so calling it twice with the same input produces different outputs.”


Functions as First-Class Citizens

One of the key ideas in functional programming is treating functions the same way you treat data — passing them around, storing them, returning them.

First-class function — a function that can be assigned to a variable, passed as an argument, or returned from another function, just like any other value.

“JavaScript has first-class functions, which is why callbacks and higher-order functions feel natural in the language.”

Higher-order function — a function that either takes one or more functions as arguments, returns a function, or both.

“Our withRetry utility is a higher-order function. You pass it any async function and it wraps it with retry logic.”

“Once you get comfortable with higher-order functions, patterns like middleware and decorators start to feel obvious.”

map / filter / reduce — three foundational higher-order functions. map transforms each element of a collection, filter selects elements matching a predicate, and reduce (also called fold) collapses a collection into a single accumulated value.

“Replace that for loop with a map and a filter — it will be half the lines and far more readable.”

“I used reduce to build the lookup object from the array. One pass, no side effects.”

Currying — transforming a function that takes multiple arguments into a sequence of functions each taking a single argument. Named after mathematician Haskell Curry.

“The add function is curried, so add(2) returns a new function waiting for the second argument. You can partially specialise it.”

“Currying is the mechanism; partial application is the use case. They’re related but not the same thing.”

Partial application — fixing a number of arguments to a function, producing a new function with a smaller arity. Unlike currying, it does not require reducing to single-argument functions.

“We use partial from Ramda to bake the base URL into our API helper. Every route function then only needs the path.”

“Partial application is great for configuration. You set the invariant parameters once and reuse the specialised function everywhere.”


Combining and Abstracting: Composition and Patterns

Function composition — combining two or more functions so that the output of one becomes the input of the next. Written mathematically as f ∘ g, meaning “apply g first, then f”.

“Instead of nesting function calls five levels deep, use compose or pipe to read the transformation as a linear pipeline.”

“Function composition is the FP answer to inheritance. Build complex behaviour from small, reusable pieces.”

Point-free style — writing function definitions without explicitly mentioning the arguments (the “points”). The function is defined purely in terms of composition and higher-order functions.

“That lambda can be written point-free: instead of x => toUpperCase(x) just pass toUpperCase directly.”

“Point-free style is elegant but can hurt readability if overused. Make sure the team is comfortable with it before going all-in.”

Tail recursion — a form of recursion where the recursive call is the very last operation in the function. A tail-recursive function can be optimised by the runtime into a loop, avoiding stack overflow for large inputs.

“The naive recursive version blows the stack on large lists. Rewrite it as tail recursion and the optimiser will turn it into iteration.”

“JavaScript doesn’t reliably optimise tail calls in most engines, so in practice we use trampolining or just iterate.”

Lazy evaluation — deferring the computation of a value until it is actually needed. Contrast with eager (strict) evaluation, which computes values immediately.

“With lazy evaluation, we can represent infinite sequences. We only compute as many elements as the consumer actually requests.”

“RxJS Observables are lazy by default — nothing runs until you subscribe. That’s a crucial difference from Promises.”


Abstract Structures: Functors and Monads

These terms come from category theory and intimidate many developers. The concepts are actually simpler than the names suggest.

Functor — any structure that can be mapped over. In practice, a functor is a container that implements a map method obeying two laws: identity and composition. Arrays in JavaScript are functors.

“An array is the simplest functor. map applies a function to each value while preserving the container structure.”

“We wrote a Result type that’s a functor. You can map over it safely — if it holds an error, map is a no-op.”

Monad — a functor with two additional operations: of (wrapping a value) and flatMap/chain (mapping with a function that itself returns a wrapped value, then flattening). Monads let you sequence computations that involve context — nullability, errors, asynchrony.

The three most practically useful monads for web developers are:

  • Maybe (Option) — represents a value that might be absent. Eliminates null checks by making the absence of a value explicit in the type.

“We wrapped our nullable DB results in a Maybe. Now the whole pipeline is null-safe without a single if check.”

  • Either — represents a computation that can succeed (Right) or fail (Left). Allows error handling without exceptions.

“Instead of throwing, the validation returns an Either. The caller can fold over it to handle both branches.”

  • IO — wraps a side-effecting computation, deferring it and making it explicit in the type signature that a function talks to the outside world.

“The IO monad makes side effects first-class values. You can compose IO actions without actually running them.”


How to Use These in Conversation

Code review: “This function is not pure — it mutates the user object passed in. Can we return a new object instead and keep our data immutable throughout the pipeline?”

Architecture discussion: “The issue is that side effects are scattered everywhere. If we push them to the boundary and keep the domain logic referentially transparent, we can test every business rule without mocking infrastructure.”

Onboarding a teammate: “Think of a monad as a box with a contract. The Maybe box says: ‘I might be empty, but you can still map over me safely.’ You never have to check for null — the box handles it.”

Pull request comment: “Nice use of currying here. One suggestion: the composed pipeline on line 47 reads right-to-left because you used compose. Consider pipe instead so it reads in the order the data flows through it.”


Quick Reference

TermOne-line definition
Pure functionSame input → same output, no side effects
Side effectAny interaction with the outside world
ImmutabilityData cannot be changed after creation
Referential transparencyExpression can be replaced by its value safely
Higher-order functionTakes or returns a function
CurryingMulti-argument function → chain of single-argument functions
Partial applicationPre-fill some arguments, return a specialised function
Function compositionChain functions so output of one feeds input of the next
FunctorContainer that supports map
MonadFunctor that supports flatMap for sequencing contextual computations