import type { FunctorMin } from './Functor' import type { Option } from './Option' import type { Semigroup } from './Semigroup' import type { These } from './These' import { identity } from './function' import { Functor } from './Functor' import * as HKT from './HKT' import * as O from './Option' import * as T from './These' import { tuple } from './tuple' export interface Semialign extends Functor { readonly alignWith_: AlignWithFn_ readonly alignWith: AlignWithFn readonly align_: AlignFn_ readonly align: AlignFn readonly alignCombine_: AlignCombineFn_ readonly alignCombine: AlignCombineFn readonly padZip_: PadZipFn_ readonly padZip: PadZipFn readonly padZipWith_: PadZipWithFn_ readonly padZipWith: PadZipWithFn readonly zipAll_: ZipAllFn_ readonly zipAll: ZipAllFn } export type SemialignMin = ( | { readonly alignWith_: AlignWithFn_ } | { readonly align_: AlignFn_ } ) & FunctorMin export function Semialign(F: SemialignMin): Semialign { const alignCombine_ = alignCombineF_(F) const padZip_ = padZipF_(F) const padZipWith_ = padZipWithF_(F) const zipAll_ = zipAllF_(F) if ('alignWith_' in F) { const align_: Semialign['align_'] = (fa, fb) => F.alignWith_(fa, fb, identity) return HKT.instance>({ ...Functor(F), alignWith_: F.alignWith_, alignWith: (fb, f) => (fa) => F.alignWith_(fa, fb, f), align_, align: (fb) => (fa) => align_(fa, fb), alignCombine_, alignCombine: (S) => (fb) => (fa) => alignCombine_(S)(fa, fb), padZip_, padZip: (fb) => (fa) => padZip_(fa, fb), padZipWith_, padZipWith: (fb, f) => (fa) => padZipWith_(fa, fb, f), zipAll_, zipAll: (fb, a, b) => (fa) => zipAll_(fa, fb, a, b) }) } else { const alignWith_: Semialign['alignWith_'] = (fa, fb, f) => F.map_(F.align_(fa, fb), f) return HKT.instance>({ ...Functor(F), alignWith_, alignWith: (fb, f) => (fa) => alignWith_(fa, fb, f), align_: F.align_, align: (fb) => (fa) => F.align_(fa, fb), alignCombine_, alignCombine: (S) => (fb) => (fa) => alignCombine_(S)(fa, fb), padZip_, padZip: (fb) => (fa) => padZip_(fa, fb), padZipWith_, padZipWith: (fb, f) => (fa) => padZipWith_(fa, fb, f), zipAll_, zipAll: (fb, a, b) => (fa) => zipAll_(fa, fb, a, b) }) } } export interface AlignFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B > ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, These > } export interface AlignFn { (fb: HKT.Kind): < N extends string, K, Q, W, X, I, S, R, E, A >( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, These > } export interface AlignWithFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, TC, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B >, f: (th: These) => C ): HKT.Kind< F, TC, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, C > } export interface AlignWithFn { ( fb: HKT.Kind, f: (th: These) => C ): ( fa: HKT.Kind< F, TC, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, TC, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, C > } export function alignWithF_(F: SemialignMin): AlignWithFn_ { if ('alignWith_' in F) { return F.alignWith_ } else { return (fa, fb, f) => F.map_(F.align_(fa, fb), f) } } export interface AlignCombineFn_ { (S: Semigroup): ( fa1: HKT.Kind, fa2: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A > } export interface AlignCombineFn { (S: Semigroup): ( fb: HKT.Kind ) => ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, A > } export function alignCombineF_(F: SemialignMin): AlignCombineFn_ { const alignWith_ = alignWithF_(F) return (S) => (fa1, fa2) => alignWith_(fa1, fa2, T.match(identity, identity, S.combine_)) } export function alignCombineF(F: SemialignMin): AlignCombineFn { return (S) => (fb) => (fa) => alignCombineF_(F)(S)(fa, fb) } export interface PadZipFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B > ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, readonly [Option, Option] > } export interface PadZipFn { (fb: HKT.Kind): < N extends string, K, Q, W, X, I, S, R, E, A >( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, readonly [Option, Option] > } export function padZipF_(F: SemialignMin): PadZipFn_ { const padZipWith_ = padZipWithF_(F) return (fa, fb) => padZipWith_(fa, fb, identity) } export function padZipF(F: SemialignMin): PadZipFn { return (fb) => (fa) => padZipF_(F)(fa, fb) } export interface PadZipWithFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B >, f: (_: readonly [Option, Option]) => D ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, D > } export interface PadZipWithFn { ( fb: HKT.Kind, f: (_: readonly [Option, Option]) => D ): ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, D > } export function padZipWithF_(F: SemialignMin): PadZipWithFn_ { const alignWith_ = alignWithF_(F) return (fa, fb, f) => alignWith_( fa, fb, T.match( (a) => f([O.Some(a), O.None()]), (b) => f([O.None(), O.Some(b)]), (a, b) => f([O.Some(a), O.Some(b)]) ) ) } export function padZipWithF(F: SemialignMin): PadZipWithFn { return (fb, f) => (fa) => padZipWithF_(F)(fa, fb, f) } export interface ZipAllFn_ { ( fa: HKT.Kind, fb: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, B >, a: A, b: B ): HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, readonly [A, B] > } export interface ZipAllFn { ( fb: HKT.Kind, a: A, b: B ): ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, readonly [A, B] > } export function zipAllF_(F: SemialignMin): ZipAllFn_ { const alignWith_ = alignWithF_(F) return (fa, fb, a, b) => alignWith_( fa, fb, T.match( (x) => [x, b], (x) => [a, x], tuple ) ) } export function zipAllF(F: SemialignMin): ZipAllFn { return (fb, a, b) => (fa) => zipAllF_(F)(fa, fb, a, b) }