export const eq = (a: T) => (b: T): boolean => a === b type TagValue = T extends Tag ? V : never export const match = >(pattern: { [key in T['tag'] | '_']?: (v: TagValue) => R }) => (tag: T): R => (pattern[tag.tag] || (pattern._ as any))(tag.value) type Tag = { tag: N; value: V } export type Union = { [N in keyof T]: Tag }[keyof T] export const constructors = >(): { [N in T['tag']]: TagValue extends null | never ? (value?: null | never) => T : (value: TagValue) => T } => new Proxy( {}, { get(_, k) { return (value: any) => ({ tag: k, value }) }, }, ) as any export const jlog = (x: any) => console.log(JSON.stringify(x, null, 2))