Skip to content

Instantly share code, notes, and snippets.

@DrBoolean
Last active February 9, 2017 12:24
Show Gist options
  • Select an option

  • Save DrBoolean/9958810 to your computer and use it in GitHub Desktop.

Select an option

Save DrBoolean/9958810 to your computer and use it in GitHub Desktop.
Traversable/Foldable of/empty issue
Nothing.prototype.traverse = function(f) {
return ?.of(Nothing()); //how to get pure if we can't call f?
}
Just.prototype.traverse = function(f) {
return f(this.val).map(Just);
}
Nothing.prototype.foldl = function(f) {
return ?.empty() // same prob as traverse - need to run f() to get correct empty
};
Just.prototype.foldl = function(f, acc) {
return f(acc, this.val);
};
// Sneaky solution
Array.prototype.traverse = function(f) {
var cons_f = function(ys, x){
var z = f(x).map(_.curry(function(x,y){ return y.concat(x); }));
ys = ys || z.of([]); // sneaky get the correct point after we extract it from f(x)
return z.ap(ys);
}
return this.reduce(cons_f, null); // use null since we don't have type hints for 'pure'
};
Array.prototype.foldl = function(f, acc) {
return this.reduce(f, acc);
};
var foldMap = _.curry(function(f, fldable) {
return fldable.foldl(function(acc, x) {
var r = f(x)
acc = acc || r.empty(); // cheat again to get empty of the correct instance
return acc.concat(r);
})
});
@SimonRichardson
Copy link
Copy Markdown

Yeah, there is no way to infer the type unfortunately, without storing it in the Option. Alternatively you could pass another function for the Nothing.

Option.prototype.sequence = function(f) {
    return this.traverse(identity, f);
};

Option.prototype.traverse = function(f, g) {
    var env = this;
    return env.cata({
        Some: function(x) {
            return f(x).map(Option.of);
        },
        None: function() {
            return g(Option.None);
        }
    });
};

Then use it like so...

Option.Some(Identity.of(1)).sequence(Identity.of)
Option.None.sequence(Identity.of)

Although I'm not sure I like that either, any thoughts?

(This is fantasy land options)

@DrBoolean
Copy link
Copy Markdown
Author

Hi Simon, I just saw this message (I have to turn on notifications or something...)

I'm torn.

One idea is that Option.None.sequence() mirrors an ambiguous type error that must be solved with a "type hint" so to speak. A type signature is a lot like an extra parameter: Option.None.sequence(Identity)

This extra parameter doesn't need to be there 99% of the time - it's there only if we can fail. So only in the case of Option/Either/Validation etc. do we actually need it.

Pros:

  • It's simpler for the caller and catches most cases
  • Less requires needed. In this example Identity would not have to be required unless you were working with a failure type

Cons

  • Harder to implement on your fantasy type (see the sneaky array trick)
  • Api is not 100% consistent

The other idea is to always pass in of or empty.

Pros:

  • Easier for the fantasy type to implement
  • Consistent API

Cons:

  • Harder for the caller of traverse/fold
  • Have to require types in order to pass in

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment