Skip to content

Instantly share code, notes, and snippets.

@tonyonodi
Created June 17, 2019 22:42
Show Gist options
  • Save tonyonodi/0aa2368afff56c54f20d3d81dac2e813 to your computer and use it in GitHub Desktop.
Save tonyonodi/0aa2368afff56c54f20d3d81dac2e813 to your computer and use it in GitHub Desktop.
An attempt at higher kinded types in TypeScript
// Maybe
class Nothing {
readonly tag: "None" = "None";
}
class Just<A> {
readonly tag: "Just" = "Just";
constructor(readonly value: A) {}
}
type Maybe<A> = Just<A> | Nothing;
const just = <A>(val: A): Maybe<A> => new Just(val);
const nothing: Maybe<never> = new Nothing();
// List
class List<A> {
readonly tag: "List" = "List";
constructor(readonly value: A[]) {}
}
const list = <A>(arr: A[]) => new List(arr);
// Functor
type Functor<A> = List<A> | Maybe<A>;
function map<A, B>(fn: (x: A) => B, m: List<A>): List<B>;
function map<A, B>(fn: (x: A) => B, m: Nothing): Nothing;
function map<A, B>(fn: (x: A) => B, m: Maybe<A>): Maybe<B>;
function map<A, B>(fn: (x: A) => B, m: Functor<A>) {
switch (m.tag) {
case "None":
return nothing;
case "Just":
return just(fn(m.value));
case "List":
return list(m.value.map(fn));
}
}
// Test code
const double = (n: number) => n * 2;
const n = map(double, nothing); // Nothing
const l1 = list([1, 2, 3, 5]);
const l2 = map(double, l1); // List<number>
const mapDoubleM = (m: Maybe<number>) => {
return map(double, m);
};
const doubled = mapDoubleM(just(5)); // Maybe<number>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment