Two configuration settings load independently, neither needing the other's value — which combining operation fits, and what does chaining them instead cost?
answer
- ask whether step two needs step one
- independent arguments, no shared results
- the dependent step does not exist yet
- combining keeps both effects reachable
- chaining fixes order and short-circuits
basics
~20 sIndependent loads belong to the combining rung, which takes contexts built side by side and a plain function of their values. Chaining them instead makes the second load a function of the first, so one evaluation order is forced and nothing from the second is available when the first is empty.
solid answer
~50 sThe combining rung takes contexts that are already built plus a plain function of their values, so both effects exist before either result is inspected: the implementation is free to evaluate them in any order or at the same time, and information from both is reachable. Chaining is a different shape — its second argument is a function `A -> Wrapper<B>`, so the second context does not exist until the first one has produced a value. Using it for independent settings overstates the dependency: the order becomes fixed, the second load is unreachable whenever the first is empty or failed, and a reader can no longer tell from the code which steps genuinely depend on which. The rule of thumb is to pick the weakest rung that expresses the step, because the rung you choose is a claim about dependency that other engineers will read.
code
pseudocode · 11 linesloadHost(source) // Wrapped<Host>
loadPort(source) // Wrapped<Port>
// independent: both contexts exist before either is inspected
endpoint = combine(loadHost(source), loadPort(source),
(host, port) -> makeEndpoint(host, port))
// dependent: the second context cannot be built until the first yields
credential = chain(loadHost(source),
host -> loadCredentialFor(host))
// loadCredentialFor needs the host value to exist firstgo deeper
Recall the test: if the second step needs the first step's value, the steps are dependent; if it does not, they are independent and can be put side by side.
Explain the two signatures and why the dependent one forces an order — the second context is the result of a function that must be handed a value before it can produce anything.
Demonstrate the diagnosis on a real assembly path: which settings were chained without needing to be, what that cost when one was missing, and how you would restructure the pipeline.
Frame it as a house convention: the rung a step uses is a claim about dependency other teams read, so decide whether the claim is worth enforcing and what enforcement would cost.
## The question the shape answers When you put two effectful steps together, exactly one question decides which rung you need: **does the second step need the first step's value?** Everything else — evaluation order, what can run at the same time, what is reachable after a failure — follows from the answer, because it follows from the shape of the operation. - **Combining** has the shape `combine(Wrapper<A>, Wrapper<B>, (A, B) -> C) -> Wrapper<C>`. Both contexts are arguments. They were built by expressions that never saw each other, and the function that merges them is plain: it works on the two values, not on the contexts. - **Chaining** has the shape `chain(Wrapper<A>, A -> Wrapper<B>) -> Wrapper<B>`. The second context is not an argument at all — it is the *result* of a function that has to be given a value of `A` first. ## What combining can do that chaining cannot Because both contexts are arguments, the combining rung knows about both effects before it looks at either result. That buys three things: - **Order freedom.** Nothing in the shape says which context is evaluated first, so an implementation may evaluate them in either order, or concurrently, without changing the meaning. - **Both sides reachable.** If the first context is empty or failed, the second one still exists and can still be inspected, so a context that wants to report on both has the material to do it. - **A readable claim.** A combining call is a statement in the code that these two loads are independent. That claim survives review in a way a comment does not. ## What chaining can do that combining cannot Chaining expresses the one thing combining structurally cannot: a step whose *input* is the previous step's *output*. Reading a region name and then reading the endpoint list stored under that region is not expressible with combining at any price, because the second lookup cannot be written down before the region value exists. That extra power arrives with two consequences that are not optional: 1. **One evaluation order.** The second context is built from the first value, so the first must be evaluated first. This is not a policy an implementation chose; it is what the shape says. 2. **Short-circuiting.** If the first context is empty or failed, the function is never applied, no second context is ever built, and nothing can be learned from a step that never ran. | | combining | chaining | |---|---|---| | second context | an argument, already built | the result of a function of the first value | | dependency it expresses | none | step two needs step one's value | | evaluation order | free | fixed, first then second | | after an empty first context | the second still exists | the second is never built | ## The cost of reaching for the stronger rung Chaining can express anything combining can — you can chain the first context and then map over the second — so a codebase can be written entirely with it. What it cannot do is express *independence*. Using it for two independent settings costs: - **Information.** Only the first empty-or-failed case is ever produced, because the second load never happened. - **Freedom the implementation could have used.** An order that was never required becomes an order that must be honoured. - **Meaning for the reader.** When every step is chained, the chain stops telling anyone anything. A reviewer has to open each step and check whether the value handed in is actually used. ## Deriving one from the other Any context that supports chaining also supports a *derived* combining operation: chain the first, then map the second, then apply the function. This matters in two directions. It means the rungs are a ladder rather than a menu — the stronger rung implies the weaker one. It also means the derived version inherits the chain's fixed order and short-circuit, so it delivers the readable claim of independence but not the order freedom. A context that wants the order freedom has to define its combining operation itself, independently of chaining. Where a context does that, the two operations can genuinely differ in behaviour while both being correct. ## Reading a pipeline In a configuration assembly, the decision is mechanical. Host and port come from separate settings, so they are combined. A credential that is looked up *by* the resolved host is chained. Trimming whitespace from an already-loaded value is neither — it is a plain function of the value, so it is mapping. Do that once per step and the pipeline documents its own dependency graph.
- What does the combining rung make possible that the chaining rung cannot?Both effects exist before either result is inspected, so an implementation may evaluate them in either order or at the same time, and information from the second is still available when the first is empty. A chain cannot offer either, because the second context is not built until the first has produced a value.
- How do you tell from a step's signature alone which rung you need?Look at the function you are holding. A function from a value to a plain value is the mapping rung. Two contexts already built plus a plain function of their values is the combining rung. A function from a value to a wrapped value is the chaining rung. The name of the step is irrelevant; the return type decides.
- Does every context that supports chaining also support combining?Yes — combining can be derived by chaining the first context and mapping over the second. But the derived version inherits the chain's fixed order and short-circuit, so it delivers the readable claim of independence without the order freedom. A context that wants that freedom must define combining itself.
saying these in an interview costs you the question
- Says the chaining rung is simply better because it is stronger
- Claims combining can express a step needing the previous value
- Says combining guarantees concurrent evaluation rather than permitting it
- Assumes a later chained step still runs after an empty one
- Treats the choice as style rather than a difference in expressiveness