Loading....
type Either<L, R> = Left<L, R> | Right<L, R>;
class Left<L, R> {
constructor(public value: L) {}
isLeft(): this is Left<L, R> {
return true;
}
isRight(): this is Right<L, R> {
return false;
}
}
class Right<L, R> {
constructor(public value: R) {}
isLeft(): this is Left<L, R> {
return false;
}
isRight(): this is Right<L, R> {
return true;
}
}
function map<L, R, U>(either: Either<L, R>, fn: (value: R) => U): Either<L, U> {
return either.isRight() ? new Right<L, U>(fn(either.value)) : new Left<L, U>(either.value);
}
function flatMap<L, R, U>(either: Either<L, R>, fn: (value: R) => Either<L, U>): Either<L, U> {
return either.isRight() ? fn(either.value) : new Left<L, U>(either.value);
}
function composeM<L, R, U, V>(
f: (x: R) => Either<L, U>,
g: (x: U) => Either<L, V>
): (x: R) => Either<L, V> {
return (x: R) => flatMap(f(x), g);
}
const parseNumber = (str: string): Either<string, number> => {
const num = Number(str);
return isNaN(num) ? new Left("Invalid number") : new Right(num);
};
const increment = (num: number): Either<string, number> => {
return new Right(num + 1);
};
const composedFunction = composeM(parseNumber, increment);
const result1 = composedFunction("42"); // Right(43)
const result2 = composedFunction("abc"); // Left("Invalid number")
console.log(result1); // Right { value: 43 }
console.log(result2); // Left { value: 'Invalid number' }
export function composeMultiple<L, R>(...fns: ((x: any) => Either<L, any>)[]): (x: R) => Either<L, R> {
return (x: R) => fns.reduce((acc, fn) => flatMap(acc, fn), new Right<L, R>(x));
}