日本語 · English

segmentBy — interval-sequence windows (cut at markers)

Translated from the canonical Japanese page reference/segmentBy.md. The source_sha above records the source revision; a consistency check flags this page when the Japanese original changes.

Category: window (body-layer core) / Signature: segmentBy(m, edges:, empties:) : Stream -> Stream(interval) / name settled (spec §5.4)

Meaning

Takes an arbitrary stream m as markers and makes each half-open interval [mᵢ, mᵢ₊₁) between adjacent markers a window. Every window whose boundaries are given by a sequence of points — fiscal closes, lunar phases (a lunisolar calendar cut at new moons), weeks (cut at the wkst-labeled day) — stands on this.

Unlike the partition type, exhaustiveness is not guaranteed, so the two arguments that state the meaning of the gaps explicitly are mandatory declarations (I5; omission is a static error). This closes off, by syntax, the accident in which firings silently vanish on missing data (ADR-15’s “accidental empty”).

Arguments

Argument Value Meaning
m stream expression the markers (the intervals’ boundary points)
edges: drop / clip / error treatment of points before the first marker / after the last marker (discard / make a partial window / error)
empties: keep / drop / error treatment of zero-element windows between markers (keep as a legitimate empty / discard / error)
labels: list (literal / list binding name) or the cyclic form cycle list anchor: real-day (ADR-47, below) a parallel label list for the window sequence (ADR-39); reading is binding-name projection name(d). For the combination constraints see “Preconditions and tightening rules” below — it cannot combine with edges: clip, empties: drop, or label:
label: lambda (p => expr) a computed label per window (ADR-34; for index expressions and conditional computations that do not fit labels:)

Examples

Lunisolar months cut at new moons — take the first day (the new-moon day) of each month. Lunar New Year 2026-02-17 appears:

# eval: 2026-01-01..2026-05-01
@JP
newMoons = [2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23, 2026-04-17T20:52]
lunarStart = newMoons |> snapTo(day)
everyDay |> segmentBy(lunarStart, edges: drop, empties: drop) |> first
#=> 2026-01-19 2026-02-17 2026-03-19
#~> 範囲外 2026-01-01..2026-01-19(newMoons covering 2026-01-19T04:52..2026-04-17T20:52)
#~> 範囲外 2026-04-17..2026-05-01(newMoons covering 2026-01-19T04:52..2026-04-17T20:52)

With edges: drop, nothing past the last marker 4/17 becomes a window (no silent continuation at the data’s edge).

labels: — a parallel label list for the window sequence (ADR-39)

Binds a data label sequence to the window sequence. Reading is binding-name projectionname(d) returns the label of the window that point d belongs to (defining equation name(d) ≡ labels[window-sequence ordinal]; in the window-sequence ordinal, the window starting at the first marker within the effective coverage is 0). A same-length check runs at evaluation: list length == window count (the window count is coverage-based = the marker count, independent of the evaluation range and the materialization range) — forgetting to update markers and labels as a pair breaks loudly as a static error (the vessel for F62):

# eval: 2026-01-01..2026-07-01
@JP
newMoons = [2026-01-19T04:52, 2026-02-17T21:01, 2026-03-19T10:23, 2026-04-17T20:52]
  covering: 2026-01-19..2026-04-30
lunarMonth = everyDay |> segmentBy((newMoons |> snapTo(day)), edges: drop, empties: error,
                                   labels: [12, 1, 2, 3])
lunarMonth |> first |> filter(d => lunarMonth(d) == 1)
#=> 2026-02-17
#~> 範囲外 2026-01-01..2026-01-19(newMoons covering 2026-01-19..2026-04-30)
#~> 範囲外 2026-05-01..2026-07-01(newMoons covering 2026-01-19..2026-04-30)

Preconditions and tightening rules (all static errors; ADR-39 decision 4): it cannot combine with edges: clip (pseudo-windows shift the ordinals); it cannot combine with empties: drop (removing empty windows compacts the ordinals); it cannot coexist with a label: lambda (doubling the label source); it does not attach to rule markers (infinite sequences of the week class — periodic labels go to cycle, computed numbers to ordinalIn or label:); composite markers (t1 | t2) split the effective coverage so the window count is not determined — fix it first with a binding-postfix coverage claim (covering:). The reading port for an empty window’s label (empties: keep) is interval membership — any point within the window interval, in practice the marker point itself (the form in which an absent period’s number still stands). For several parallel sequences (numbers and names) the canonical form is separate window bindings over the same markers (the check bites twice; ../../stdlib/kyureki.md (Japanese) §1).

labels: cycle — a periodic label for the window sequence (ADR-47)

