Skip to content

Instantly share code, notes, and snippets.

@polgfred
Created May 20, 2010 04:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save polgfred/407195 to your computer and use it in GitHub Desktop.
Save polgfred/407195 to your computer and use it in GitHub Desktop.
var Tree = exports.Tree = function(value, branches) {
// @param: value => the value held by this node in the tree
// @param: branches => the child nodes of this tree
// @returns: the Tree
this.value = value
this.branches = branches
}
Tree.unfold = function(seed, transformer) {
// @param: seed => the initial seed value for constructing the tree
// @param: transformer(seed) => given a seed, return the node value for this
// tree, along with the next generation of seeds
// i.e. [value, [next generation of seeds]]
// @returns: the unfolded Tree
return _unfold(seed)
function _unfold(seed) {
var result = transformer(seed),
value = result[0],
seeds = result[1]
return new Tree(value, seeds.map(_unfold))
}
}
Tree.prototype.fold = function(transformer) {
// @param: transformer(value, next generation of seeds) => given a node value
// and the next generation of seeds, return a seed for this tree
// (opposite of unfold)
// @returns: a seed value representing this Tree
return _fold(this)
function _fold(tree) {
return transformer(tree.value, tree.branches.map(_fold))
}
}
Tree.prototype.map = function(transformer) {
// @param: transformer(value) => given a node value, return a new node value
// @returns: a new Tree
return _map(this)
function _map(tree) {
return new Tree(transformer(tree.value), tree.branches.map(_map))
}
}
Tree.prototype.traverse = function(visitor) {
// @param: visitor(value, level) -> callback for traversal
// @returns: nothing; used for side-effects
var level = 1
_visit(this)
function _visit(tree) {
visitor(tree.value, level)
level++
tree.branches.forEach(_visit)
level--
}
}
Tree.prototype.toString = function() {
return this.fold(function(value, seeds) {
return '<' + value + ': [' + seeds.join(',') + ']>'
})
}
Tree.prototype.toPrettyString = function(indent) {
indent = indent || '\t'
var out = []
this.traverse(function(value, level) {
out.push(new Array(level).join(indent) + value)
})
return out.join('\n')
}
////////////////////////////
// A basic heap
var t = Tree.unfold(1, function(seed) {
return [seed, seed < 64 ? [(2 * seed), (2 * seed) + 1] : []]
})
console.log(t.toPrettyString())
@polgfred
Copy link
Author

This is a CommonJS module which requires at least JavaScript 1.7 for Array#map and destructuring assignment

@polgfred
Copy link
Author

Added traversal and pretty printing.

@polgfred
Copy link
Author

Added folding.

@kangax
Copy link

kangax commented May 21, 2010

Yeah, immediately invoked function expressions make for really concise code here. Although, I wouldn't say function declaration -based alternative is that much uglier / longer (arguably, it even adds more clarity :))

Tree.prototype.map = function (transformer) {
  function _map(tree) {
    return new Tree(transformer(tree.value), tree.branches.map(_map));
  }
  return _map(this);
};

On an unrelated note... I don't see why you need map(String) in this.branches.map(String).join(',')join already coerces values to string.

@polgfred
Copy link
Author

Indeed, so it does. [snip]

When the functions are this short, declaration style is probably mostly a matter of preference. One more reason to keep functions short. :)

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