Skip to content

Instantly share code, notes, and snippets.

@flysand7
Created December 9, 2023 14:23
Show Gist options
  • Save flysand7/5742f3a756a002e4bb8b21fac9c22fbe to your computer and use it in GitHub Desktop.
Save flysand7/5742f3a756a002e4bb8b21fac9c22fbe to your computer and use it in GitHub Desktop.
functional-typescript-test
import * as http from "http";
type Result<T, E> = readonly [T, null] | readonly [null, E];
function Ok<E, T>(value: T): readonly [T, null] {
return [value, null] as const;
}
function Err<E, T>(error: E): readonly [null, E] {
return [null, error] as const;
}
function isOk<E,T>([res, err]: Result<T,E>): boolean {
return res != null;
}
function MatchOk<T,E>([res, err]: Result<T,E>): [T, boolean] {
return [res as T, res !== null];
}
function MatchErr<T,E>([res, err]: Result<T,E>): [E, boolean] {
return [err as E, err !== null];
}
function isErr<E,T>([res, err]: Result<T,E>): boolean {
return err != null;
}
type Maybe<T> = T | null;
function Some<T>(value: T): Maybe<T> {
return value;
}
function None<T>(): Maybe<T> {
return null;
}
function MatchSome<T>(value: Maybe<T>): [T, boolean] {
return [value as T, value !== null];
}
function MatchNone<T>(value: Maybe<T>): [null, boolean] {
return [null, value === null];
}
function promise_maybe<T>(promise: Promise<T>): Promise<Maybe<T>> {
return promise
.then((r) => Some(r))
.catch((e) => None());
}
function promise_result<T>(promise: Promise<T>): Promise<Result<T, Error>> {
return promise
.then((r) => Ok(r))
.catch((e) => Err(e));
}
function http_get(url: string): Promise<Result<Buffer, Error>> {
return promise_result(new Promise((resolve, reject) => {
http.get(url, (result) => {
let data: Buffer[] = [];
result.on('data', chunk => {
data.push(chunk);
});
result.on('end', () => {
resolve(Buffer.concat(data));
});
}).on('error', (e) => {
reject(e);
});
}));
}
class Fatal extends Error {}
type MatchFunc<T,M> = (value: T)=>[M, boolean];
type ResultFunc<M,R> = (value: M)=>R;
class MatchingState<T, ExclSet=T, ResSet=never> {
private matched = false;
private computed!: ResSet;
constructor(private value: T) {}
with<M,R>(match: MatchFunc<T,M>, result: ResultFunc<M,R>): MatchingState<T, Exclude<ExclSet, M>, ResSet|R> {
if(this.matched) {
return this as unknown as MatchingState<T, Exclude<ExclSet, M>, ResSet | R>;
}
const [res, ok] = match(this.value)
if(ok) {
this.computed = result(res) as unknown as ResSet;
this.matched = true;
}
return this as unknown as MatchingState<T, Exclude<ExclSet, M>, ResSet | R>;
}
otherwise<R>(result: ResultFunc<ExclSet, R>): ResSet|R {
return result(this.value as unknown as ExclSet)
}
complete(): (never extends ExclSet ? ResSet : never) {
return this.computed as (never extends ExclSet ? ResSet : never);
}
}
function match<T>(value: T): MatchingState<T> {
return new MatchingState(value);
}
function fatal(message: string): never {
throw new Fatal(message)
}
async function test_requests(): Promise<void> {
console.log("Trying to connect to an address");
const response_2 = match(await http_get('http://google.com'))
.with(MatchOk, res => String(res))
.with(MatchErr, err => fatal(`Unable to connect`))
.complete();
console.log(response_2);
}
test_requests();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment