Time is warped either on the query span (before) or on the hap spans (after) a pattern is queried
Strudel separates time manipulation into two orthogonal axes. withQuerySpan(func) applies a function to the query timespan before it reaches the inner pattern — this is how speed and shift operations like fast, slow, and late are built, because changing what time range you ask for changes which events come back. withHapSpan(func) applies a function to the timespans of the haps after they are returned, transforming the reported timing of results without changing which events are selected. Knowing which axis to touch is the key to writing correct low-level time combinators.
Examples
// speed up by compressing the query span before querying: pat.withQuerySpan(span => span.withTime(t => t * 2)) // shift reported event times half a cycle later: pat.withHapSpan(span => span.withTime(t => t + 0.5))
Assessment
Explain why fast must transform the query span rather than the hap span, and describe the observable difference from instead halving all hap spans with withHapSpan.