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; /** * {@link Lazied} version of {@link Monoid}. */ export type MonoidL = Lazied; /** * Type class constraints for type class {@link Monoid}. */ export interface TypeClass$$Monoid { /** * 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 { * value: S; * } * * declare module "rivo/typeclass/Monoid" { * interface MonoidImpl { * StringHolder: ImplMonoidFor; * // ^^^^^^^^^^^^ * // Can be any property key * } * } * * interface StringHolder$$Monoid extends TypeClass$$Monoid { * Empty: StringHolder<"">; * } * ``` */ export type ImplMonoidFor> = [ 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 { * value: T; * } * interface BoxedL extends Boxed> {} * * declare module "rivo/typeclass/Monoid" { * interface MonoidImpl { * Boxed: ImplMonoidForGeneric, Boxed$$Monoid$$Relaxer, Boxed$$Monoid$$Builder>; * // ^^^^^^^^^^^^^^^ * // Lazied version of `Boxed` instead of `Boxed` to avoid circular reference error * } * } * * // Used to relax the type of `Monoid` instance to its construct, e.g. `Boxed<42>` -> `Boxed`, * // `Boxed>` -> `Boxed>`, etc. * interface Boxed$$Monoid$$Relaxer extends Fn<[Boxed], Boxed>> { * def: ([m]: Args) => Boxed>; * } * * // Used to build type class instance for `Monoid` instance, e.g. `Boxed<42>` -> `Boxed$$Monoid`, * // `Boxed>` -> `Boxed$$Monoid>`, etc. * interface Boxed$$Monoid$$Builder extends Fn<[Boxed>], Boxed$$Monoid>> { * def: ([mCons]: Args) => Boxed$$Monoid<(typeof mCons)["value"]>; * } * * interface Boxed$$Monoid> extends TypeClass$$Monoid> { * Empty: Boxed["Monoid"]>; * } * * type R = Boxed$$Monoid; * // ^?: Boxed<""> * ``` */ export type ImplMonoidForGeneric< T extends Semigroup, Relaxer extends Fn1, TypeClassBuilder extends Fn1>, > = [T, Relaxer, TypeClassBuilder]; /** * Get the matching entry of {@link MonoidImpl} for `M`. * @private */ type _Monoid$GetMatch = 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 * type R3 = Monoid$GetConstruct<[["foo", "bar"], ["baz"]]>; * // ^?: List> * ``` */ export type Monoid$GetConstruct = Eq extends true ? Monoid : _Monoid$GetMatch extends [infer T, unknown] ? T : _Monoid$GetMatch extends [unknown, infer Relaxer extends Fn1, unknown] ? Call1 : never; /** * The **unsafe** version of {@link Monoid$GetConstruct} (i.e. no type checking with `M`). */ export type Monoid$GetConstructW = M extends Monoid ? Monoid$GetConstruct : 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 * type R3 = Monoid$GetTypeClass<[["foo", "bar"], ["baz"]]>; * // ^?: List$$Monoid> * ``` */ export type Monoid$GetTypeClass = ( _Monoid$GetMatch extends [unknown, infer TypeClass] ? TypeClass : _Monoid$GetMatch extends ( [unknown, infer Relaxer extends Fn1, infer TypeClassBuilder] ) ? Call1W> : 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 extends Monoid ? Monoid$GetTypeClass : never; /*********** * Methods * ***********/ /** * Methods for `Monoid`. */ export namespace Monoid {}