Functional JavaScript — Monads
Tags: webdev, programming, functional, javascript
Published: 2021-01-25 01:35:52

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to pipe functions and functors with JavaScript.

### MayBe Functors

A MayBe functor is one that lets us implement a `map` function in a different way.

We start off by creating a constructor that stores a value:

```
const MayBe = function(val) {
  this.value = val;
}

MayBe.of = function(val) {
  return new MayBe(val);
}
```

Then we add the methods unique to the `MayBe` functor.

We have the `isNothing` method to check if `this.value` has anything.

The `map` method will return something different depending on whether `this.value` has something or not.

We add:

```
MayBe.prototype.isNothing = function() {
  return (this.value === null || this.value === undefined);
};

MayBe.prototype.map = function(fn) {
  return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this.value));
};
```

Together, we have:

```
const MayBe = function(val) {
  this.value = val;
}

MayBe.of = function(val) {
  return new MayBe(val);
}

MayBe.prototype.isNothing = function() {
  return (this.value === null || this.value === undefined);
};

MayBe.prototype.map = function(fn) {
  return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this.value));
};
```

Then we can use it by writing:

```
const str = MayBe.of("foo").map((x) => x.toUpperCase())
```

Then we get the the `value` property of the `MayBe` instance is `'FOO'` .

If `this.value` is `null` or `undefined` , then `map` will return a `MayBe` functor with `value` being `null` .

So if we have something like:

```
const str = MayBe.of("james")
  .map(() => undefined)
  .map((x) => `Mr. ${x}`)
```

We’ll get the final value of `value` being `null` instead of throwing an error.

### Either Functor

The `Either` functor allows us to solve problems with branches.

We create a `Nothing` or `Some` functor and out them in an object.

So we write:

```
const Nothing = function(val) {
  this.value = val;
};

Nothing.of = function(val) {
  return new Nothing(val);
};

Nothing.prototype.map = function(f) {
  return this;
};

const Some = function(val) {
  this.value = val;
};

Some.of = function(val) {
  return new Some(val);
};

Some.prototype.map = function(fn) {
  return Some.of(fn(this.value));
}
```

Now if want to hold some data, then we can use the `Some` functor.

Otherwise, we use the `Nothing` functor to hold some non-existent value.

### Monads

A monad is a functor with a `chain` method.

The `chain` method calls a `join` method to call it return an a `MayBe` instance if `this.value` has a value.

For example, we can write:

```
const MayBe = function(val) {
  this.value = val;
}

MayBe.of = function(val) {
  return new MayBe(val);
}

MayBe.prototype.isNothing = function() {
  return (this.value === null || this.value === undefined);
};

MayBe.prototype.map = function(fn) {
  return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this.value));
};

MayBe.prototype.join = function() {
  return this.isNothing() ? MayBe.of(null) : this.value;
}

MayBe.prototype.chain = function(f) {
  return this.map(f).join()
}
```

The `join` method checks if `this.value` is `null` or `undefined` .

If it is, then we return a `null` `MayBe` functor.

Otherwise, we return `this.value` .

`chain` just calls `map` and `join` together.

This way, if we map something to `null` , then it stays `null` .

Then we can use this by writing:

```
let mayBe = MayBe.of({
  data: [{
    title: 'foo',
    children: [{
      bar: 2
    }]
  }]
})

let ans = mayBe.map((arr) => arr.data)
  .chain((obj) => map(obj, (x) => {
    return {
      title: x.title
    }
  }))
```

then we get the `title` from the object we passed into `of` .

### Conclusion

A monad is a functor that has the `chain` method, which does the mapping and joining together.