diff options
Diffstat (limited to 'u/types/fn')
-rw-r--r-- | u/types/fn/callable.ts | 2 | ||||
-rw-r--r-- | u/types/fn/either.ts | 56 | ||||
-rw-r--r-- | u/types/fn/optional.ts | 8 |
3 files changed, 43 insertions, 23 deletions
diff --git a/u/types/fn/callable.ts b/u/types/fn/callable.ts index 51756d7..60d747b 100644 --- a/u/types/fn/callable.ts +++ b/u/types/fn/callable.ts @@ -10,6 +10,8 @@ export interface Mapper<T, U> extends Callable<U, T> { (t: T): U; } +export interface Predicate<T> extends Mapper<T, boolean> {} + export interface BiMapper<T, U, R> extends Callable { (t: T, u: U): R; } diff --git a/u/types/fn/either.ts b/u/types/fn/either.ts index aa67d41..80f32b4 100644 --- a/u/types/fn/either.ts +++ b/u/types/fn/either.ts @@ -1,18 +1,36 @@ -import { BiMapper, IOptional, type Mapper, Optional, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno'; +import { + BiMapper, + IOptional, + type Mapper, + Optional, + Predicate, + type Supplier, + Tagged, + isTagged, +} from '@emprespresso/pengueno'; export const IEitherTag = 'IEither' as const; export type IEitherTag = typeof IEitherTag; export const isEither = <E, T>(o: unknown): o is IEither<E, T> => isTagged(o, IEitherTag); export interface IEither<E, T> extends Tagged<IEitherTag> { - readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>; - readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T; readonly left: Supplier<IOptional<E>>; readonly right: Supplier<IOptional<T>>; - readonly moveRight: <_T>(t: _T) => IEither<E, _T>; + readonly mapRight: <_T>(mapper: Mapper<T, _T>) => IEither<E, _T>; + readonly filter: (mapper: Predicate<T>) => IEither<E, T>; readonly mapLeft: <_E>(mapper: Mapper<E, _E>) => IEither<_E, T>; + readonly mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>; + readonly flatMap: <_T>(mapper: Mapper<T, IEither<E, _T>>) => IEither<E, _T>; readonly flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>; + + readonly moveRight: <_T>(t: _T) => IEither<E, _T>; + readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T; + readonly joinRight: <O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) => IEither<E, _T>; + readonly joinRightAsync: <O, _T>( + other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>, + mapper: BiMapper<O, T, _T>, + ) => Promise<IEither<E, _T>>; } const ELeftTag = 'E.Left' as const; @@ -62,6 +80,11 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> { return Either.left<E, _T>(this.self.err); } + public filter(mapper: Predicate<T>): IEither<E, T> { + if (isLeft(this.self)) return Either.left<E, T>(this.self.err); + return Either.fromFailable<E, T>(() => this.right().filter(mapper).get()); + } + public async flatMapAsync<_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>): Promise<IEither<E, _T>> { if (isLeft(this.self)) return Promise.resolve(Either.left(this.self.err)); return await mapper(this.self.ok).catch((err) => Either.left(err)); @@ -82,23 +105,18 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> { return Optional.none(); } - static joinRight<K, E, T>( - arr: Array<K>, - mapper: BiMapper<K, T, IEither<E, T>>, - init: IEither<E, T>, - ): IEither<E, T> { - return arr.reduce((acc: IEither<E, T>, x: K) => acc.flatMap((t) => mapper(x, t)), init); + public joinRight<O, _T>(other: IEither<E, O>, mapper: BiMapper<O, T, _T>) { + return this.flatMap((t) => other.mapRight((o) => mapper(o, t))); } - static joinRightAsync<K, E, T>( - arr: Array<K>, - mapper: BiMapper<K, T, Promise<IEither<E, T>>>, - init: IEither<E, T>, - ): Promise<IEither<E, T>> { - return arr.reduce( - (acc: Promise<IEither<E, T>>, x: K) => acc.then((res) => res.flatMapAsync((t) => mapper(x, t))), - Promise.resolve(init), - ); + public joinRightAsync<O, _T>( + other: Supplier<Promise<IEither<E, O>>> | Promise<IEither<E, O>>, + mapper: BiMapper<O, T, _T>, + ) { + return this.flatMapAsync(async (t) => { + const o = typeof other === 'function' ? other() : other; + return o.then((other) => other.mapRight((o) => mapper(o, t))); + }); } static left<E, T>(e: E): IEither<E, T> { diff --git a/u/types/fn/optional.ts b/u/types/fn/optional.ts index 3396a45..504e496 100644 --- a/u/types/fn/optional.ts +++ b/u/types/fn/optional.ts @@ -1,4 +1,4 @@ -import { type Mapper, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno'; +import { type Mapper, Predicate, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno'; export type MaybeGiven<T> = T | undefined | null; @@ -9,7 +9,7 @@ export class IOptionalEmptyError extends Error {} export interface IOptional<t, T extends NonNullable<t> = NonNullable<t>> extends Tagged<IOptionalTag>, Iterable<T> { readonly move: <_T>(t: MaybeGiven<_T>) => IOptional<_T>; readonly map: <_T>(mapper: Mapper<T, MaybeGiven<_T>>) => IOptional<_T>; - readonly filter: (mapper: Mapper<T, boolean>) => IOptional<T>; + readonly filter: (mapper: Predicate<T>) => IOptional<T>; readonly flatMap: <_T>(mapper: Mapper<T, MaybeGiven<IOptional<_T>>>) => IOptional<_T>; readonly orSome: (supplier: Supplier<MaybeGiven<t>>) => IOptional<T>; readonly get: Supplier<T>; @@ -48,11 +48,11 @@ export class Optional<t, T extends NonNullable<t> = NonNullable<t>> extends _Tag } public get(): T { - if (isNone(this.self)) throw new IOptionalEmptyError('empty value'); + if (isNone(this.self)) throw new IOptionalEmptyError('called get() on None optional'); return this.self.value; } - public filter(mapper: Mapper<T, boolean>): IOptional<T> { + public filter(mapper: Predicate<T>): IOptional<T> { if (isNone(this.self) || !mapper(this.self.value)) return Optional.none(); return Optional.some(this.self.value); } |