type F = (v: L) => L; export type L = T & { run: () => T }; const defer: (run: () => T) => L = (run: () => T) => Object.assign(((p: Parameters[0]): ReturnType => { let v: F; return defer(() => run()(defer(() => v ??= p.run())).run()); }) as T, { run }); export const _ = (v: T): L => defer(() => v); export const fromNative: (v: T) => L = v => defer(() => v as any); export const toNative: (v: L) => T = (v: L) => v.run() as T; export const y = (f: () => L) => defer(() => f().run()); export const undef: any = defer(() => { throw new Error('undefined'); }); export const id: L<(v: T) => T> = _(v => v); export const cnst: L<(v: T) => L<(_: unknown) => T>> = _(v => _(_ => v)) as L<(v: T) => L<(_: unknown) => T>>; export const pipe: L<(f: L<(v: B) => C>) => L<(g: L<(v: A) => B>) => L<(v: A) => C>>> = _((f: L<(v: B) => C>) => _((g: L<(v: A) => B>) => _((v: A) => f(g(v)))));