Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- So, let's play with some Semigroups and (maybe?) Monoids for combining lists in interesting ways
- */
- //This one is pretty straightforward
- //Union (keep all values from both lists, but no repeats)
- const Union = function(xs){
- if (!(this instanceof Union)) {
- return new Union(xs);
- }
- this.xs = xs;
- }
- Union.of = xs => Union(xs);
- //exploit ES6 sets
- Union.prototype.concat = function({xs:ys}) {
- return Union(
- [...(new Set(this.xs.concat(ys)))]
- )
- };
- Union.prototype.fold = function(f=(x=>x)) {
- return f(this.xs);
- };
- Union.empty = Union.prototype.empty = () => Union([]);
- //Union.zero = Union.prototype.zero = //???? I think this would
- //hypothetically be a list of all possible values but let's not try...
- //Intersection: the concat should keep any values that appear in BOTH lists
- const Intersection = function(xs){
- if (!(this instanceof Intersection)) {
- return new Intersection(xs);
- }
- this.xs = xs;
- }
- Intersection.of = xs => Intersection(xs);
- Intersection.prototype.concat = function({xs}) {
- return Intersection(
- this.xs.filter(
- x=>xs.some(y=>x===y)
- )
- )
- };
- Intersection.prototype.fold = function(f=(x=>x)) {
- return f(this.xs);
- };
- //here's the tricky bit: not sure empty is straightforwardly possible to have an mempty that fits intuition in all ways
- //Intersection([]), for instance, fails monoid laws
- //Intersection.empty = Intersection.prototype.empty = ???
- Intersection.zero = Intersection.prototype.zero = () => Intersection([]);
- //that means any foldMap-ish thing we use HAS to avoid using mempty to work as expected,
- //and also make sure that the first element is mapped along with the rest
- //anyhow... the next one is a "difference" of lists, and here things get way weirder for me.
- //First we'll need a quick utility to just get the non-symetrical difference of two lists
- function difference(first, second) {
- var out = [];
- var idx = 0;
- var firstLen = first.length;
- while (idx < firstLen) {
- if (!second.includes(first[idx]) && !out.includes(first[idx])) {
- out[out.length] = first[idx];
- }
- idx += 1;
- }
- return out;
- }
- //and now we can think about a _symmetric_ Difference semigroup as
- //Difference: any values which are NOT in "both" lists
- //something about "in both" here worries me...
- const Difference = function(xs){
- if (!(this instanceof Difference)) {
- return new Difference(xs);
- }
- this.xs = xs;
- }
- Difference.of = xs => Difference(xs);
- Difference.prototype.concat = function({xs}) {
- return Difference(
- difference(this.xs, xs).concat(difference(xs, this.xs))
- )
- };
- Difference.prototype.fold = function(f=(x=>x)) {
- return f(this.xs);
- };
- Difference.empty = Difference.prototype.empty = () => Difference([]);
- //seems straightforward, but then...
- /*
- Difference([3,4]).concat(Difference([4,5]));//-> [3,5]
- Difference([3,4])
- .concat(Difference([4,5]))
- .concat(Difference([4,5]));//-> [3,4] but wait, 4 is in EVERY list in this operation!
- What's happening is that the first concat op rejects the 4 as "in both", but then there's no 4 left
- in the next operation... so it's "not in both" again. This seems to all work out per the associativity
- law, but it's confusing as heck if you want to think of "unique elements" when foldMapping.
- That's clearly NOT what this does/gets...
- */
- //so maybe we could create a semigroup with a sense of its "history"? Ruling out what it's "seen" so far?
- const DifferenceH = function(xs,out){
- if (!(this instanceof DifferenceH)) {
- return new DifferenceH(xs, out);
- }
- this.xs = xs;
- this.out = out;
- }
- DifferenceH.of = xs => DifferenceH(xs, []);
- //almost certainly more efficient ways to do this but this should be right...
- DifferenceH.prototype.concat = function({xs,out}) {
- return DifferenceH(
- this.xs.filter(
- x=>!xs.concat(out).includes(x)
- )
- .concat(
- xs.filter(
- x=>!this.xs.concat(this.out).includes(x)
- )
- ),
- Intersection(this.xs)
- .concat(Intersection(xs))
- .fold(x=>x)
- .concat(out)//add in previous outs as well...
- .concat(this.out)
- )
- };
- DifferenceH.prototype.fold = function(f=(x=>x)) {
- return f(this.xs);//here we're losing the history on purpose
- };
- DifferenceH.empty = DifferenceH.prototype.empty = () => DifferenceH([],[]);
- //And guess what, it actually seems to work/fit intuition!
- //of course, it also fails my intuition in another way: outside of its use in a foldMap, how/why would a
- //type acquire a "history" outside of the context of a larger operation?
- //Like, DifferenceH.of([1,2]) vs. DifferenceH([1,2],[3,4])
- //weird stuff, an probably some bigger patterns I'm missing
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement