rivo
Version:
🤖 The ultimate library you need for composable type-level programming in TypeScript, powered by HKT.
97 lines (87 loc) • 2.75 kB
TypeScript
import type ChainFn from "./Chain";
import type FlattenFn from "./Flatten";
import type { Fn1, PartialApply } from "../../HKT";
import type { ValueOf } from "../../Obj/ValueOf";
import type { Eq, Lazied, Lazied$Get } from "../../helpers";
import type { Applicative } from "../Applicative";
import type { HKT, Kind } from "../HKT";
/**
* A type class for types that can be converted to a string.
*/
export type Monad<T = unknown> = Lazied$Get<MonadL<T>>;
/**
* {@link Lazied} version of {@link Monad}.
*/
export type MonadL<T = unknown> = Lazied<Kind<MonadImpl[keyof MonadImpl][0], T>>;
/**
* Type class constraints for type class {@link Monad}.
*/
export interface TypeClass$$Monad<F extends Applicative> {
/**
* Flatten a nested structure of a {@link Monad}.
*
* **⚠️ Warning:** Correctness of the method is not fully checked, so be careful when implementing
* this method.
*
* Sig: `<F<~>, T>(f: F<F<T>>) => F<T>`
*/
Flatten: Fn1<Kind<F, F>, F>;
}
/**
* Implementations for type class {@link Monad}.
*/
export interface MonadImpl {}
/**
* Helper type for implementing type class {@link Monad}.
*/
export type ImplMonadFor<F extends Applicative, TypeClass extends TypeClass$$Monad<F>> = [
F,
TypeClass,
];
/**
* Get the matching entry of {@link MonadImpl} for `F`.
* @private
*/
type _Monad$GetMatch<F extends Monad> = ValueOf<{
[P in keyof MonadImpl as F extends MonadImpl[P][0] ? P : never]: MonadImpl[P];
}>;
/**
* Get the constructor of `F` from {@link MonadImpl}.
*/
export type Monad$GetConstruct<F extends Monad> =
Eq<F, Monad> extends true ? Monad
: _Monad$GetMatch<F> extends [infer F extends HKT, unknown] ? F
: never;
/**
* The **unsafe** version of {@link Monad$GetConstruct} (i.e. no type checking with `F`).
*/
export type Monad$GetConstructW<F> = F extends Monad ? Monad$GetConstruct<F> : never;
/**
* Get the type class of `F` from {@link MonadImpl}.
*/
export type Monad$GetTypeClass<F extends Monad> =
_Monad$GetMatch<F> extends [unknown, infer TypeClass] ? TypeClass : never;
/**
* The **unsafe** version of {@link Monad$GetTypeClass} (i.e. no type checking with `F`).
*/
export type Monad$GetTypeClassW<F> = F extends Monad ? Monad$GetTypeClass<F> : never;
/***********
* Methods *
***********/
/**
* Methods for `Monad`.
*/
export namespace Monad {
/**
* [Fn] Flatten a {@link Monad} of a {@link Monad} into a {@link Monad}.
*
* Sig: `<F<~>, T>(f: F<F<T>>) => F<T>`
*/
export type Flatten = FlattenFn;
/**
* [Fn] Map a function over a {@link Monad} and flatten the result.
*
* Sig: `<F<~>, T, U>[f: (x: T) => F<U>](fa: F<T>) => F<U>`
*/
export type Chain<F extends Fn1<never, Monad>> = PartialApply<ChainFn, [F]>;
}