Skip to content

Instantly share code, notes, and snippets.

@zeusdeux
Last active February 19, 2024 19:20
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeusdeux/cb573186899f82571ae72e040c4e2755 to your computer and use it in GitHub Desktop.
Save zeusdeux/cb573186899f82571ae72e040c4e2755 to your computer and use it in GitHub Desktop.
Another Maybe and Either implementation in Typescript without making the value constructors (Just, Nothing, Left and Right) types themeselves as in the previous attempt
import { Maybe, Just, Nothing } from "./Maybe";
import { Either, Left, Right } from "./Either";
import { match } from "./match";
const a: Maybe<number> = Just(5);
const b: Maybe<number> = Nothing();
const x: Either<Error, number> = Right(10);
const y: Either<Error, string> = Left(new Error("DB broken bud"));
// match on a Maybe
// m has the inferred type number | null
let m = match(a, {
just: v => v,
nothing: () => null
});
// n has the inferred type number | string
let n = match(b, {
just: v => v,
nothing: () => "ugh"
});
// match on an Either
// o has the inferred type void | number
let o = match(x, {
left: err => console.log(err),
right: v => v
});
// p has the inferred type string | { name: string }
let p = match(y, {
left: err => err.message,
right: v => ({ name: v })
});
console.log(m, n, o, p);
// Either monad using discriminated unions
export type Either<L, R> =
| { type: "left"; value: L }
| { type: "right"; value: R };
export function Left<L, R>(a: L): Either<L, R> {
return {
type: "left",
value: a
};
}
export function Right<L, R>(b: R): Either<L, R> {
return {
type: "right",
value: b
};
}
export type EitherMatchers<L, R, U, V> = {
left: (v: L) => U;
right: (v: R) => V;
};
// match/caseOf on Maybe and Either types
import { Maybe, MaybeMatchers } from "./Maybe";
import { Either, EitherMatchers } from "./Either";
export function match<T, U, V>(
v: Maybe<T>,
matchers: MaybeMatchers<T, U, V>
): U | V;
export function match<L, R, U, V>(
v: Either<L, R>,
matchers: EitherMatchers<L, R, U, V>
): U | V;
export function match(v: any, matchers: any) {
if (v.type === "left") {
return matchers.left(v.value);
} else if (v.type === "right") {
return matchers.right(v.value);
} else if (v.type === "just") {
return matchers.just(v.value);
} else if (v.type === "nothing") {
return matchers.nothing();
}
}
// Maybe monad using discriminated unions
export type Maybe<T> = { type: "just"; value: T } | { type: "nothing" };
export function Just<T>(a: T): Maybe<T> {
return {
type: "just",
value: a
};
}
export function Nothing<T>(): Maybe<T> {
return {
type: "nothing"
};
}
export type MaybeMatchers<T, U, V> = {
just: (v: T) => U;
nothing: () => V;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment