Skip to content

Instantly share code, notes, and snippets.

@amy-langley
Last active August 2, 2018 18:51
Show Gist options
  • Save amy-langley/960edc4a383dab3a9d7be83f6ffa0f38 to your computer and use it in GitHub Desktop.
Save amy-langley/960edc4a383dab3a9d7be83f6ffa0f38 to your computer and use it in GitHub Desktop.
An implementation of zippers over s-expressions represented as nested javascript arrays
class Node {
constructor(value, children) {
this.value = value;
this.children = children;
}
setValue(newValue) {
return new Node(newValue, this.children);
}
appendChild() {
return new Node(this.value, this.children.concat(new Node(null, [])));
}
removeChild(index) {
return new Node(this.value, this.children.slice(0, index).concat(this.children.slice(index+1)));
}
print(nest) {
nest = nest || "";
console.log(nest+this.value);
(this.children || []).forEach(child => child.print("+"+nest));
}
zipper() {
return new Zipper(this, []);
}
}
class Crumb {
constructor(parent, left, right) {
this.parent = parent;
this.left = left || [];
this.right = right || [];
}
}
class Zipper {
constructor(item, crumbs) {
this.item = item;
this.crumbs = crumbs || [];
}
mutate(lambda) {
return new Zipper(lambda(this.item), this.crumbs);
}
childAt(index) {
return new Zipper(this.item.children[index], [this.crumbFrom(index)].concat(this.crumbs));
}
crumbFrom(index) {
return new Crumb(this.item.value, this.item.children.slice(0, index), this.item.children.slice(index+1));
}
isRoot() {
return this.crumbs.length == 0;
}
up() {
let crumb = this.crumbs[0];
return new Zipper(new Node(crumb.parent, crumb.left.concat(this.item, crumb.right)), this.crumbs.slice(1))
}
print() {
console.log("ITEM");
this.item.print();
console.log("CRUMBS");
console.log(this.crumbs);
}
printItem() {
this.item.print();
}
}
const sampleTree = new Node(
"root", [
new Node("A", [
new Node("E", null)
]),
new Node("B", [
new Node("C", [
new Node("F", null)
]),
new Node("D", null)
])
]);
@amy-langley
Copy link
Author

amy-langley commented Aug 2, 2018

example:

sampleTree.zipper().
  childAt(1).mutate(n => n.setValue('Q')).up().
  childAt(0).mutate(n => n.appendChild()).
    childAt(1).mutate(n => n.setValue('new node')).
  up().
up().print();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment