Created
November 22, 2018 13:44
-
-
Save morozovamv/ee9011366d4552959b59e560b5a3dd28 to your computer and use it in GitHub Desktop.
Road to monad: applicative and chain (+setoid)
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
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