JavaScript monads part 5
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.