import type { Base, Infer, Kind, Param, URIS } from './HKT' export const pattern_: ( n: N ) => { ) => any }>( m: X, _: K ): ReturnType ) => any }, H>( m: X, _: K, __: (_: Exclude) => H ): { [k in keyof K]: ReturnType> }[keyof K] | H } = (n) => ((m: any, _: any, d: any) => { return (_[m[n]] ? _[m[n]](m) : d(m)) as any }) as any export const pattern: ( n: N ) => { ) => any }>(_: K): ( m: X ) => ReturnType ) => any }, H>( _: K, __: (_: Exclude) => H ): (m: X) => { [k in keyof K]: ReturnType> }[keyof K] | H } = (n) => ((_: any, d: any) => (m: any) => { return (_[m[n]] ? _[m[n]](m) : d(m)) as any }) as any export const matchTag_ = pattern_('_tag') export const matchTag = pattern('_tag') type InferMatcherParam< URI extends URIS, C, P extends Param | 'A', K extends Record any> > = Infer< URI, C, P, { [k in keyof K]: ReturnType }[keyof K] > type InferMatcherParamWithDefault = Infer< URI, C, P, | { [k in keyof K]: K[k] extends (...args: any) => any ? ReturnType : never }[keyof K] | Ret > export function matchers(_: Base) { function match( tag: N ): { < X extends { [tag in N]: string }, K extends { [k in X[N]]: ( _: Extract< X, { [tag in N]: k } > ) => Kind } >( matcher: K ): ( _: X ) => Kind< URI, C, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam > < X extends { [tag in N]: string }, K extends Partial< { [k in X[N]]: ( _: Extract< X, { [tag in N]: k } > ) => Kind } >, Ret extends Kind >( matcher: K, def: (_: Exclude) => Ret ): ( _: X ) => Kind< URI, C, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault > } { return (...args: any[]) => { return (_: any) => { const matcher = args[0][_[tag]] return matcher ? matcher(_) : args[1](_) } } } function matchIn( tag: N ): < X extends { [tag in N]: string } >() => { < K extends { [k in X[N]]: ( _: Extract< X, { [tag in N]: k } > ) => Kind } >( matcher: K ): ( _: X ) => Kind< URI, C, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam, InferMatcherParam > < K extends Partial< { [k in X[N]]: ( _: Extract< X, { [tag in N]: k } > ) => Kind } >, Ret extends Kind >( matcher: K, def: (_: Exclude) => Ret ): ( _: X ) => Kind< URI, C, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault, InferMatcherParamWithDefault > } { return () => (...args: any[]) => { return (_: any) => { const matcher = args[0][_[tag]] return matcher ? matcher(_) : args[1](_) } } } const matchTagIn = matchIn('_tag') const matchTag = match('_tag') return { match, matchTag, matchIn, matchTagIn } }