import { identity } from './function' import * as HKT from './HKT' export interface Bifunctor extends HKT.Base { readonly bimap_: BimapFn_ readonly bimap: BimapFn readonly mapLeft_: MapLeftFn_ readonly mapLeft: MapLeftFn readonly mapRight_: MapRightFn_ readonly mapRight: MapRightFn } export type BifunctorMin = | { readonly mapLeft_: MapLeftFn_, readonly mapRight_: MapRightFn_ } | { readonly bimap_: BimapFn_ } | { readonly mapLeft_: MapLeftFn_, readonly mapRight_: MapRightFn_, readonly bimap_: BimapFn_ } export function Bifunctor(F: BifunctorMin): Bifunctor { let mapLeft_: MapLeftFn_ let mapRight_: MapRightFn_ let bimap_: BimapFn_ if ('mapLeft_' in F && 'mapRight_' in F && 'bimap_' in F) { mapLeft_ = F.mapLeft_ mapRight_ = F.mapRight_ bimap_ = F.bimap_ } if ('mapLeft_' in F && 'mapRight_' in F) { mapLeft_ = F.mapLeft_ mapRight_ = F.mapRight_ bimap_ = (fea, f, g) => F.mapRight_(F.mapLeft_(fea, f), g) } else { mapLeft_ = (fea, f) => F.bimap_(fea, f, identity) mapRight_ = (fa, f) => F.bimap_(fa, identity, f) bimap_ = F.bimap_ } return HKT.instance>({ mapLeft_, mapLeft: (f) => (fea) => mapLeft_(fea, f), mapRight_, mapRight: (f) => (fea) => mapRight_(fea, f), bimap_, bimap: (f, g) => (fea) => bimap_(fea, f, g) }) } export interface BimapFn { (f: (e: E) => H, g: (a: A) => B): ( fea: HKT.Kind ) => HKT.Kind } export interface BimapFn_ { ( fea: HKT.Kind, f: (e: E) => H, g: (a: A) => B ): HKT.Kind } export interface MapLeftFn { (f: (e: E) => H): ( fea: HKT.Kind ) => HKT.Kind } export interface MapLeftFn_ { ( fea: HKT.Kind, f: (e: E) => H ): HKT.Kind } export interface MapRightFn { (f: (a: A) => B): ( fea: HKT.Kind ) => HKT.Kind } export interface MapRightFn_ { ( fea: HKT.Kind, f: (a: A) => B ): HKT.Kind }