Книга: Functional Programming in JavaScript
Назад: Monads
Дальше: Promises

Maybes

Maybes allow us to gracefully work with data that might be null and to have defaults. A maybe is a variable that either has some value or it doesn't. And it doesn't matter to the caller.

On its own, it might seem like this is not that big a deal. Everybody knows that null-checks are easily accomplished with an statement:

if (getUsername() == null ) {   username = 'Anonymous') { else {   username = getUsername(); }

But with functional programming, we're breaking away from the procedural, line-by-line way of doing things and instead working with pipelines of functions and data. If we had to break the chain in the middle just to check if the value existed or not, we would have to create temporary variables and write more code. Maybes are just tools to help us keep the logic flowing through the pipeline.

To implement maybes, we'll first need to create some constructors.

// the Maybe monad constructor, empty for now var Maybe = function(){};   // the None instance, a wrapper for an object with no value var None = function(){};  None.prototype = Object.create(Maybe.prototype); None.prototype.toString = function(){return 'None';};  // now we can write the `none` function // saves us from having to write `new None()` all the time var none = function(){return new None()};  // and the Just instance, a wrapper for an object with a value var Just = function(x){return this.x = x;}; Just.prototype = Object.create(Maybe.prototype); Just.prototype.toString = function(){return "Just "+this.x;}; var just = function(x) {return new Just(x)};

Finally, we can write the function. It returns a new function that either returns nothing or a maybe. It is a functor.

var maybe = function(m){   if (m instanceof None) {     return m;   }   else if (m instanceof Just) {     return just(m.x);      }   else {     throw new TypeError("Error: Just or None expected, " + m.toString() + " given.");    } }

And we can also create a functor generator just like we did with arrays.

var maybeOf = function(f){   return function(m) {     if (m instanceof None) {       return m;     }     else if (m instanceof Just) {       return just(f(m.x));     }     else {       throw new TypeError("Error: Just or None expected, " + m.toString() + " given.");      }   } }

So is a monad, is a functor, and returns a functor that is already assigned to a morphism.

We'll need one more thing before we can move forward. We'll need to add a method to the monad object that helps us use it more intuitively.

Maybe.prototype.orElse = function(y) {   if (this instanceof Just) {     return this.x;   }   else {     return y;   } }

In its raw form, maybes can be used directly.

maybe(just(123)).x; // Returns 123 maybeOf(plusplus)(just(123)).x; // Returns 124 maybe(plusplus)(none()).orElse('none'); // returns 'none'

Anything that returns a method that is then executed is complicated enough to be begging for trouble. So we can make it a little cleaner by calling on our function.

maybePlusPlus = maybeOf.curry()(plusplus); maybePlusPlus(just(123)).x; // returns 123 maybePlusPlus(none()).orElse('none'); // returns none

But the real power of maybes will become clear when the dirty business of directly calling the and functions is abstracted. We'll do this with an example object , that uses maybes for the username.

var User = function(){   this.username = none(); // initially set to `none` }; User.prototype.setUsername = function(name) {   this.username = just(str(name)); // it's now a `just }; User.prototype.getUsernameMaybe = function() {   var usernameMaybe = maybeOf.curry()(str);   return usernameMaybe(this.username).orElse('anonymous'); };  var user = new User(); user.getUsernameMaybe(); // Returns 'anonymous'  user.setUsername('Laura'); user.getUsernameMaybe(); // Returns 'Laura'

And now we have a powerful and safe way to define defaults. Keep this object in mind because we'll be using it later on in this chapter.

Назад: Monads
Дальше: Promises

bsn
thank
Vesa Karvonen
I hope you don't mind, but I’d like to point you and your readers to my high-performance optics library for JavaScript that is in production use in multiple projects, has comprehensive support for partial optics and interactive documentation: https://calmm-js.github.io/partial.lenses/ (this takes a moment to load — be patient!)