Tonal Root Nodes and Subtonal Features #
Tone is paradigmatic. A Tonal Root Node (TRN) is a bundle of
subtonal features [±upper] and [±raised] ([Yip80]
[Pul86]), each of which links to a TBU (mora, syllable).
This file follows [Lio22a]'s reformulation of register-tier
geometry: the four tier organisation (subtonal features → TRN → TBU)
is shared with [Sni99], but the features themselves are
paradigmatic targets, not syntagmatic shifts.
Main definitions #
Subtonal— the two paradigmatic subtonal feature dimensions[±upper]and[±raised].TRN— Tonal Root Node, a bundle ofOption Boolvalues for the two subtonal features. Linked to itsSubtonal → Option Boolview byTRN.toBundle/TRN.ofBundle.TRN.empty,TRN.downstep,TRN.upstep— register-only TRNs for Drubea/Numèè-style systems.TRN.H,TRN.M,TRN.L,TRN.superHigh— the four[±u, ±r]combinations underlying the Laal-style 3-tone system.realizePitch,pitchDeltas,realizePitchUtterance— terracing realisation (cumulative register shifts).TRN.absolutePitch— paradigmatic Laal-style realisation.ThreeToneGap— the four typological classes of 3-tone systems.TBUKind,WordProsodicType,DownstepProperties,AnalysisInventory— prosodic typology primitives.IsCulminative— at most one[-raised]TRN per stem.hEpenthesis,hEpenthesisSpread— postlexical operations.subtonalAssimilate,mergeTRN,dockFloating— subtonal feature operations via the bundle view.
Implementation notes #
Why paradigmatic, not syntagmatic #
[Sni99]'s h/l features are defined both paradigmatically
(specifying register half) and syntagmatically ("higher / lower than
the preceding register"). [Lio22a] argues this dual
definition is overloaded: the same feature does double duty as a
representational primitive and as a phonological process trigger.
Switching to purely paradigmatic [±upper]/[±raised] separates the
two roles — the features are the representation, the operations
(spreading, OCP merger, deletion) are the processes.
Geometry #
[±upper] Register-half subtonal feature tier
[±raised] Within-register subtonal feature tier
○ Tonal Root Node (TRN) — bundles both features
|
TBU Tone-bearing unit (mora / syllable)
A TRN is the structural node that gathers a [±upper] value and a
[±raised] value and links them to a TBU. Either or both features may
be underspecified (none), with surface values filled in by default.
Subtonal features #
Equations
- Tone.instDecidableEqSubtonal x✝ y✝ = if h : x✝.ctorIdx = y✝.ctorIdx then isTrue ⋯ else isFalse ⋯
Equations
- Tone.instReprSubtonal = { reprPrec := Tone.instReprSubtonal.repr }
Equations
- Tone.instReprSubtonal.repr Tone.Subtonal.upper prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Tone.Subtonal.upper")).group prec✝
- Tone.instReprSubtonal.repr Tone.Subtonal.raised prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Tone.Subtonal.raised")).group prec✝
Instances For
Equations
- Tone.instInhabitedSubtonal = { default := Tone.instInhabitedSubtonal.default }
Tonal root node #
A Tonal Root Node: a structural node that bundles a [±upper]
and a [±raised] subtonal-feature value and links them to a TBU.
Either or both fields may be none (underspecified). For the
register-only Drubea/Numèè system the upper field is uniformly
none; for full 3-tone Laal both fields are usually specified.
Implemented as a structure rather than Subtonal → Option Bool
so that DecidableEq and Repr derive automatically (and BEq
follows from DecidableEq, below) and so that decide-based proofs
over concrete TRN literals reduce cleanly. The bundle view is
recovered by TRN.toBundle.
- upper : Option Bool
- raised : Option Bool
Instances For
Equations
- Tone.instDecidableEqTRN.decEq { upper := a, raised := a_1 } { upper := b, raised := b_1 } = if h : a = b then h ▸ if h : a_1 = b_1 then h ▸ isTrue ⋯ else isFalse ⋯ else isFalse ⋯
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Tone.instReprTRN = { reprPrec := Tone.instReprTRN.repr }
Equations
- Tone.instInhabitedTRN = { default := Tone.instInhabitedTRN.default }
Boolean equality on TRN as decidable equality, so that LawfulBEq
holds. Required for simp-based reasoning over (t == t).
Equations
- Tone.TRN.instBEq = { beq := fun (a b : Tone.TRN) => decide (a = b) }
The empty / fully underspecified TRN. In the Drubea/Numèè register- only system, this is the registerless mora.
Equations
- Tone.TRN.empty = { upper := none, raised := none }
Instances For
A floating [-raised] subtonal feature, no [upper] value.
In the register-only system this is the downstep TRN: it lowers
the running register baseline.
Equations
- Tone.TRN.downstep = { upper := none, raised := some false }
Instances For
A floating [+raised] subtonal feature, no [upper] value.
In the register-only system this is the upstep TRN — used by
pre-downstep h-epenthesis ([Lio25]).
Equations
- Tone.TRN.upstep = { upper := none, raised := some true }
Instances For
The High tone of Laal-style 3-tone systems: [+upper, -raised]
([Lio22a] ex. 51). Highest pitch.
Equations
- Tone.TRN.H = { upper := some true, raised := some false }
Instances For
The Mid tone of Laal-style 3-tone systems: [-upper, +raised]
([Lio22a] ex. 51). M is one of the four [±u, ±r]
combinations, derived from the binary subtonal features — not a
primitive enum constructor.
Equations
- Tone.TRN.M = { upper := some false, raised := some true }
Instances For
The Low tone of Laal-style 3-tone systems: [-upper, -raised]
([Lio22a] ex. 51). Lowest pitch.
Equations
- Tone.TRN.L = { upper := some false, raised := some false }
Instances For
The fourth combination [+upper, +raised] — unattested in Laal,
where it is the gap of the subtonal system ([Lio22a] ex. 51:
"Missing from this system is the subtonal specification
[+upper, +raised]"). Provided for completeness; an attested 4-tone
language or a different 3-tone gap would use this.
Equations
- Tone.TRN.superHigh = { upper := some true, raised := some true }
Instances For
View a TRN as a Subtonal → Option Bool (the parametric
foundation in Features.Bundle). The bundle algebra
(merge, assimilate, delete, set, refines) is then directly available
via this view.
Equations
Instances For
Recover a TRN from a generic subtonal-feature bundle. Inverse of
toBundle.
Equations
- Tone.TRN.ofBundle b = { upper := b Tone.Subtonal.upper, raised := b Tone.Subtonal.raised }
Instances For
Pitch realisation #
Syntagmatic register shift contributed by a TRN, used by the
terracing realisation realizePitch. Reads only the [raised]
subtonal feature: [-raised] lowers, [+raised] raises,
underspecified is inert.
This is not the paradigmatic interpretation of [raised]
([Lio22a] §5.1). It is the realisation pattern attested in
register-only systems like Drubea and Numèè ([Lio25]),
where each [-raised] triggers a downstep operation that resets
the register baseline.
Equations
- t.pitchEffect = match t.raised with | none => 0 | some false => -1 | some true => 1
Instances For
Terracing realisation: realise a TRN sequence as a sequence of
pitch levels, where each [-raised] cumulatively lowers the
baseline ([Sni99] [Lio25]).
Used for register-only systems (Drubea, Numèè) and for catathesis
in Japanese / English intonation ([BP86]).
For the paradigmatic Laal-style realisation see TRN.absolutePitch.
Defined by direct case-split on the [raised] value so that
realizePitch n [TRN.empty, …] reduces to n :: … definitionally
(the alternative level + t.pitchEffect form does not reduce for
opaque n : Int, since n + 0 = n is not definitional).
Equations
- Tone.realizePitch x✝ [] = []
- Tone.realizePitch x✝ ({ upper := upper, raised := none } :: rest) = x✝ :: Tone.realizePitch x✝ rest
- Tone.realizePitch x✝ ({ upper := upper, raised := some false } :: rest) = (x✝ - 1) :: Tone.realizePitch (x✝ - 1) rest
- Tone.realizePitch x✝ ({ upper := upper, raised := some true } :: rest) = (x✝ + 1) :: Tone.realizePitch (x✝ + 1) rest
Instances For
A uniform cons rewrite for realizePitch in terms of pitchEffect.
Pitch deltas — the theory-primary view ([Sni99] [Lio25]). Cumulative register shifts produced by a TRN sequence, expressed as integer offsets from the start. There is no privileged "zero" pitch; only the differences are meaningful.
Equations
- Tone.pitchDeltas ts = Tone.realizePitch 0 ts
Instances For
realizePitch n ts is pitchDeltas ts shifted by the offset n.
Utterance-initial phonetic neutralisation: an utterance-initial
[-raised] TRN is realised at the starting pitch (no preceding
register to contrast with — [Lio25] §3.5, §4.5). The
feature is not removed from the underlying form: it remains
phonologically active for blocking pre-downstep h-epenthesis on
itself and for feeding raising on a following registerless TRN.
Equations
- Tone.realizePitchUtterance level [] = []
- Tone.realizePitchUtterance level (t :: rest) = if t.raised = some false ∧ t.upper = none then level :: Tone.realizePitch level rest else Tone.realizePitch level (t :: rest)
Instances For
Paradigmatic Laal-style pitch realisation ([Lio22a]
§4). Pitch is computed from [upper] (×2) plus [raised] (×1),
independently per TRN — no terracing, no register-baseline state.
Unspecified features contribute 0. The four combinations give:
H = 2, M = 1, L = 0, superHigh = 3 (Laal's gap).
Equations
- t.absolutePitch = (if t.upper = some true then 2 else 0) + if t.raised = some true then 1 else 0
Instances For
Lionnet's 3-tone typology #
The four classes of 3-tone system definable over the binary subtonal
features [±upper]/[±raised] ([Lio22a] ex. 51): with four
full specifications available, a 3-tone system realises three of them,
and the unselected combination is the gap. The four-way classification
by gap is a systematisation of Lionnet's binary-feature account (Laal
itself has the [+upper, +raised] gap), not a typology the paper
surveys.
- upperRaised : ThreeToneGap
Gap =
[+upper, +raised](Laal pattern). - upperLowered : ThreeToneGap
Gap =
[+upper, -raised]. - lowerRaised : ThreeToneGap
Gap =
[-upper, +raised]. - lowerLowered : ThreeToneGap
Gap =
[-upper, -raised].
Instances For
Equations
- Tone.instDecidableEqThreeToneGap x✝ y✝ = if h : x✝.ctorIdx = y✝.ctorIdx then isTrue ⋯ else isFalse ⋯
Equations
- Tone.instReprThreeToneGap = { reprPrec := Tone.instReprThreeToneGap.repr }
Equations
- One or more equations did not get rendered due to their size.
Instances For
Which TRN combination is the gap for a given 3-tone language type.
Equations
Instances For
Laal's gap is [+upper, +raised] ([Lio22a] ex. 51).
TBU and word-prosodic typology #
Equations
- Tone.instDecidableEqTBUKind x✝ y✝ = if h : x✝.ctorIdx = y✝.ctorIdx then isTrue ⋯ else isFalse ⋯
Equations
- Tone.instReprTBUKind.repr Tone.TBUKind.mora prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Tone.TBUKind.mora")).group prec✝
- Tone.instReprTBUKind.repr Tone.TBUKind.syllable prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "Tone.TBUKind.syllable")).group prec✝
Instances For
Equations
- Tone.instReprTBUKind = { reprPrec := Tone.instReprTBUKind.repr }
Word-prosodic system types ([Hym06], enriched by [Lio25]).
Tone systems split into tone-based (paradigmatic — full TRN
contrasts) and register-based (only [raised] varies, with
cumulative terracing realisation).
- toneBased : WordProsodicType
Paradigmatic H/L contrast (e.g., Yoruba, Mandarin).
- registerBased : WordProsodicType
Syntagmatic downstep contrast (e.g., Drubea, Numèè).
- stressAccent : WordProsodicType
Prominence-based (e.g., English, Russian).
- mixed : WordProsodicType
Both tone and register (e.g., Paicî, Baga Pukur).
Instances For
Equations
- Tone.instDecidableEqWordProsodicType x✝ y✝ = if h : x✝.ctorIdx = y✝.ctorIdx then isTrue ⋯ else isFalse ⋯
Equations
- Tone.instReprWordProsodicType = { reprPrec := Tone.instReprWordProsodicType.repr }
Equations
- One or more equations did not get rendered due to their size.
Instances For
Core definitional properties of downstep, following [Leb18b] as refined by [Lio25].
Properties (a)–(c) are definitional; (d)–(f) are cross-linguistic tendencies that need not hold in every system.
- affectsDomain : Bool
(a) Affects the entire prosodic domain, not just a single tone.
- changesRegister : Bool
(b) Changes the register for what follows.
- isCumulative : Bool
(c) Cumulative: multiple downsteps stack (unlimited in principle).
- uttInitialNeutral : Bool
(d) Utterance-initially, no phonetic contrast with undownstepped.
- characteristicallyAffectsH : Bool
(e) Characteristically affects H tones.
- functionsContrastively : Bool
(f) Functions contrastively (phonological, syntactic, morphophonological, or lexical).
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Tone.instReprDownstepProperties = { reprPrec := Tone.instReprDownstepProperties.repr }
Inventory of primitives in a phonological analysis ([Lio25]).
- underlyingPrimitives : ℕ
- postlexicalProcesses : ℕ
Instances For
Equations
- Tone.instReprAnalysisInventory = { reprPrec := Tone.instReprAnalysisInventory.repr }
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Culminativity #
Register culminativity: at most one [-raised] TRN per stem.
Holds for all native Drubea and Numèè stems
([Lio25] §3.10). The Lionnet 2022 framing: a stem
contains at most one bundle whose [raised] value is some false.
Equations
- Tone.IsCulminative ts = (List.countP (fun (t : Tone.TRN) => t.raised == some false) ts ≤ 1)
Instances For
Postlexical operations #
Pre-downstep h-epenthesis ([Lio25]): insert an upstep TRN immediately before a downstep, on a registerless host.
The rule fires when an empty (⟨none, none⟩) TRN is immediately
followed by a downstep TRN (⟨none, some false⟩); the empty TRN
is replaced by an upstep (⟨none, some true⟩). An underlying
downstep blocks the rule on itself — that is the diagnostic that
survives utterance-initial phonetic neutralisation.
Equations
- Tone.hEpenthesis [] = []
- Tone.hEpenthesis [t] = [t]
- Tone.hEpenthesis ({ upper := none, raised := none } :: { upper := none, raised := some false } :: rest) = Tone.TRN.upstep :: Tone.TRN.downstep :: Tone.hEpenthesis rest
- Tone.hEpenthesis (t :: rest) = t :: Tone.hEpenthesis rest
Instances For
Spreading h-epenthesis: raise all registerless TRNs in the sequence preceding a downstep, not just the immediately preceding one ([Lio25] §3.2). Models the abrupt-spreading variant.
Equations
- One or more equations did not get rendered due to their size.
- Tone.hEpenthesisSpread [] = []
- Tone.hEpenthesisSpread ({ upper := none, raised := some false } :: rest) = Tone.TRN.downstep :: Tone.hEpenthesisSpread rest
- Tone.hEpenthesisSpread ({ upper := none, raised := some true } :: rest) = Tone.TRN.upstep :: Tone.hEpenthesisSpread rest
- Tone.hEpenthesisSpread (t :: rest) = t :: Tone.hEpenthesisSpread rest
Instances For
Subtonal feature operations #
Subtonal assimilation at feature f: the target TRN takes its
value at f from the source TRN, leaving its other feature
untouched. The Laal M-lowering rule ([Lio22a] §5.2)
is subtonalAssimilate Subtonal.raised src tgt: a [-raised]
value spreads from src to tgt, so a target M (⟨-u, +r⟩)
becomes L (⟨-u, -r⟩) without altering its [upper] value.
Equations
- Tone.subtonalAssimilate f src tgt = Tone.TRN.ofBundle (Features.Bundle.assimilate f src.toBundle tgt.toBundle)
Instances For
Binary TRN merger ([Lio22a] ex. 53–54): merge two TRNs' subtonal
features into one, taking each feature from the left TRN where it is specified and
falling back to the right (Features.Bundle.merge). Models the autosegmental fusion
of two associated tones ([Gol76]); the tier-level OCP merger that
collapses a run of identical tones is OCP.collapse.
Equations
- Tone.mergeTRN t₁ t₂ = Tone.TRN.ofBundle (Features.Bundle.merge t₁.toBundle t₂.toBundle)
Instances For
Merging a TRN with itself is the identity: mergeTRN is idempotent on equal
tones.
Floating-feature docking ([Lio22a] §5.3): a free
[±f] subtonal feature docks onto a target TRN, overwriting
whatever value it had at f. Used for the morphosyntactic
[-raised] suffix in Laal that triggers M-lowering.
Equations
- Tone.dockFloating f v t = Tone.TRN.ofBundle (Features.Bundle.set f v t.toBundle)
Instances For
Verification: Laal subtonal identities #
The Laal H/M/L tones are exactly three of the four binary
[±u, ±r] combinations — the gap is superHigh.
M-lowering as [-raised] assimilation ([Lio22a]
§5.2). When a [-raised] source assimilates onto an M target, the
result is L: M's [+raised] is overwritten to [-raised], and its
[-upper] is preserved.
Critically, the [upper] feature is not changed — this is what
makes the operation subtonal-level rather than full-tone replacement.
The same operation has no effect when the source itself is M:
assimilating [+raised] onto M leaves M unchanged.
Floating [-raised] docking onto M produces L
([Lio22a] §5.3): the morphosyntactic suffix is a free
floating feature that overwrites the target's [raised] value.
Verification: Drubea/Numèè register-only realisation #
Registerless sequences have uniform pitch.
A single downstep lowers pitch by one step.
Multiple downsteps produce cumulative terracing.
Deltas-only view of three downsteps: pitch falls by 1, 2, 3 register steps from the start. No anchor required.
Concrete terracing from offset 4 (mid-high on the 1–5 scale).
h-epenthesis raises the registerless TRN before a downstep.
h-epenthesis + realisation: the raised TRN is higher than baseline.
An underlying downstep blocks h-epenthesis on itself: the rule only
targets registerless TRNs immediately preceding a downstep. This
is what the underlying initial downstep (preserved by
realizePitchUtterance) buys us — the contrast /X ⁺Y/ (raises X)
vs /⁺X ⁺Y/ (no raising on ⁺X) survives even when the initial X
is utterance-initial and phonetically flat.
Phonetic suppression of an utterance-initial downstep: the realized pitch sequence starts flat, indistinguishable from a registerless initial.
The phonetic neutralisation is only utterance-initial: a non-initial downstep still drops pitch, even after the suppression rule fires.
Underlying culminativity is preserved under utterance-initial
suppression: an initial downstep still counts toward the stem-level
[-raised] budget. The phonetic interface does not delete it.
Culminativity: a single [-raised] is culminative.
Non-culminativity: two [-raised] TRNs violate culminativity.
Monotonicity (catathesis-blocking) #
TRN order by syntagmatic pitch effect: t₁ ≤ t₂ iff t₁ is at least
as lowering as t₂. Lifted from the Int order along TRN.pitchEffect
(Preorder.lift) — a Preorder, not a PartialOrder, since TRNs
sharing a [raised] value share a pitch effect.
Equations
- Tone.instPreorderTRN = Preorder.lift Tone.TRN.pitchEffect
Equations
- Tone.instDecidableRelTRNLe x✝¹ x✝ = x✝¹.pitchEffect.decLe x✝.pitchEffect
Monotonicity of realizePitch in the baseline: a higher starting
pitch produces pointwise higher output for any fixed TRN sequence.
Structural basis for catathesis blocking ([BP86]): when an ip boundary resets the register, subsequent pitches are higher than if catathesis had continued from a compressed baseline.
Full monotonicity of realizePitch: pointwise lowering features
plus a lower baseline give pointwise lower output. Subsumes
realizePitch_baseline_mono.