From d51c9d74857aca3c2f172609297266968bc7f809 Mon Sep 17 00:00:00 2001 From: Elizabeth Alexander Hunt Date: Mon, 12 May 2025 09:40:12 -0700 Subject: The big refactor TM --- u/fn/either.ts | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 u/fn/either.ts (limited to 'u/fn/either.ts') diff --git a/u/fn/either.ts b/u/fn/either.ts new file mode 100644 index 0000000..8b233bf --- /dev/null +++ b/u/fn/either.ts @@ -0,0 +1,97 @@ +import type { BiMapper, Mapper, Supplier } from "@emprespresso/pengueno"; +import { isObject } from "../leftpadesque/mod.ts"; + +type IEitherTag = "IEither"; +const iEitherTag: IEitherTag = "IEither"; + +export interface IEither { + readonly _tag: IEitherTag; + mapBoth: ( + errBranch: Mapper, + okBranch: Mapper, + ) => IEither; + fold: (folder: BiMapper) => Tt; + moveRight: (t: Tt) => IEither; + mapRight: (mapper: Mapper) => IEither; + mapLeft: (mapper: Mapper) => IEither; + flatMap: (mapper: Mapper>) => IEither; + flatMapAsync: ( + mapper: Mapper>>, + ) => Promise>; +} + +export class Either implements IEither { + private constructor( + private readonly err?: E, + private readonly ok?: T, + public readonly _tag: IEitherTag = iEitherTag, + ) {} + + public moveRight(t: Tt) { + return this.mapRight(() => t); + } + + public fold(folder: BiMapper): R { + return folder(this.err ?? undefined, this.ok ?? undefined); + } + + public mapBoth( + errBranch: Mapper, + okBranch: Mapper, + ): Either { + if (this.err !== undefined) return Either.left(errBranch(this.err)); + return Either.right(okBranch(this.ok!)); + } + + public flatMap(mapper: Mapper>): Either { + if (this.ok !== undefined) return mapper(this.ok); + return Either.left(this.err!); + } + + public mapRight(mapper: Mapper): IEither { + if (this.ok !== undefined) return Either.right(mapper(this.ok)); + return Either.left(this.err!); + } + + public mapLeft(mapper: Mapper): IEither { + if (this.err !== undefined) return Either.left(mapper(this.err)); + return Either.right(this.ok!); + } + + public async flatMapAsync( + mapper: Mapper>>, + ): Promise> { + if (this.err !== undefined) { + return Promise.resolve(Either.left(this.err)); + } + return await mapper(this.ok!).catch((err) => Either.left(err as E)); + } + + static left(e: E) { + return new Either(e); + } + + static right(t: T) { + return new Either(undefined, t); + } + + static fromFailable(s: Supplier) { + try { + return Either.right(s()); + } catch (e) { + return Either.left(e as E); + } + } + + static async fromFailableAsync(s: Promise) { + try { + return Either.right(await s); + } catch (e) { + return Either.left(e as E); + } + } +} + +export const isEither = (o: unknown): o is IEither => { + return isObject(o) && "_tag" in o && o._tag === "IEither"; +}; -- cgit v1.2.3-70-g09d2