Last active
September 27, 2021 12:14
-
-
Save OliverBrotchie/9a718512120dac47a1e330e04455d5f7 to your computer and use it in GitHub Desktop.
Match example
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
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