/** * @since 0.24.0 */ import { dual, identity, SK } from "effect/Function" import type { Kind, TypeLambda } from "effect/HKT" import type { Covariant } from "./Covariant.js" import type { Semigroup } from "./Semigroup.js" import * as semigroup from "./Semigroup.js" import type { SemiProduct } from "./SemiProduct.js" /** * @category type class * @since 0.24.0 */ export interface SemiApplicative extends SemiProduct, Covariant {} /** * Lift a `Semigroup` into 'F', the inner values are combined using the provided `Semigroup`. * * @category lifting * @since 0.24.0 */ export const getSemigroup = (F: SemiApplicative) => (S: Semigroup): Semigroup> => semigroup.make( (self, that) => F.map(F.product(self, that), ([a1, a2]) => S.combine(a1, a2)), (self, collection) => F.map(F.productMany(self, collection), ([head, ...tail]) => S.combineMany(head, tail)) ) /** * Zips two `F` values together using a provided function, returning a new `F` of the result. * * @since 0.24.0 */ export const zipWith = (F: SemiApplicative): { ( that: Kind, f: (a: A, b: B) => C ): (self: Kind) => Kind ( self: Kind, that: Kind, f: (a: A, b: B) => C ): Kind } => dual( 3, ( self: Kind, that: Kind, f: (a: A, b: B) => C ): Kind => F.map(F.product(self, that), ([a, b]) => f(a, b)) ) /** * @since 0.24.0 */ export const ap = (F: SemiApplicative): { ( that: Kind ): ( self: Kind B> ) => Kind ( self: Kind B>, that: Kind ): Kind } => dual(2, ( self: Kind B>, that: Kind ): Kind => zipWith(F)(self, that, (f, a) => f(a))) /** * @since 0.24.0 */ export const zipLeft = (F: SemiApplicative): { ( that: Kind ): (self: Kind) => Kind ( self: Kind, that: Kind ): Kind } => dual(2, ( self: Kind, that: Kind ): Kind => zipWith(F)(self, that, identity)) /** * @since 0.24.0 */ export const zipRight = (F: SemiApplicative): { ( that: Kind ): (self: Kind) => Kind ( self: Kind, that: Kind ): Kind } => dual(2, ( self: Kind, that: Kind ): Kind => zipWith(F)(self, that, SK)) /** * Lifts a binary function into `F`. * * @category lifting * @since 0.24.0 */ export const lift2 = (F: SemiApplicative) => (f: (a: A, b: B) => C): { ( that: Kind ): (self: Kind) => Kind ( self: Kind, that: Kind ): Kind } => dual(2, ( self: Kind, that: Kind ): Kind => zipWith(F)(self, that, f))