Skip to content

Instantly share code, notes, and snippets.

@reedho
Last active March 18, 2023 05:05
Show Gist options
  • Save reedho/e3db4dca6de2f56dbb8ec58e43e6094f to your computer and use it in GitHub Desktop.
Save reedho/e3db4dca6de2f56dbb8ec58e43e6094f to your computer and use it in GitHub Desktop.
5 minute fp-ts fundamental overview
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)<string>()
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]
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment