Created
May 20, 2010 04:22
-
-
Save polgfred/407195 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) |
Added traversal and pretty printing.
Added folding.
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.
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
This is a CommonJS module which requires at least JavaScript 1.7 for
Array#map
and destructuring assignment