ADR-0083 · Option/Result are universal prelude types; Either IS the built-in binary sum (not a nominal type); the first witnessed isomorphisms
-
Status: Accepted
-
Summary: Now that generic data (ADR-0079) + annotation-free introduction (ADR-0081) are in, the universal generic types are promoted to the INJECTED PRELUDE (the opt-out module, Q34):
data Option a = None | Some(a)anddata Result e a = Err(e) | Ok(a), filtered per-name likeStr/Char(zero runtime fuel — data decls are elaboration-only).Eitheris NOT a nominal data type — it IS the built-in binary sume + a:Left/Right/matchare already RESERVED surface primitives (ADR/#53), so a nominaldata Either = Left | RightCOLLIDES and breaks the sum corpus; one-construct-per-problem ⟹Either= the sum, and the isomorphism conversions bridgeResult/Optionto it. Seven functions (mapOption,mapResult,bimap, and the four iso conversions) are injected CONDITIONALLY — only when the program mentions the name (surfUsesVar) — so existing fuel-bounded#guards are UNCHANGED. The four ISO round-trips (from∘to = id) are the FIRST WITNESSED ISOMORPHISMS (Q41's witnessed rung), property-tested throughSource.eval. Kernel/HasCTy/census UNTOUCHED (frontend leaf). -
Depends-on: 0079, 0081, 0068, 0074
-
Relates-to: Q41 (type isomorphism — the witnessed rung, now realized), Q34 (prelude-as-opt-out), Q26 (the Functor/Monad instances over these carriers = HKT bite-3, ADR-0082), #53 (the built-in sum whose
Left/RightEitherreuses) -
Status: Accepted (operator-approved 2026-07-07) — landed
1ac850a(prelude IC) -
Date: 2026-07-07
-
Layer: C + surface/checker (tested superset). Frontend LEAF (
TypeCheck, fan-in 0); census byte-identical, kernel untouched. -
Builds on: ADR-0079 (generic data —
Option/Resultare generic decls), ADR-0081 (annotation-free intro —Some(x)constructs with no annotation), ADR-0068 (traits/laws — an iso is a witnessed law), ADR-0074 (the string prelude — the injection mechanism this extends).
Context
Option/Result/Either are the universal generic types every program wants; before bite-1 + #55 they had
to be redefined per program. With generic data (ADR-0079) + annotation-free introduction (ADR-0081) in, they
become expressible as PRELUDE types. The question raised alongside (Q41) — Result e a ≅ Either e a,
Option a ≅ Either Unit a — makes the isomorphism conversions the first concrete test of the witnessed-iso
rung.
Decision
Option/Resultas prelude data types.data Option a = None | Some(a),data Result e a = Err(e) | Ok(a), prepended byelabProgand filtered per-name against user decls (likeStr/Char); data decls cost zero runtime fuel.EitherIS the built-in binary sume + a.Left/Right/matchare reserved surface primitives (#53). A nominaldata Either = Left | Rightcollides with them and breaks the existing sum corpus. One-construct-per-problem:Either= the sum; the isos convertResult/Optionto it.- Maps + isos, CONDITIONALLY injected.
mapOption,mapResult(success-side),bimap(bifunctor overe + a), andresultToEither/eitherToResult,optionToEither/eitherToOption— injected only when the program mentions the name (surfUsesVar, a total Surf traversal), so unused programs pay zero fuel and every existing fuel-bounded#guardis unchanged. - Four witnessed isomorphisms. Round-trip
#guards (from∘to = id, sentinel on the wrong branch):eitherToResult∘resultToEitheronOk/Err,eitherToOption∘optionToEitheronSome/None— Q41's witnessed rung made real via the oracle. - Three sum-sibling checker moves (the sum analogs of the ADR-0081 #55 PRODUCT moves, needed for the
sum-ranging isos):
synthSCmatchS.vhole ⟹ .sum ?A ?B;elabSmatchS placeholder-hole arm binders;elabSinl/inr ANF a computation payload (value payloads byte-identical). Frontend-leaf, additive.
Rejected / staged
- A nominal
data Either— collides with the reservedLeft/Right(#53), breaking the sum corpus. A future session wanting a nominalEithermust pick non-Left/Rightconstructor names. Deliberately not provided. - Unconditional function injection — the 7 fn-wrappers cost ~+10 fuel and tipped existing fuel-20 sum
guards over. The conditional (
surfUsesVar) injection is the fix (keep existing guards unchanged, per the landing gate). mapEitherinstead ofbimap—bimap(maps both sides ofe + a) is the more general bifunctor operation; chosen + documented.
Consequences
Option/Result/Eitherare universal (no per-program redefinition);parser-combinatorsdogfoods the preludeOption(its localdata Optiondeleted).- The first witnessed isomorphisms exist (Q41), on the bite-2 law machinery — the model for a future
derive Iso/Serialisablecodec (the schema thread). - These are the instance CARRIERS for the Functor/Monad HKT tier (ADR-0082 Stage D).
Revisit if
A nominal Either is wanted (needs non-reserved ctor names); OR a Functor/Monad trait unifies the
per-type maps (HKT, ADR-0082) — then mapOption/mapResult/bimap become one lawful fmap; OR structural
iso DERIVATION (Q41's derive rung) replaces the hand-written conversions.