/** * @since 0.24.0 */ import { dual } from "effect/Function" import type { Kind, TypeLambda } from "effect/HKT" import type { Invariant } from "./Invariant.js" /** * @category type class * @since 0.24.0 */ export interface Covariant extends Invariant { readonly map: { (f: (a: A) => B): (self: Kind) => Kind (self: Kind, f: (a: A) => B): Kind } } /** * Returns a default `map` composition. * * @since 0.24.0 */ export const mapComposition = ( F: Covariant, G: Covariant ): ( self: Kind>, f: (a: A) => B ) => Kind> => (self, f) => F.map(self, G.map(f)) /** * Returns a default `imap` implementation. * * @since 0.24.0 */ export const imap = ( map: (self: Kind, f: (a: A) => B) => Kind ): Invariant["imap"] => dual(3, (self, to, _) => map(self, to)) /** * @category mapping * @since 0.24.0 */ export const flap = (F: Covariant): { (self: Kind B>): (a: A) => Kind (a: A, self: Kind B>): Kind } => dual( 2, (a: A, self: Kind B>): Kind => F.map(self, (f) => f(a)) ) /** * @category mapping * @since 0.24.0 */ export const as = (F: Covariant): { (b: B): (self: Kind) => Kind (self: Kind, b: B): Kind } => dual( 2, (self: Kind, b: B): Kind => F.map(self, () => b) ) /** * @category mapping * @since 0.24.0 */ export const asVoid = ( F: Covariant ): (self: Kind) => Kind => as(F)(undefined) const let_ = ( F: Covariant ): { ( name: Exclude, f: (a: A) => B ): ( self: Kind ) => Kind ( self: Kind, name: Exclude, f: (a: A) => B ): Kind } => dual(3, ( self: Kind, name: Exclude, f: (a: A) => B ): Kind => F.map(self, (a) => Object.assign({}, a, { [name]: f(a) }) as any)) export { /** * **Example** * * ```ts * import * as covariant from "@effect/typeclass/Covariant" * import type { HKT } from "effect" * import { dual, pipe } from "effect/Function" * * interface MyData { * readonly value: A * } * * interface MyDataTypeLambda extends HKT.TypeLambda { * readonly type: MyData * } * * const map: covariant.Covariant["map"] = dual( * 2, * (self: MyData, f: (a: A) => B): MyData => ({ value: f(self.value) }) * ) * * const Covariant: covariant.Covariant = { imap: covariant.imap(map), map } * * const notation = { * Do: { value: {} } as MyData<{}>, * let: covariant.let(Covariant) * } * * console.log(pipe(notation.Do, notation.let("foo", () => "bar"))) * // { value: { foo: "bar" } } * ``` * * @category do notation * @since 0.24.0 */ let_ as let }