rivo
Version:
🤖 The ultimate library you need for composable type-level programming in TypeScript, powered by HKT.
174 lines (165 loc) • 5.28 kB
TypeScript
import type { Call1, Call1W, Fn1 } from "../../HKT";
import type { ValueOf } from "../../Obj/ValueOf";
import type { Eq, Lazied, Lazied$Get } from "../../helpers";
import type { Semigroup } from "../Semigroup";
/**
* A type class for types that can be compared.
*/
export type Monoid = Lazied$Get<MonoidL>;
/**
* {@link Lazied} version of {@link Monoid}.
*/
export type MonoidL = Lazied<MonoidImpl[keyof MonoidImpl][0]>;
/**
* Type class constraints for type class {@link Monoid}.
*/
export interface TypeClass$$Monoid<T extends Semigroup> {
/**
* The empty value for the {@link Monoid} instance.
*/
Empty: T;
}
/**
* Implementations for type class {@link Monoid}.
*/
export interface MonoidImpl {}
/**
* Helper type for implementing type class {@link Monoid}.
*
* @example
* ```typescript
* import type { Args, Fn, Monoid } from "rivo";
* import type { TypeClass$$Monoid } from "rivo/typeclass";
*
* interface StringHolder<S extends string = string> {
* value: S;
* }
*
* declare module "rivo/typeclass/Monoid" {
* interface MonoidImpl {
* StringHolder: ImplMonoidFor<StringHolder, MyType$$Monoid>;
* // ^^^^^^^^^^^^
* // Can be any property key
* }
* }
*
* interface StringHolder$$Monoid extends TypeClass$$Monoid<StringHolder> {
* Empty: StringHolder<"">;
* }
* ```
*/
export type ImplMonoidFor<T extends Semigroup, TypeClass extends TypeClass$$Monoid<T>> = [
T,
TypeClass,
];
/**
* Helper type for implementing type class {@link Monoid} for generic types.
*
* @example
* ```typescript
* import type { Args, Cons, Fn, Lazied, Lazied$Get, Monoid, MonoidL } from "rivo";
* import type { Monoid$GetConstruct, Monoid$GetTypeClass, TypeClass$$Monoid } from "rivo/typeclass";
*
* interface Boxed<T> {
* value: T;
* }
* interface BoxedL<L extends Lazied> extends Boxed<Lazied$Get<L>> {}
*
* declare module "rivo/typeclass/Monoid" {
* interface MonoidImpl {
* Boxed: ImplMonoidForGeneric<BoxedL<MonoidL>, Boxed$$Monoid$$Relaxer, Boxed$$Monoid$$Builder>;
* // ^^^^^^^^^^^^^^^
* // Lazied version of `Boxed` instead of `Boxed<Monoid>` to avoid circular reference error
* }
* }
*
* // Used to relax the type of `Monoid` instance to its construct, e.g. `Boxed<42>` -> `Boxed<number>`,
* // `Boxed<Boxed<42>>` -> `Boxed<Boxed<number>>`, etc.
* interface Boxed$$Monoid$$Relaxer extends Fn<[Boxed<Monoid>], Boxed<Cons<Monoid>>> {
* def: ([m]: Args<this>) => Boxed<Monoid$GetConstruct<(typeof m)["value"]>>;
* }
*
* // Used to build type class instance for `Monoid` instance, e.g. `Boxed<42>` -> `Boxed$$Monoid<number>`,
* // `Boxed<Boxed<42>>` -> `Boxed$$Monoid<Boxed<number>>`, etc.
* interface Boxed$$Monoid$$Builder extends Fn<[Boxed<Cons<Monoid>>], Boxed$$Monoid<Cons<Monoid>>> {
* def: ([mCons]: Args<this>) => Boxed$$Monoid<(typeof mCons)["value"]>;
* }
*
* interface Boxed$$Monoid<M extends Cons<Monoid>> extends TypeClass$$Monoid<Boxed<M>> {
* Empty: Boxed<Monoid$GetTypeClass<M>["Monoid"]>;
* }
*
* type R = Boxed$$Monoid<string>;
* // ^?: Boxed<"">
* ```
*/
export type ImplMonoidForGeneric<
T extends Semigroup,
Relaxer extends Fn1<T, T>,
TypeClassBuilder extends Fn1<T, TypeClass$$Monoid<T>>,
> = [T, Relaxer, TypeClassBuilder];
/**
* Get the matching entry of {@link MonoidImpl} for `M`.
* @private
*/
type _Monoid$GetMatch<M extends Monoid> = ValueOf<{
[P in keyof MonoidImpl as M extends MonoidImpl[P][0] ? P : never]: MonoidImpl[P];
}>;
/**
* Get the construct of `M` from {@link MonoidImpl}.
*
* @example
* ```typescript
* type R1 = Monoid$GetConstruct<42>;
* // ^?: number
* type R2 = Monoid$GetConstruct<[42]>;
* // ^?: List<number>
* type R3 = Monoid$GetConstruct<[["foo", "bar"], ["baz"]]>;
* // ^?: List<List<string>>
* ```
*/
export type Monoid$GetConstruct<M extends Monoid> =
Eq<M, Monoid> extends true ? Monoid
: _Monoid$GetMatch<M> extends [infer T, unknown] ? T
: _Monoid$GetMatch<M> extends [unknown, infer Relaxer extends Fn1<any, any>, unknown] ?
Call1<Relaxer, M>
: never;
/**
* The **unsafe** version of {@link Monoid$GetConstruct} (i.e. no type checking with `M`).
*/
export type Monoid$GetConstructW<M> = M extends Monoid ? Monoid$GetConstruct<M> : never;
/**
* Get the type class of `M` from {@link MonoidImpl}.
*
* @example
* ```typescript
* type R1 = Monoid$GetTypeClass<42>;
* // ^?: Num$$Monoid
* type R2 = Monoid$GetTypeClass<[42]>;
* // ^?: List$$Monoid<number>
* type R3 = Monoid$GetTypeClass<[["foo", "bar"], ["baz"]]>;
* // ^?: List$$Monoid<List<string>>
* ```
*/
export type Monoid$GetTypeClass<M extends Monoid> =
(
_Monoid$GetMatch<M> extends [unknown, infer TypeClass] ? TypeClass
: _Monoid$GetMatch<M> extends (
[unknown, infer Relaxer extends Fn1<any, unknown>, infer TypeClassBuilder]
) ?
Call1W<TypeClassBuilder, Call1<Relaxer, M>>
: never
) extends infer R extends { Empty: any } ?
R
: never;
/**
* The **unsafe** version of {@link Monoid$GetTypeClass} (i.e. no type checking with `M`).
*/
export type Monoid$GetTypeClassW<M> = M extends Monoid ? Monoid$GetTypeClass<M> : never;
/***********
* Methods *
***********/
/**
* Methods for `Monoid`.
*/
export namespace Monoid {}