Skip to content

Instantly share code, notes, and snippets.

@awto
Last active September 3, 2019 04:14
Show Gist options
  • Save awto/425b00b8fefcf6da58d5d4686b4def81 to your computer and use it in GitHub Desktop.
Save awto/425b00b8fefcf6da58d5d4686b4def81 to your computer and use it in GitHub Desktop.
Normalization by evaluation in JavaScript
const AbstractSym = Symbol("Abstract");
function abstract(init) {
const proxy = new Proxy(
function() {
throw new Error("shouldn't be called");
},
{
get(object, prop) {
if (prop === AbstractSym) return init;
return abstract({ type: "prop", object: proxy, prop });
},
apply(fun, _, args) {
return abstract({ type: "apply", fun: proxy, args });
}
}
);
return proxy;
}
function print(value, ...args) {
const v = value && value[AbstractSym];
if (v) {
switch (v.type) {
case "prop":
return `${print(v.object)}.${v.prop}`;
case "apply":
return `${print(v.fun)}(${v.args.map(print).join()})`;
case "var":
return v.id;
default:
throw new TypeError(`unknown abstract value type: ${v.type}`);
}
}
switch (typeof value) {
case "object":
if (!value) return "null";
const flds = Object.entries(value).map(([k, v]) => `${k}: ${print(v)}`);
return `{${flds.join()}`;
case "function":
const vars = Array.from(
Array(value.length - args.length),
(_, x) => `v${x}`
);
const res = value(
...args,
...vars.map(id => abstract({ type: "var", id }))
);
return `(${vars.join()}) => (${print(res)})`;
default:
return String(value);
}
}
// EXAMPLE
console.log(
print(
function test1(a, b, obj, num) {
function sum(a, b) {
return a + b;
}
const v3 = obj.f1(sum(a, b));
return { v1: obj.f1(obj.f2(obj.f1_2, num, v3)), v2: { v3 } };
},
2,
3
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment