skip to content

In a course catalogue pipeline, why does a chain of dependent lookups written as nested element-wise maps force an edit at every level when a stage is added?

level: seniorimportance: should knowfreq 36%

answer

  1. the next argument does not exist yet
  2. written inside, not after
  3. each stage returns a structure
  4. depth is part of the shape
  5. collapse per stage keeps it flat

basics

~20 s

Each dependent stage can only be written inside the previous one's function, and shape-preserving mapping keeps its result whole, so every stage adds a level of nesting. Adding one changes the shape every enclosing function and the final consumer were written against.

solid answer

~40 s

A dependent lookup can only be called with a value the previous stage produced, and with element-wise mapping the only place that value exists is inside the function passed to the previous map. So stage two is written inside stage one, stage three inside stage two. Mapping is shape-preserving, so each function's returned structure lands whole in a slot and the result gains one level of nesting per stage. Depth is part of the shape: appending a stage deepens the result, so every enclosing function's body and the consumer at the end all change. A chain of `bind` steps collapses the level each stage adds, so the running value between any two stages is flat, the stages sit side by side rather than nested, and adding one is appending a step.

code

pseudocode · 10 lines
pseudocode
// nested: each stage is written inside the previous function
nested = map(courses, course ->
           map(sessionsOf(course), session ->
             bookingsOf(session)))
// courses -> sessions -> bookings: three levels deep

// bind chain: each stage collapses the level it just added
sessions = bind(courses,  course  -> sessionsOf(course))
bookings = bind(sessions, session -> bookingsOf(session))
// flat throughout; a third stage is one more line, not a rewrite

go deeper

for a junior

Notice where the second lookup has to be written: inside the first function, because its argument only exists there.

for a middle

Explain that each stage returning a structure adds a level, and that collapsing per stage is what keeps the value between stages flat.

for a senior

Argue the maintenance cost concretely: appending a stage to a nested pipeline changes the shape every enclosing function and the final consumer were written against.

for a principal

Weigh the flat chain against the grouped shape for a pipeline other teams consume, since the collapse discards provenance that no downstream stage can reconstruct without a key on each element.

## Where the second stage has to be written Two lookups, each one-to-many: a course yields its sessions, a session yields its room bookings. The second lookup can only be called with a **session**, and there are no sessions until the first lookup has run. That is what *dependent* means here - the argument of the second stage is a value the first stage produced, so the second stage cannot even be named until the first one has run. With element-wise mapping, the only place that value exists is inside the function passed to the first map. So the second stage gets written **inside** the first: - stage one is a map over the courses; - stage two is a map over the sessions, written in the body of stage one's function; - stage three, when it comes, is written in the body of stage two's function. Nothing is wrong yet - the code runs and the bookings are all there - but the shape and the edit cost both grow with every stage. ## Why the depth grows Mapping is shape-preserving: whatever the function returns lands whole in one slot. The innermost function returns a **structure** of bookings, so the middle result is a structure of structures, and the outer map puts each of those into a slot of its own. Three stages that each return a structure leave a result nested three levels deep - courses, then sessions, then bookings. That depth is part of the value's shape, which is why adding a stage is not a local change: 1. the new innermost function returns a structure, so the depth goes up by one; 2. every enclosing function's body now returns something one level deeper than it did; 3. the consumer at the end - the report, the writer, the count - was written against a shape that no longer exists, so it changes too. An edit at every level, for one stage appended at the bottom. ## What a bind chain changes Bind collapses the level it has just added, so the running value between stages is always one level deep. | | nested mapping stages | chain of bind stages | |---|---|---| | shape after stage 1 | structure of structures | flat structure of sessions | | shape after stage 2 | three levels deep | flat structure of bookings | | where stage 2 is written | inside stage 1's function | after stage 1, at the same level | | adding a stage | edit every enclosing level | append one step | | grouping retained | all of it | none of it | The dependence is untouched by the change: bind still hands the function one concrete element at a time, and the function still chooses the structure it returns **from that element** - including how many results it holds, and whether it holds none. What changes is that the pipeline reads as a sequence of stages rather than as a nest, and the shape between any two of them is the same shape. ## Dependence is the thing being expressed It is worth separating this from combining two structures that are both known in advance. If the second structure does not depend on the first, you can pair them up without any of this machinery. The catalogue case is not that: which bookings get looked up is decided by a session that did not exist when the pipeline was written. A step that expands each element into a structure **chosen from that element** is precisely what expresses that dependence, and it is what shape-preserving mapping cannot do - mapping commits to one output slot per input element before it knows anything about the element. ## What the flat pipeline costs Collapsing is lossy, and a senior answer says so. After the chain, a booking no longer sits under the session and the course that produced it. If the report groups by course, that association has to be carried on the element itself - the booking paired with its course - or the nesting has to be kept deliberately and dismantled at the end. Decide before writing the pipeline: flat when every booking is treated alike, grouped when the boundaries are part of the output. Reconstructing the grouping afterwards is only possible if something in each element still names its group. There is a second cost worth naming: a nested shape lets you see how many bookings each session produced, and a flat one does not. A stage that must report *the sessions that produced no bookings* has to observe that before the collapse, because afterwards those sessions have left no trace at all.

  • What does the bind chain give up compared with the nested shape?
    The grouping. Once each level is collapsed, a booking no longer sits under the session and course it came from, and a session that produced no bookings leaves no trace at all. Anything that needs that association has to carry it on the element itself or keep the nesting, because grouped to flat is cheap and flat back to grouped is impossible without a key.
  • Why can the second stage not simply be a plain map over the first stage's output?
    It can, once that output is flat - which is exactly what the collapse buys. Applied to the uncollapsed structure of structures, a plain map hands its function an inner structure rather than a session, so the function has to open it, and the nesting reappears one line later.
  • Does the same argument apply when the second structure is fixed in advance?
    No. If the second structure does not depend on the element, the two can be combined without expressing dependence at all. The reason bind is needed here is that the second lookup's argument is a value the first stage produced, so the step cannot be decided until that element is in hand.

saying these in an interview costs you the question

  • Claims nested maps flatten themselves as they return
  • Thinks the depth of the result is only a readability concern
  • Believes bind changes when the second lookup runs, not the shape
  • Says a flat chain keeps which course each booking came from
  • Treats two dependent stages as if either could run first