skip to content

Currying & Partial Application

Turning an n-argument function into a chain of single-argument ones, and pre-filling arguments to make a specialised function. Interviewers ask for the distinction, which most candidates blur.

on this pageshow

questions

4

What distinguishes currying a three-argument permission check from partially applying its role argument?

level: middleimportance: must knowfreq 66%

answer

  1. one is about shape, one about values
  2. a transformation versus an application
  3. currying names no argument value
  4. n parameters become n one-argument rungs
  5. fix k arguments, one function of n minus k

basics

~20 s

Currying reshapes the check itself into a chain of one-argument functions, one per parameter, and mentions no argument values. Partial application supplies actual values for some parameters and hands back a single function that still needs the rest.

solid answer

~50 s

Currying is a transformation of shape. A check taking `role`, `resource` and `action` becomes a function of `role` that returns a function of `resource` that returns a function of `action`. Nothing is applied; you can curry a check you never call, and every three-parameter function curries the same way. Partial application is about values: you hand the check a role now and get back one function that still needs the resource and the action. Fixing `k` of `n` arguments leaves a single function of `n - k` arguments, in one step, not `k` steps. The two coincide at each rung of a curried function - applying the curried check to the role has the same effect as partially applying the role - which is why candidates blur them, but currying is what made the rungs exist and partial application is what you do with an argument value.

code

pseudocode · 12 lines
pseudocode
function check(role, resource, action)
    // returns allow or deny

// currying: reshape the same check into three one-argument rungs
function curried(role)
    return function(resource)
        return function(action)
            return check(role, resource, action)

// partial application: fix two values now, get one function back
function adminOnDocs(action)
    return check(adminRole, documentResource, action)

go deeper

for a junior

Remember the one-line separation: currying changes a function's shape into one-argument steps, partial application supplies some argument values and gives back a function needing the rest.

for a middle

Be able to count. A three-parameter check curries to three rungs with two intermediate functions; fixing two of three arguments in one partial application leaves one function of one argument.

for a senior

Show where each belongs in a real service: specialise at wiring time where the narrowing values are known, and keep the general check as the single place the decision logic lives.

for a principal

The judgment is whether to publish a general check plus specialisation, or a family of named checkers. The first has one source of truth and more indirection; the second reads better and drifts.

Both operations end with a function that needs fewer arguments than the one you started with, and that shared ending is why most candidates blur them. They are different operations, and the difference is what each one is *about*: one is about the **shape** of a function, the other about **values** you have decided to commit. ## The setting Take a permission check with three parameters - the `role` of the requester, the `resource` being touched, and the `action` being attempted - returning an allow-or-deny decision. It is called on every request, and several parts of the system want a narrower version of it: a checker for one resource type, or a checker for one role. ## Currying: a transformation of shape Currying rewrites that one three-parameter check as a chain: a function of the role that returns a function of the resource that returns a function of the action that finally returns the decision. Three properties follow directly from that description: - It mentions **no argument values**. Currying is something you do to a function, not to a call. You can curry a check you will never invoke. - It is **mechanical**: an `n`-parameter function becomes `n` nested one-parameter functions. A three-parameter check becomes three rungs, with exactly two intermediate functions between the first call and the decision. - It is **reversible**: the opposite transformation, uncurrying, collapses the chain back into one function of three parameters. Languages differ in how much of this they do for you. In some, every function is one-argument by construction and the chain is the only thing that exists; in most, a multi-parameter call is primitive and currying is something a helper or a hand-written wrapper performs. The transformation itself is the same in both. ## Partial application: a commitment of values Partial application starts from a function *and some actual arguments*. Give the check a role and a resource now, and you get back a function that still needs the action. The counting is different from currying: - It is **about values**. You cannot partially apply anything without deciding what to fix. - It is **not one argument at a time**. Fixing two of three arguments yields one function of one argument, in a single step. - It **does not require currying first**. Writing a new function whose body calls the original with the chosen values written in place is a partial application, and it works on a plain multi-parameter check. ## Side by side | | Currying | Partial application | |---|---|---| | What you give it | a function, alone | a function plus some argument values | | Result for an `n`-parameter check | a chain of `n` one-argument functions | one function of `n - k` arguments | | Does it mention values? | no | yes, that is the whole point | | Steps to a decision | `n` successive calls | one call now, the remainder later | | Typical purpose | make every prefix an addressable step | produce a named, specialised checker | ## Why they get blurred Apply a curried check to its first argument and you get a function of the remaining two - which is precisely the effect of partially applying that one argument. So on a curried function the two operations coincide at every rung, and it is natural to conclude they are one thing. The one-sentence separation worth memorising: **currying reshapes a function; partial application feeds one.** A second test: describe the operation without naming any value. If you can, you are describing currying. ## What each one is worth here 1. Currying makes every prefix of the argument list a thing you can name and pass: the checker-for-this-role is a value, not a call you have to remember to repeat. 2. Partial application turns a general check into a specialised one at the point where the specialising values are known - typically once, at wiring time, rather than on every request. 3. Together they let one general check serve many narrow call sites without either duplicating the check or threading the same two arguments through every layer. ## Two things this is not - It is **not** the same as a function that pre-configures itself from a surrounding variable it captured. That mechanism works from the enclosing scope rather than from an argument position, and it is a separate subject. - It is **not** composition. Feeding one function's output into the next is wiring stages end to end; currying and partial application both leave you with a single function that is still waiting for arguments.

  • Is applying a curried check to one argument the same thing as partially applying that argument?
    In effect, yes for that one argument: both leave a function awaiting the rest. The difference is what made it possible. The rung exists because the check was curried; supplying the role is the application. On an uncurried check you can still partially apply, but you write the specialised function yourself.
  • Can you partially apply a function that has not been curried?
    Yes. Fixing values needs no reshaping - you write a new function that takes the remaining arguments and calls the original with the chosen values in place, or use a helper that does the same thing. Currying makes prefixes addressable; it is not a precondition for specialising.
  • How many intermediate functions does currying a three-parameter check create?
    Two. The first call, on the role, returns one; that one, called with the resource, returns the second; calling the second with the action returns the decision. Three calls, two function values in between, and no decision until the third.

Currying is rebuilding a door with one three-part lock into three doors with one lock each. Partial application is walking through the first two doors now and leaving yourself standing at the third, ready to go whenever someone brings the last key.

saying these in an interview costs you the question

  • Says currying and partial application are two names for the same operation.
  • Claims the check runs as soon as its first argument is supplied.
  • Thinks partial application can only fix one argument at a time.
  • Believes a function must be curried before any argument can be fixed.
  • Assumes currying exists only where a language offers syntax for it.
open as a page

A curried permission check over role, resource and action is called with only the role - what comes back?

level: juniorimportance: should knowfreq 46%

basics

~10 s

Another function comes back: one that still expects the resource and, after that, the action. Nothing has been checked yet, and no decision exists until the final argument arrives at the last rung.

open as a page

How should a three-argument permission check order its parameters so the specialised checkers you want are cheap to take?

level: middleimportance: should knowfreq 48%

basics

~20 s

Put the arguments you specialise on - the slow-changing ones such as role and resource - in the leading positions and the per-call argument last, because the usual specialisation helpers and every curried chain consume the parameter list from the left.

open as a page

A caller of a curried permission check omits one argument - why does that bug surface far from the call site?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Because an under-applied curried call is well formed: it returns the next rung instead of failing. That function value then travels - stored, returned, passed on - and the trouble appears wherever something expects a decision and meets a function.

open as a page