The shape “window sequence = the calendar’s unit, label = a fixed period” (the twelve branches of sekki-cut months, the monthly nine stars, the moon’s twelve signs) is written with the cyclic form labels: cycle list anchor: real-day. The semantics are identical to cycle on a window binding — “the window containing the anchor carries the first label” (list[(window-sequence ordinal − anchor window's ordinal) mod N]; negatives normalized by the modulus). No same-length check is imposed — as the covering grows over multiple years and markers increase, the anchor stays and the expression does not change by a single character (compatibility with external supply 〈ADR-46〉 is the aim of this form).

# eval: 2026-02-03..2026-02-06
@JP
setsu = [2026-01-05, 2026-02-04, 2026-03-05, 2026-04-05] covering: 2026-01-05..2026-04-05
sekkiMonth = everyDay |> segmentBy(setsu, edges: drop, empties: error,
                                   labels: cycle [寅, 卯, 辰, 巳, 午, 未, 申, 酉, 戌, 亥, 子, 丑]
                                   anchor: 2026-02-04)
everyDay |> filter(d => sekkiMonth(d) == 寅)
#=> 2026-02-04 2026-02-05

label: (ADR-34)

The parenthesized named-arg segmentBy(m, edges:, empties:, label: (p => expr)) attaches a computed label to each window (p = the window’s first point; lazy evaluation at projection time). When merely pasting a data column, labels: is canonical (ADR-39, ADR-30 revised); label: is for computations involving index expressions and conditions (../../stdlib/kyureki.md (Japanese) §7 (5)).

Externally supplied data labels — the form whose expression stays unchanged as coverage grows (reflux mail 20 §2, 2026-09-03): receive the markers through external and attach its label column (supplied together with the dates under the same-length contract of ADR-30) with label: (p => markerTable(p)). p is the window’s first point — the marker point itself — so the projection returns that marker’s label as is. Even for non-periodic data labels such as lunisolar month numbers (a leap month repeats the preceding number), the same-length check lives on the supply contract’s side (契約違反: labels は時点列と同長), and the text of the expression does not change with the yearly coverage update — “if the date is authoritative, so is the label that names it”, realized with the existing machinery:

# eval: 2026-02-15..2026-02-22
# resolve: saku = dates 2026-01-19 2026-02-17 2026-03-19 2026-04-17 2026-05-17 covering: 2026-01-01..2026-05-31 asof: 2026-09-03 labels: m12 m1 m2 m3 m4
premise L { calendar-system: Gregorian; tz: "Asia/Tokyo"; wkst: Mon; source: "moon/saku"
  saku  = external(kind: dates, labels: [m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12])
  lunar = day |> segmentBy(saku, edges: drop, empties: keep, label: (p => saku(p)))
}
@L
everyDay |> filter(d => lunar(d) == m1)
#=> 2026-02-17 2026-02-18 2026-02-19 2026-02-20 2026-02-21

When the supply grows by one new moon (2026-05-17 with m4), lunar simply gains one window and the definition above is untouched (measured: with five new moons, m1 = 30 days, m2 = 29 days, m3 = 4/17–5/16). The value-domain declaration labels: [m1, …, m12] is static knowledge (a leap month repeats a name inside the domain). A point sequence derived by filter carries no labels (labels are properties of tables and windows — ADR-30/34/42), so the projection does not stand when the new moons are filtered out of another table — supply the new moons as their own external (if you already compute them upstream, just ship the dates and the month numbers together).

Using labels as numbers (reflux regular mail 2026-09-08 §3): the value domain of labels: is enumeration names (labels: on external accepts identifiers only — ADR-30’s value-domain declaration is static knowledge), so a definition that does arithmetic on a label, such as a lunisolar month number, keeps a name-to-number function inside the premise: monthNo = l => l == m1 ? 1 : l == m2 ? 2 : … : 12 (a nested conditional; the readability cost is explicit). In the supplier’s measurement the rokuyō (大安) definition written this way matched the static labels: version point for point. A one-word projection that takes the ordinal from the declaration order (something like ord(lunar(d))) is not in the 1.0 vocabulary; it is a post-1.0 candidate in 90-open-questions.

Pitfalls

within · snapTo (granularity-matching the markers) · cycle (periodic labels) · table literals (bringing marker data in) · ADR-07/08/15 · I5.

A segmentBy window sequence borne by rule markers (no coverage annotations) is accepted as an effective partition for within’s w and for split’s parent and by: (ADR-48; the term is in spec §6.3) — regular period cuts like the 4-4-5 fiscal calendar’s “periods” can be written in either the segmentBy canonical form or the split form (worked example: the recipe “4-4-5 fiscal calendar”; the extensional match on the split side is the weekPart doctest on the split page).