inet-lib
Version:
JavaScript Engine for Interaction Nets
342 lines (273 loc) • 5.29 kB
Plain Text
\print {
/* Output results of read-back. */
this.nf = M;
++this.total;
} \atom_{M};
\read_{C}[a] {
/* Unshare variable. */
++this.total;
} \share[\copy(b, \read_{C}(a)), b];
\read_{C}[a] {
/* Initiate application. */
++this.total;
} \apply[\lambda(b, \read_{C}(a)), b];
\read_{C}[a] {
/* Read back abstraction. */
++this.total;
} \lambda[\atom_{this.mkid()}, \read_{this.abst(C)}(a)];
\lambda[\read_{this.appl(M)}(a), a] {
/* Read back application. */
++this.total;
} \atom_{M};
\read_{C}[\atom_{this.atom(C, M)}] {
/* Read back an atom. */
++this.total;
} \atom_{M};
\copy[\atom_{M}, \atom_{this.clone(M)}] {
/* Copy an atom. */
++this.total;
} \atom_{M};
\dup[\atom_{M}, \atom_{this.clone(M)}] {
/* Duplicate an atom. */
++this.total;
} \atom_{M};
\lambda[a, b] {
/* Unshare variable. */
++this.total;
} \share[\copy(c, \lambda(a, b)), c];
\lambda[a, b] {
/* Initiate application. */
++this.total;
} \apply[\lambda(c, \lambda(a, b)), c];
\lambda[a, b] {
/* Apply a closed term. */
++this.beta;
++this.total;
} \lambda[a, b];
\copy[a, b] {
/* Unshare variable. */
++this.total;
} \share[\copy(c, \copy(a, b)), c];
\copy[a, b] {
/* Initiate application. */
++this.total;
} \apply[\lambda(c, \copy(a, b)), c];
\copy[\lambda(a, b), \lambda(c, d)] {
/* Initiate copy of a closed term. */
++this.total;
} \lambda[\dup(a, c), \dup(b, d)];
\dup[a, b] {
/* Unshare variable. */
++this.total;
} \share[\copy(c, \dup(a, b)), c];
\dup[a, b] {
/* Duplicate sharing. */
++this.total;
} \copy[\dup(\amb(c, \share(a, d), d), \amb(e, \share(b, f), f)), \dup(c, e)];
\dup[\apply(a, b), \apply(c, d)] {
/* Duplicate application. */
++this.total;
} \apply[\dup(a, c), \dup(b, d)];
\dup[\lambda(a, b), \lambda(c, d)] {
/* Duplicate abstraction. */
++this.total;
} \lambda[\dup(a, c), \dup(b, d)];
\dup[a, b] {
/* Finish duplication. */
++this.total;
} \dup[a, b];
\erase {
/* Erase an atom. */
++this.total;
} \atom_{M};
\erase {
/* Erase sharing. */
++this.total;
} \share[a, a];
\erase {
/* Erase application. */
++this.total;
} \apply[\erase, \erase];
\erase {
/* Erase abstraction. */
++this.total;
} \lambda[\erase, \erase];
\erase {
/* Erase copy initiator. */
++this.total;
} \copy[\erase, \erase];
\erase {
/* Erase duplicator. */
++this.total;
} \dup[\erase, \erase];
\erase {
/* Finish erasing. */
++this.total;
} \erase;
$$
\read_{this.mkhole()}(!print) = root;
root = \lambda(w1, w3);
w3 = \apply(w4, w5);
w4 = \apply(w6, w7);
w6 = \lambda(w2, w8);
w8 = w2;
w7 = \atom_{this.mkid("v1")};
w5 = w1;
$$
const gfv = [];
let id = 0;
function mkvar(fresh)
{
if (fresh)
++id;
return "v" + id.toFixed(0);
}
function mkid(name)
{
const fv = {};
const obj = {
node: "atom",
name: name,
fv: fv
};
if (name) {
gfv[name] = true;
return obj;
}
do {
name = mkvar(true);
} while (gfv[name]);
obj.name = name;
fv[name] = true;
return obj;
}
function mkhole()
{
const obj = {};
obj.fv = {};
obj.bv = {};
obj.hole = obj;
return obj;
}
function subst(hole, obj)
{
const parent = hole.parent;
const body = obj.body;
const left = obj.left;
const right = obj.right;
if (parent)
obj.parent = hole.parent;
else
delete obj.parent;
Object.assign(hole, obj);
if (body)
body.parent = hole;
if (left)
left.parent = hole;
if (right)
right.parent = hole;
}
function eta(obj)
{
let parent, left, right, name;
if ("appl" != obj.node)
return;
parent = obj.parent;
if (!parent)
return;
if ("abst" != parent.node)
return;
right = obj.right;
if ("atom" != right.node)
return;
name = parent.var;
if (name != right.name)
return;
left = obj.left;
if (left.fv[name])
return;
subst(parent, left);
eta(parent);
}
function atom(context, obj, name)
{
const ofv = obj.fv;
const cfv = context.fv;
const bv = context.bv;
const chole = context.hole;
const ohole = obj.hole;
if (name)
bv[name] = true;
for (const key in ofv)
if (!(key in bv))
cfv[key] = true;
subst(chole, obj);
if (ohole) {
delete chole.hole;
context.hole = ohole;
} else {
delete context.hole;
eta(chole);
}
return context;
}
function abst(context)
{
const hole = mkhole();
const name = mkvar();
const obj = {
node: "abst",
var: name,
body: hole,
fv: {},
hole: hole
};
hole.parent = obj;
return atom(context, obj, name);
}
function appl(left)
{
const context = mkhole();
const hole = mkhole();
const obj = {
node: "appl",
left: left,
right: hole,
fv: Object.assign({}, left.fv),
hole: hole
};
left.parent = obj;
hole.parent = obj;
return atom(context, obj);
}
function clone(obj, root, hole, parent)
{
const copy = {};
if (!obj)
return;
if (!root) {
root = copy;
hole = obj.hole;
}
copy.node = obj.node;
copy.var = obj.var;
copy.name = obj.name;
copy.parent = parent;
copy.body = clone(obj.body, root, hole, copy);
copy.left = clone(obj.left, root, hole, copy);
copy.right = clone(obj.right, root, hole, copy);
copy.fv = Object.assign({}, obj.fv);
copy.bv = Object.assign({}, obj.bv);
if (obj === hole)
root.hole = copy;
return copy;
}
this.clone = clone;
this.mkid = mkid;
this.mkvar = mkvar;
this.mkhole = mkhole;
this.abst = abst;
this.appl = appl;
this.atom = atom;
this.beta = 0;
this.total = 0;