Skip to content

Instantly share code, notes, and snippets.

@morozovamv
Created November 22, 2018 13:44
Show Gist options
  • Save morozovamv/ee9011366d4552959b59e560b5a3dd28 to your computer and use it in GitHub Desktop.
Save morozovamv/ee9011366d4552959b59e560b5a3dd28 to your computer and use it in GitHub Desktop.
Road to monad: applicative and chain (+setoid)
import { Option, some, none, fromNullable, getSetoid as getSetoidOpt } from 'fp-ts/lib/Option';
import { success, getSetoid as getSetoidRD } from '@devexperts/remote-data-ts';
import { of, Observable, combineLatest } from 'rxjs';
import { setoidNumber, setoidString, getRecordSetoid } from 'fp-ts/lib/Setoid';
import { Function1 } from 'fp-ts/lib/function';
type TUser = {
name: string;
};
const setoidUser = getRecordSetoid<TUser>({
name: setoidString,
});
const x = success<string, Option<TUser>>(some({ name: 'sasha' }));
const y = success<string, Option<TUser>>(some({ name: 'sasha' }));
const isEq = getSetoidRD(setoidString, getSetoidOpt(setoidUser)).equals(x, y);
console.log('isEq', isEq);
// A.of(B) -> A<B>
// Option.some(B) -> Option<B>
// some(4) -> Option<number>
// Observable.of(B) -> Observable<B>
// of(4) -> Observable<number>
// RemoteDate.of<E, B>(B) -> RemoteDate<E, B>
// success<Error, number>(4) -> RemoteDate<Error, number>
// Rules
// Identity: A.ap(A.of(a => a), fa) = fa
const value = 1;
const identity = <A>(v: A): A => v; // identity(141) === 141
const xOptId = some(value); //option(number)
const yOptId = xOptId.ap(some<Function1<number, number>>(identity)); //option(number)
const isEqualsOptId = xOptId.isSome() && yOptId.isSome() && xOptId.value === yOptId.value;
const xRdId = success<string, number>(value);
const yRdId = xRdId.ap(success<string, Function1<number, number>>(identity));
const isEqualsRdId = getSetoidRD(setoidString, setoidNumber).equals(xRdId, yRdId); // избыточная проверка
const xObsId = of<number>(value);
const yObsId = ap(of<Function1<number, number>>(identity), xObsId);
const isEqualsObsId = combineLatest(yObsId, xObsId, (x, y) => setoidNumber.equals(x, y));
console.group('Identity');
console.log('option', isEqualsOptId);
console.log('remoteData', isEqualsRdId);
isEqualsObsId.subscribe(x => console.log('observable', x));
console.groupEnd();
// Homomorphism: A.ap(A.of(ab), A.of(a)) = A.of(ab(a))
const plusTwo = (n: number): number => n + 2;
const xOptH = some(value).ap(some(plusTwo));
const yOptH = some(plusTwo(value));
const isEqualsOptH = getSetoidOpt(setoidNumber).equals(xOptH, yOptH);
const xRdH = success<string, number>(value).ap(success(plusTwo));
const yRdH = success<string, number>(plusTwo(value));
const isEqualsRDH = getSetoidRD(setoidString, setoidNumber).equals(xRdH, yRdH);
const xObsH = ap(of(plusTwo), of(value));
const yObsH = of(plusTwo(value));
const comparedObsH = combineLatest(xObsH, yObsH, (x, y) => setoidNumber.equals(x, y));
console.group('Homomorphism');
console.log('option', isEqualsOptH);
console.log('remoteData', isEqualsRDH);
comparedObsH.subscribe(x => console.log('observable', x));
console.groupEnd();
// Interchange: A.ap(fab, A.of(a)) = A.ap(A.of(ab => ab(a)), fab)
type TFn = (fn: Function1<number, number>) => number;
const xOpt = some(value).ap(some(plusTwo));
const yOpt = some(plusTwo).ap(some<TFn>(fn => fn(value)));
const isEqualsOptIn = getSetoidOpt(setoidNumber).equals(xOpt, yOpt);
const xRD = success<string, number>(value).ap(success(plusTwo));
const yRD = success<string, Function1<number, number>>(plusTwo).ap(success<string, TFn>(fn => fn(value)));
const isEqualsRDI = getSetoidRD(setoidString, setoidNumber).equals(xRD, yRD);
const xObsI = ap(of(plusTwo), of(value));
const yObsI = ap(of<TFn>(fn => fn(value)), of(plusTwo));
const isEqualsObsI = combineLatest(xObsI, yObsI, (x, y) => setoidNumber.equals(x, y));
console.group('Interchange');
console.log('option', isEqualsOptIn);
console.log('remoteData', isEqualsRDI);
isEqualsObsI.subscribe(x => console.log('observable', x));
console.groupEnd();
// chain example
const initialData = [1, 2, 3, 4] || null;
const data = fromNullable(initialData); // some([1, 2, 3, 4]) Functor | Apply | Applicative
// need first element
// const first = data.isSome() && data.value[0]; // if [] => undefined
const head = <T>(a: Array<T>): Option<T> => (a.length === 0 ? none : some(a[0]));
// of - class: M<T>; argument: T --- Applicative A.of(T) => M<T>
// map - class: M<T>; argument: T -> T` --- Functor F.map(T -> T`)
// const firstItemMap = data.map(head);
// ap - class: M<T>; argument: M<T -> T`> --- Apply A.ap(M<T -> T`>)
// const firstItemAp = data.ap(some<(n: Array<number>) => Option<number>>(head));
// chain - class: M<T>; argument: T -> M<T`> --- Chain C.chain(T -> M<T`>)
// function chain<V, R>(g: (value: V) => Option<R>, value: Option<V>): Option<R> {
// if (value.isSome()) {
// return g(value.value);
// }
// return none;
// }
const firstItemFn = data.chain(head);
console.log('firstItemFn', firstItemFn);
function ap<A, B>(fn: Observable<(a: A) => B>, value: Observable<A>): Observable<B> {
return combineLatest(fn, value, (fn, value) => fn(value));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment