/** * FnEither is also known as ReaderEither. In essence a FnEither is * a function that returns an either. This pattern can be used as * a validation, a failable computation, a computation resulting * in a "Choice", and many other things. * * @module FnEither */ import "./_dnt.polyfills.js"; import type { In, Kind, Out } from "./kind.js"; import type { Applicable } from "./applicable.js"; import type { Bimappable } from "./bimappable.js"; import type { Combinable } from "./combinable.js"; import type { Composable } from "./composable.js"; import type { Either } from "./either.js"; import type { Failable } from "./failable.js"; import type { Flatmappable } from "./flatmappable.js"; import type { Fn } from "./fn.js"; import type { Mappable } from "./mappable.js"; import type { Predicate } from "./predicate.js"; import type { Premappable } from "./premappable.js"; import type { Refinement } from "./refinement.js"; import type { Wrappable } from "./wrappable.js"; /** * A FnEither, also known as ReaderEither, is a type over a variadic * javascript function that returns an Either. * ie. (a: number, b: string) => Either can be * a FnEither. As an algebraic data type, the associated type class * instances for Fn are limited to single variable inputs so they will * look like (a: number) => Either, with only one * argument. The purposes of a FnEither are many and varied, some * common purposes are: failable computation, reading values from a * shared environment, and sub-computations in a modified * environment. * * Currently, there is no implementation of Chain recursion or * trampolining for FnEIther implemented, but it is likely to be a future * feature. Once implemented Fn will gain some much needed stack safety. * * @since 2.0.0 */ export type FnEither = Fn>; /** * A FnEither type over any, useful for constraining generics that * take or return FnEithers. * * @since 2.0.0 */ export type AnyFnEither = FnEither; /** * Specifies FnEither as a Higher Kinded Type, with * covariant parameter A and B corresponding to the 0th * and 1st indices of any Substitutions and a contravariant * parameter D corresponding to the 0th index of * any Substititions. The FnEither KindFnEither is unique in that * it constrains the FnEither type to taking a single * argument for the purposes of type substitution * while the implementations of FnEither combinators such * as map, flatmap, etc are mostly variadic (multiple * arguments). * * @since 2.0.0 */ export interface KindFnEither extends Kind { readonly kind: FnEither, Out, Out>; } /** * Specifies FnEither as a Higher Kinded Type, with * covariant parameter A corresponding to the 0th * index of any Substitutions and a contravariant * parameter D corresponding to the 0th index of * any Substititions. KindRightFnEither curries the Left parameter * of the output Either. This is useful when one * needs to Fix the Left output with a Combinable or * some other collection algebraic structure. * * @since 2.0.0 */ export interface KindRightFnEither extends Kind { readonly kind: FnEither, B, Out>; } /** * Wrap any function in a try catch block. The returned * function will lazily call and handle any throwing of * the wrapped function. Non-throwing calls will be * returned in a Right, and throwing calls will have * their error and arguments passed to the onThrow function * before being returned in a Left. * * @example * ```ts * import { tryCatch } from "./fn_either.ts"; * import { todo } from "./fn.ts"; * * const throws = tryCatch(todo, () => "Failed!"); * const returns = tryCatch((n: number) => n, () => "Failed!"); * * const result1 = throws()(0); // Left("Failed!"); * const result2 = returns(1)(0); // Right(1); * ``` * * @since 2.0.0 */ export declare function tryCatch(ua: (...d: D) => A, onThrow: (e: unknown, d: D) => B): (...d: D) => FnEither; /** * Create a FnEither that always returns a Left(B). * * @example * ```ts * import { left } from "./fn_either.ts"; * * const leftNumber = left(1); * * const result = leftNumber(0); // Left(1); * ``` * * @since 2.0.0 */ export declare function left(left: B): FnEither; /** * Create a FnEither that always returns a Right(A). * * @example * ```ts * import { right } from "./fn_either.ts"; * * const rightNumber = right(1); * * const result = rightNumber(null); // Right(1); * ``` * * @since 2.0.0 */ export declare function right(right: A): FnEither; /** * Turn an Either into a FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import * as E from "./either.ts"; * * const left = E.left(1); * const right = E.right(1); * * const fnLeft = FE.fromEither(left); * const fnRight = FE.fromEither(right); * * const result1 = fnLeft(null); // Left(1); * const result2 = fnRight(null); // Right(1); * ``` * * @since 2.0.0 */ export declare function fromEither(ua: Either): FnEither; /** * Lift a Fn into FnEither<[D], never, A> * * @example * ```ts * import { fromFn } from "./fn_either.ts"; * * const double = (first: number) => first + first; * const lifted = fromFn(double); * * const result = lifted(1); // Right(2) * ``` * * @since 2.0.0 */ export declare function fromFn(fda: Fn): FnEither; /** * Create a FnEither from a Predicate or a Refinement. * If the Predicate or Refinement returns true then the * FnEither returns Right, otherwise it returns Left. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const isPositive = (n: number) => n > 0; * const computation = FE.fromPredicate(isPositive); * * const result1 = computation(0); // Left(0) * const result2 = computation(1); // Right(1) * ``` * * @since 2.0.0 */ export declare function fromPredicate(refinement: Refinement): FnEither; export declare function fromPredicate(predicate: Predicate): FnEither; /** * An alias for right. Creates a FnEither from a value. The created * FnEither does not require any arguments, but can widen when used * in a flatmap. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const computation = pipe( * FE.id(), // Ask for a number * FE.map(n => n + 1), // Add one * FE.flatmap(_ => FE.wrap("Hello")), // Forget about the number * ); * * const result = computation(1); // Right("Hello") * ``` * * @since 2.0.0 */ export declare function wrap(a: A): FnEither; /** * @since 2.0.0 */ export declare function fail(b: B): FnEither; /** * Given a FnEither returning a function A => I and a FnEither returning * a value A, combine them into a FnEither returning an I. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * type Person = { name: string; age: number }; * * const person = (name: string) => (age: number): Person => ({ name, age }); * * const result = pipe( * FE.wrap(person), * FE.apply(FE.wrap("Brandon")), * FE.apply(FE.wrap(37)), * ); // FnEither<[], never, Person> * ``` * * @since 2.0.0 */ export declare function apply(ua: FnEither): (ufai: FnEither I>) => FnEither; /** * Provide an alternative FnEither in the event that an original * FnEither returns Left. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const result = pipe( * FE.left("Oh no I broke!"), * FE.alt(FE.right("But I work")), * )(null); // Right("But I work") * ``` * * @since 2.0.0 */ export declare function alt(ub: FnEither): (ua: FnEither) => FnEither; /** * Map over the left and right return values of a FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import * as E from "./either.ts"; * import { pipe } from "./fn.ts"; * * const boundedValue = (n: number) => n > 10 || n < 0 ? E.left(n) : E.right(n); * * const log = pipe( * boundedValue, * FE.bimap(n => `Out of bounds: ${n}`, n => `Received a good value: ${n}`), * ); * * const result1 = log(1); // Right("Received a good value: 1") * const result2 = log(20); // Left("Out of bounds: 20") * ``` * * @since 2.0.0 */ export declare function bimap(fbj: (b: B) => J, fai: (a: A) => I): (ua: FnEither) => FnEither; /** * Map over the right return value of a FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const result = pipe( * FE.id(), * FE.map(n => n + 1), * )(0); // Right(1) * ``` * * @since 2.0.0 */ export declare function map(fai: (a: A) => I): (ua: FnEither) => FnEither; /** * Map over the left return value of a FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const result1 = pipe( * FE.id(), * FE.mapSecond((n: number) => n + 1), * )(0); // Right(0) * * const result2 = pipe( * FE.idLeft(), * FE.mapSecond(n => n + 1), * )(0); // Left(1) * ``` * * @since 2.0.0 */ export declare function mapSecond(fbj: (b: B) => J): (ua: FnEither) => FnEither; /** * Flatten nested FnEithers with the same input and * left types. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const result = pipe( * FE.right(FE.right(1)), * FE.join, * )(null); // Right(1) * ``` * * @since 2.0.0 */ export declare function join(tua: FnEither>): FnEither; /** * Chain the right result of one FnEither into another * FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const result = pipe( * FE.id(), * FE.flatmap(s => FE.right(s.length)), * )("Hello"); // Right(5) * ``` * * @since 2.0.0 */ export declare function flatmap(fati: (a: A) => FnEither): (ua: FnEither) => FnEither; /** * Chain the left result of one FnEither into another * FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const result = pipe( * FE.id(), * FE.flatmap(s => FE.left(s.length)), * FE.recover(n => FE.right(String(n))), * )("Hello"); // Right("5") * ``` * * @since 2.0.0 */ export declare function recover(fbtj: (b: B) => FnEither): (ua: FnEither) => FnEither; /** * Map over the input value of a FnEither. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * // This has type FnEither<[Date], never, number> * const computation = pipe( * FE.id(), * FE.premap((d: Date) => d.valueOf()), * ); * * const result = computation(new Date(0)); // Right(0) * ``` * * @since 2.0.0 */ export declare function premap(fld: (l: L) => D): (ua: FnEither) => FnEither; /** * Map over the input of a FnEither contravariantly and the * right result of a FnEither covariantly. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * // This has type FnEither<[Date], never, string> * const computation = pipe( * FE.id(), * FE.dimap( * (d: Date) => d.valueOf(), * String, * ), * ); * * const result = computation(new Date(0)); // Right('0') * ``` * * @since 2.0.0 */ export declare function dimap(fld: (l: L) => D, fai: (a: A) => I): (ua: FnEither) => FnEither; /** * Perform the same function as Reader ask. Given a type A * (and optionally a type B), return a FnEither<[A], B, A>. * This is useful for starting a FnEither flatmap. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const computation = FE.id(); * * const result1 = computation(1); // Right(1); * const result2 = computation(2); // Right(2); * ``` * * @since 2.0.0 */ export declare function id(): FnEither; /** * Perform the same function as Reader askLeft. Given a type B * (and optionally a type A), return a FnEither<[B], B, A>. * This is useful for starting a FnEither flatmap with a left value. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const computation = FE.idLeft(); * * const result1 = computation(1); // Left(1); * const result2 = computation(2); // Left(2); * ``` * * @since 2.0.0 */ export declare function idLeft(): FnEither; /** * Compose two FnEithers, passing the right value of the first * into the second. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { pipe } from "./fn.ts"; * * const isPositive = (n: number) => n > 0; * const isInteger = (n: number) => Number.isInteger(n); * * const isPositiveInteger = pipe( * FE.fromPredicate(isPositive), * FE.compose(FE.fromPredicate(isInteger)), * ); * * const result1 = isPositiveInteger(0); // Left(0) * const result2 = isPositiveInteger(1); // Right(1) * const result3 = isPositiveInteger(1.1); // Left(1.1) * ``` * * @since 2.0.0 */ export declare function compose(second: FnEither): (first: FnEither) => FnEither; /** * Create a Flatmappable for FnEither where left values are combined using the * supplied Combinable. * * @example * ```ts * import * as FE from "./fn_either.ts"; * import { InitializableNumberSum } from "./number.ts"; * import { pipe } from "./fn.ts"; * * const { apply } = FE.getRightFlatmappable(InitializableNumberSum); * * const result1 = pipe( * FE.left(1), * apply(FE.left(1)), * ); // Left(2) * ``` * * @since 2.0.0 */ export declare function getRightFlatmappable({ combine }: Combinable): Flatmappable>; /** * @since 2.0.0 */ export declare const ApplicableFnEither: Applicable; /** * The canonical implementation of Bimappable for FnEither. It contains * the methods bimap and mapSecond. * * @since 2.0.0 */ export declare const BimappableFnEither: Bimappable; /** * @since 2.0.0 */ export declare const ComposableFnEither: Composable; /** * The canonical implementation of Flatmappable for FnEither. It contains * the methods wrap, apply, map, and flatmap. * * @since 2.0.0 */ export declare const FlatmappableFnEither: Flatmappable; /** * @since 2.0.0 */ export declare const FailableFnEither: Failable; /** * @since 2.0.0 */ export declare const MappableFnEither: Mappable; /** * The canonical implementation of Premappable for FnEither. It contains * the method premap. * * @since 2.0.0 */ export declare const PremappableFnEither: Premappable; /** * @since 2.0.0 */ export declare const WrappableFnEither: Wrappable; /** * @since 2.0.0 */ export declare const tap: (fn: (value: A) => void) => (ua: FnEither) => FnEither; /** * @since 2.0.0 */ export declare const bind: (name: Exclude, faui: (a: A) => FnEither) => (ua: FnEither) => FnEither; /** * @since 2.0.0 */ export declare const bindTo: (name: N) => (ua: FnEither) => FnEither;