🦋 Monas — Scala monads for javascript
“To Vik Lovell who told me dragons did not exist, then led me to their lairs …”
― Ken Kesey, One Flew Over the Cuckoo’s Nest
Here’s code that finds an item in a given collection:
let item = collection.find(…);
if (item !== null && typeof item !== 'undefined') {
// do something useful
...
}
In order to detect if the item was found it should be verified on null and undefined. Should look familiar to everyone, but what if there is a better way,… something like this:
collection.find(…).map(…)
Please meet 🦋 monas — scala monads for javascript.
> npm install monas
A long story short…
Monads eliminate null pointer exceptions and reduce branching (if statement) by treating results of a function as a collection rather than a nullable value. It’s more beneficial to work with an empty collection instead if null/undefined because it can be chained. Code looks more readable and this style of coding forces to write only pure functions.
Consider two coding styles:
1. Here the variable “a” is nullable:
let a = null
if (a !== null) {
return 'Hello ' + a;
}
2. Here it’s an empty collection:
[].map(a => 'Hello' + a)
The Monas library is built on the top of this concept and introduces two fundamental monads: Option<A>
and Either<A, B>
.
Option
Represents optional values. Instances of Option are either Some
or the object None
. Basic operations:
1. Create option
let a: Option<A> = option(smth);
where smth
— is an instance of A
or null/undefined
.
2. Transform option
Let’s say A
is a number
and I want to add 42 and filter only positive values.
let positiveNumber = a.map(_ => _ + 42).filter(_ => _ > 0);
3. Print it out
Now I want to print the result or return -1
.
let result: number = positiveNumber.getOrElse(-1);
To learn more check out repository here:
https://github.com/ddoronin/monas
P.S. Monas + React
It can be nifty to apply options to JSX templates when you want to put some if/else logic inside.
Let’s say there is a find()
function that can return a nullable result:
let result: A | null = find();
Instead of doing this:
{ result && <div>{result}</div> }
{ !result && <div>Not found.</div> }
one can treat it as an option and write a function that will return the template:
let result: Option<A> = option(findSomething());
...
// jsx{ result
.map(res => <div>{res}</div>)
.getOrElse(<div>Not found.</div>)
}
Or using reoption it can be rewritten as:
import { Match } from ‘reoption’
...
<Match option={result}
some={res => <div>{res}</div>}
none={<div>Not found.</div>}/>