Plato on Github
Report Home
src/tagged.js
Maintainability
72.43
Lines of code
144
Difficulty
35.38
Estimated Errors
0.85
Function weight
By Complexity
By SLOC
// // ## tagged(name, fields) // // Creates a simple constructor for a tagged object. // // var Tuple = tagged('Tuple', ['a', 'b']); // var x = Tuple(1, 2); // var y = new Tuple(3, 4); // x instanceof Tuple && y instanceof Tuple; // function tagged(name, fields) { function wrapped() { var self = getInstance(this, wrapped), total = fields.length, values = [].slice.call(arguments), i; if (values.length != total) { throw new TypeError("Expected " + fields.length + " arguments, got " + values.length + " for " + name); } for (i = 0; i < total; i++) { self[fields[i]] = values[i]; } self.toString = makeToString(values); /* Make sure we don't overwrite already existing implementations */ if (!self.toArray) { self.toArray = makeToArray(values); } return self; } function makeToString(a) { return function() { var values = squishy.map(a, function(x) { return x.toString ? x.toString() : '' + x; }), flattened = squishy.reduce(values, function(x, y) { return x + ', ' + y; }); return name + (values.length > 0 ? '(' + flattened + ')' : ''); }; } function makeToArray(a) { return function() { var values = squishy.map(a, function(x) { return x.toArray ? x.toArray() : x; }), flattened = squishy.fold(values, [], function(x, y) { return squishy.concat(x, y); }); return flattened; }; } /* Make sure the fields is an array */ if (!isArray(fields)) { throw new TypeError("Expected Array but got `" + (typeof fields) + "`"); } /* Make sure the tagged are named */ wrapped._name = name; wrapped._length = fields.length; return wrapped; } // // ## taggedSum(constructors) // // Creates a disjoint union of constructors, with a catamorphism. // // var List = taggedSum({ // Cons: ['car', 'cdr'], // Nil: [] // }); // function listLength(l) { // return l.match({ // Cons: function(car, cdr) { // return 1 + listLength(cdr); // }, // Nil: function() { // return 0; // } // }); // } // listLength(List.Cons(1, new List.Cons(2, List.Nil()))) == 2; // function taggedSum(name, constructors) { var key, proto; function definitions() { throw new TypeError('Tagged sum was called instead of one of its properties.'); } function constructMatch(key) { return function(dispatches) { var fields = constructors[key], accessor = dispatches[key], args = squishy.select(this, fields); if(!accessor) { throw new TypeError("Constructors given to match didn't include: " + key); } return accessor.apply(this, args); }; } function makeProto(key, constructors) { var proto = create(definitions.prototype); proto.match = constructMatch(key); /* - Make sure the taggedSum are named - Pass the constructors around so we can then do recursive matching. - Make sure that taggedSum items have a toString */ proto._name = key; proto._tagged = definitions; proto._constructors = constructors; proto.toString = constant(key); return proto; } for (key in constructors) { if (!constructors[key].length) { definitions[key] = makeProto(key, definitions); definitions[key].toArray = constant([]); continue; } definitions[key] = tagged(key, constructors[key]); definitions[key].prototype = makeProto(key, constructors); } definitions._name = name; return definitions; } // // append methods to the squishy environment. // squishy = squishy .property('tagged', tagged) .property('taggedSum', taggedSum);