fantasyland / fantasy-land

Specification for interoperability of common algebraic structures in JavaScript
MIT License
10.08k stars 373 forks source link

Cofoldable #53

Open joneshf opened 10 years ago

joneshf commented 10 years ago

As mentioned here I'd like to propose a Cofoldable. There's detailed information about it here

The idea is that while Foldable and Cofoldable are lawless alone, together you can suggest some laws on them.

It should have one of two methods:

I'm actually unsure on the definition of unfold Should it be (a -> b -> b) -> b -> b -> f a as in the definition for `build in the link, or something else? In any case, one can be derived from the other.

Please discuss.

DrBoolean commented 10 years ago

There's an Unfoldable package that gives some guidance here: http://hackage.haskell.org/package/unfoldable-0.8.1/docs/Data-Unfoldable.html It even provides fromList

Regarding #7, it seems like Cofoldable makes sense over Unfoldable if the whole purpose is to provide some laws. Although in that case, my opinion is that we're being really specific about a natural transformation or isomorphism.

Anyways, for unfold:

Since this is fantasy land, I think we should use Option to flag the end of the unfold rather than a guard fn or null.

Array's instance could be:

//+ unfold :: (b -> Option([a, b])) -> b -> [a]
Array.prototype.unfold = function(step, seed) {
  var output = this;
  return step(seed).cata({
    Some: function(result) {
      return output.concat(result[0]).unfold(step, result[1]);
    },
    None: function() {
      return output;
    }
  });
}

var result = [].unfold(function(x){ return (x > 10) ? None : Some([x, x+1]); }, 0)
console.log(result);
SimonRichardson commented 10 years ago

:+1: on using Option instead of a guard func & null. Looks nice and clean to me.

safareli commented 8 years ago

Just an idea: chainRec of Array could be used as unfold

Array.chainRec(function(next, done, x) {
  return (x == 10) ? [done(x)] : [done(x), next(x+1)]
}, 0) // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

// implementation of Array.chainRec
function stepNext(x) { return {value: x, done: false }; }
function stepDone(x) { return {value: x, done: true }; }

Array.chainRec = function _chainRec(f, i) {
  var todo = [i];
  var res = [];
  var buffer, xs, idx;
  while (todo.length > 0) {
    xs = f(stepNext, stepDone, todo.shift());
    buffer = [];
    for (idx = 0; idx < xs.length; idx += 1) {
      (xs[idx].done ? res : buffer).push(xs[idx].value);
    }
    Array.prototype.unshift.apply(todo, buffer);
  }
  return res;
};