Skip to content

Instantly share code, notes, and snippets.

@kelly-dance
Last active April 22, 2024 22:17
Show Gist options
  • Save kelly-dance/81268f90e34374086626035a964a3c51 to your computer and use it in GitHub Desktop.
Save kelly-dance/81268f90e34374086626035a964a3c51 to your computer and use it in GitHub Desktop.
Mandlebrot thing I did ~2 years ago
// data structures
const trp = a => b => c => f => f(a)(b)(c);
const fst3 = p => p(a => b => c => a);
const snd3 = p => p(a => b => c => b);
const trd3 = p => p(a => b => c => c);
const tup = a => b => f => f(a)(b);
const fst = p => p(a => b => a);
const snd = p => p(a => b => b);
// boolean logic
const True = a => b => a;
const False = a => b => b;
const not = a => a(False)(True);
const or = a => b => a(a)(b);
const and = a => b => a(b)(a);
const xor = a => b => and(or(a)(b))(not(and(a)(b)));
const xand = a => b => not(xor(a)(b));
// y combinator
const Y = f => (y => y(y))(y => f(x => y(y)(x)));
const id = a => a;
// naturals
const zero = Y(self => trp(False)(False)(self));
const one = trp(True)(True)(zero);
const arithNext = self => a => b => co => s => and(not(co))(and(not(snd3(a)))(not(snd3(b))))(() => s(trp(s)(True)(zero))(zero))(() => trp(s)(True)(self(co)(trd3(a))(trd3(b))))()
const addCarryin = Y(self => c => a => b => arithNext(self)(a)(b)(or(and(fst3(a))(fst3(b)))(and(xor(fst3(a))(fst3(b)))(c)))(xor(c)(xor(fst3(a))(fst3(b)))))
const add = a => b => addCarryin(False)(a)(b);
const succ = a => addCarryin(True)(a)(zero);
const minusCarryin = Y(self => c => a => b => arithNext(self)(a)(b)(or(and(c)(fst3(b)))(and(or(c)(fst3(b)))(not(fst3(a)))))(and(c)(fst3(b))(fst3(a))(or(c)(fst3(b))(not(fst3(a)))(fst3(a)))))
const minus = a => b => minusCarryin(False)(a)(b);
const pred = a => minusCarryin(True)(a)(zero);
const mul2 = a => trp(False)(True)(a);
const div2 = trd3;
const repAp = Y(self => f => c => v => snd3(c)(() => self(f)(trd3(c))(self(f)(trd3(c))(fst3(c)(f)(id)(v))))(() => v)());
const mult = Y(self => a => b => add(fst3(a)(b)(zero))(snd3(a)(() => mul2(self(trd3(a))(b)))(() => zero)()));
const pow = a => p => repAp(mult(a))(p)(one);
const compare = Y(self => a => b => and(not(snd3(a)))(not(snd3(b)))(() => snd3)(() => self(trd3(a))(trd3(b))(trp(() => fst3)(() => xand(fst3(a))(fst3(b))(() => snd3)(() => and(fst3(a))(not(fst3(b)))(fst3)(trd3))())(() => trd3))())());
const eq = a => b => compare(a)(b)(trp(False)(True)(False));
const lt = a => b => compare(a)(b)(trp(False)(False)(True));
const lte = a => b => compare(a)(b)(trp(False)(True)(True));
const gt = a => b => compare(a)(b)(trp(True)(False)(False));
const gte = a => b => compare(a)(b)(trp(True)(True)(False));
const isz = a => eq(zero)(a);
const slowdivmod = Y(self => a => b => lt(a)(b)(() => tup(zero)(a))(() => (r => tup(succ(fst(r)))(snd(r)))(self(minus(a)(b))(b)))());
const divmod = Y(self => a => b => lt(a)(b)(() => tup(zero)(a))(() => (r => (r2 => tup(add(mul2(mul2(mul2(fst(r)))))(fst(r2)))(snd(r2)))(slowdivmod(snd(r))(b)))(self(a)(mul2(mul2(mul2(b))))))());
const div = a => b => fst(divmod(a)(b));
// Z Operations
const NtoZ = n => tup(False)(n);
const zeroZ = NtoZ(zero);
const succZ = z => isz(snd(z))(() => tup(False)(succ(zero)))(() => tup(fst(z))(fst(z)(pred)(succ)(snd(z))))();
const negate = z => tup(not(fst(z)))(snd(z));
const predZ = z => negate(succZ(negate(z)));
const addZ = a => b => xand(fst(a))(fst(b))(() => tup(fst(a))(add(snd(a))(snd(b))))(() => (c => tup(fst(c(a)(b)))(minus(snd(c(a)(b)))(snd(c(b)(a)))))(gt(snd(a))(snd(b))))();
const multZ = a => b => tup(xor(fst(a))(fst(b)))(mult(snd(a))(snd(b)));
const divZ = a => b => tup(xor(fst(a))(fst(b)))(div(snd(a))(snd(b)));
const eqZ = a => b => xand(fst(a))(fst(b))(() => eq(snd(a))(snd(b)))(False)();
// Q Opertions
const precission = mul2(mul2(mul2(mul2(one)))); // 16
const zeroQ = zeroZ;
const ZtoQ = z => tup(fst(z))(repAp(mul2)(precission)(snd(z)));
const QtoZ = z => tup(fst(z))(repAp(div2)(precission)(snd(z)));
const multQ = a => b => QtoZ(multZ(a)(b));
const divQ = a => b => divZ(ZtoQ(a))(b);
const addQ = addZ;
const negateQ = negate;
// C Operations
const zeroC = tup(zeroQ)(zeroQ);
const addC = a => b => tup(addQ(fst(a))(fst(b)))(addQ(snd(a))(snd(b)));
const multC = a => b => tup(addQ(multQ(fst(a))(fst(b)))(negateQ(multQ(snd(a))(snd(b)))))(addQ(multQ(fst(a))(snd(b)))(multQ(snd(a))(fst(b))));
// mandlebrot
const step = c => z => addC(multC(z)(z))(c);
const escapedQ = q => gte(snd(QtoZ(q)))(mul2(one));
const escapedC = c => or(escapedQ(fst(c)))(escapedQ(snd(c)));
const maxIters = mul2(mul2(mul2(mul2(mul2(one)))));
const sim = c => Y(self => s => z => isz(s)(() => True)(() => escapedC(z)(() => False)(() => self(pred(s))(step(c)(z)))())())(maxIters)(c);
const res = ZtoQ(NtoZ(maxIters));
const resolutionStep = divQ(ZtoQ(NtoZ(one)))(res);
const stepr = tup(resolutionStep)(zeroQ);
const stepi = tup(zeroQ)(negateQ(resolutionStep));
const start = tup(ZtoQ(predZ(predZ(zeroZ))))(ZtoQ(succZ(zeroZ)));
const row = Y(self => c => tup(sim(c))(() => self(addC(c)(stepr))));
const grid = Y(self => c => tup(row(c))(() => self(addC(c)(stepi))))(start);
// not lambda calculus. just the stuff needed to display
const take = (n, p) => n === 0 ? [] : (e => [fst(e), ...take(n - 1, snd(e))])(p());
console.log(take(65, () => grid).map(r => take(97, () => r).map(b => b('#')('.')).join('')).join('\n'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment