Created
June 26, 2018 05:13
-
-
Save maxgherman/01c129d07a13d8118a0d24387ce2a136 to your computer and use it in GitHub Desktop.
Typescript functional computations
This file contains hidden or 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
class Box<F, T> { } | |
class IsArray {} | |
interface IFunctor<F> { | |
fmap<A, B>(f: (a: A) => B, fa: Box<F, A>) : Box<F, B>; | |
} | |
type ArrayF<T> = Box<IsArray, T> & Array<T>; | |
class BoxedArray<K, T extends Array<K>> extends Box<IsArray, T> { | |
private constructor(private value: T) { | |
super(); | |
this.value = value || []; | |
} | |
public static wrap<K, T extends Array<K>>(value: T) { | |
return new BoxedArray<K, T>(value); | |
} | |
public unwrap(): T { | |
return this.value; | |
} | |
} | |
class PlainArrayFunctor implements IFunctor<IsArray> { | |
fmap<A, B>(f: (a: A) => B, fa: ArrayF<A>) : ArrayF<B> { | |
return fa.map(f); | |
} | |
} | |
class BoxedArrayFunctor<A, B> implements IFunctor<IsArray> { | |
fmap<A, B>(f: (a: A) => B, fa: BoxedArray<A, A[]>) : BoxedArray<B, B[]> { | |
return BoxedArray.wrap(fa.unwrap().map(f)); | |
} | |
} | |
class Maybe<T> { | |
private _isNothing: boolean; | |
private constructor(private _value?: T) { | |
this._isNothing = _value ? false : true; | |
} | |
public static from<R>(value?: R) { | |
return new Maybe<R>(value); | |
} | |
public static Nothing<R>() { | |
return new Maybe<R>(); | |
} | |
public get isJust() { | |
return !this.isNothing; | |
} | |
public get isNothing() { | |
return this._isNothing; | |
} | |
public get value() { | |
return this._value; | |
} | |
} | |
class IsMaybe {} | |
type MaybeF<T> = Box<IsMaybe, T> & Maybe<T>; | |
class MaybeFunctor implements IFunctor<IsMaybe> { | |
fmap = <A, B>(f: (a: A) => B, fa: MaybeF<A>) : MaybeF<B> => | |
fa.isNothing ? Maybe.Nothing() : Maybe.from(f(fa.value as A)); | |
} | |
class Either<T1, T2> { | |
private _isLeft: boolean; | |
private _isRight: boolean; | |
private constructor(private _left?: T1, private _right?: T2) { | |
this._isLeft = _left ? true: false; | |
this._isRight = _right ? true: false; | |
} | |
public static Left<T>(a: T) { | |
return new Either<T, {}>(a); | |
} | |
public static Right<T>(a: T) { | |
return new Either<{}, T>(undefined, a); | |
} | |
public get isLeft() { | |
return this._isLeft; | |
} | |
public get isRight() { | |
return this._isRight; | |
} | |
public get value() { | |
return this._isLeft ? this._left : this._right; | |
} | |
} | |
class IsEither {} | |
type EitherF<T1, T2> = Box<IsEither, T2> & Either<T1, T2>; | |
class EitherFunctor<R> implements IFunctor<IsEither> { | |
fmap = <A, B>(f: (a: A) => B, fa: EitherF<R, A>) : EitherF<R, B> => | |
fa.isLeft ? | |
Either.Left(fa.value) as EitherF<R, B> : | |
Either.Right(f(fa.value as A)) as EitherF<R, B>; | |
} | |
const apply = (f, g) => (...args) => f(g(...args)); | |
const compose = (...fns: Function[]) => fns.reduce(apply); | |
const papply = (f, a) => b => f(a, b) | |
/// ------------------------------------------------------------------ | |
const arrayF = new PlainArrayFunctor(); | |
const arrayFResult = arrayF.fmap((item: number) => item * 2, [1, 2, 3]); | |
const arrayBoxed = new BoxedArrayFunctor(); | |
const arrayBResult = arrayBoxed.fmap((item) => item * 2, BoxedArray.wrap<number, number[]>([1, 2, 3])); | |
const maybeF = new MaybeFunctor(); | |
const maybeFResult = maybeF.fmap((item) => item * 2, Maybe.from(123)); | |
const eitherF = new EitherFunctor(); | |
const eitherFResult = eitherF.fmap((item) => item * 2, Either.Right(123)); | |
// console.log('arrayF ', arrayFResult); | |
// console.log('arrayB ', arrayBResult); | |
// console.log('maybeF ', maybeFResult); | |
// console.log('eitherF ', eitherFResult); | |
const maybeMapper1 = papply(maybeF.fmap, (item) => item * 2); | |
const maybeMapper2 = papply(maybeF.fmap, (item) => item + 7.5); | |
const maybeMapper3 = papply(maybeF.fmap, (item) => Math.pow(item, 0.5)); | |
const logger = (item) => { console.log(item); return item }; | |
const composer = compose( | |
maybeMapper3, | |
logger, | |
maybeMapper1, | |
logger, | |
maybeMapper2 | |
); | |
console.log(composer(Maybe.from(5))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment