Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name and existence of functor or monad to chain and terminate sequence of operations

Please forgive me, I'll do my best to describe what I am looking for. I don't have a name for it, so it makes it that much more difficult.

Looking at libraries such as Folktale and monet.js, I like being able to chain operations with map without null-checking or if statements, using e.g. Maybe, Either, Task.

I am wondering whether a similar construct exists to solve the following problem:

  • I have an initial input.
  • I want to construct a chain of functions that operate on the input.
  • Each function may or may not return a result.
  • If a function does not return a result, call the next function in the chain.
  • As soon as a function returns a result, ignore the rest of the functions in the chain (similarly to mapping a function on a Maybe.Nothing)
  • Return the result.

In other words, I'm looking for something similar to Maybe which holds a value and maps a function on Just but ignores a function mapped on Nothing, and you can extract the value. I'm looking for something that holds an input and an initial null result. When you map a function, it runs the function on the input only if result is null. If the function returns a value, that becomes the result and any other functions that are mapped are ignored. Finally, you can extract the result.

In imperative programming, this might look like:

var result1 = function1(input);
if (result1) {
  return result1;
}
var result2 = function2(input);
if (result2) {
  return result2;
}
// and so on.

Instead, I'd like to construct something along the lines of

Something(input).map(function1).map(function2).result()

or

compose(result, map(compose(function2, function1))(Something(input))

Does such a construct exist? Does it have a name? Even if this doesn't exist and I could write it myself, I'm at a loss as to what to call it. Suggestions welcome.

Thanks for your help!

UPDATE

Following the solution by @Bergi I used Maybe.orElse. I wrote a little helper called ShortCircuit, which I am posting below in case anyone finds this useful.

import Maybe from "data.maybe";

const ShortCircuit = function(input, result) {
  this.input = input;
  this.result = result;
};

ShortCircuit.of = function(input, f) {
  return new ShortCircuit(input, Maybe.fromNullable(f(input)));
};

ShortCircuit.prototype.orElseMaybe = function(f) {
  return new ShortCircuit(this.input, this.result.orElse(() => Maybe.fromNullable(f(this.input))));
};

ShortCircuit.prototype.get = function() {
  return this.result.get();
};

export default ShortCircuit;

And here is how you use it:

const result = ShortCircuit.of(input, f1).orElseMaybe(f2).orElseMaybe(f3).get();

Suggestions for improvement are welcome.

like image 339
foxdonut Avatar asked Dec 13 '15 19:12

foxdonut


1 Answers

What you are looking for is known as the Alternative type class in Haskell. I have not yet found1 a JS library implementing it, though there is support for it in PureScript and a discussion about specifying it in FantasyLand.

Regardless, I've found a function in Folktale that does exactly what you want: Maybe's orElse. You'd use it like this:

Something(input).orElse(function1).orElse(function2).get() // `get` throws when all failed

Even better, orElse is available not only for Maybe but also on Either, Validation and Task!

The getOrElse method, known as orElse in Monet.js, is not really helpful as it wouldn't execute your "handlers" only in the case of a fail. You can implement your own Alternative though using the cata method.

1: Googling "JS alternative" is not really helpful either, even when you know the name :-)


Oh, and just in case you are using promises, there's always the .catch(…) method which has broad (ES6-backed) support.

like image 97
Bergi Avatar answered Sep 18 '22 02:09

Bergi