// ets_tracing: off import { pipe, tuple } from "../../Function/index.js" import type { EnforceNonEmptyRecord } from "../../Utils/index.js" import type { Apply } from "../Apply/index.js" import type * as HKT from "../HKT/index.js" export function apF( F: Apply ): ( fa: HKT.Kind ) => ( fab: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, (a: A) => B > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, B > export function apF( F: Apply> ): (fa: HKT.HKT) => (fab: HKT.HKT B>) => HKT.HKT { return (fa) => (fab) => pipe( F.both(fab)(fa), F.map(({ tuple: [a, f] }) => f(a)) ) } function curried(f: Function, n: number, acc: ReadonlyArray) { return function (x: unknown) { const combined = acc.concat([x]) // eslint-disable-next-line prefer-spread return n === 0 ? f.apply(null, combined) : curried(f, n - 1, combined) } } function getRecordConstructor(keys: ReadonlyArray) { const len = keys.length return curried( (...args: ReadonlyArray) => { const r: Record = {} for (let i = 0; i < len; i++) { r[keys[i]!] = args[i] } return r }, len - 1, [] ) } export function structF( F: Apply ): < NER extends Record< string, HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, unknown > >, K = HKT.Initial, Q = HKT.Initial, W = HKT.Initial, X = HKT.Initial, I = HKT.Initial, S = HKT.Initial, R = HKT.Initial, E = HKT.Initial >( r: EnforceNonEmptyRecord & Record< string, HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, unknown > > ) => HKT.Kind< F, C, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, { [K in keyof NER]: HKT.Infer } > export function structF( F: Apply> ): (r: Record>) => HKT.HKT> { const ap = apF(F) return (r) => { const keys = Object.keys(r) const len = keys.length const f = getRecordConstructor(keys) let fr = F.map(f)(r[keys[0]!]!) for (let i = 1; i < len; i++) { fr = ap(r[keys[i]!]!)(fr) } return fr } } const tupleConstructors: Record unknown> = {} function getTupleConstructor(len: number): (a: unknown) => any { // eslint-disable-next-line no-prototype-builtins if (!tupleConstructors.hasOwnProperty(len)) { tupleConstructors[len] = curried(tuple, len - 1, []) } return tupleConstructors[len]! } export function tupleF( F: Apply ): < T extends Array< HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, unknown > >, K = HKT.Initial, Q = HKT.Initial, W = HKT.Initial, X = HKT.Initial, I = HKT.Initial, S = HKT.Initial, R = HKT.Initial, E = HKT.Initial >( ...t: T & { readonly 0: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, unknown > } ) => HKT.Kind< F, C, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, { [K in keyof T]: [T[K]] extends [ HKT.Kind ] ? A : never } > export function tupleF(F: Apply>): any { const ap = apF(F) return (...args: Array>) => { const len = args.length const f = getTupleConstructor(len) let fas = F.map(f)(args[0]!) for (let i = 1; i < len; i++) { fas = ap(args[i]!)(fas) } return fas } }