Last active
July 11, 2022 06:06
-
-
Save erodactyl/568aee5af425f8dd741f999375f0c788 to your computer and use it in GitHub Desktop.
Maybe monad implemented functionally in typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class None {} | |
class Some<T> { | |
constructor(public value: T) {} | |
} | |
type Maybe<T> = None | Some<T>; | |
export const none = new None(); | |
export const some = <T>(val: T) => new Some(val); | |
export const maybe = <T>(val: T | null) => { | |
return val === null ? none : some(val); | |
}; | |
export const nonEmpty = <T>(m: Maybe<T>): m is Some<T> => { | |
if (m === none) return false; | |
return true; | |
}; | |
/** | |
* Unwraps a Maybe object with value. Can only be called on Some<T>. | |
* Confirm that the object is Some<T> before calling. | |
*/ | |
export const unwrap = <T>(m: Some<T>): T => { | |
return m.value; | |
}; | |
export const bind = <T, V>(m: Maybe<T>, operator: (val: T) => V) => { | |
if (!nonEmpty(m)) return none; | |
return some(operator(unwrap(m))); | |
}; | |
export const match = <T, V>( | |
m: Maybe<T>, | |
matcher: { | |
some: (val: T) => V; | |
none: () => V; | |
} | |
) => { | |
if (!nonEmpty(m)) return matcher.none(); | |
return matcher.some(unwrap(m)); | |
}; | |
// USAGE | |
const getUser = () => (Math.random() < 0.5 ? null : { username: "Erik" }); | |
const user = maybe(getUser()); | |
const username = bind(user, (u) => u.username); | |
const initials = bind(username, (un) => un.slice(0, 2)); | |
const len = bind(initials, (in_) => in_.length); | |
const final = match(len, { | |
some: (l) => l * 2, | |
none: () => 8, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment