In a right-to-left composition written compose(compress, watermark, resize), which stage sees the raw photo first?
answer
- same wiring, two listings
- listing order is a convention
- reading order versus run order
- rightmost stage touches the argument
- compose mirrors nested calls
basics
~10 sResize sees it first. A right-to-left combinator applies the last-listed function to the argument and feeds each result leftwards, so the stages are listed in the reverse of the order they run.
solid answer
~30 sA right-to-left `compose` hands its argument to the **rightmost** function, then passes that result to the one on its left, and so on. So `compose(compress, watermark, resize)` resizes the photo, watermarks the resized image, and compresses last - the listing reads backwards from the run order. The left-to-right form of the same chain is `pipe(resize, watermark, compress)`, where listed order and run order agree. The wiring, the result and the number of stages are identical; only the listing convention differs. Both forms build a new one-argument function, and no stage touches a photo until that function is called with one.
code
pseudocode · 9 linesfunction compose(f, g, h)
return function(x) { return f(g(h(x))) }
function pipe(f, g, h)
return function(x) { return h(g(f(x))) }
stored = compose(compress, watermark, resize)(photo)
same = pipe(resize, watermark, compress)(photo)
// both: resize runs first, compress runs lastgo deeper
Recall that a composition helper's listing order is a convention, not the run order. Be able to point at the stage that touches the input and say why before tracing anything else.
Explain the nesting: a right-to-left listing is the nested-call form with the argument removed, so the rightmost stage is the innermost call. Show that the left-to-right form rewires nothing and only reorders the line.
Demonstrate how you confirm a helper's direction in code you did not write - reading its implementation, or applying it to two stages with distinguishable effects - rather than trusting the name or the convention you are used to.
Frame direction as a convention whose cost is paid on every read and every review, not as a correctness question, and be ready to say what you would standardise on and why.
A photo upload is handled in three steps: **resize** the original, **watermark** the resized image, then **compress** the result for storage. There are two conventional ways to write that wiring as one function, and they disagree about the order the stages appear on the line. ## The two listings - **Right-to-left composition**, usually called `compose`: `compose(compress, watermark, resize)`. The combinator applies the **rightmost** function to the argument, hands that result to the function on its left, and keeps moving left. The listing is the reverse of the run order. - **Left-to-right piping**, usually called `pipe`: `pipe(resize, watermark, compress)`. The combinator applies the **leftmost** function to the argument and walks rightwards. The listing is the run order. Both calls build **one new function of one argument**. Handed the same photo, both produce the same bytes, run the same three stages, and do the same work. The only difference is which end of the written line the data enters. ## Trace it once 1. The built function is called with the original photo. 2. `resize` runs on the original and returns a smaller photo. 3. `watermark` runs on the **smaller** photo - so the mark is sized for the resized image, not the original. 4. `compress` runs on the watermarked photo and returns what is stored. That trace is identical for both listings. If a candidate reads `compose(compress, watermark, resize)` left to right and concludes the original is compressed first, they have read the listing as the run order. ## Reading order against application order | | `compose(compress, watermark, resize)` | `pipe(resize, watermark, compress)` | |---|---|---| | Stage that receives the photo | `resize`, the rightmost | `resize`, the leftmost | | Listing versus run order | reverse of it | the same as it | | Spoken without ambiguity | "compress **after** watermark **after** resize" | "resize, **then** watermark, **then** compress" | | Shape it mirrors | nested calls read outward | steps read in sequence | The words **after** and **then** are the cheapest fix for the ambiguity: "compose these three" says nothing about direction, while "compress after watermark" pins it. ## Why the right-to-left convention exists at all Write the chain out as ordinary nested application and it reads `compress(watermark(resize(photo)))`. The innermost call runs first, so reading the line left to right gives you the **last** stage first. Right-to-left composition preserves exactly that order: it is the nested form with the parentheses and the argument removed, which is why the stage nearest the (absent) argument sits on the right. Left-to-right piping abandons that heritage in favour of the order the data actually moves, which is the order a reader traces when debugging. ## What does not change with direction - The **result**: the same photo goes in and the same bytes come out. - The **join requirement**: each stage's result still has to be acceptable to the stage that receives it next. - The **cost**: the same three stages run once each; direction is a notation, not an optimisation. - The **moment work happens**: composing produces a function; the stages run when that function is applied to a photo. What does change is the reading cost. In a right-to-left listing, the reader's eye moves opposite to the data, and in a long chain that reversal is where mistakes get made - especially in a codebase where both conventions are present and a listing written for one helper is handed to the other. ## What an interviewer is listening for The checkable part of the answer is one sentence: **the rightmost stage in a right-to-left composition is the one that touches the input**. The better answer adds that this is a convention of the helper, not a law, so in unfamiliar code you confirm it - read the helper's few lines, or apply it to a single-stage chain and see which end moves - instead of assuming the convention you happen to be used to. Candidates who say "it depends which helper this is, and here is how I would check" are demonstrating the habit that keeps mixed-direction codebases from producing silently wrong images.
- Does building the chain do any work to the photo?No. Both combinators return a new function of one argument; the three stages run only when that function is applied to a photo. Building it a hundred times resizes nothing. That is why a wiring mistake in the listing shows up as a wrong image later, at the call site, rather than as a failure where the chain was assembled.
- How would you say the chain aloud so the direction is unambiguous?Use the joining word to carry the direction: "compress after watermark after resize" for a right-to-left listing, "resize, then watermark, then compress" for a left-to-right one. "Compose compress, watermark and resize" carries no direction at all, which is exactly how a reviewer ends up approving a reversed chain.
- You open unfamiliar code and cannot tell which direction its helper uses - what do you do?Read the helper; it is usually three lines and the nesting answers it outright. Failing that, apply it to two stages whose effects are distinguishable - one that appends a marker and one that truncates - and see which marker survives. Guessing from the name is unreliable, because names for both conventions vary between codebases.
Reading a right-to-left composition is like reading an address on an envelope: the street comes first but the letter reaches the country first. Same journey, written from the wrong end.
saying these in an interview costs you the question
- Says compose and pipe produce different final results
- Claims the first function listed always runs first
- Cannot say which listed stage receives the original argument
- Assumes every codebase's compose runs left to right
- Thinks assembling the chain already processed the photo