/** * @since 1.0.0 */ import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import type * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import * as of_ from "@fp-ts/core/typeclass/Of" import type * as pointed from "@fp-ts/core/typeclass/Pointed" import type * as product_ from "@fp-ts/core/typeclass/Product" import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import type * as traversable from "@fp-ts/core/typeclass/Traversable" /** * @category models * @since 1.0.0 */ export type Identity = A /** * @category type lambdas * @since 1.0.0 */ export interface IdentityTypeLambda extends TypeLambda { readonly type: Identity } /** * @category type lambdas * @since 1.0.0 */ export interface IdentityTypeLambdaFix extends TypeLambda { readonly type: Identity } const map: { (f: (a: A) => B): (self: Identity) => Identity (self: Identity, f: (a: A) => B): Identity } = dual(2, (self: Identity, f: (a: A) => B): Identity => f(self)) const imap = covariant.imap(map) /** * @category instances * @since 1.0.0 */ export const Covariant: covariant.Covariant = { imap, map } /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { imap } const of: (a: A) => Identity = identity /** * @category instances * @since 1.0.0 */ export const Of: of_.Of = { of } /** * @category instances * @since 1.0.0 */ export const Pointed: pointed.Pointed = { of, imap, map } const flatMap: { (f: (a: A) => B): (self: Identity) => Identity (self: Identity, f: (a: A) => B): Identity } = dual(2, (self: Identity, f: (a: A) => B): Identity => f(self)) /** * @category instances * @since 1.0.0 */ export const FlatMap: flatMap_.FlatMap = { flatMap } /** * @category instances * @since 1.0.0 */ export const Chainable: chainable.Chainable = { imap, map, flatMap } /** * @category instances * @since 1.0.0 */ export const Monad: monad.Monad = { imap, of, map, flatMap } const product = (self: Identity, that: Identity): Identity<[A, B]> => [self, that] const productMany = ( self: Identity, collection: Iterable ): [A, ...Array] => [self, ...collection] /** * @category instances * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { imap, product, productMany } /** * @category instances * @since 1.0.0 */ export const Product: product_.Product = { of, imap, product, productMany, productAll: readonlyArray.fromIterable } /** * @category instances * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, product, productMany } /** * @category instances * @since 1.0.0 */ export const Applicative: applicative.Applicative = { imap, of, map, product, productMany, productAll: readonlyArray.fromIterable } /** * @category instances * @since 1.0.0 */ export const getSemiCoproduct = ( S: Semigroup ): semiCoproduct.SemiCoproduct> => ({ imap, coproduct: dual(2, S.combine), coproductMany: dual(2, S.combineMany) }) /** * @category instances * @since 1.0.0 */ export const getSemiAlternative = ( S: Semigroup ): semiAlternative.SemiAlternative> => ({ ...getSemiCoproduct(S), map }) /** * @category instances * @since 1.0.0 */ export const Foldable: foldable.Foldable = { reduce: dual(3, (self: Identity, b: B, f: (b: B, a: A) => B): B => f(b, self)) } const traverse = ( F: applicative.Applicative ): { (f: (a: A) => Kind): (self: Identity) => Kind (self: Identity, f: (a: A) => Kind): Kind } => dual( 2, (self: Identity, f: (a: A) => Kind): Kind => f(self) ) /** * @category instances * @since 1.0.0 */ export const Traversable: traversable.Traversable = { traverse } // ------------------------------------------------------------------------------------- // do notation // ------------------------------------------------------------------------------------- /** * @category do notation * @since 1.0.0 */ export const bindTo: { (name: N): (self: Identity) => Identity<{ [K in N]: A }> (self: Identity, name: N): Identity<{ [K in N]: A }> } = invariant.bindTo(Invariant) const let_: { ( name: Exclude, f: (a: A) => B ): (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> ( self: Identity, name: Exclude, f: (a: A) => B ): Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> } = covariant.let(Covariant) export { /** * @category do notation * @since 1.0.0 */ let_ as let } /** * @category do notation * @since 1.0.0 */ export const Do: Identity<{}> = of_.Do(Of) /** * @category do notation * @since 1.0.0 */ export const bind: { ( name: Exclude, f: (a: A) => Identity ): (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> ( self: Identity, name: Exclude, f: (a: A) => Identity ): Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> } = chainable.bind(Chainable) /** * A variant of `bind` that sequentially ignores the scope. * * @category do notation * @since 1.0.0 */ export const andThenBind: { ( name: Exclude, that: Identity ): (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> ( self: Identity, name: Exclude, that: Identity ): Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> } = semiProduct.andThenBind(SemiProduct)