Prompt
Two functional-programming staples:
curry(fn)— collects arguments across calls (f(1)(2),f(1, 2),f(1)(2, 3)all work) and invokesfnonce it hasfn.lengthof themcompose(...fns)— right-to-left composition:compose(f, g)(x) === f(g(x))
Solution
These two are asked together because they're the same idea from both ends: treating functions as data. Curry specializes a function by fixing arguments; compose builds a pipeline out of small functions. Every middleware chain you've used — Redux, Express — is compose wearing a costume.
The parts worth narrating:
fn.lengthis the arity — the number of declared parameters — and it's the termination condition. Senior caveat to say out loud: default parameters and rest args don't count toward.length, socurry((a, b = 1) => ...)has length 1 and fires early. Curry works on honest signatures.- Accumulate, never mutate:
[...args, ...more]builds a fresh array per partial call, soconst add2 = add(2)can be reused safely — a mutated shared array would make two partials contaminate each other. reduceRightis right-to-left because composition reads like math:compose(f, g)(x)is f(g(x)). If the interviewer asks forpipe, it's the same body withreduce— say that instead of writing it twice.
The Redux connection that lands: applyMiddleware literally composes middlewares, and each middleware's store => next => action => ... signature is a curried function — you're writing this pattern every time you write a middleware, whether you name it or not.
Say it: "Curry accumulates arguments until fn.length is satisfied; compose is reduceRight over the functions — and Redux middleware is exactly these two patterns combined."