type DyadicOp = { op: string; a: Op; b: Op } type MonadicOp = { op: string; a: Op } export type Op = string | MonadicOp | DyadicOp; export type OpToStr = O extends string ? O : O extends { op: string, a: infer a extends string, b: infer b extends string } ? `(${a} ${O['op']} ${b})` : O extends { op: string, a: infer a extends DyadicOp | MonadicOp, b: infer b extends string } ? `(${OpToStr} ${O['op']} ${b})` : O extends { op: string, a: infer a extends string, b: infer b extends DyadicOp | MonadicOp } ? `(${a} ${O['op']} ${OpToStr})` : O extends { op: string, a: infer a extends DyadicOp | MonadicOp, b: infer b extends DyadicOp | MonadicOp } ? `(${OpToStr} ${O['op']} ${OpToStr})` : O extends { op: string, a: infer a extends string } ? `${O['op']}(${a})` : O extends { op: string, a: infer a extends DyadicOp } ? `${O['op']}(${OpToStr})` : never; type RwType = 'rewrite' | 'imperative'; export interface RewriteBase { type: RwType; left: Op; right: Op; assume?: Record; } export interface Rewrite extends RewriteBase { type: Typ; left: left; right: right; }; export type Sym = Rewrite; export type Subst = Rewrite export type SubstEq> = Rewrite export type ApplyRewrite = R['type'] extends 'imperative' ? (R & { left: O })['right'] : O extends R['left'] ? R['right'] : O extends string ? O : O extends DyadicOp ? ( ApplyRewrite extends O['a'] ? (ApplyRewrite extends O['b'] ? O : Omit & { b: ApplyRewrite }) : Omit & { a: ApplyRewrite } ) : O extends MonadicOp ? ( ApplyRewrite extends O['a'] ? O : Omit & { a: ApplyRewrite } ) : never; export type ChainRewrites = Rws extends [] ? O : Rws extends [infer R extends RewriteBase, ...infer Rs extends RewriteBase[]] ? ChainRewrites> : never; export type VerifyEquation = Eq['right'] extends 'true' ? true : false & Eq['right']; export type Evaluate = ApplyRewrite; export type assert = T; export type assertFalse = T; export type Eq = ([a] extends [b] ? ([b] extends [a] ? true : false & { lhs: a; rhs: b }) : false & { lhs: a; rhs: b }); export type Equation = { op: '=', a: A, b: B }; export interface Refl extends RewriteBase { type: 'imperative'; left: Op; right: this['left'] extends { op: '=', a: infer a, b: infer b } ? (Eq extends true ? 'true' : this['left']) : this['left']; }; // Like Refl, but you have to specify the sides of the equation and this one works recursively export type ReflR = Rewrite, 'true'>;