Browse Clojure Foundations for Java Developers

Returning Functions from Functions in Clojure

Learn what it means for a Clojure function to return another function, how closures work, and when this pattern is simpler than Java-style factories or strategy objects.

If passing a function as an argument lets you choose behavior at the call site, returning a function lets you configure behavior once and reuse it later.

That is the core idea behind this section.

In Java terms, this often replaces small factory classes, strategy objects, or configuration-heavy builders. In Clojure, it is often just a function that returns a function.

Closure: A function value that retains access to bindings from the scope where it was created.

The Core Shape

Here is the smallest useful example:

1(defn multiplier [factor]
2  (fn [x]
3    (* factor x)))
4
5(def double-it (multiplier 2))
6(def triple-it (multiplier 3))
7
8(double-it 10)
9;; => 20

The returned function “remembers” factor because it closes over that binding.

That is the important concept:

  • the outer function chooses configuration
  • the inner function does the later work
  • the closure keeps the needed values available without a mutable object

Why This Matters To A Java Developer

The closest Java comparison is returning a lambda that captures local variables.

That comparison is useful, but Clojure makes the pattern much more central to ordinary design.

Java tendency Clojure tendency
Create a small class or strategy object to hold configurable behavior Return a function that closes over the configuration
Treat captured behavior as a special pattern Treat it as ordinary function construction
Reach for interfaces early Reach for plain functions first when polymorphism is not the real problem

This does not mean records, protocols, and Java classes disappear. It means you should not reach for a heavier abstraction when a closure already models the problem cleanly.

Two Common Ways To Return Functions

1. Write The Inner Function Explicitly

This is best when the returned behavior has real logic:

1(defn order-validator [minimum-total]
2  (fn [order]
3    (and (= :draft (:order/status order))
4         (>= (:order/total order) minimum-total))))

Now you can build specialized validators:

1(def premium-order? (order-validator 1000M))
2(def standard-order? (order-validator 100M))

2. Use partial When The Shape Is Simple

Sometimes you are only fixing one or more arguments of an existing function.

1(def premium-discount
2  (partial * 0.90M))
3
4(premium-discount 200M)
5;; => 180.00M

partial is ideal when the returned function is just “this function, with some arguments already supplied.”

But it is not always the clearest choice. If the callback needs explanation or domain meaning, a named fn or defn is often easier to read.

A Design Rule That Helps

Use a returned function when:

  • some configuration is chosen now
  • the actual data arrives later
  • the behavior will be reused more than once

That shape appears constantly in real programs:

Choose now Apply later
threshold validation function
discount policy pricing function
environment config adapter function
field selection projection function

If the code has that shape, returning a function is usually a good fit.

Closures Are About Values, Not Magic State

Closures often feel mysterious until you remember what is really happening:

the returned function simply retains access to bindings from the outer call.

1(defn make-greeter [prefix]
2  (fn [name]
3    (str prefix ", " name)))
4
5(def greet-customer (make-greeter "Welcome"))
6(greet-customer "Ava")
7;; => "Welcome, Ava"

No global variable is involved. No object field had to be introduced. The function keeps access to prefix because it was created in that scope.

A Useful REPL Nuance About partial

One subtle point matters during interactive development:

partial captures the function value it receives, not future redefinitions of the var at the REPL.

That means code like this can surprise you while experimenting:

1(defn score [x] (* 2 x))
2(def score-twice (partial score))

If you later redefine score at the REPL, score-twice still holds the old function value. The official Clojure FAQ calls this out directly.

In normal running applications, this is usually irrelevant. In active REPL work, it means:

  • partial is still correct
  • but if you expect live redefinition behavior, an explicit wrapper can be clearer

When Returning A Function Is Better Than Returning Data

Do not force this pattern everywhere.

Return a function when the result is genuinely reusable behavior.

Return data when the result is just configuration.

Better to return a function Better to return data
A validator specialized by a threshold A map of threshold values
A formatter specialized by rendering options A map of rendering options
A scoring function specialized by weighting rules A weights configuration map

If callers still need to interpret the result before doing anything useful, returning data may be the clearer design.

Knowledge Check

### In the `multiplier` example, what does the returned function retain access to? - [x] The `factor` binding from the outer function call - [ ] A hidden mutable global variable - [ ] Only the argument passed to the inner function - [ ] A Java interface implementation generated at runtime > **Explanation:** The inner function is a closure. It retains access to the outer binding `factor`, which is why `double-it` and `triple-it` can behave differently. ### When is `partial` usually a good fit? - [x] When the new function is just an existing function with some arguments fixed in advance - [ ] When the code needs to mutate shared state - [ ] When you want to replace all named functions with anonymous ones - [ ] When you need a protocol implementation > **Explanation:** `partial` is best for simple function specialization. If the returned behavior needs more explanation or branching logic, an explicit function is often clearer. ### Which situation most strongly suggests returning a function? - [x] Configuration is chosen now, but the behavior will be applied repeatedly to later data - [ ] The result is a static settings map with no behavior attached - [ ] You only need one immediate calculation and no reuse - [ ] You need a mutable field shared by many objects > **Explanation:** Returning a function is a good fit when you are constructing reusable behavior from earlier configuration. ### What is the REPL-specific caveat about `partial`? - [x] It captures the function value it received, not later redefinitions of that var - [ ] It cannot be used with named functions - [ ] It only works for one-argument functions - [ ] It forces eager evaluation of all later inputs > **Explanation:** In ordinary app code this is usually fine, but in interactive REPL work it matters because redefining the original var does not change previously created partial functions.
Revised on Friday, April 24, 2026