Skip to content

Instantly share code, notes, and snippets.

@OliverBrotchie
Last active September 27, 2021 12:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OliverBrotchie/9a718512120dac47a1e330e04455d5f7 to your computer and use it in GitHub Desktop.
Save OliverBrotchie/9a718512120dac47a1e330e04455d5f7 to your computer and use it in GitHub Desktop.
Match example
const None = Symbol("None");
const DefaultErr = Symbol("Err");
type Option<T> = ((s: (val: T) => T) => T) | typeof None;
type Some<T> = (val: T) => Option<T>;
const Some: <T>(val: T) => Option<T> = (val) => (s) => s(val);
type Result<T, E> = (o: (val: T) => E, s: (val: symbol) => E) => E;
type Err<T> = T;
const Err: <A, B>(val: symbol) => Result<A, B> = (val: symbol) => (_, g) =>
g(val);
const Ok: <T, E>(val: T) => Result<T, E> = (val) => (f, _) => f(val);
/**
* A generic function with one argument.
*/
type OneArgFn<T, U> = (value: T) => U;
/**
* A generic function without arguments.
*/
type NoArgFn<T> = () => T;
const Default = Symbol("Default");
const Var = Symbol("Variable");
export function unwrap<T, U>(value: Option<T> | Result<T, U>): T {
if ((value as Option<T>) === None) throw `unwrap on None.`;
else if (
typeof value == "function" &&
(value.toString() === "(s) => s(val)" ||
value.toString() === "(f, _) => f(val)" ||
value.toString() === "(_, g) => g(val)")
) {
return (value as Result<T, T>)(
(val) => val as T,
(val) => {
throw `unwrap on ${val.toString()}.`;
}
);
} else return value as unknown as T;
}
export function getDetails<T>(value: unknown): {
callStructure: Array<string>;
value: T;
} {
const callStructure: Array<string> = [];
let val = value;
while (
typeof val == "function" &&
(val.toString() === "(s) => s(val)" ||
val.toString() === "(f, _) => f(val)" ||
val.toString() === "(_, g) => g(val)")
) {
callStructure.push(val.toString());
val(
(v: unknown) => (val = v),
(v: unknown) => (val = v)
);
}
return { callStructure: callStructure, value: val as T };
}
export function peek<T>(value: unknown): T {
return getDetails(value).value as T;
}
export function match<T, U, O>(
value: T,
cases: Array<[Result<U, U> | Option<U> | unknown, OneArgFn<U, O>]>
) {
const valueDetails = getDetails(value);
let found = false;
for (const c of cases) {
const caseDetails = getDetails(c[0]);
if (
JSON.stringify(valueDetails) == JSON.stringify(caseDetails) ||
(JSON.stringify(valueDetails.callStructure) ==
JSON.stringify(caseDetails.callStructure) &&
caseDetails.value === Var) ||
(!found && caseDetails.value === Default)
) {
c[1](valueDetails.value as U);
found = true;
}
}
}
// Usage of both result and option in a function
function divide(
numerator: unknown,
denominator: unknown
): Result<Option<number>, Err<typeof DefaultErr>> {
if (typeof numerator != "number" || typeof denominator != "number") {
return Err(DefaultErr);
} else if (denominator == 0) {
return Ok(None);
} else {
return Ok(Some(numerator / denominator));
}
}
match(divide(4, 2), [
[
Ok(Some(2)), // Example of case. Function will run if call strucuture and value of case is a match
(e) => {
console.log(`Value is ${e}!`);
},
],
[
Ok(Some(Var)), // Example usage of generic variable. Will run if call structure of case is a match
(e) => {
console.log(`Some(Var) was triggered. Value is ${e}!`);
},
],
[
Ok(None),
() => {
console.log(`Value is None`);
},
],
[
Err(DefaultErr),
() => {
console.log(`Error!`);
},
],
[
Default, // Case runs if no other case was triggered
() => {
console.log("Default Case!");
},
],
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment