A curried permission check over role, resource and action is called with only the role - what comes back?
answer
- each rung hands back another function
- no decision until the last argument
- three arguments, three successive calls
- two intermediate function values exist
- the rung is a value you can name and reuse
basics
~10 sAnother 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.
solid answer
~40 sYou get a function, not a decision. A curried three-parameter check is a chain of three one-argument rungs, so supplying the role climbs one rung and hands back the next function, which awaits the resource; that one hands back a third, which awaits the action; only the third call produces allow or deny. The intermediate value is an ordinary value - you can name it, store it, pass it to another function and reuse it for many later calls. Nothing about the permission has been evaluated: no policy has been read and no decision made, because the check has not yet seen what action is being attempted. Calling with too few arguments is therefore not an error in a curried chain; it is the normal way to use one.
code
pseudocode · 8 lines// curried check: role, then resource, then action
forEditor = curried(editorRole) // a function; nothing checked yet
onPosts = forEditor(postResource) // still a function
decision = onPosts(deleteAction) // now the check finally runs
// the middle rung is an ordinary value, reusable
onComments = forEditor(commentResource)
other = onComments(deleteAction)go deeper
Recall the shape of the answer: a curried call that has not received every argument returns a function, and the result appears only when the last argument arrives.
Explain the counting - three arguments, three calls, two intermediate functions - and why no decision can exist before the check knows the resource and the action.
Point out the operational value: the early rungs do no work, so they can be built once at wiring time and handed to modules that only ever ask the narrower question.
Weigh readability. A chain of anonymous rungs passed between modules hides which arguments are already fixed; insist that each retained rung carries a name saying so.
The question is really about *when* work happens in a chain of one-argument functions, and the answer surprises people who expect a call to produce a result. ## The chain, rung by rung A permission check needs three things: the `role` of the requester, the `resource` being touched, and the `action` being attempted. Curried, it is no longer one function of three parameters but three functions of one parameter each, nested. Each call consumes exactly one argument and hands back the next function: 1. Call with the role. You hold a function that expects a resource. No policy has been consulted. 2. Call that with the resource. You hold a function that expects an action. Still nothing decided. 3. Call that with the action. Now every parameter has a value, the original check body can run, and you get allow or deny. | After supplying | What you hold | What it still needs | |---|---|---| | nothing | the curried check | role, resource, action | | the role | a one-argument function | resource, action | | role and resource | a one-argument function | action | | all three | the decision | nothing | There are exactly two intermediate function values between the first call and the decision, and three calls in total. ## Nothing is checked until the last rung This is the part worth being precise about. A permission decision cannot be made from a role alone: the check has no idea what is being touched or what is being done to it. So the first rung cannot be doing the work, even partially. What the rung carries forward is only the argument already supplied, waiting for the rest to arrive. A useful consequence: nothing observable happens on the early rungs, so building them is cheap and safe to do ahead of time - at start-up, once per resource type, or wherever the narrowing values become known. ## The intermediate rung is an ordinary value The function you get back after supplying the role is a value like any other: - You can give it a name that says what it is, such as a checker for one role. - You can store it in a table, pass it into another function, or return it from one. - You can call it many times with different resources, and each of those calls starts again from the same rung - one use does not consume or alter it. - You can hand it around without the receiver needing to know what was already supplied. That last point cuts both ways, and it is why the naming matters: a bare function value does not announce which arguments are already baked in. ## Where this trips people up - **Expecting an error.** In a plain multi-parameter call, leaving out an argument is a mistake. In a curried chain, supplying one argument at a time *is* the calling convention, so the short call is well formed and silently yields a function. - **Expecting a partial decision.** There is no such thing as a half-made allow-or-deny; the rung is a function, not a provisional verdict. - **Expecting several arguments per rung.** Each rung consumes exactly one. Supplying two values at once is a different operation, and on a strictly curried chain it is not available at all. - **Assuming the rung is a private implementation detail.** It is a first-class value, and its whole point is that you can keep it. ## Why anyone wants this Because the prefix becomes addressable. If a module only ever checks one role, it can hold the rung for that role and pass around a function that asks two questions instead of three. The general check stays in one place, and the narrowing happens once instead of at every call site - which is the same payoff as fixing arguments in one step, reached one rung at a time.
- Can the function you got after supplying the role be reused for many resources?Yes. It is an ordinary value, and each call to it starts from the same rung, so one use neither consumes it nor affects another. That holds as long as the check is pure; if the underlying check performs an effect, every completed chain performs it again.
- Why is a short call not an error here, when it would be on a plain three-parameter check?Because a curried check is not a three-parameter function at all. It is a one-parameter function, so a one-argument call is complete and correct. What it returns happens to be another one-parameter function rather than a decision.
saying these in an interview costs you the question
- Thinks the check runs as soon as the role is supplied.
- Expects an error because two arguments are missing.
- Says the intermediate result is a decision with defaults filled in.
- Believes one rung can accept several arguments at once.
- Assumes the intermediate function cannot be stored or passed on.