JavaScript monads part 5

Mbedingfield
2 min readDec 4, 2022

--

Hopefully you have been following this series which starts here.

Let’s pick up where we left off and add a function that can add a composable feel to our maybes. We’ll see what composable is in a later post. I probably should have covered that first, but we are winging this, so that is that. Here is our new maybe function:

export const Maybe = {
just: maybe,
nothing: () => maybe(null),
chain: (...fns) => (x) => fns.reduce((y, f) => y.map(f), x)
};

Now, let’s change our test code:

const appendToC = Maybe.chain(prop('b'), prop('c'), append(' works still'));

const goodInput = Maybe.just({
b: {
c: 'my code',
},
});

const badInput = Maybe.just({});

console.log(appendToC(goodInput).extract());
console.log(appendToC(badInput).extract());

At this point, just for posterities sake, your index.js should look like this:

console.log('you are ready to start coding...');
import { Maybe } from './Maybe';

const root = document.createElement('div');
root.id = 'root';
document.body.appendChild(root);

const main = document.createElement('div');
const child = document.createElement('p');
child.innerHTML = 'Hello';
main.appendChild(child);
root.appendChild(main);

const maybeNumberOne = Maybe.just(1);
const mappedJust = maybeNumberOne.map((x) => x + 1);
console.log(mappedJust.extract());

const maybeNumberTwo = Maybe.nothing();
const mappedNothing = maybeNumberTwo.map((x) => x + 1);
console.log(mappedNothing.extract());

const prop = (propName) => (obj) => obj[propName];
const append = (appendee) => (appendix) => appendix + appendee;

const appendToC = Maybe.chain(prop('b'), prop('c'), append(' works still'));

const goodInput = Maybe.just({
b: {
c: 'my code',
},
});

const badInput = Maybe.just({});

console.log(appendToC(goodInput).extract());
console.log(appendToC(badInput).extract());

And your Maybe.js should look like this:

const isNullOrUndef = (v) => v === null || typeof v === 'undefined';

const maybe = (x) => ({
isNothing: () => isNullOrUndef(x),
extract: () => x,
map: (f) => (!isNullOrUndef(x) ? Maybe.just(f(x)) : Maybe.nothing()),
});

export const Maybe = {
just: maybe,
nothing: () => maybe(null),
chain:
(...fns) =>
(x) =>
fns.reduce((y, f) => y.map(f), x),
};

Just wanted to clear that up. Now our console should look like this:

I think this is all pretty dope. Hopefully this was a good understanding of what you can really do with this with actual real data, but if not, we’ll look at that too in the next story.

--

--