Trying out the thing, and since this is ycombinator after all:
type Lazy<A> = () => A;
const lazy = <A,>(f: Lazy<A>) => {
let thunk: Lazy<A> = () => { throw null; }
thunk = () => {
const y = f();
thunk = () => y
return y;
};
return thunk;
};
const tap = <A,B>(f: Lazy<(a: Lazy<A>) => Lazy<B>>, a: Lazy<A>): Lazy<B> =>
lazy(() => f()(a)());
const ap = (f: any, a: any): any => tap<any,any>(f, a);
const y = <A,>(f : (a: Lazy<A>) => Lazy<A>): Lazy<A> => ap(((x: any) => ap(ap(f, x), x)),((x: any) => ap(ap(f,x),x)));
type Cat = {
name: string,
friend: Cat,
prefersDryFood: boolean,
foodPerWeek: number
};
export const cat = y<Cat>(self => lazy(() => ({
name: "lol",
friend: self(),
prefersDryFood: false,
foodPerWeek: 4,
})))();
Breaks typescript though. Also, the laziness won't work here.