import { id } from "../../../fun/domains/id/state"; import { unit, Unit } from "../../../fun/domains/unit/state"; import { BasicUpdater, Updater } from "../../../fun/domains/updater/state"; import { BasicFun, Fun } from "../../../fun/state"; export type LeftValue = { value: a; kind: "l" }; export const LeftValue = { Updaters: { value: (_: BasicUpdater): Updater> => Updater((v) => ({ ...v, value: _(v.value) })), }, }; export type RightValue = { value: b; kind: "r" }; export const RightValue = { Updaters: { value: (_: BasicUpdater): Updater> => Updater((v) => ({ ...v, value: _(v.value) })), }, }; export type Sum = { value: a; kind: "l" } | { value: b; kind: "r" }; export type Either = Sum; export type Option = Sum; export const Sum = Object.assign( () => ({ Default: { left: Fun((_: a): Sum => ({ value: _, kind: "l" })), right: Fun((_: b): Sum => ({ value: _, kind: "r" })), }, Updaters: { left: Fun( (_: BasicUpdater): Updater> => Updater(Sum().Updaters.map2(_, id)), ), right: Fun( (_: BasicUpdater): Updater> => Updater(Sum().Updaters.map2(id, _)), ), map2: ( l: BasicFun, r: BasicFun, ): Fun, Sum> => Sum().Operations.fold>( Fun(l).then(Sum().Default.left), Fun(r).then(Sum().Default.right), ), }, Operations: { fold: ( l: BasicFun, r: BasicFun, ): Fun, c> => Fun((_) => (_.kind == "l" ? l(_.value) : r(_.value))), }, }), { Default: { left: (_: a): Sum => ({ value: _, kind: "l" }), right: (_: b): Sum => ({ value: _, kind: "r" }), }, Updaters: { left: (_: BasicUpdater): Updater> => Updater(Sum.Updaters.map2(_, id)), right: (_: BasicUpdater): Updater> => Updater(Sum.Updaters.map2(id, _)), map2: ( l: BasicFun, r: BasicFun, ): Fun, Sum> => Sum.Operations.fold>( Fun(l).then(Sum.Default.left), Fun(r).then(Sum.Default.right), ), }, Operations: { fold: ( l: BasicFun, r: BasicFun, ): Fun, c> => Fun((_) => (_.kind == "l" ? l(_.value) : r(_.value))), ofOption: ( onNone: BasicFun, ): BasicFun, Sum> => Sum.Updaters.map2(onNone, id), }, }, ); export const Either = Sum; export const Option = { Default: { none: (): Option => Sum.Default.left(unit), some: (_: a): Option => Sum.Default.right(_), }, Updaters: { none: (): Updater> => Sum.Updaters.left((_) => unit), some: (_: BasicUpdater): Updater> => Sum.Updaters.right(_), map2: (some: BasicFun): Fun, Option> => Sum.Updaters.map2(id, some), }, };