Advertisement
Guest User

Untitled

a guest
Jan 16th, 2017
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.53 KB | None | 0 0
  1. /*
  2. So, let's play with some Semigroups and (maybe?) Monoids for combining lists in interesting ways
  3. */
  4.  
  5. //This one is pretty straightforward
  6. //Union (keep all values from both lists, but no repeats)
  7. const Union = function(xs){
  8. if (!(this instanceof Union)) {
  9. return new Union(xs);
  10. }
  11. this.xs = xs;
  12. }
  13.  
  14. Union.of = xs => Union(xs);
  15.  
  16. //exploit ES6 sets
  17. Union.prototype.concat = function({xs:ys}) {
  18. return Union(
  19. [...(new Set(this.xs.concat(ys)))]
  20. )
  21. };
  22. Union.prototype.fold = function(f=(x=>x)) {
  23. return f(this.xs);
  24. };
  25.  
  26.  
  27. Union.empty = Union.prototype.empty = () => Union([]);
  28. //Union.zero = Union.prototype.zero = //???? I think this would
  29. //hypothetically be a list of all possible values but let's not try...
  30.  
  31. //Intersection: the concat should keep any values that appear in BOTH lists
  32. const Intersection = function(xs){
  33. if (!(this instanceof Intersection)) {
  34. return new Intersection(xs);
  35. }
  36. this.xs = xs;
  37. }
  38.  
  39. Intersection.of = xs => Intersection(xs);
  40.  
  41. Intersection.prototype.concat = function({xs}) {
  42. return Intersection(
  43. this.xs.filter(
  44. x=>xs.some(y=>x===y)
  45. )
  46. )
  47. };
  48. Intersection.prototype.fold = function(f=(x=>x)) {
  49. return f(this.xs);
  50. };
  51.  
  52. //here's the tricky bit: not sure empty is straightforwardly possible to have an mempty that fits intuition in all ways
  53. //Intersection([]), for instance, fails monoid laws
  54. //Intersection.empty = Intersection.prototype.empty = ???
  55. Intersection.zero = Intersection.prototype.zero = () => Intersection([]);
  56.  
  57.  
  58. //that means any foldMap-ish thing we use HAS to avoid using mempty to work as expected,
  59. //and also make sure that the first element is mapped along with the rest
  60.  
  61. //anyhow... the next one is a "difference" of lists, and here things get way weirder for me.
  62. //First we'll need a quick utility to just get the non-symetrical difference of two lists
  63. function difference(first, second) {
  64. var out = [];
  65. var idx = 0;
  66. var firstLen = first.length;
  67. while (idx < firstLen) {
  68. if (!second.includes(first[idx]) && !out.includes(first[idx])) {
  69. out[out.length] = first[idx];
  70. }
  71. idx += 1;
  72. }
  73. return out;
  74. }
  75.  
  76.  
  77.  
  78. //and now we can think about a _symmetric_ Difference semigroup as
  79. //Difference: any values which are NOT in "both" lists
  80. //something about "in both" here worries me...
  81.  
  82. const Difference = function(xs){
  83. if (!(this instanceof Difference)) {
  84. return new Difference(xs);
  85. }
  86. this.xs = xs;
  87. }
  88.  
  89. Difference.of = xs => Difference(xs);
  90.  
  91. Difference.prototype.concat = function({xs}) {
  92. return Difference(
  93. difference(this.xs, xs).concat(difference(xs, this.xs))
  94. )
  95. };
  96. Difference.prototype.fold = function(f=(x=>x)) {
  97. return f(this.xs);
  98. };
  99.  
  100.  
  101. Difference.empty = Difference.prototype.empty = () => Difference([]);
  102. //seems straightforward, but then...
  103.  
  104. /*
  105. Difference([3,4]).concat(Difference([4,5]));//-> [3,5]
  106. Difference([3,4])
  107. .concat(Difference([4,5]))
  108. .concat(Difference([4,5]));//-> [3,4] but wait, 4 is in EVERY list in this operation!
  109.  
  110. What's happening is that the first concat op rejects the 4 as "in both", but then there's no 4 left
  111. in the next operation... so it's "not in both" again. This seems to all work out per the associativity
  112. law, but it's confusing as heck if you want to think of "unique elements" when foldMapping.
  113. That's clearly NOT what this does/gets...
  114. */
  115.  
  116. //so maybe we could create a semigroup with a sense of its "history"? Ruling out what it's "seen" so far?
  117. const DifferenceH = function(xs,out){
  118. if (!(this instanceof DifferenceH)) {
  119. return new DifferenceH(xs, out);
  120. }
  121. this.xs = xs;
  122. this.out = out;
  123. }
  124.  
  125. DifferenceH.of = xs => DifferenceH(xs, []);
  126.  
  127. //almost certainly more efficient ways to do this but this should be right...
  128. DifferenceH.prototype.concat = function({xs,out}) {
  129. return DifferenceH(
  130. this.xs.filter(
  131. x=>!xs.concat(out).includes(x)
  132. )
  133. .concat(
  134. xs.filter(
  135. x=>!this.xs.concat(this.out).includes(x)
  136. )
  137. ),
  138. Intersection(this.xs)
  139. .concat(Intersection(xs))
  140. .fold(x=>x)
  141. .concat(out)//add in previous outs as well...
  142. .concat(this.out)
  143. )
  144. };
  145. DifferenceH.prototype.fold = function(f=(x=>x)) {
  146. return f(this.xs);//here we're losing the history on purpose
  147. };
  148.  
  149. DifferenceH.empty = DifferenceH.prototype.empty = () => DifferenceH([],[]);
  150.  
  151. //And guess what, it actually seems to work/fit intuition!
  152. //of course, it also fails my intuition in another way: outside of its use in a foldMap, how/why would a
  153. //type acquire a "history" outside of the context of a larger operation?
  154. //Like, DifferenceH.of([1,2]) vs. DifferenceH([1,2],[3,4])
  155. //weird stuff, an probably some bigger patterns I'm missing
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement