Skip to content

Instantly share code, notes, and snippets.

@venil7
Last active January 31, 2020 13:06
Show Gist options
  • Save venil7/027b62be1c20ba8acf511ea3264d2fde to your computer and use it in GitHub Desktop.
Save venil7/027b62be1c20ba8acf511ea3264d2fde to your computer and use it in GitHub Desktop.
State Monad in TypeScript
class StateMonad<S, A> {
constructor(public runState: (s: S) => ({ s: S, a: A })) {
}
static return_<S, A>(a: A): StateMonad<S, A> {
return new StateMonad(s => ({ s, a }));
}
bind<B>(func: (a: A) => StateMonad<S, B>): StateMonad<S, B> {
return new StateMonad<S, B>((s: S) => {
const { s: s_, a } = this.runState(s);
return func(a).runState(s_);
});
}
}
const createCounter = (regex: RegExp) => new StateMonad((s: string) =>
s.split('')
.reduce((acc, c) =>
(regex.test(c)) ? { s: acc.s.replace(c, ''), a: acc.a + 1 } : acc,
{ s, a: 0 })
);
const countLowerCase = createCounter(/[a-z]/);
const countDigits = createCounter(/[0-9]/);
const { a } = countLowerCase /* -- haskell equivalent */
.bind(n1 => countDigits /* do n1 <- countLowerCase */
.bind(n2 => StateMonad /* n2 <- countDigits */
.return_(n1 + n2))) /* return n1 + n2 */
.runState("abc123ABC");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment