import assert from 'assert' import * as Ma from 'fp-ts/Magma' import * as Fu from 'fp-ts/Functor' import * as Ap from 'fp-ts/Applicative' import * as FN from 'fp-ts/function' import * as B from 'fp-ts/boolean' import * as S from 'fp-ts/string' import * as N from 'fp-ts/number' import * as A from 'fp-ts/Array' /* ================================================================== * boolean ** INSTANCES B.BooleanAlgebra B.Eq B.MonoidAny B.MonoidAll B.Ord B.SemigroupAny B.SemigroupAll B.Show ** REFINEMENTS B.isBoolean ** PATTERN MATCHING B.fold B.foldW B.match B.matchW */ assert.strictEqual( B.MonoidAll.concat(true, false), false ) assert.strictEqual( Ma.concatAll(B.SemigroupAll)(true)([true, true, true, true]), true ) assert.strictEqual( FN.pipe(true, B.fold(FN.constant(1), FN.constant(2))), 2 ) assert.strictEqual( FN.pipe(true, B.foldW(FN.constant(1), FN.constant('2'))), '2' ) assert.strictEqual( FN.pipe(true, B.match(FN.constant(1), FN.constant(2))), 2 ) assert.strictEqual(B.isBoolean("true"), false) assert.strictEqual(B.isBoolean(false), true) /* ================================================================== * number ** INSTANCES N.Bounded N.Eq N.Ord N.Field N.MagmaSub N.SemigroupProduct N.SemigroupSum N.MonoidProduct N.MonoidSum N.Show ** REFINEMENTS isNumber */ assert.strictEqual(N.isNumber(1), true) assert.strictEqual(N.isNumber('1'), false) assert.strictEqual(N.Bounded.bottom, -Infinity) assert.strictEqual(N.Bounded.top, Infinity) assert.strictEqual(N.Bounded.compare(1, 1), 0) assert.strictEqual(N.Bounded.compare(1, 2), -1) assert.strictEqual(N.Bounded.compare(2, 1), 1) assert.strictEqual(N.Bounded.equals(N.Bounded.bottom, -Infinity), true) assert.strictEqual(N.SemigroupProduct.concat(2, 3), 6) assert.strictEqual(N.SemigroupSum.concat(2, 3), 5) assert.strictEqual(N.MonoidProduct.empty, 1) assert.strictEqual(N.MonoidSum.empty, 0) assert.strictEqual(Ma.concatAll(N.MonoidProduct)(1)([1, 2, 3]), 6) assert.strictEqual(Ma.concatAll(N.MonoidSum)(0)([1, 2, 3]), 6) assert.strictEqual( FN.pipe([1, 2, 3, 4], Ma.concatAll(N.MonoidProduct)(1)), 24 ) /* ================================================================== * string ** INSTANCES S.Eq S.Ord S.Monoid S.Semigroup S.Show ** REFINEMENTS S.isString ** UTILS S.empty S.replace S.size S.slice S.split S.toLowerCase S.toUpperCase S.trim S.trimLeft S.trimRight S.isEmpty S.includes S.startsWith S.endsWith */ assert.strictEqual(FN.pipe('hello', S.isEmpty), false) assert.deepEqual(FN.pipe('hello world', S.split(/\s+/)), ['hello', 'world']) /* ================================================================== * function ** INSTANCES FN.getBooleanAlgebra FN.getMonoid FN.getSemigroup FN.getSemiring FN.getRing let f = FN.getBooleanAlgebra(booleanAlgebraVoid) console.log(f()) */ let x = FN.getMonoid(N.MonoidSum)() let y = x.concat(x => x.length, y => y.length)('12345') assert.strictEqual(y, 10) /* ================================================================== * Functor */ Fu.bindTo Fu.flap Fu.let Fu.map assert.deepEqual( A.Functor.map([1, 2, 3], x => x.toString().repeat(x)), ["1", "22", "333"] ) /* ================================================================== * Apply & Applicative */ Ap.getApplicativeMonoid assert.deepEqual( A.Apply.ap([x => x + 1, x => x * 2], [1, 2, 3]), [2, 3, 4, 2, 4, 6] ) assert.deepEqual(A.Applicative.of(0), [0]) // `map` vs `lift` // Kita bisa membuat `lift` menggunakan `map` dan sebaliknya. interface IFn1 { (x: number): number } interface IFn2 { (x: number): IFn1 } interface IFn3 { (x: number): IFn2 } interface IFn4 { (x: number): IFn3 } let lift = (f0: IFn1) => (xs: number[]) => A.Functor.map(xs, f0) // Ternyata, A.map adalah lift let f1: IFn1 = x => x + 1 assert.deepEqual( lift(f1)([1, 2, 3]), [2, 3, 4] ) assert.deepEqual( lift(f1)([1, 2, 3]), A.map(f1)([1, 2, 3]) ) assert.deepEqual( FN.pipe(f1, lift, x => x([1, 2, 3])), FN.pipe([1, 2, 3], A.map(f1)) ) /* ================================================================== * lifting -- An operation of Applicative * lift (a -> b) :: F a -> F b * liftA2 (a -> b -> c) :: F a -> F b -> F c * liftA3 (a -> b -> c -> d) :: F a -> F b -> F c -> F d f1 :: a -> b f2 :: a -> b -> c f3 :: a -> b -> c -> d pipe(of(f1), ap([1, 2])) pipe(of(f2), ap([1, 2]), ap([10])) pipe(of(f3), ap([1, 2]), ap([10]), ap([100])) */ // `liftA1` assert.deepEqual( A.ap([1, 2, 3])(A.of(f1)), [2, 3, 4] ) assert.deepEqual( FN.pipe([1, 2, 3], A.map(f1)), [2, 3, 4] ) assert.deepEqual( FN.pipe(A.of(f1), A.ap([1, 2, 3])), [2, 3, 4] ) // `liftA2` let f2: IFn2 = x => y => x + y assert.deepEqual( FN.pipe([1, 2, 3], A.map(f2), A.ap([10])), [11, 12, 13] ) assert.deepEqual( FN.pipe(A.of(f2), A.ap([1, 2, 3]), A.ap([10])), [11, 12, 13] ) // `liftA3` & `liftA4` let f3: IFn3 = x => y => z => x + y + z assert.deepEqual( FN.pipe(A.of(f3), A.ap([1, 2, 3]), A.ap([10]), A.ap([100])), [111, 112, 113] ) let f4: IFn4 = x => y => z => a => x + y + z + a assert.deepEqual( FN.pipe(A.of(f4), A.ap([1, 2, 3]), A.ap([10]), A.ap([100]), A.ap([1000])), [1111, 1112, 1113] )