Public
Edited
Sep 12, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
getterFun = fn({
name: 'getter',
class: 'function',
isNative: true,
interpret: ([obj, name]) => obj[name],
})
Insert cell
setterFun = fn({
name: 'setter',
class: 'function',
isNative: true,
interpret: ([obj, name, value]) => ({...obj, [name]: value}),
})
Insert cell
Insert cell
Insert cell
Insert cell
typeof_ = fn({
name: 'typeof',
class: 'function',
isNative: true,
interpret: ([x]) => typeof x,
})
Insert cell
Insert cell
Insert cell
expr = call(lambda('x', seq(
setter('y', getter('x')),
typeof_(getter('y')),
)), value(1))
Insert cell
interp = interpret(expr)[1]
Insert cell
evalRes = evaluate(interp)
Insert cell
toString(evalRes)
Insert cell
function toString(node) {
if (node.class === 'call') {
return toString(node.fun) + '(' + toString(node.args) + ')';
} else if (node.class === 'function') {
return node.name;
} else if (node.class === 'list') {
return '[' + node.elems.map(elem => toString(elem)).join(', ') + ']';
} else if (node.class === 'value') {
return JSON.stringify(node.value);
} else if (node.class === 'getter') {
return 'GETTER(' + toString(node.name) + ')';
} else {
return '-';
}
}
Insert cell
function evaluate(node) {
if (node.class === 'call') {
const fun = evaluate(node.fun);
const args = evaluate(node.args);
if (fun.class === 'function' && args.class === 'value') {
return value(fun.interpret(args.value));
}
} else if (node.class === 'list') {
const values = [];
let allValues = true;
for (const elem of node.elems) {
const elemVal = evaluate(elem);
if (elemVal.class !== 'value') {
allValues = false;
break;
}
values.push(elemVal.value);
}
if (allValues) return value(values);
}
return node;
}
Insert cell
function interpret(ctx, node) {
if (typeof node === 'undefined') {
node = ctx;
return interpret(emptyContext, node);
} else if (node.class === 'call') {
const [ctx1, fun] = interpret(ctx, node.fun);
const [ctx2, args] = interpret(ctx1, node.args);
return [ctx2, fun.apply(args)];
} else if (node.class === 'function') {
return [ctx, node.syntax];
} else if (node.class === 'list') {
const elemResArr = [];
for (const elem of node.elems) {
const [nextCtx, elemValue] = interpret(ctx, elem);
ctx = nextCtx;
elemResArr.push(elemValue);
}
return [ctx, list(...elemResArr)];
} else if (node.class === 'value') {
return [ctx, node];
} else if (node.class === 'getter') {
const [ctx1, name] = interpret(ctx, node.name);
return [ctx1, getterFun(ctx1, name)];
} else if (node.class === 'setter') {
const [ctx1, name] = interpret(ctx, node.name);
const [ctx2, val] = interpret(ctx1, node.value);
const resCtx = setterFun(ctx2, name, val);
return [resCtx, value(null)];
} else if (node.class === 'sequence') {
let lastValue;
const [ctx0, stmts] = interpret(ctx, node.statements);
ctx = ctx0;
for (const stmt of stmts.value) {
const [nextCtx, value] = interpret(ctx, stmt);
ctx = nextCtx;
lastValue = value;
}
return [ctx, lastValue];
} else if (node.class === 'lambda') {
const [ctx1, name] = interpret(ctx, node.name);
const [ctx2, expr] = interpret(ctx1, node.expr);
const lambda = arg => {
const localCtx = setterFun(ctx2, name, arg);
return interpret(localCtx, expr.value)[1];
};
return [ctx2, {
class: 'lambda',
name,
expr,
apply: lambda,
}]
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more