monads-typescript v1.1.1
monads-typescript
In functional programming, a monad is a design pattern that allows structuring programs generically while automating away boilerplate code needed by the program logic.
In a strongly typed liked language like Scala, with built-in types like the Option type, you are very likely
to have already used or will eventually end up using monads without even knowing you are using them. This project
is my attempt at understanding monads by writing them, and I decided to use TypeScript because it forces me to
build monads from "scratch", but with support for strong typing.
Installation
npm i monads-typescriptUsage
Import the appropriate static methods from the library like so:
import { left, right } from 'monads-typescript';
import { maybe } from 'monads-typescript';
...Maybe Monad
The first monad, the Maybe monad, is based on Scala's
Option type. It's very useful when you want
to encapsulate computation on values that might be null or undefined.
Here's an example of some code you might find yourself writing in JavaScript/TypeScript:
const greetUser = (userId) => {
const user = getUser(userId);
let name;
if (user) {
name = user.getName();
}
if (name) {
return `Hello ${name}`;
} else {
return 'Hello, guest';
}
}Using the Maybe monad:
const greetUser = (userId: number) => {
return maybe(getUser(userId))
.map((user) => user.getName())
.map((name) => `Hello, ${name}`)
.getOrElse('Hello, guest');
};Depending on your application, you could simplify this even further, like so:
const getName = (user: User) => user.getName();
const greetName = (name: string) => `Hello, ${name}`;
const greetUser = (userId: number) => {
return maybe(getUser(userId))
.map(getName)
.map(greetName)
.getOrElse(greetName('guest'));
};As you can see, using the Maybe monad abstracts away a lot of boilerplate, giving you a flat, composable
interface to work with that's much more readable.
Either Monad
Similarly, the Either monad is based on Scala's
Either type.
The Either monad is useful when you want to represent one of two possible types. An instance of
Either is either a Left or Right. By convention, Right is used to represent a success type, while
Left is used to hold a failure type.
Here's another example of some code you might write in imperative TypeScript:
const getAge = (uid: number): number | never => ...;
const canDrink = (age: number): boolean => age >= 18;
const okToDrink = (uid: number) => {
try {
const age = getAge(uid);
if (age) {
return canDrink(age);
}
} catch {
return false;
}
} Rewriting this using the Either monad:
const getAge = (uid: number): Either<string, number> => ...; // the left represents an error string
const canDrink = (age: number): boolean => age >= 18;
const okToDrink = (uid: number) => {
getAge(uid).fold(
(error) => {
console.log(`Error getting age: ${error}`);
return false;
},
(age) => canDrink(age)
)
}Resources
- Demystifying the Monad in Scala, Sinisa Louc, a well-written, technical, yet approachable explanation of monads in Scala.
- Douglas Crockford, Monads and Gonads, Google Tech Talks Most talks about Monads involve some assumption that types are essential in creating monadic abstractions. This talk is a refreshing non-academic take on why we need monads (in programming) to begin with, and how you could build one in vanilla (untyped) JavaScript.