Repository: gcanti/fp-ts
Pull request #991 (2019-10-29 23:41:05)

Add init for NonEmptyArray


Patch:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 5c9e589d..ef0bd92b 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -5,6 +5,8 @@
 - If you've fixed a bug or added code that should be tested, add tests!
 - Ensure the test suite passes (`npm test`).
 
+**Note**. If you've fixed a bug please link the related issue or, if missing, open an issue before sending a PR.
+
 **Note**. If you find a typo in the **documentation**, make sure to modify the corresponding source (docs are generated).
 
 **Note**. If you want to send a PR related to `fp-ts@1.x` please create your branch from `1.x`
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 47102c4f..97bef4c5 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,3 @@
 {
-  "typescript.tsdk": "./node_modules/typescript/lib",
-  "prettier.printWidth": 120,
-  "prettier.semi": false,
-  "prettier.singleQuote": true,
-  "rewrap.wrappingColumn": 120
+  "typescript.tsdk": "./node_modules/typescript/lib"
 }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5433c68..2c3f9b71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,11 @@
 **Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a
 high state of flux, you're at risk of it changing without notice.
 
+# 2.1.2
+
+- **Bug Fix**
+  - `fromNullable` now uses `NonNullable` in its return type, fixes #1004 (@gcanti)
+
 # 2.1.1
 
 - **Bug Fix**
diff --git a/docs/introduction/upgrade-to-v2.md b/docs/introduction/upgrade-to-v2.md
index dbc9e2d0..233dcf4c 100644
--- a/docs/introduction/upgrade-to-v2.md
+++ b/docs/introduction/upgrade-to-v2.md
@@ -69,7 +69,7 @@ import * as O from 'fp-ts/lib/Option'
 
 O.some(1)
   .map(n => n * 2)
-  .chain(n === 0 ? O.none : O.some(1 / n))
+  .chain(n => (n === 0 ? O.none : O.some(1 / n)))
   .filter(n => n > 1)
   .foldL(() => 'ko', () => 'ok')
 ```
@@ -84,7 +84,7 @@ import { pipe } from 'fp-ts/lib/pipeable'
 pipe(
   O.some(1),
   O.map(n => n * 2),
-  O.chain(n === 0 ? O.none : O.some(1 / n)),
+  O.chain(n => (n === 0 ? O.none : O.some(1 / n))),
   O.filter(n => n > 1),
   O.fold(() => 'ko', () => 'ok')
 )
diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md
index cabc892f..3788f8ee 100644
--- a/docs/modules/Array.ts.md
+++ b/docs/modules/Array.ts.md
@@ -252,12 +252,22 @@ export function comprehension<A, R>(input: [Array<A>], f: (a: A) => boolean, g?:
 import { comprehension } from 'fp-ts/lib/Array'
 import { tuple } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(comprehension([[1, 2, 3], ['a', 'b']], tuple, (a, b) => (a + b.length) % 2 === 0), [
-  [1, 'a'],
-  [1, 'b'],
-  [3, 'a'],
-  [3, 'b']
-])
+assert.deepStrictEqual(
+  comprehension(
+    [
+      [1, 2, 3],
+      ['a', 'b']
+    ],
+    tuple,
+    (a, b) => (a + b.length) % 2 === 0
+  ),
+  [
+    [1, 'a'],
+    [1, 'b'],
+    [3, 'a'],
+    [3, 'b']
+  ]
+)
 ```
 
 Added in v2.0.0
@@ -438,7 +448,10 @@ import { findFirst } from 'fp-ts/lib/Array'
 import { some } from 'fp-ts/lib/Option'
 
 assert.deepStrictEqual(
-  findFirst((x: { a: number; b: number }) => x.a === 1)([{ a: 1, b: 1 }, { a: 1, b: 2 }]),
+  findFirst((x: { a: number; b: number }) => x.a === 1)([
+    { a: 1, b: 1 },
+    { a: 1, b: 2 }
+  ]),
   some({ a: 1, b: 1 })
 )
 ```
@@ -514,7 +527,10 @@ import { findLast } from 'fp-ts/lib/Array'
 import { some } from 'fp-ts/lib/Option'
 
 assert.deepStrictEqual(
-  findLast((x: { a: number; b: number }) => x.a === 1)([{ a: 1, b: 1 }, { a: 1, b: 2 }]),
+  findLast((x: { a: number; b: number }) => x.a === 1)([
+    { a: 1, b: 1 },
+    { a: 1, b: 2 }
+  ]),
   some({ a: 1, b: 2 })
 )
 ```
@@ -541,7 +557,10 @@ interface X {
   a: number
   b: number
 }
-const xs: Array<X> = [{ a: 1, b: 0 }, { a: 1, b: 1 }]
+const xs: Array<X> = [
+  { a: 1, b: 0 },
+  { a: 1, b: 1 }
+]
 assert.deepStrictEqual(findLastIndex((x: { a: number }) => x.a === 1)(xs), some(1))
 assert.deepStrictEqual(findLastIndex((x: { a: number }) => x.a === 4)(xs), none)
 ```
@@ -612,7 +631,10 @@ export function foldLeft<A, B>(onNil: () => B, onCons: (head: A, tail: Array<A>)
 ```ts
 import { foldLeft } from 'fp-ts/lib/Array'
 
-const len: <A>(as: Array<A>) => number = foldLeft(() => 0, (_, tail) => 1 + len(tail))
+const len: <A>(as: Array<A>) => number = foldLeft(
+  () => 0,
+  (_, tail) => 1 + len(tail)
+)
 assert.strictEqual(len([1, 2, 3]), 3)
 ```
 
@@ -1170,7 +1192,12 @@ const byAge = ord.contramap(ordNumber, (p: Person) => p.age)
 
 const sortByNameByAge = sortBy([byName, byAge])
 
-const persons = [{ name: 'a', age: 1 }, { name: 'b', age: 3 }, { name: 'c', age: 2 }, { name: 'b', age: 2 }]
+const persons = [
+  { name: 'a', age: 1 },
+  { name: 'b', age: 3 },
+  { name: 'c', age: 2 },
+  { name: 'b', age: 2 }
+]
 assert.deepStrictEqual(sortByNameByAge(persons), [
   { name: 'a', age: 1 },
   { name: 'b', age: 2 },
@@ -1222,7 +1249,10 @@ export function splitAt(n: number): <A>(as: Array<A>) => [Array<A>, Array<A>] {
 ```ts
 import { splitAt } from 'fp-ts/lib/Array'
 
-assert.deepStrictEqual(splitAt(2)([1, 2, 3, 4, 5]), [[1, 2], [3, 4, 5]])
+assert.deepStrictEqual(splitAt(2)([1, 2, 3, 4, 5]), [
+  [1, 2],
+  [3, 4, 5]
+])
 ```
 
 Added in v2.0.0
@@ -1399,7 +1429,17 @@ export function unzip<A, B>(as: Array<[A, B]>): [Array<A>, Array<B>] { ... }
 ```ts
 import { unzip } from 'fp-ts/lib/Array'
 
-assert.deepStrictEqual(unzip([[1, 'a'], [2, 'b'], [3, 'c']]), [[1, 2, 3], ['a', 'b', 'c']])
+assert.deepStrictEqual(
+  unzip([
+    [1, 'a'],
+    [2, 'b'],
+    [3, 'c']
+  ]),
+  [
+    [1, 2, 3],
+    ['a', 'b', 'c']
+  ]
+)
 ```
 
 Added in v2.0.0
@@ -1442,7 +1482,11 @@ export function zip<A, B>(fa: Array<A>, fb: Array<B>): Array<[A, B]> { ... }
 ```ts
 import { zip } from 'fp-ts/lib/Array'
 
-assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [[1, 'a'], [2, 'b'], [3, 'c']])
+assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [
+  [1, 'a'],
+  [2, 'b'],
+  [3, 'c']
+])
 ```
 
 Added in v2.0.0
@@ -1463,7 +1507,10 @@ export function zipWith<A, B, C>(fa: Array<A>, fb: Array<B>, f: (a: A, b: B) =>
 ```ts
 import { zipWith } from 'fp-ts/lib/Array'
 
-assert.deepStrictEqual(zipWith([1, 2, 3], ['a', 'b', 'c', 'd'], (n, s) => s + n), ['a1', 'b2', 'c3'])
+assert.deepStrictEqual(
+  zipWith([1, 2, 3], ['a', 'b', 'c', 'd'], (n, s) => s + n),
+  ['a1', 'b2', 'c3']
+)
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/BooleanAlgebra.ts.md b/docs/modules/BooleanAlgebra.ts.md
index 6b717d8a..20aa4cda 100644
--- a/docs/modules/BooleanAlgebra.ts.md
+++ b/docs/modules/BooleanAlgebra.ts.md
@@ -1,6 +1,6 @@
 ---
 title: BooleanAlgebra.ts
-nav_order: 7
+nav_order: 8
 parent: Modules
 ---
 
diff --git a/docs/modules/Bounded.ts.md b/docs/modules/Bounded.ts.md
index 371e1b28..9db4bf9b 100644
--- a/docs/modules/Bounded.ts.md
+++ b/docs/modules/Bounded.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Bounded.ts
-nav_order: 8
+nav_order: 9
 parent: Modules
 ---
 
diff --git a/docs/modules/BoundedDistributiveLattice.ts.md b/docs/modules/BoundedDistributiveLattice.ts.md
index 17c13894..640b6617 100644
--- a/docs/modules/BoundedDistributiveLattice.ts.md
+++ b/docs/modules/BoundedDistributiveLattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: BoundedDistributiveLattice.ts
-nav_order: 9
+nav_order: 10
 parent: Modules
 ---
 
diff --git a/docs/modules/BoundedJoinSemilattice.ts.md b/docs/modules/BoundedJoinSemilattice.ts.md
index 7968377b..ab325ae1 100644
--- a/docs/modules/BoundedJoinSemilattice.ts.md
+++ b/docs/modules/BoundedJoinSemilattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: BoundedJoinSemilattice.ts
-nav_order: 10
+nav_order: 11
 parent: Modules
 ---
 
diff --git a/docs/modules/BoundedLattice.ts.md b/docs/modules/BoundedLattice.ts.md
index e70070f1..219b09bc 100644
--- a/docs/modules/BoundedLattice.ts.md
+++ b/docs/modules/BoundedLattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: BoundedLattice.ts
-nav_order: 11
+nav_order: 12
 parent: Modules
 ---
 
diff --git a/docs/modules/BoundedMeetSemilattice.ts.md b/docs/modules/BoundedMeetSemilattice.ts.md
index 59fe9952..e6746fbe 100644
--- a/docs/modules/BoundedMeetSemilattice.ts.md
+++ b/docs/modules/BoundedMeetSemilattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: BoundedMeetSemilattice.ts
-nav_order: 12
+nav_order: 13
 parent: Modules
 ---
 
diff --git a/docs/modules/Category.ts.md b/docs/modules/Category.ts.md
index fcfff235..116dbca6 100644
--- a/docs/modules/Category.ts.md
+++ b/docs/modules/Category.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Category.ts
-nav_order: 13
+nav_order: 14
 parent: Modules
 ---
 
diff --git a/docs/modules/Chain.ts.md b/docs/modules/Chain.ts.md
index 19c5a280..87d9b52a 100644
--- a/docs/modules/Chain.ts.md
+++ b/docs/modules/Chain.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Chain.ts
-nav_order: 14
+nav_order: 15
 parent: Modules
 ---
 
diff --git a/docs/modules/ChainRec.ts.md b/docs/modules/ChainRec.ts.md
index ee32156c..5967c84d 100644
--- a/docs/modules/ChainRec.ts.md
+++ b/docs/modules/ChainRec.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ChainRec.ts
-nav_order: 15
+nav_order: 16
 parent: Modules
 ---
 
diff --git a/docs/modules/Choice.ts.md b/docs/modules/Choice.ts.md
index 4fbb2776..f4e70e3c 100644
--- a/docs/modules/Choice.ts.md
+++ b/docs/modules/Choice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Choice.ts
-nav_order: 16
+nav_order: 17
 parent: Modules
 ---
 
diff --git a/docs/modules/Comonad.ts.md b/docs/modules/Comonad.ts.md
index a9e33e6e..678495cc 100644
--- a/docs/modules/Comonad.ts.md
+++ b/docs/modules/Comonad.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Comonad.ts
-nav_order: 17
+nav_order: 18
 parent: Modules
 ---
 
diff --git a/docs/modules/Compactable.ts.md b/docs/modules/Compactable.ts.md
index d59c1d17..2a9d9e65 100644
--- a/docs/modules/Compactable.ts.md
+++ b/docs/modules/Compactable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Compactable.ts
-nav_order: 18
+nav_order: 19
 parent: Modules
 ---
 
diff --git a/docs/modules/Console.ts.md b/docs/modules/Console.ts.md
index ef0fadb8..6f960b01 100644
--- a/docs/modules/Console.ts.md
+++ b/docs/modules/Console.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Console.ts
-nav_order: 19
+nav_order: 20
 parent: Modules
 ---
 
diff --git a/docs/modules/Const.ts.md b/docs/modules/Const.ts.md
index 2cd9b918..e08a9151 100644
--- a/docs/modules/Const.ts.md
+++ b/docs/modules/Const.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Const.ts
-nav_order: 20
+nav_order: 21
 parent: Modules
 ---
 
diff --git a/docs/modules/Contravariant.ts.md b/docs/modules/Contravariant.ts.md
index 8d5d07ec..16f772bf 100644
--- a/docs/modules/Contravariant.ts.md
+++ b/docs/modules/Contravariant.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Contravariant.ts
-nav_order: 21
+nav_order: 22
 parent: Modules
 ---
 
diff --git a/docs/modules/Date.ts.md b/docs/modules/Date.ts.md
index 0d81d395..49b94162 100644
--- a/docs/modules/Date.ts.md
+++ b/docs/modules/Date.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Date.ts
-nav_order: 22
+nav_order: 23
 parent: Modules
 ---
 
diff --git a/docs/modules/DistributiveLattice.ts.md b/docs/modules/DistributiveLattice.ts.md
index efc98116..04ef6659 100644
--- a/docs/modules/DistributiveLattice.ts.md
+++ b/docs/modules/DistributiveLattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: DistributiveLattice.ts
-nav_order: 23
+nav_order: 24
 parent: Modules
 ---
 
diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md
index 415e47c5..5b73ccb8 100644
--- a/docs/modules/Either.ts.md
+++ b/docs/modules/Either.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Either.ts
-nav_order: 24
+nav_order: 25
 parent: Modules
 ---
 
@@ -197,12 +197,33 @@ Added in v2.0.0
 
 # fold (function)
 
+Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function,
+if the value is a `Right` the inner value is applied to the second function.
+
 **Signature**
 
 ```ts
 export function fold<E, A, B>(onLeft: (e: E) => B, onRight: (a: A) => B): (ma: Either<E, A>) => B { ... }
 ```
 
+**Example**
+
+```ts
+import { fold, left, right } from 'fp-ts/lib/Either'
+import { pipe } from 'fp-ts/lib/pipeable'
+
+function onLeft(errors: Array<string>): string {
+  return `Errors: ${errors.join(', ')}`
+}
+
+function onRight(value: number): string {
+  return `Ok: ${value}`
+}
+
+assert.strictEqual(pipe(right(1), fold(onLeft, onRight)), 'Ok: 1')
+assert.strictEqual(pipe(left(['error 1', 'error 2']), fold(onLeft, onRight)), 'Errors: error 1, error 2')
+```
+
 Added in v2.0.0
 
 # fromNullable (function)
@@ -213,7 +234,18 @@ the provided default as a `Left`
 **Signature**
 
 ```ts
-export function fromNullable<E>(e: E): <A>(a: A | null | undefined) => Either<E, A> { ... }
+export function fromNullable<E>(e: E): <A>(a: A) => Either<E, NonNullable<A>> { ... }
+```
+
+**Example**
+
+```ts
+import { fromNullable, left, right } from 'fp-ts/lib/Either'
+
+const parse = fromNullable('nully')
+
+assert.deepStrictEqual(parse(1), right(1))
+assert.deepStrictEqual(parse(null), left('nully'))
 ```
 
 Added in v2.0.0
@@ -501,7 +533,10 @@ const unsafeHead = <A>(as: Array<A>): A => {
 }
 
 const head = <A>(as: Array<A>): Either<Error, A> => {
-  return tryCatch(() => unsafeHead(as), e => (e instanceof Error ? e : new Error('unknown error')))
+  return tryCatch(
+    () => unsafeHead(as),
+    e => (e instanceof Error ? e : new Error('unknown error'))
+  )
 }
 
 assert.deepStrictEqual(head([]), left(new Error('empty array')))
diff --git a/docs/modules/EitherT.ts.md b/docs/modules/EitherT.ts.md
index 413852a0..c0610ab7 100644
--- a/docs/modules/EitherT.ts.md
+++ b/docs/modules/EitherT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: EitherT.ts
-nav_order: 25
+nav_order: 26
 parent: Modules
 ---
 
diff --git a/docs/modules/Eq.ts.md b/docs/modules/Eq.ts.md
index 3e7a97b8..cb2e2500 100644
--- a/docs/modules/Eq.ts.md
+++ b/docs/modules/Eq.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Eq.ts
-nav_order: 26
+nav_order: 27
 parent: Modules
 ---
 
diff --git a/docs/modules/Extend.ts.md b/docs/modules/Extend.ts.md
index 13a89153..9d8640fd 100644
--- a/docs/modules/Extend.ts.md
+++ b/docs/modules/Extend.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Extend.ts
-nav_order: 27
+nav_order: 28
 parent: Modules
 ---
 
diff --git a/docs/modules/Field.ts.md b/docs/modules/Field.ts.md
index 2588594c..0abe8d0f 100644
--- a/docs/modules/Field.ts.md
+++ b/docs/modules/Field.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Field.ts
-nav_order: 28
+nav_order: 29
 parent: Modules
 ---
 
diff --git a/docs/modules/Filterable.ts.md b/docs/modules/Filterable.ts.md
index 98356dfc..785055cf 100644
--- a/docs/modules/Filterable.ts.md
+++ b/docs/modules/Filterable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Filterable.ts
-nav_order: 29
+nav_order: 30
 parent: Modules
 ---
 
diff --git a/docs/modules/FilterableWithIndex.ts.md b/docs/modules/FilterableWithIndex.ts.md
index 0498dcd6..7ed5fd21 100644
--- a/docs/modules/FilterableWithIndex.ts.md
+++ b/docs/modules/FilterableWithIndex.ts.md
@@ -1,6 +1,6 @@
 ---
 title: FilterableWithIndex.ts
-nav_order: 30
+nav_order: 31
 parent: Modules
 ---
 
diff --git a/docs/modules/Foldable.ts.md b/docs/modules/Foldable.ts.md
index 0ed7447f..ddab1e9b 100644
--- a/docs/modules/Foldable.ts.md
+++ b/docs/modules/Foldable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Foldable.ts
-nav_order: 31
+nav_order: 32
 parent: Modules
 ---
 
@@ -271,7 +271,10 @@ import { option, some } from 'fp-ts/lib/Option'
 import { make, tree } from 'fp-ts/lib/Tree'
 
 const t = make(1, [make(2, []), make(3, []), make(4, [])])
-assert.deepStrictEqual(foldM(option, tree)(t, 0, (b, a) => (a > 2 ? some(b + a) : some(b))), some(7))
+assert.deepStrictEqual(
+  foldM(option, tree)(t, 0, (b, a) => (a > 2 ? some(b + a) : some(b))),
+  some(7)
+)
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/FoldableWithIndex.ts.md b/docs/modules/FoldableWithIndex.ts.md
index 9570eccf..229bed66 100644
--- a/docs/modules/FoldableWithIndex.ts.md
+++ b/docs/modules/FoldableWithIndex.ts.md
@@ -1,6 +1,6 @@
 ---
 title: FoldableWithIndex.ts
-nav_order: 32
+nav_order: 33
 parent: Modules
 ---
 
diff --git a/docs/modules/Functor.ts.md b/docs/modules/Functor.ts.md
index 2ced8aac..ae77953b 100644
--- a/docs/modules/Functor.ts.md
+++ b/docs/modules/Functor.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Functor.ts
-nav_order: 34
+nav_order: 35
 parent: Modules
 ---
 
diff --git a/docs/modules/FunctorWithIndex.ts.md b/docs/modules/FunctorWithIndex.ts.md
index 514dd74f..97e7e38a 100644
--- a/docs/modules/FunctorWithIndex.ts.md
+++ b/docs/modules/FunctorWithIndex.ts.md
@@ -1,6 +1,6 @@
 ---
 title: FunctorWithIndex.ts
-nav_order: 35
+nav_order: 36
 parent: Modules
 ---
 
diff --git a/docs/modules/Group.ts.md b/docs/modules/Group.ts.md
index c0e973ec..7201245b 100644
--- a/docs/modules/Group.ts.md
+++ b/docs/modules/Group.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Group.ts
-nav_order: 36
+nav_order: 37
 parent: Modules
 ---
 
diff --git a/docs/modules/HKT.ts.md b/docs/modules/HKT.ts.md
index 642e76b1..f71a81ef 100644
--- a/docs/modules/HKT.ts.md
+++ b/docs/modules/HKT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: HKT.ts
-nav_order: 38
+nav_order: 39
 parent: Modules
 ---
 
diff --git a/docs/modules/HeytingAlgebra.ts.md b/docs/modules/HeytingAlgebra.ts.md
index f057669b..1c8a796a 100644
--- a/docs/modules/HeytingAlgebra.ts.md
+++ b/docs/modules/HeytingAlgebra.ts.md
@@ -1,6 +1,6 @@
 ---
 title: HeytingAlgebra.ts
-nav_order: 37
+nav_order: 38
 parent: Modules
 ---
 
diff --git a/docs/modules/IO.ts.md b/docs/modules/IO.ts.md
index c34918c6..5e5de62f 100644
--- a/docs/modules/IO.ts.md
+++ b/docs/modules/IO.ts.md
@@ -1,6 +1,6 @@
 ---
 title: IO.ts
-nav_order: 42
+nav_order: 43
 parent: Modules
 ---
 
@@ -154,7 +154,7 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export const io: Monad1<URI> & MonadIO1<URI> = ...
+export const io: Monad1<URI> & MonadIO1<URI> & ChainRec1<URI> = ...
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/IOEither.ts.md b/docs/modules/IOEither.ts.md
index c263e960..28f5031d 100644
--- a/docs/modules/IOEither.ts.md
+++ b/docs/modules/IOEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: IOEither.ts
-nav_order: 43
+nav_order: 44
 parent: Modules
 ---
 
@@ -141,9 +141,10 @@ Added in v2.0.0
 
 # bracket (function)
 
-Make sure that a resource is cleaned up in the event of an exception. The
-release action is called regardless of whether the body action throws or
-returns.
+Make sure that a resource is cleaned up in the event of an exception (_). The release action is called regardless of
+whether the body action throws (_) or returns.
+
+(\*) i.e. returns a `Left`
 
 **Signature**
 
diff --git a/docs/modules/IORef.ts.md b/docs/modules/IORef.ts.md
index 59e6f64e..bc45d6a4 100644
--- a/docs/modules/IORef.ts.md
+++ b/docs/modules/IORef.ts.md
@@ -1,6 +1,6 @@
 ---
 title: IORef.ts
-nav_order: 44
+nav_order: 45
 parent: Modules
 ---
 
diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md
index 484c7cf6..f4efbd9f 100644
--- a/docs/modules/Identity.ts.md
+++ b/docs/modules/Identity.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Identity.ts
-nav_order: 39
+nav_order: 40
 parent: Modules
 ---
 
diff --git a/docs/modules/Invariant.ts.md b/docs/modules/Invariant.ts.md
index 72ccbc43..3db08999 100644
--- a/docs/modules/Invariant.ts.md
+++ b/docs/modules/Invariant.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Invariant.ts
-nav_order: 41
+nav_order: 42
 parent: Modules
 ---
 
diff --git a/docs/modules/JoinSemilattice.ts.md b/docs/modules/JoinSemilattice.ts.md
index 09cc63bf..324411df 100644
--- a/docs/modules/JoinSemilattice.ts.md
+++ b/docs/modules/JoinSemilattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: JoinSemilattice.ts
-nav_order: 45
+nav_order: 46
 parent: Modules
 ---
 
diff --git a/docs/modules/Lattice.ts.md b/docs/modules/Lattice.ts.md
index 74634d1a..631d2bc9 100644
--- a/docs/modules/Lattice.ts.md
+++ b/docs/modules/Lattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Lattice.ts
-nav_order: 46
+nav_order: 47
 parent: Modules
 ---
 
diff --git a/docs/modules/Magma.ts.md b/docs/modules/Magma.ts.md
index f7b7ba6e..02919360 100644
--- a/docs/modules/Magma.ts.md
+++ b/docs/modules/Magma.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Magma.ts
-nav_order: 47
+nav_order: 48
 parent: Modules
 ---
 
diff --git a/docs/modules/Map.ts.md b/docs/modules/Map.ts.md
index a88193bb..b81430e5 100644
--- a/docs/modules/Map.ts.md
+++ b/docs/modules/Map.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Map.ts
-nav_order: 48
+nav_order: 49
 parent: Modules
 ---
 
diff --git a/docs/modules/MeetSemilattice.ts.md b/docs/modules/MeetSemilattice.ts.md
index 0184a65f..731ccfbf 100644
--- a/docs/modules/MeetSemilattice.ts.md
+++ b/docs/modules/MeetSemilattice.ts.md
@@ -1,6 +1,6 @@
 ---
 title: MeetSemilattice.ts
-nav_order: 49
+nav_order: 50
 parent: Modules
 ---
 
diff --git a/docs/modules/Monad.ts.md b/docs/modules/Monad.ts.md
index 0d6a26c2..be388eeb 100644
--- a/docs/modules/Monad.ts.md
+++ b/docs/modules/Monad.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Monad.ts
-nav_order: 50
+nav_order: 51
 parent: Modules
 ---
 
diff --git a/docs/modules/MonadIO.ts.md b/docs/modules/MonadIO.ts.md
index f803c581..bdf201bd 100644
--- a/docs/modules/MonadIO.ts.md
+++ b/docs/modules/MonadIO.ts.md
@@ -1,6 +1,6 @@
 ---
 title: MonadIO.ts
-nav_order: 51
+nav_order: 52
 parent: Modules
 ---
 
diff --git a/docs/modules/MonadTask.ts.md b/docs/modules/MonadTask.ts.md
index 9252dcc3..9d354be7 100644
--- a/docs/modules/MonadTask.ts.md
+++ b/docs/modules/MonadTask.ts.md
@@ -1,6 +1,6 @@
 ---
 title: MonadTask.ts
-nav_order: 52
+nav_order: 53
 parent: Modules
 ---
 
diff --git a/docs/modules/MonadThrow.ts.md b/docs/modules/MonadThrow.ts.md
index 07ea2984..702822fb 100644
--- a/docs/modules/MonadThrow.ts.md
+++ b/docs/modules/MonadThrow.ts.md
@@ -1,6 +1,6 @@
 ---
 title: MonadThrow.ts
-nav_order: 53
+nav_order: 54
 parent: Modules
 ---
 
diff --git a/docs/modules/Monoid.ts.md b/docs/modules/Monoid.ts.md
index 5ae6420c..fcdb911e 100644
--- a/docs/modules/Monoid.ts.md
+++ b/docs/modules/Monoid.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Monoid.ts
-nav_order: 54
+nav_order: 55
 parent: Modules
 ---
 
diff --git a/docs/modules/NonEmptyArray.ts.md b/docs/modules/NonEmptyArray.ts.md
index d88da6ce..dfa78965 100644
--- a/docs/modules/NonEmptyArray.ts.md
+++ b/docs/modules/NonEmptyArray.ts.md
@@ -1,6 +1,6 @@
 ---
 title: NonEmptyArray.ts
-nav_order: 55
+nav_order: 56
 parent: Modules
 ---
 
diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md
index c437ded4..99ac4a85 100644
--- a/docs/modules/Option.ts.md
+++ b/docs/modules/Option.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Option.ts
-nav_order: 56
+nav_order: 57
 parent: Modules
 ---
 
@@ -233,7 +233,8 @@ Added in v2.0.0
 
 # fold (function)
 
-We can pattern match using the `fold` function
+Takes a default value, a function, and an `Option` value, if the `Option` value is `None` the default value is
+returned, otherwise the function is applied to the value inside the `Some` and the result is returned.
 
 **Signature**
 
@@ -250,7 +251,10 @@ import { pipe } from 'fp-ts/lib/pipeable'
 assert.strictEqual(
   pipe(
     some(1),
-    fold(() => 'a none', a => `a some containing ${a}`)
+    fold(
+      () => 'a none',
+      a => `a some containing ${a}`
+    )
   ),
   'a some containing 1'
 )
@@ -258,7 +262,10 @@ assert.strictEqual(
 assert.strictEqual(
   pipe(
     none,
-    fold(() => 'a none', a => `a some containing ${a}`)
+    fold(
+      () => 'a none',
+      a => `a some containing ${a}`
+    )
   ),
   'a none'
 )
@@ -274,7 +281,7 @@ returns the value wrapped in a `Some`
 **Signature**
 
 ```ts
-export function fromNullable<A>(a: A | null | undefined): Option<A> { ... }
+export function fromNullable<A>(a: A): Option<NonNullable<A>> { ... }
 ```
 
 **Example**
@@ -717,20 +724,8 @@ export function toNullable<A>(ma: Option<A>): A | null { ... }
 import { some, none, toNullable } from 'fp-ts/lib/Option'
 import { pipe } from 'fp-ts/lib/pipeable'
 
-assert.strictEqual(
-  pipe(
-    some(1),
-    toNullable
-  ),
-  1
-)
-assert.strictEqual(
-  pipe(
-    none,
-    toNullable
-  ),
-  null
-)
+assert.strictEqual(pipe(some(1), toNullable), 1)
+assert.strictEqual(pipe(none, toNullable), null)
 ```
 
 Added in v2.0.0
@@ -751,20 +746,8 @@ export function toUndefined<A>(ma: Option<A>): A | undefined { ... }
 import { some, none, toUndefined } from 'fp-ts/lib/Option'
 import { pipe } from 'fp-ts/lib/pipeable'
 
-assert.strictEqual(
-  pipe(
-    some(1),
-    toUndefined
-  ),
-  1
-)
-assert.strictEqual(
-  pipe(
-    none,
-    toUndefined
-  ),
-  undefined
-)
+assert.strictEqual(pipe(some(1), toUndefined), 1)
+assert.strictEqual(pipe(none, toUndefined), undefined)
 ```
 
 Added in v2.0.0
@@ -791,7 +774,10 @@ assert.deepStrictEqual(
   }),
   none
 )
-assert.deepStrictEqual(tryCatch(() => 1), some(1))
+assert.deepStrictEqual(
+  tryCatch(() => 1),
+  some(1)
+)
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/OptionT.ts.md b/docs/modules/OptionT.ts.md
index f3a006da..9d0442ac 100644
--- a/docs/modules/OptionT.ts.md
+++ b/docs/modules/OptionT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: OptionT.ts
-nav_order: 57
+nav_order: 58
 parent: Modules
 ---
 
@@ -11,6 +11,7 @@ parent: Modules
 - [OptionM (interface)](#optionm-interface)
 - [OptionM1 (interface)](#optionm1-interface)
 - [OptionM2 (interface)](#optionm2-interface)
+- [OptionM2C (interface)](#optionm2c-interface)
 - [OptionT (interface)](#optiont-interface)
 - [OptionT1 (type alias)](#optiont1-type-alias)
 - [OptionT2 (type alias)](#optiont2-type-alias)
@@ -73,6 +74,27 @@ export interface OptionM2<M extends URIS2> extends ApplicativeComposition21<M, U
 
 Added in v2.0.0
 
+# OptionM2C (interface)
+
+**Signature**
+
+```ts
+export interface OptionM2C<M extends URIS2, E> extends ApplicativeComposition2C1<M, URI, E> {
+  readonly chain: <A, B>(ma: OptionT2<M, E, A>, f: (a: A) => OptionT2<M, E, B>) => OptionT2<M, E, B>
+  readonly alt: <A>(fx: OptionT2<M, E, A>, fy: () => OptionT2<M, E, A>) => OptionT2<M, E, A>
+  readonly fold: <A, R>(
+    ma: OptionT2<M, E, A>,
+    onNone: () => Kind2<M, E, R>,
+    onSome: (a: A) => Kind2<M, E, R>
+  ) => Kind2<M, E, R>
+  readonly getOrElse: <A>(ma: OptionT2<M, E, A>, onNone: () => Kind2<M, E, A>) => Kind2<M, E, A>
+  readonly fromM: <A>(ma: Kind2<M, E, A>) => OptionT2<M, E, A>
+  readonly none: <A = never>() => OptionT2<M, E, A>
+}
+```
+
+Added in v2.2.0
+
 # OptionT (interface)
 
 **Signature**
@@ -109,6 +131,7 @@ Added in v2.0.0
 
 ```ts
 export function getOptionM<M extends URIS2>(M: Monad2<M>): OptionM2<M>
+export function getOptionM<M extends URIS2, E>(M: Monad2C<M, E>): OptionM2C<M, E>
 export function getOptionM<M extends URIS>(M: Monad1<M>): OptionM1<M>
 export function getOptionM<M>(M: Monad<M>): OptionM<M> { ... }
 ```
diff --git a/docs/modules/Ord.ts.md b/docs/modules/Ord.ts.md
index 96fa7f6f..2cd83808 100644
--- a/docs/modules/Ord.ts.md
+++ b/docs/modules/Ord.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Ord.ts
-nav_order: 58
+nav_order: 59
 parent: Modules
 ---
 
@@ -184,12 +184,72 @@ Added in v2.0.0
 
 # getSemigroup (function)
 
+Returns an `Ord` such that its `concat(ord1, ord2)` operation will order first by `ord1`, and then by `ord2`.
+
 **Signature**
 
 ```ts
 export function getSemigroup<A = never>(): Semigroup<Ord<A>> { ... }
 ```
 
+**Example**
+
+```ts
+import { sort } from 'fp-ts/lib/Array'
+import { contramap, getDualOrd, getSemigroup, ordBoolean, ordNumber, ordString } from 'fp-ts/lib/Ord'
+import { pipe } from 'fp-ts/lib/pipeable'
+import { fold } from 'fp-ts/lib/Semigroup'
+
+interface User {
+  id: number
+  name: string
+  age: number
+  rememberMe: boolean
+}
+
+const byName = pipe(
+  ordString,
+  contramap((p: User) => p.name)
+)
+
+const byAge = pipe(
+  ordNumber,
+  contramap((p: User) => p.age)
+)
+
+const byRememberMe = pipe(
+  ordBoolean,
+  contramap((p: User) => p.rememberMe)
+)
+
+const S = getSemigroup<User>()
+
+const users: Array<User> = [
+  { id: 1, name: 'Guido', age: 47, rememberMe: false },
+  { id: 2, name: 'Guido', age: 46, rememberMe: true },
+  { id: 3, name: 'Giulio', age: 44, rememberMe: false },
+  { id: 4, name: 'Giulio', age: 44, rememberMe: true }
+]
+
+// sort by name, then by age, then by `rememberMe`
+const O1 = fold(S)(byName, [byAge, byRememberMe])
+assert.deepStrictEqual(sort(O1)(users), [
+  { id: 3, name: 'Giulio', age: 44, rememberMe: false },
+  { id: 4, name: 'Giulio', age: 44, rememberMe: true },
+  { id: 2, name: 'Guido', age: 46, rememberMe: true },
+  { id: 1, name: 'Guido', age: 47, rememberMe: false }
+])
+
+// now `rememberMe = true` first, then by name, then by age
+const O2 = fold(S)(getDualOrd(byRememberMe), [byName, byAge])
+assert.deepStrictEqual(sort(O2)(users), [
+  { id: 4, name: 'Giulio', age: 44, rememberMe: true },
+  { id: 2, name: 'Guido', age: 46, rememberMe: true },
+  { id: 3, name: 'Giulio', age: 44, rememberMe: false },
+  { id: 1, name: 'Guido', age: 47, rememberMe: false }
+])
+```
+
 Added in v2.0.0
 
 # getTupleOrd (function)
diff --git a/docs/modules/Ordering.ts.md b/docs/modules/Ordering.ts.md
index a518f4e8..89cd6581 100644
--- a/docs/modules/Ordering.ts.md
+++ b/docs/modules/Ordering.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Ordering.ts
-nav_order: 59
+nav_order: 60
 parent: Modules
 ---
 
diff --git a/docs/modules/Profunctor.ts.md b/docs/modules/Profunctor.ts.md
index 543c7c79..ec68c08c 100644
--- a/docs/modules/Profunctor.ts.md
+++ b/docs/modules/Profunctor.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Profunctor.ts
-nav_order: 61
+nav_order: 62
 parent: Modules
 ---
 
diff --git a/docs/modules/Random.ts.md b/docs/modules/Random.ts.md
index efe23c27..ff201d6b 100644
--- a/docs/modules/Random.ts.md
+++ b/docs/modules/Random.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Random.ts
-nav_order: 62
+nav_order: 63
 parent: Modules
 ---
 
diff --git a/docs/modules/Reader.ts.md b/docs/modules/Reader.ts.md
index df121cf6..b32ed7af 100644
--- a/docs/modules/Reader.ts.md
+++ b/docs/modules/Reader.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Reader.ts
-nav_order: 63
+nav_order: 64
 parent: Modules
 ---
 
@@ -128,7 +128,8 @@ Added in v2.0.0
 
 # local (function)
 
-changes the value of the local context during the execution of the action `ma`
+Changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
+`contramap`).
 
 **Signature**
 
diff --git a/docs/modules/ReaderEither.ts.md b/docs/modules/ReaderEither.ts.md
index a2bab194..1236b083 100644
--- a/docs/modules/ReaderEither.ts.md
+++ b/docs/modules/ReaderEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ReaderEither.ts
-nav_order: 64
+nav_order: 65
 parent: Modules
 ---
 
diff --git a/docs/modules/ReaderT.ts.md b/docs/modules/ReaderT.ts.md
index bc145aff..2ec4fe53 100644
--- a/docs/modules/ReaderT.ts.md
+++ b/docs/modules/ReaderT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ReaderT.ts
-nav_order: 65
+nav_order: 66
 parent: Modules
 ---
 
@@ -11,6 +11,7 @@ parent: Modules
 - [ReaderM (interface)](#readerm-interface)
 - [ReaderM1 (interface)](#readerm1-interface)
 - [ReaderM2 (interface)](#readerm2-interface)
+- [ReaderM2C (interface)](#readerm2c-interface)
 - [ReaderM3 (interface)](#readerm3-interface)
 - [ReaderT (interface)](#readert-interface)
 - [ReaderT1 (interface)](#readert1-interface)
@@ -80,6 +81,26 @@ export interface ReaderM2<M extends URIS2> {
 
 Added in v2.0.0
 
+# ReaderM2C (interface)
+
+**Signature**
+
+```ts
+export interface ReaderM2C<M extends URIS2, E> {
+  readonly map: <R, A, B>(ma: ReaderT2<M, R, E, A>, f: (a: A) => B) => ReaderT2<M, R, E, B>
+  readonly of: <R, A>(a: A) => ReaderT2<M, R, E, A>
+  readonly ap: <R, A, B>(mab: ReaderT2<M, R, E, (a: A) => B>, ma: ReaderT2<M, R, E, A>) => ReaderT2<M, R, E, B>
+  readonly chain: <R, A, B>(ma: ReaderT2<M, R, E, A>, f: (a: A) => ReaderT2<M, R, E, B>) => ReaderT2<M, R, E, B>
+  readonly ask: <R>() => ReaderT2<M, R, E, R>
+  readonly asks: <R, A>(f: (r: R) => A) => ReaderT2<M, R, E, A>
+  readonly local: <R, A, Q>(ma: ReaderT2<M, R, E, A>, f: (d: Q) => R) => ReaderT2<M, Q, E, A>
+  readonly fromReader: <R, A>(ma: Reader<R, A>) => ReaderT2<M, R, E, A>
+  readonly fromM: <R, A>(ma: Kind2<M, E, A>) => ReaderT2<M, R, E, A>
+}
+```
+
+Added in v2.2.0
+
 # ReaderM3 (interface)
 
 **Signature**
@@ -161,6 +182,7 @@ Added in v2.0.0
 ```ts
 export function getReaderM<M extends URIS3>(M: Monad3<M>): ReaderM3<M>
 export function getReaderM<M extends URIS2>(M: Monad2<M>): ReaderM2<M>
+export function getReaderM<M extends URIS2, E>(M: Monad2C<M, E>): ReaderM2C<M, E>
 export function getReaderM<M extends URIS>(M: Monad1<M>): ReaderM1<M>
 export function getReaderM<M>(M: Monad<M>): ReaderM<M> { ... }
 ```
diff --git a/docs/modules/ReaderTaskEither.ts.md b/docs/modules/ReaderTaskEither.ts.md
index 9c7e2fbb..265b0352 100644
--- a/docs/modules/ReaderTaskEither.ts.md
+++ b/docs/modules/ReaderTaskEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ReaderTaskEither.ts
-nav_order: 66
+nav_order: 67
 parent: Modules
 ---
 
@@ -159,9 +159,10 @@ Added in v2.0.0
 
 # bracket (function)
 
-Make sure that a resource is cleaned up in the event of an exception. The
-release action is called regardless of whether the body action throws or
-returns.
+Make sure that a resource is cleaned up in the event of an exception (_). The release action is called regardless of
+whether the body action throws (_) or returns.
+
+(\*) i.e. returns a `Left`
 
 **Signature**
 
diff --git a/docs/modules/Record.ts.md b/docs/modules/Record.ts.md
index 76f5007a..9e204c34 100644
--- a/docs/modules/Record.ts.md
+++ b/docs/modules/Record.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Record.ts
-nav_order: 67
+nav_order: 68
 parent: Modules
 ---
 
@@ -285,12 +285,19 @@ interface User {
   name: string
 }
 
-const users: Array<User> = [{ id: 'id1', name: 'name1' }, { id: 'id2', name: 'name2' }, { id: 'id1', name: 'name3' }]
-
-assert.deepStrictEqual(fromFoldableMap(getLastSemigroup<User>(), array)(users, user => [user.id, user]), {
-  id1: { id: 'id1', name: 'name3' },
-  id2: { id: 'id2', name: 'name2' }
-})
+const users: Array<User> = [
+  { id: 'id1', name: 'name1' },
+  { id: 'id2', name: 'name2' },
+  { id: 'id1', name: 'name3' }
+]
+
+assert.deepStrictEqual(
+  fromFoldableMap(getLastSemigroup<User>(), array)(users, user => [user.id, user]),
+  {
+    id1: { id: 'id1', name: 'name3' },
+    id2: { id: 'id2', name: 'name2' }
+  }
+)
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/Ring.ts.md b/docs/modules/Ring.ts.md
index e19c660d..51c81dfb 100644
--- a/docs/modules/Ring.ts.md
+++ b/docs/modules/Ring.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Ring.ts
-nav_order: 68
+nav_order: 69
 parent: Modules
 ---
 
diff --git a/docs/modules/Semigroup.ts.md b/docs/modules/Semigroup.ts.md
index 0b7357db..805d826d 100644
--- a/docs/modules/Semigroup.ts.md
+++ b/docs/modules/Semigroup.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Semigroup.ts
-nav_order: 69
+nav_order: 70
 parent: Modules
 ---
 
diff --git a/docs/modules/Semigroupoid.ts.md b/docs/modules/Semigroupoid.ts.md
index a6024f9e..5fda4828 100644
--- a/docs/modules/Semigroupoid.ts.md
+++ b/docs/modules/Semigroupoid.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Semigroupoid.ts
-nav_order: 70
+nav_order: 71
 parent: Modules
 ---
 
diff --git a/docs/modules/Semiring.ts.md b/docs/modules/Semiring.ts.md
index 80004708..9c5a9eab 100644
--- a/docs/modules/Semiring.ts.md
+++ b/docs/modules/Semiring.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Semiring.ts
-nav_order: 71
+nav_order: 72
 parent: Modules
 ---
 
diff --git a/docs/modules/Set.ts.md b/docs/modules/Set.ts.md
index 953e4cd7..ccbf34f8 100644
--- a/docs/modules/Set.ts.md
+++ b/docs/modules/Set.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Set.ts
-nav_order: 72
+nav_order: 73
 parent: Modules
 ---
 
diff --git a/docs/modules/Show.ts.md b/docs/modules/Show.ts.md
index 9f2dc6b9..b0db1eab 100644
--- a/docs/modules/Show.ts.md
+++ b/docs/modules/Show.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Show.ts
-nav_order: 73
+nav_order: 74
 parent: Modules
 ---
 
diff --git a/docs/modules/State.ts.md b/docs/modules/State.ts.md
index 83c0bc4d..e20021b8 100644
--- a/docs/modules/State.ts.md
+++ b/docs/modules/State.ts.md
@@ -1,9 +1,16 @@
 ---
 title: State.ts
-nav_order: 74
+nav_order: 75
 parent: Modules
 ---
 
+# Overview
+
+The `State` monad is a synonym for the `StateT` monad transformer, applied to the `Identity` monad.
+
+For a good introduction to the state monad, see the following blog post by [@pfgray](https://github.com/pfgray): [The
+State monad](https://paulgray.net/the-state-monad/)
+
 ---
 
 <h2 class="text-delta">Table of contents</h2>
diff --git a/docs/modules/StateReaderTaskEither.ts.md b/docs/modules/StateReaderTaskEither.ts.md
index e195ac05..8444d2d7 100644
--- a/docs/modules/StateReaderTaskEither.ts.md
+++ b/docs/modules/StateReaderTaskEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: StateReaderTaskEither.ts
-nav_order: 75
+nav_order: 76
 parent: Modules
 ---
 
diff --git a/docs/modules/StateT.ts.md b/docs/modules/StateT.ts.md
index aa2aad45..cb7d2f89 100644
--- a/docs/modules/StateT.ts.md
+++ b/docs/modules/StateT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: StateT.ts
-nav_order: 76
+nav_order: 77
 parent: Modules
 ---
 
diff --git a/docs/modules/Store.ts.md b/docs/modules/Store.ts.md
index eb632e83..24fde574 100644
--- a/docs/modules/Store.ts.md
+++ b/docs/modules/Store.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Store.ts
-nav_order: 77
+nav_order: 78
 parent: Modules
 ---
 
diff --git a/docs/modules/Strong.ts.md b/docs/modules/Strong.ts.md
index 851c51e3..ffffb58d 100644
--- a/docs/modules/Strong.ts.md
+++ b/docs/modules/Strong.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Strong.ts
-nav_order: 78
+nav_order: 79
 parent: Modules
 ---
 
diff --git a/docs/modules/Task.ts.md b/docs/modules/Task.ts.md
index e1d00103..c2d9ed91 100644
--- a/docs/modules/Task.ts.md
+++ b/docs/modules/Task.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Task.ts
-nav_order: 79
+nav_order: 80
 parent: Modules
 ---
 
diff --git a/docs/modules/TaskEither.ts.md b/docs/modules/TaskEither.ts.md
index e4036854..f448f920 100644
--- a/docs/modules/TaskEither.ts.md
+++ b/docs/modules/TaskEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: TaskEither.ts
-nav_order: 80
+nav_order: 81
 parent: Modules
 ---
 
@@ -168,9 +168,10 @@ Added in v2.0.0
 
 # bracket (function)
 
-Make sure that a resource is cleaned up in the event of an exception. The
-release action is called regardless of whether the body action throws or
-returns.
+Make sure that a resource is cleaned up in the event of an exception (_). The release action is called regardless of
+whether the body action throws (_) or returns.
+
+(\*) i.e. returns a `Left`
 
 **Signature**
 
@@ -341,12 +342,30 @@ Added in v2.0.0
 
 # tryCatch (function)
 
+Transforms a `Promise` that may reject to a `Promise` that never rejects and returns an `Either` instead.
+
+Note: `f` should never `throw` errors, they are not caught.
+
 **Signature**
 
 ```ts
 export function tryCatch<E, A>(f: Lazy<Promise<A>>, onRejected: (reason: unknown) => E): TaskEither<E, A> { ... }
 ```
 
+**Example**
+
+```ts
+import { left, right } from 'fp-ts/lib/Either'
+import { tryCatch } from 'fp-ts/lib/TaskEither'
+
+tryCatch(() => Promise.resolve(1), String)().then(result => {
+  assert.deepStrictEqual(result, right(1))
+})
+tryCatch(() => Promise.reject('error'), String)().then(result => {
+  assert.deepStrictEqual(result, left('error'))
+})
+```
+
 Added in v2.0.0
 
 # alt (export)
diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md
index cc218f54..b640c60b 100644
--- a/docs/modules/These.ts.md
+++ b/docs/modules/These.ts.md
@@ -1,6 +1,6 @@
 ---
 title: These.ts
-nav_order: 81
+nav_order: 82
 parent: Modules
 ---
 
diff --git a/docs/modules/Traced.ts.md b/docs/modules/Traced.ts.md
index 805a4cda..22c7e578 100644
--- a/docs/modules/Traced.ts.md
+++ b/docs/modules/Traced.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traced.ts
-nav_order: 82
+nav_order: 83
 parent: Modules
 ---
 
diff --git a/docs/modules/Traversable.ts.md b/docs/modules/Traversable.ts.md
index d981d1ed..b906afd2 100644
--- a/docs/modules/Traversable.ts.md
+++ b/docs/modules/Traversable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traversable.ts
-nav_order: 83
+nav_order: 84
 parent: Modules
 ---
 
diff --git a/docs/modules/TraversableWithIndex.ts.md b/docs/modules/TraversableWithIndex.ts.md
index cecd7db6..12b2ed6e 100644
--- a/docs/modules/TraversableWithIndex.ts.md
+++ b/docs/modules/TraversableWithIndex.ts.md
@@ -1,6 +1,6 @@
 ---
 title: TraversableWithIndex.ts
-nav_order: 84
+nav_order: 85
 parent: Modules
 ---
 
diff --git a/docs/modules/Tree.ts.md b/docs/modules/Tree.ts.md
index d7a2cdd2..3d6a1f4e 100644
--- a/docs/modules/Tree.ts.md
+++ b/docs/modules/Tree.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Tree.ts
-nav_order: 85
+nav_order: 86
 parent: Modules
 ---
 
diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md
index f0dd9faa..efb00053 100644
--- a/docs/modules/Tuple.ts.md
+++ b/docs/modules/Tuple.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Tuple.ts
-nav_order: 86
+nav_order: 87
 parent: Modules
 ---
 
diff --git a/docs/modules/Unfoldable.ts.md b/docs/modules/Unfoldable.ts.md
index be75c76e..e5d90cfe 100644
--- a/docs/modules/Unfoldable.ts.md
+++ b/docs/modules/Unfoldable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Unfoldable.ts
-nav_order: 87
+nav_order: 88
 parent: Modules
 ---
 
diff --git a/docs/modules/ValidationT.ts.md b/docs/modules/ValidationT.ts.md
index 74064d8f..aef8ce00 100644
--- a/docs/modules/ValidationT.ts.md
+++ b/docs/modules/ValidationT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ValidationT.ts
-nav_order: 88
+nav_order: 89
 parent: Modules
 ---
 
diff --git a/docs/modules/Witherable.ts.md b/docs/modules/Witherable.ts.md
index 430e4b2d..bbfad43a 100644
--- a/docs/modules/Witherable.ts.md
+++ b/docs/modules/Witherable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Witherable.ts
-nav_order: 89
+nav_order: 90
 parent: Modules
 ---
 
diff --git a/docs/modules/Writer.ts.md b/docs/modules/Writer.ts.md
index e3f8335a..83269d28 100644
--- a/docs/modules/Writer.ts.md
+++ b/docs/modules/Writer.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Writer.ts
-nav_order: 90
+nav_order: 91
 parent: Modules
 ---
 
diff --git a/docs/modules/boolean.ts.md b/docs/modules/boolean.ts.md
new file mode 100644
index 00000000..159eb187
--- /dev/null
+++ b/docs/modules/boolean.ts.md
@@ -0,0 +1,48 @@
+---
+title: boolean.ts
+nav_order: 7
+parent: Modules
+---
+
+---
+
+<h2 class="text-delta">Table of contents</h2>
+
+- [fold (function)](#fold-function)
+
+---
+
+# fold (function)
+
+Defines the fold over a boolean value.
+Takes two thunks `onTrue`, `onFalse` and a `boolean` value.
+If `value` is false, `onFalse()` is returned, otherwise `onTrue()`.
+
+**Signature**
+
+```ts
+export function fold<A>(onFalse: () => A, onTrue: () => A): (value: boolean) => A { ... }
+```
+
+**Example**
+
+```ts
+import { some, map } from 'fp-ts/lib/Option'
+import { pipe } from 'fp-ts/lib/pipeable'
+import { fold } from 'fp-ts/lib/boolean'
+
+assert.deepStrictEqual(
+  pipe(
+    some(true),
+    map(
+      fold(
+        () => 'false',
+        () => 'true'
+      )
+    )
+  ),
+  some('true')
+)
+```
+
+Added in v2.2.0
diff --git a/docs/modules/function.ts.md b/docs/modules/function.ts.md
index bccf546f..177ba3e4 100644
--- a/docs/modules/function.ts.md
+++ b/docs/modules/function.ts.md
@@ -1,6 +1,6 @@
 ---
 title: function.ts
-nav_order: 33
+nav_order: 34
 parent: Modules
 ---
 
@@ -288,10 +288,7 @@ import { flow } from 'fp-ts/lib/function'
 const len = (s: string): number => s.length
 const double = (n: number): number => n * 2
 
-const f = flow(
-  len,
-  double
-)
+const f = flow(len, double)
 
 assert.strictEqual(f('aaa'), 6)
 ```
diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md
index dc6a207d..7f940f30 100644
--- a/docs/modules/index.ts.md
+++ b/docs/modules/index.ts.md
@@ -1,6 +1,6 @@
 ---
 title: index.ts
-nav_order: 40
+nav_order: 41
 parent: Modules
 ---
 
@@ -14,6 +14,7 @@ parent: Modules
 - [apply (export)](#apply-export)
 - [array (export)](#array-export)
 - [bifunctor (export)](#bifunctor-export)
+- [boolean (export)](#boolean-export)
 - [booleanAlgebra (export)](#booleanalgebra-export)
 - [bounded (export)](#bounded-export)
 - [boundedDistributiveLattice (export)](#boundeddistributivelattice-export)
@@ -160,6 +161,16 @@ typeof bifunctor
 
 Added in v2.0.0
 
+# boolean (export)
+
+**Signature**
+
+```ts
+typeof boolean
+```
+
+Added in v2.2.0
+
 # booleanAlgebra (export)
 
 **Signature**
diff --git a/docs/modules/pipeable.ts.md b/docs/modules/pipeable.ts.md
index 6d0acb96..c49d8fa1 100644
--- a/docs/modules/pipeable.ts.md
+++ b/docs/modules/pipeable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: pipeable.ts
-nav_order: 60
+nav_order: 61
 parent: Modules
 ---
 
diff --git a/docs/recipes/async.md b/docs/recipes/async.md
index 52b1e62b..6e893cd6 100644
--- a/docs/recipes/async.md
+++ b/docs/recipes/async.md
@@ -131,3 +131,25 @@ array
   .traverse(task)(items, checkPathExists)()
   .then(console.log) // [ { path: '/bin', exists: true }, { path: '/no/real/path', exists: false } ]
 ```
+
+## Comparison with `Promise` methods
+
+Following is a table comparing `Task`/`TaskEither` with `Promise`. It assumes the following imports:
+
+```ts
+import * as T from 'fp-ts/lib/Task'
+import * as TE from 'fp-ts/lib/TaskEither'
+import { array } from 'fp-ts/lib/Array'
+import { fold } from 'fp-ts/lib/Monoid'
+```
+
+| | Promise | Task | TaskEither |
+| --- | --- | --- | --- |
+| resolve to success | `Promise.resolve(value)` | `T.task.of(value)` | `TE.taskEither.of(value)` or `TE.right(value)` |
+| resolve to failure | `Promise.reject(value)` | N/A | `TE.left(value)` |
+| transform the result of a task with the function `f` | `promise.then(f)` | `T.task.map(task, f)` | `T.taskEither.map(taskEither, f)` |
+| perform a task depending on the result of a previous one | `promise.then(r => getPromise(r))` | `T.task.chain(task, r => getTask(r))` | `T.taskEither.chain(taskEither, r => getTaskEither(r))` |
+| execute an array of tasks in parallel | `Promise.all(promises)` | `array.sequence(T.task)(tasks)` | `array.sequence(TE.taskEither)(taskEithers)` |
+| execute an array of tasks in parallel, collecting all failures and successes | `Promise.allSettled(promises)` | N/A | `array.sequence(T.task)(taskEithers)` |
+| execute an array of tasks and succeed/fail with a single value as soon as one of the tasks succeeds/fails | `Promise.race(promises)` | `fold(T.getRaceMonoid())(tasks)` | `fold(T.getRaceMonoid())(taskEithers)` |
+
diff --git a/dtslint/ts3.5/index.ts b/dtslint/ts3.5/index.ts
index 27dd3dd5..2f15288d 100644
--- a/dtslint/ts3.5/index.ts
+++ b/dtslint/ts3.5/index.ts
@@ -167,6 +167,31 @@ type C = A | B
 // $ExpectError
 O.getRefinement<C, A>(c => (c.type === 'B' ? O.some(c) : O.none))
 
+// fromNullable
+
+declare const fromNullableTest1: number | null | undefined
+O.fromNullable(fromNullableTest1) // $ExpectType Option<number>
+
+interface fromNullableTest2 {
+  foo: number | undefined
+}
+declare const fromNullableTest3: <Key extends keyof fromNullableTest2>(key: Key) => fromNullableTest2[Key]
+// $ExpectType Option<number>
+Fu.flow(
+  fromNullableTest3,
+  O.fromNullable
+)('foo')
+
+//
+// Either
+//
+
+// $ExpectType Either<string, number>
+Fu.flow(
+  fromNullableTest3,
+  E.fromNullable('error')
+)('foo')
+
 //
 // HKT
 //
diff --git a/package-lock.json b/package-lock.json
index 7c6494a0..5d7425bf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "2.1.0",
+  "version": "2.1.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1924,7 +1924,7 @@
       }
     },
     "dtslint": {
-      "version": "github:gcanti/dtslint#ca68c83d54dec21183288b37da1a873c27c92d53",
+      "version": "github:gcanti/dtslint#fc1e289597786080ce559b4f8cc8798bb537080e",
       "from": "github:gcanti/dtslint",
       "dev": true,
       "requires": {
@@ -1932,7 +1932,7 @@
         "parsimmon": "^1.12.0",
         "strip-json-comments": "^2.0.1",
         "tslint": "^5.12.0",
-        "typescript": "^3.7.0-dev.20190829"
+        "typescript": "^3.8.0-dev.20191105"
       },
       "dependencies": {
         "ansi-styles": {
@@ -1955,6 +1955,12 @@
             "supports-color": "^5.3.0"
           }
         },
+        "diff": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
+          "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
+          "dev": true
+        },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -1971,16 +1977,16 @@
           }
         },
         "tslint": {
-          "version": "5.19.0",
-          "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.19.0.tgz",
-          "integrity": "sha512-1LwwtBxfRJZnUvoS9c0uj8XQtAnyhWr9KlNvDIdB+oXyT+VpsOAaEhEgKi1HrZ8rq0ki/AAnbGSv4KM6/AfVZw==",
+          "version": "5.20.0",
+          "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz",
+          "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==",
           "dev": true,
           "requires": {
             "@babel/code-frame": "^7.0.0",
             "builtin-modules": "^1.1.1",
             "chalk": "^2.3.0",
             "commander": "^2.12.1",
-            "diff": "^3.2.0",
+            "diff": "^4.0.1",
             "glob": "^7.1.1",
             "js-yaml": "^3.13.1",
             "minimatch": "^3.0.4",
@@ -2001,9 +2007,9 @@
           }
         },
         "typescript": {
-          "version": "3.7.0-dev.20190829",
-          "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.0-dev.20190829.tgz",
-          "integrity": "sha512-qyRMr1LuxkE8Su38W6t7YtRI8wotu4TiAUpnD8QIxYBHiyalNTC2GsGJGGrYXSZ5d1RM0VG4PNrHOxA0byfhKg==",
+          "version": "3.8.0-dev.20191105",
+          "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.0-dev.20191105.tgz",
+          "integrity": "sha512-bKujrrC0aQRihwWPuavqvlCArHqwXqGmUTwzpyojkTiHBMbfuuVxqM5fYDYLALe6B1eRGm5bFeNtFF/d/8CpCQ==",
           "dev": true
         }
       }
@@ -5740,9 +5746,9 @@
       "dev": true
     },
     "prettier": {
-      "version": "1.18.2",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
-      "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+      "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
       "dev": true
     },
     "pretty-format": {
@@ -7235,9 +7241,9 @@
       "dev": true
     },
     "typescript": {
-      "version": "3.6.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
-      "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
+      "integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==",
       "dev": true
     },
     "uglify-js": {
diff --git a/package.json b/package.json
index e49912ae..62f5d4b0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "2.1.1",
+  "version": "2.1.2",
   "description": "Functional programming in TypeScript",
   "files": [
     "lib",
@@ -52,14 +52,14 @@
     "glob": "^7.1.3",
     "jest": "^24.8.0",
     "mocha": "^5.2.0",
-    "prettier": "^1.18.2",
+    "prettier": "^1.19.1",
     "rimraf": "2.6.2",
     "ts-jest": "^24.0.2",
     "ts-node": "^8.0.2",
     "ts-simple-ast": "17.1.1",
     "tslint": "5.11.0",
     "tslint-config-standard": "8.0.1",
-    "typescript": "^3.6.3"
+    "typescript": "^3.7.2"
   },
   "tags": [
     "typescript",
diff --git a/src/Applicative.ts b/src/Applicative.ts
index e131e49b..f9d6c984 100644
--- a/src/Applicative.ts
+++ b/src/Applicative.ts
@@ -241,6 +241,9 @@ export function getApplicativeComposition<F, G>(F: Applicative<F>, G: Applicativ
     ...getFunctorComposition(F, G),
     of: a => F.of(G.of(a)),
     ap: <A, B>(fgab: HKT<F, HKT<G, (a: A) => B>>, fga: HKT<F, HKT<G, A>>): HKT<F, HKT<G, B>> =>
-      F.ap(F.map(fgab, h => (ga: HKT<G, A>) => G.ap<A, B>(h, ga)), fga)
+      F.ap(
+        F.map(fgab, h => (ga: HKT<G, A>) => G.ap<A, B>(h, ga)),
+        fga
+      )
   }
 }
diff --git a/src/Array.ts b/src/Array.ts
index 4b678e41..f60bf39e 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -1242,7 +1242,11 @@ export function comprehension<R>(
  */
 export function union<A>(E: Eq<A>): (xs: Array<A>, ys: Array<A>) => Array<A> {
   const elemE = elem(E)
-  return (xs, ys) => concat(xs, ys.filter(a => !elemE(a, xs)))
+  return (xs, ys) =>
+    concat(
+      xs,
+      ys.filter(a => !elemE(a, xs))
+    )
 }
 
 /**
@@ -1377,7 +1381,12 @@ export const array: Monad1<URI> &
     return (ta, f) => traverseWithIndexF(ta, (_, a) => f(a))
   },
   sequence: <F>(F: Applicative<F>) => <A>(ta: Array<HKT<F, A>>): HKT<F, Array<A>> => {
-    return array.reduce(ta, F.of(array.zero()), (fas, fa) => F.ap(F.map(fas, as => (a: A) => snoc(as, a)), fa))
+    return array.reduce(ta, F.of(array.zero()), (fas, fa) =>
+      F.ap(
+        F.map(fas, as => (a: A) => snoc(as, a)),
+        fa
+      )
+    )
   },
   zero: () => empty,
   alt: (fx, f) => concat(fx, f()),
@@ -1407,7 +1416,10 @@ export const array: Monad1<URI> &
     f: (i: number, a: A) => HKT<F, B>
   ): HKT<F, Array<B>> => {
     return array.reduceWithIndex(ta, F.of<Array<B>>(array.zero()), (i, fbs, a) =>
-      F.ap(F.map(fbs, bs => (b: B) => snoc(bs, b)), f(i, a))
+      F.ap(
+        F.map(fbs, bs => (b: B) => snoc(bs, b)),
+        f(i, a)
+      )
     )
   },
   partitionMapWithIndex: <A, B, C>(
diff --git a/src/Choice.ts b/src/Choice.ts
index 6adc01e1..fe1f71ff 100644
--- a/src/Choice.ts
+++ b/src/Choice.ts
@@ -92,11 +92,7 @@ export function splitChoice<F>(
 export function splitChoice<F>(
   F: Category<F> & Choice<F>
 ): <A, B, C, D>(pab: HKT2<F, A, B>, pcd: HKT2<F, C, D>) => HKT2<F, Either<A, C>, Either<B, D>> {
-  return (pab, pcd) =>
-    F.compose(
-      F.left(pab),
-      F.right(pcd)
-    )
+  return (pab, pcd) => F.compose(F.left(pab), F.right(pcd))
 }
 
 /**
@@ -136,9 +132,6 @@ export function fanin<F>(
   const splitChoiceF = splitChoice(F)
   return <A, B, C>(pac: HKT2<F, A, C>, pbc: HKT2<F, B, C>): HKT2<F, Either<A, B>, C> => {
     const join: HKT2<F, Either<C, C>, C> = F.promap(F.id<C>(), e => (e._tag === 'Left' ? e.left : e.right), identity)
-    return F.compose(
-      join,
-      splitChoiceF(pac, pbc)
-    )
+    return F.compose(join, splitChoiceF(pac, pbc))
   }
 }
diff --git a/src/Either.ts b/src/Either.ts
index cd48f311..356a4f46 100644
--- a/src/Either.ts
+++ b/src/Either.ts
@@ -108,10 +108,18 @@ export function right<E = never, A = never>(a: A): Either<E, A> {
  * Takes a default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use
  * the provided default as a `Left`
  *
+ * @example
+ * import { fromNullable, left, right } from 'fp-ts/lib/Either'
+ *
+ * const parse = fromNullable('nully')
+ *
+ * assert.deepStrictEqual(parse(1), right(1))
+ * assert.deepStrictEqual(parse(null), left('nully'))
+ *
  * @since 2.0.0
  */
-export function fromNullable<E>(e: E): <A>(a: A | null | undefined) => Either<E, A> {
-  return a => (a == null ? left(e) : right(a))
+export function fromNullable<E>(e: E): <A>(a: A) => Either<E, NonNullable<A>> {
+  return <A>(a: A) => (a == null ? left(e) : right(a as NonNullable<A>))
 }
 
 /**
@@ -155,6 +163,36 @@ export function tryCatch<E, A>(f: Lazy<A>, onError: (e: unknown) => E): Either<E
 }
 
 /**
+ * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function,
+ * if the value is a `Right` the inner value is applied to the second function.
+ *
+ * @example
+ * import { fold, left, right } from 'fp-ts/lib/Either'
+ * import { pipe } from 'fp-ts/lib/pipeable'
+ *
+ * function onLeft(errors: Array<string>): string {
+ *   return `Errors: ${errors.join(', ')}`
+ * }
+ *
+ * function onRight(value: number): string {
+ *   return `Ok: ${value}`
+ * }
+ *
+ * assert.strictEqual(
+ *   pipe(
+ *     right(1),
+ *     fold(onLeft, onRight)
+ *   ),
+ *   'Ok: 1'
+ * )
+ * assert.strictEqual(
+ *   pipe(
+ *     left(['error 1', 'error 2']),
+ *     fold(onLeft, onRight)
+ *   ),
+ *   'Errors: error 1, error 2'
+ * )
+ *
  * @since 2.0.0
  */
 export function fold<E, A, B>(onLeft: (e: E) => B, onRight: (a: A) => B): (ma: Either<E, A>) => B {
@@ -508,11 +546,10 @@ export const either: Monad2<URI> &
   mapLeft: (fea, f) => (isLeft(fea) ? left(f(fea.left)) : fea),
   alt: (fx, fy) => (isLeft(fx) ? fy() : fx),
   extend: (wa, f) => (isLeft(wa) ? wa : right(f(wa))),
-  chainRec: <E, A, B>(a: A, f: (a: A) => Either<E, Either<A, B>>): Either<E, B> => {
-    return tailRec(f(a), e =>
+  chainRec: (a, f) =>
+    tailRec(f(a), e =>
       isLeft(e) ? right(left(e.left)) : isLeft(e.right) ? left(f(e.right.left)) : right(right(e.right.right))
-    )
-  },
+    ),
   throwError: left
 }
 
diff --git a/src/EitherT.ts b/src/EitherT.ts
index 1d2281b8..5de17ffc 100644
--- a/src/EitherT.ts
+++ b/src/EitherT.ts
@@ -102,7 +102,11 @@ export function getEitherM<M>(M: Monad<M>): EitherM<M> {
     mapLeft: (ma, f) => M.map(ma, e => either.mapLeft(e, f)),
     fold: (ma, onLeft, onRight) => M.chain(ma, fold(onLeft, onRight)),
     getOrElse: (ma, onLeft) => M.chain(ma, fold(onLeft, M.of)),
-    orElse: (ma, f) => M.chain(ma, fold(f, a => A.of(a))),
+    orElse: (ma, f) =>
+      M.chain(
+        ma,
+        fold(f, a => A.of(a))
+      ),
     swap: ma => M.map(ma, swap),
     rightM: ma => M.map(ma, right),
     leftM: ml => M.map(ml, left),
diff --git a/src/IO.ts b/src/IO.ts
index f29525a8..ca7a4908 100644
--- a/src/IO.ts
+++ b/src/IO.ts
@@ -95,6 +95,7 @@ import { MonadIO1 } from './MonadIO'
 import { Monoid } from './Monoid'
 import { pipeable } from './pipeable'
 import { Semigroup } from './Semigroup'
+import { ChainRec1 } from './ChainRec'
 
 declare module './HKT' {
   interface URItoKind<A> {
@@ -146,13 +147,20 @@ export const of = <A>(a: A): IO<A> => () => a
 /**
  * @since 2.0.0
  */
-export const io: Monad1<URI> & MonadIO1<URI> = {
+export const io: Monad1<URI> & MonadIO1<URI> & ChainRec1<URI> = {
   URI,
   map: (ma, f) => () => f(ma()),
   of,
   ap: (mab, ma) => () => mab()(ma()),
   chain: (ma, f) => () => f(ma())(),
-  fromIO: identity
+  fromIO: identity,
+  chainRec: (a, f) => () => {
+    let e = f(a)()
+    while (e._tag === 'Left') {
+      e = f(e.left)()
+    }
+    return e.right
+  }
 }
 
 const { ap, apFirst, apSecond, chain, chainFirst, flatten, map } = pipeable(io)
diff --git a/src/IOEither.ts b/src/IOEither.ts
index a50e4004..d10b5ac0 100644
--- a/src/IOEither.ts
+++ b/src/IOEither.ts
@@ -122,9 +122,10 @@ export function tryCatch<E, A>(f: Lazy<A>, onError: (reason: unknown) => E): IOE
 }
 
 /**
- * Make sure that a resource is cleaned up in the event of an exception. The
- * release action is called regardless of whether the body action throws or
- * returns.
+ * Make sure that a resource is cleaned up in the event of an exception (*). The release action is called regardless of
+ * whether the body action throws (*) or returns.
+ *
+ * (*) i.e. returns a `Left`
  *
  * @since 2.0.0
  */
diff --git a/src/Identity.ts b/src/Identity.ts
index daf393c9..e35e8922 100644
--- a/src/Identity.ts
+++ b/src/Identity.ts
@@ -1,6 +1,6 @@
 import { Alt1 } from './Alt'
 import { Applicative } from './Applicative'
-import { ChainRec1 } from './ChainRec'
+import { ChainRec1, tailRec } from './ChainRec'
 import { Comonad1 } from './Comonad'
 import { Eq } from './Eq'
 import { Foldable1 } from './Foldable'
@@ -63,13 +63,7 @@ export const identity: Monad1<URI> & Foldable1<URI> & Traversable1<URI> & Alt1<U
   alt: id,
   extract: id,
   extend: (wa, f) => f(wa),
-  chainRec: (a, f) => {
-    let v = f(a)
-    while (v._tag === 'Left') {
-      v = f(v.left)
-    }
-    return v.right
-  }
+  chainRec: tailRec
 }
 
 const {
diff --git a/src/Map.ts b/src/Map.ts
index 93f01581..acf398d2 100644
--- a/src/Map.ts
+++ b/src/Map.ts
@@ -539,7 +539,10 @@ export function getWitherable<K>(O: Ord<K>): Witherable2C<URI, K> & TraversableW
       // tslint:disable-next-line: strict-boolean-expressions
       while (!(e = entries.next()).done) {
         const [key, a] = e.value
-        fm = F.ap(F.map(fm, m => (b: B) => new Map(m).set(key, b)), f(key, a))
+        fm = F.ap(
+          F.map(fm, m => (b: B) => new Map(m).set(key, b)),
+          f(key, a)
+        )
       }
       return fm
     }
diff --git a/src/NonEmptyArray.ts b/src/NonEmptyArray.ts
index f1fe4f2a..f6b88f35 100644
--- a/src/NonEmptyArray.ts
+++ b/src/NonEmptyArray.ts
@@ -227,6 +227,21 @@ export function last<A>(nea: NonEmptyArray<A>): A {
   return nea[nea.length - 1]
 }
 
+/**
+ * Get all but the last element of an array, creating a new array.
+ *
+ * @example
+ * import { init } from 'fp-ts/lib/NonEmptyArray'
+ *
+ * assert.deepStrictEqual(init([1, 2, 3]), [1, 2])
+ * assert.deepStrictEqual(init([1]), [])
+ *
+ * @since 2.0.0
+ */
+export function init<A>(nea: NonEmptyArray<A>): Array<A> {
+  return nea.slice(0, -1)
+}
+
 /**
  * @since 2.0.0
  */
diff --git a/src/Option.ts b/src/Option.ts
index de48070f..de879119 100644
--- a/src/Option.ts
+++ b/src/Option.ts
@@ -118,7 +118,8 @@ export function isNone<A>(fa: Option<A>): fa is None {
 }
 
 /**
- * We can pattern match using the `fold` function
+ * Takes a default value, a function, and an `Option` value, if the `Option` value is `None` the default value is
+ * returned, otherwise the function is applied to the value inside the `Some` and the result is returned.
  *
  * @example
  * import { some, none, fold } from 'fp-ts/lib/Option'
@@ -159,8 +160,8 @@ export function fold<A, B>(onNone: () => B, onSome: (a: A) => B): (ma: Option<A>
  *
  * @since 2.0.0
  */
-export function fromNullable<A>(a: A | null | undefined): Option<A> {
-  return a == null ? none : some(a)
+export function fromNullable<A>(a: A): Option<NonNullable<A>> {
+  return a == null ? none : some(a as NonNullable<A>)
 }
 
 /**
diff --git a/src/OptionT.ts b/src/OptionT.ts
index 4b1e202e..87624699 100644
--- a/src/OptionT.ts
+++ b/src/OptionT.ts
@@ -1,12 +1,13 @@
 import {
-  ApplicativeCompositionHKT1,
   ApplicativeComposition11,
   ApplicativeComposition21,
+  ApplicativeComposition2C1,
+  ApplicativeCompositionHKT1,
   getApplicativeComposition
 } from './Applicative'
 import { HKT, Kind, Kind2, URIS, URIS2 } from './HKT'
-import { Monad, Monad1, Monad2 } from './Monad'
-import { fold, none, Option, some, URI, option } from './Option'
+import { Monad, Monad1, Monad2, Monad2C } from './Monad'
+import { fold, none, Option, option, some, URI } from './Option'
 
 /**
  * @since 2.0.0
@@ -63,10 +64,27 @@ export interface OptionM2<M extends URIS2> extends ApplicativeComposition21<M, U
   readonly none: <E = never, A = never>() => OptionT2<M, E, A>
 }
 
+/**
+ * @since 2.2.0
+ */
+export interface OptionM2C<M extends URIS2, E> extends ApplicativeComposition2C1<M, URI, E> {
+  readonly chain: <A, B>(ma: OptionT2<M, E, A>, f: (a: A) => OptionT2<M, E, B>) => OptionT2<M, E, B>
+  readonly alt: <A>(fx: OptionT2<M, E, A>, fy: () => OptionT2<M, E, A>) => OptionT2<M, E, A>
+  readonly fold: <A, R>(
+    ma: OptionT2<M, E, A>,
+    onNone: () => Kind2<M, E, R>,
+    onSome: (a: A) => Kind2<M, E, R>
+  ) => Kind2<M, E, R>
+  readonly getOrElse: <A>(ma: OptionT2<M, E, A>, onNone: () => Kind2<M, E, A>) => Kind2<M, E, A>
+  readonly fromM: <A>(ma: Kind2<M, E, A>) => OptionT2<M, E, A>
+  readonly none: <A = never>() => OptionT2<M, E, A>
+}
+
 /**
  * @since 2.0.0
  */
 export function getOptionM<M extends URIS2>(M: Monad2<M>): OptionM2<M>
+export function getOptionM<M extends URIS2, E>(M: Monad2C<M, E>): OptionM2C<M, E>
 export function getOptionM<M extends URIS>(M: Monad1<M>): OptionM1<M>
 export function getOptionM<M>(M: Monad<M>): OptionM<M>
 export function getOptionM<M>(M: Monad<M>): OptionM<M> {
@@ -75,8 +93,16 @@ export function getOptionM<M>(M: Monad<M>): OptionM<M> {
 
   return {
     ...A,
-    chain: (ma, f) => M.chain(ma, fold(() => fnone, f)),
-    alt: (fx, fy) => M.chain(fx, fold(fy, a => M.of(some(a)))),
+    chain: (ma, f) =>
+      M.chain(
+        ma,
+        fold(() => fnone, f)
+      ),
+    alt: (fx, fy) =>
+      M.chain(
+        fx,
+        fold(fy, a => M.of(some(a)))
+      ),
     fold: (ma, onNone, onSome) => M.chain(ma, fold(onNone, onSome)),
     getOrElse: (ma, onNone) => M.chain(ma, fold(onNone, M.of)),
     fromM: ma => M.map(ma, some),
diff --git a/src/Ord.ts b/src/Ord.ts
index addc7867..3012a4af 100644
--- a/src/Ord.ts
+++ b/src/Ord.ts
@@ -159,6 +159,63 @@ export function fromCompare<A>(compare: (x: A, y: A) => Ordering): Ord<A> {
 }
 
 /**
+ * Returns an `Ord` such that its `concat(ord1, ord2)` operation will order first by `ord1`, and then by `ord2`.
+ *
+ * @example
+ * import { sort } from 'fp-ts/lib/Array'
+ * import { contramap, getDualOrd, getSemigroup, ordBoolean, ordNumber, ordString } from 'fp-ts/lib/Ord'
+ * import { pipe } from 'fp-ts/lib/pipeable'
+ * import { fold } from 'fp-ts/lib/Semigroup'
+ *
+ * interface User {
+ *   id: number
+ *   name: string
+ *   age: number
+ *   rememberMe: boolean
+ * }
+ *
+ * const byName = pipe(
+ *   ordString,
+ *   contramap((p: User) => p.name)
+ * )
+ *
+ * const byAge = pipe(
+ *   ordNumber,
+ *   contramap((p: User) => p.age)
+ * )
+ *
+ * const byRememberMe = pipe(
+ *   ordBoolean,
+ *   contramap((p: User) => p.rememberMe)
+ * )
+ *
+ * const S = getSemigroup<User>()
+ *
+ * const users: Array<User> = [
+ *   { id: 1, name: 'Guido', age: 47, rememberMe: false },
+ *   { id: 2, name: 'Guido', age: 46, rememberMe: true },
+ *   { id: 3, name: 'Giulio', age: 44, rememberMe: false },
+ *   { id: 4, name: 'Giulio', age: 44, rememberMe: true }
+ * ]
+ *
+ * // sort by name, then by age, then by `rememberMe`
+ * const O1 = fold(S)(byName, [byAge, byRememberMe])
+ * assert.deepStrictEqual(sort(O1)(users), [
+ *   { id: 3, name: 'Giulio', age: 44, rememberMe: false },
+ *   { id: 4, name: 'Giulio', age: 44, rememberMe: true },
+ *   { id: 2, name: 'Guido', age: 46, rememberMe: true },
+ *   { id: 1, name: 'Guido', age: 47, rememberMe: false }
+ * ])
+ *
+ * // now `rememberMe = true` first, then by name, then by age
+ * const O2 = fold(S)(getDualOrd(byRememberMe), [byName, byAge])
+ * assert.deepStrictEqual(sort(O2)(users), [
+ *   { id: 4, name: 'Giulio', age: 44, rememberMe: true },
+ *   { id: 2, name: 'Guido', age: 46, rememberMe: true },
+ *   { id: 3, name: 'Giulio', age: 44, rememberMe: false },
+ *   { id: 1, name: 'Guido', age: 47, rememberMe: false }
+ * ])
+ *
  * @since 2.0.0
  */
 export function getSemigroup<A = never>(): Semigroup<Ord<A>> {
diff --git a/src/Reader.ts b/src/Reader.ts
index fbeac77f..edf1e7f5 100644
--- a/src/Reader.ts
+++ b/src/Reader.ts
@@ -51,7 +51,8 @@ export const ask: <R>() => Reader<R, R> = T.ask
 export const asks: <R, A>(f: (r: R) => A) => Reader<R, A> = T.asks
 
 /**
- * changes the value of the local context during the execution of the action `ma`
+ * Changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
+ * `contramap`).
  *
  * @since 2.0.0
  */
diff --git a/src/ReaderT.ts b/src/ReaderT.ts
index 56ba2b6a..8f700c2f 100644
--- a/src/ReaderT.ts
+++ b/src/ReaderT.ts
@@ -1,5 +1,5 @@
 import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
-import { Monad, Monad1, Monad2, Monad3 } from './Monad'
+import { Monad, Monad1, Monad2, Monad2C, Monad3 } from './Monad'
 import { Reader } from './Reader'
 
 /**
@@ -68,6 +68,21 @@ export interface ReaderM2<M extends URIS2> {
   readonly fromM: <R, E, A>(ma: Kind2<M, E, A>) => ReaderT2<M, R, E, A>
 }
 
+/**
+ * @since 2.2.0
+ */
+export interface ReaderM2C<M extends URIS2, E> {
+  readonly map: <R, A, B>(ma: ReaderT2<M, R, E, A>, f: (a: A) => B) => ReaderT2<M, R, E, B>
+  readonly of: <R, A>(a: A) => ReaderT2<M, R, E, A>
+  readonly ap: <R, A, B>(mab: ReaderT2<M, R, E, (a: A) => B>, ma: ReaderT2<M, R, E, A>) => ReaderT2<M, R, E, B>
+  readonly chain: <R, A, B>(ma: ReaderT2<M, R, E, A>, f: (a: A) => ReaderT2<M, R, E, B>) => ReaderT2<M, R, E, B>
+  readonly ask: <R>() => ReaderT2<M, R, E, R>
+  readonly asks: <R, A>(f: (r: R) => A) => ReaderT2<M, R, E, A>
+  readonly local: <R, A, Q>(ma: ReaderT2<M, R, E, A>, f: (d: Q) => R) => ReaderT2<M, Q, E, A>
+  readonly fromReader: <R, A>(ma: Reader<R, A>) => ReaderT2<M, R, E, A>
+  readonly fromM: <R, A>(ma: Kind2<M, E, A>) => ReaderT2<M, R, E, A>
+}
+
 /**
  * @since 2.0.0
  */
@@ -101,6 +116,7 @@ export interface ReaderM3<M extends URIS3> {
  */
 export function getReaderM<M extends URIS3>(M: Monad3<M>): ReaderM3<M>
 export function getReaderM<M extends URIS2>(M: Monad2<M>): ReaderM2<M>
+export function getReaderM<M extends URIS2, E>(M: Monad2C<M, E>): ReaderM2C<M, E>
 export function getReaderM<M extends URIS>(M: Monad1<M>): ReaderM1<M>
 export function getReaderM<M>(M: Monad<M>): ReaderM<M>
 export function getReaderM<M>(M: Monad<M>): ReaderM<M> {
diff --git a/src/ReaderTaskEither.ts b/src/ReaderTaskEither.ts
index 1eafc905..6bc92380 100644
--- a/src/ReaderTaskEither.ts
+++ b/src/ReaderTaskEither.ts
@@ -130,7 +130,10 @@ export function fold<R, E, A, B>(
   return ma => r =>
     pipe(
       ma(r),
-      TE.fold(e => onLeft(e)(r), a => onRight(a)(r))
+      TE.fold(
+        e => onLeft(e)(r),
+        a => onRight(a)(r)
+      )
     )
 }
 
@@ -201,9 +204,10 @@ export function local<Q, R>(f: (f: Q) => R): <E, A>(ma: ReaderTaskEither<R, E, A
 }
 
 /**
- * Make sure that a resource is cleaned up in the event of an exception. The
- * release action is called regardless of whether the body action throws or
- * returns.
+ * Make sure that a resource is cleaned up in the event of an exception (*). The release action is called regardless of
+ * whether the body action throws (*) or returns.
+ *
+ * (*) i.e. returns a `Left`
  *
  * @since 2.0.4
  */
@@ -212,7 +216,12 @@ export function bracket<R, E, A, B>(
   use: (a: A) => ReaderTaskEither<R, E, B>,
   release: (a: A, e: Either<E, B>) => ReaderTaskEither<R, E, void>
 ): ReaderTaskEither<R, E, B> {
-  return r => TE.bracket(aquire(r), a => use(a)(r), (a, e) => release(a, e)(r))
+  return r =>
+    TE.bracket(
+      aquire(r),
+      a => use(a)(r),
+      (a, e) => release(a, e)(r)
+    )
 }
 
 /**
diff --git a/src/State.ts b/src/State.ts
index 6bcee1b1..5872d6c7 100644
--- a/src/State.ts
+++ b/src/State.ts
@@ -1,3 +1,9 @@
+/**
+ * @file The `State` monad is a synonym for the `StateT` monad transformer, applied to the `Identity` monad.
+ *
+ * For a good introduction to the state monad, see the following blog post by [@pfgray](https://github.com/pfgray): [The
+ * State monad](https://paulgray.net/the-state-monad/)
+ */
 import { Monad2 } from './Monad'
 import { getStateM } from './StateT'
 import { identity } from './Identity'
diff --git a/src/Strong.ts b/src/Strong.ts
index 6c091689..1670aa7f 100644
--- a/src/Strong.ts
+++ b/src/Strong.ts
@@ -91,11 +91,7 @@ export function splitStrong<F>(
 export function splitStrong<F>(
   F: Category<F> & Strong<F>
 ): <A, B, C, D>(pab: HKT2<F, A, B>, pcd: HKT2<F, C, D>) => HKT2<F, [A, C], [B, D]> {
-  return (pab, pcd) =>
-    F.compose(
-      F.first(pab),
-      F.second(pcd)
-    )
+  return (pab, pcd) => F.compose(F.first(pab), F.second(pcd))
 }
 
 /**
@@ -134,9 +130,6 @@ export function fanout<F>(
   const splitStrongF = splitStrong(F)
   return <A, B, C>(pab: HKT2<F, A, B>, pac: HKT2<F, A, C>): HKT2<F, A, [B, C]> => {
     const split: HKT2<F, A, [A, A]> = F.promap(F.id<A>(), identity, a => [a, a])
-    return F.compose(
-      splitStrongF(pab, pac),
-      split
-    )
+    return F.compose(splitStrongF(pab, pac), split)
   }
 }
diff --git a/src/TaskEither.ts b/src/TaskEither.ts
index e94debf1..36b23b36 100644
--- a/src/TaskEither.ts
+++ b/src/TaskEither.ts
@@ -137,16 +137,32 @@ export function getApplyMonoid<E, A>(M: Monoid<A>): Monoid<TaskEither<E, A>> {
 }
 
 /**
+ * Transforms a `Promise` that may reject to a `Promise` that never rejects and returns an `Either` instead.
+ *
+ * Note: `f` should never `throw` errors, they are not caught.
+ *
+ * @example
+ * import { left, right } from 'fp-ts/lib/Either'
+ * import { tryCatch } from 'fp-ts/lib/TaskEither'
+ *
+ * tryCatch(() => Promise.resolve(1), String)().then(result => {
+ *   assert.deepStrictEqual(result, right(1))
+ * })
+ * tryCatch(() => Promise.reject('error'), String)().then(result => {
+ *   assert.deepStrictEqual(result, left('error'))
+ * })
+ *
  * @since 2.0.0
  */
 export function tryCatch<E, A>(f: Lazy<Promise<A>>, onRejected: (reason: unknown) => E): TaskEither<E, A> {
-  return () => f().then(a => E.right(a), reason => E.left(onRejected(reason)))
+  return () => f().then(E.right, reason => E.left(onRejected(reason)))
 }
 
 /**
- * Make sure that a resource is cleaned up in the event of an exception. The
- * release action is called regardless of whether the body action throws or
- * returns.
+ * Make sure that a resource is cleaned up in the event of an exception (*). The release action is called regardless of
+ * whether the body action throws (*) or returns.
+ *
+ * (*) i.e. returns a `Left`
  *
  * @since 2.0.0
  */
@@ -187,7 +203,6 @@ export function bracket<E, A, B>(
  * const stat = taskify(fs.stat)
  * assert.strictEqual(stat.length, 0)
  *
- *
  * @since 2.0.0
  */
 export function taskify<L, R>(f: (cb: (e: L | null | undefined, r?: R) => void) => void): () => TaskEither<L, R>
diff --git a/src/These.ts b/src/These.ts
index 704d347e..361c4652 100644
--- a/src/These.ts
+++ b/src/These.ts
@@ -107,7 +107,11 @@ export function fold<E, A, B>(
  */
 export function getShow<E, A>(SE: Show<E>, SA: Show<A>): Show<These<E, A>> {
   return {
-    show: fold(l => `left(${SE.show(l)})`, a => `right(${SA.show(a)})`, (l, a) => `both(${SE.show(l)}, ${SA.show(a)})`)
+    show: fold(
+      l => `left(${SE.show(l)})`,
+      a => `right(${SA.show(a)})`,
+      (l, a) => `both(${SE.show(l)}, ${SA.show(a)})`
+    )
   }
 }
 
diff --git a/src/Tree.ts b/src/Tree.ts
index 079fbd0d..74eca541 100644
--- a/src/Tree.ts
+++ b/src/Tree.ts
@@ -229,7 +229,10 @@ export const tree: Monad1<URI> & Foldable1<URI> & Traversable1<URI> & Comonad1<U
     const concat = getMonoid<Tree<B>>().concat
     return {
       value,
-      forest: concat(forest, fa.forest.map(t => tree.chain(t, f)))
+      forest: concat(
+        forest,
+        fa.forest.map(t => tree.chain(t, f))
+      )
     }
   },
   reduce: <A, B>(fa: Tree<A>, b: B, f: (b: B, a: A) => B): B => {
diff --git a/src/boolean.ts b/src/boolean.ts
new file mode 100644
index 00000000..1f8b88d2
--- /dev/null
+++ b/src/boolean.ts
@@ -0,0 +1,24 @@
+/**
+ * Defines the fold over a boolean value.
+ * Takes two thunks `onTrue`, `onFalse` and a `boolean` value.
+ * If `value` is false, `onFalse()` is returned, otherwise `onTrue()`.
+ *
+ *
+ * @example
+ * import { some, map } from 'fp-ts/lib/Option'
+ * import { pipe } from 'fp-ts/lib/pipeable'
+ * import { fold } from 'fp-ts/lib/boolean'
+ *
+ * assert.deepStrictEqual(
+ *  pipe(
+ *    some(true),
+ *    map(fold(() => 'false', () => 'true'))
+ *  ),
+ *  some('true')
+ * )
+ *
+ * @since 2.2.0
+ */
+export function fold<A>(onFalse: () => A, onTrue: () => A): (value: boolean) => A {
+  return value => (value ? onTrue() : onFalse())
+}
diff --git a/src/index.ts b/src/index.ts
index dbe952a5..10948524 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -4,6 +4,7 @@ import * as applicative from './Applicative'
 import * as apply from './Apply'
 import * as array from './Array'
 import * as bifunctor from './Bifunctor'
+import * as boolean from './boolean'
 import * as booleanAlgebra from './BooleanAlgebra'
 import * as bounded from './Bounded'
 import * as boundedDistributiveLattice from './BoundedDistributiveLattice'
@@ -112,6 +113,10 @@ export {
    * @since 2.0.0
    */
   bifunctor,
+  /**
+   * @since 2.2.0
+   */
+  boolean,
   /**
    * @since 2.0.0
    */
diff --git a/src/pipeable.ts b/src/pipeable.ts
index 65a2f666..432a2c9f 100644
--- a/src/pipeable.ts
+++ b/src/pipeable.ts
@@ -1301,10 +1301,18 @@ export function pipeable<F, I>(I: { URI: F } & I): Record<string, unknown> {
   }
   if (isApply<F>(I)) {
     const ap: PipeableApply<F>['ap'] = fa => fab => I.ap(fab, fa)
-    const apFirst: PipeableApply<F>['apFirst'] = fb => fa => I.ap(I.map(fa, a => () => a), fb)
+    const apFirst: PipeableApply<F>['apFirst'] = fb => fa =>
+      I.ap(
+        I.map(fa, a => () => a),
+        fb
+      )
     r.ap = ap
     r.apFirst = apFirst
-    r.apSecond = <B>(fb: HKT<F, B>) => <A>(fa: HKT<F, A>): HKT<F, B> => I.ap(I.map(fa, () => (b: B) => b), fb)
+    r.apSecond = <B>(fb: HKT<F, B>) => <A>(fa: HKT<F, A>): HKT<F, B> =>
+      I.ap(
+        I.map(fa, () => (b: B) => b),
+        fb
+      )
   }
   if (isChain<F>(I)) {
     const chain: PipeableChain<F>['chain'] = f => ma => I.chain(ma, f)
@@ -1391,11 +1399,7 @@ export function pipeable<F, I>(I: { URI: F } & I): Record<string, unknown> {
     r.promap = promap
   }
   if (isSemigroupoid<F>(I)) {
-    const compose: PipeableSemigroupoid<F>['compose'] = that => fa =>
-      I.compose(
-        fa,
-        that
-      )
+    const compose: PipeableSemigroupoid<F>['compose'] = that => fa => I.compose(fa, that)
     r.compose = compose
   }
   if (isMonadThrow<F>(I)) {


Test patch:
diff --git a/test/Apply.ts b/test/Apply.ts
index f36c5309..f357a833 100644
--- a/test/Apply.ts
+++ b/test/Apply.ts
@@ -17,10 +17,7 @@ describe('Apply', () => {
     const a2 = ['a', 'b', 'c']
     const a3 = [true, false]
     assert.deepStrictEqual(
-      pipe(
-        sequenceT(array)(a1, a2, a3),
-        arr => arr.map(([x, y, z]) => `(${x}, ${y}, ${z})`)
-      ),
+      pipe(sequenceT(array)(a1, a2, a3), arr => arr.map(([x, y, z]) => `(${x}, ${y}, ${z})`)),
       [
         '(1, a, true)',
         '(1, a, false)',
@@ -66,10 +63,7 @@ describe('Apply', () => {
     const a2 = ['a', 'b', 'c']
     const a3 = [true, false]
     assert.deepStrictEqual(
-      pipe(
-        sequenceS(array)({ a1, a2, a3 }),
-        arr => arr.map(({ a1, a2, a3 }) => `(${a1}, ${a2}, ${a3})`)
-      ),
+      pipe(sequenceS(array)({ a1, a2, a3 }), arr => arr.map(({ a1, a2, a3 }) => `(${a1}, ${a2}, ${a3})`)),
       [
         '(1, a, true)',
         '(1, a, false)',
diff --git a/test/Array.ts b/test/Array.ts
index de40f537..0acec062 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -76,7 +76,10 @@ describe('Array', () => {
   const as = [1, 2, 3]
 
   it('alt', () => {
-    assert.deepStrictEqual(array.alt([1, 2], () => [3, 4]), [1, 2, 3, 4])
+    assert.deepStrictEqual(
+      array.alt([1, 2], () => [3, 4]),
+      [1, 2, 3, 4]
+    )
   })
 
   it('getMonoid', () => {
@@ -251,7 +254,10 @@ describe('Array', () => {
   it('findFirst', () => {
     assert.deepStrictEqual(findFirst(x => x === 2)([]), O.none)
     assert.deepStrictEqual(
-      findFirst((x: { a: number; b: number }) => x.a === 1)([{ a: 1, b: 1 }, { a: 1, b: 2 }]),
+      findFirst((x: { a: number; b: number }) => x.a === 1)([
+        { a: 1, b: 1 },
+        { a: 1, b: 2 }
+      ]),
       O.some({ a: 1, b: 1 })
     )
     interface A {
@@ -287,11 +293,17 @@ describe('Array', () => {
   it('findLast', () => {
     assert.deepStrictEqual(findLast(x => x === 2)([]), O.none)
     assert.deepStrictEqual(
-      findLast((x: { a: number; b: number }) => x.a === 1)([{ a: 1, b: 1 }, { a: 1, b: 2 }]),
+      findLast((x: { a: number; b: number }) => x.a === 1)([
+        { a: 1, b: 1 },
+        { a: 1, b: 2 }
+      ]),
       O.some({ a: 1, b: 2 })
     )
     assert.deepStrictEqual(
-      findLast((x: { a: number; b: number }) => x.a === 1)([{ a: 1, b: 2 }, { a: 2, b: 1 }]),
+      findLast((x: { a: number; b: number }) => x.a === 1)([
+        { a: 1, b: 2 },
+        { a: 2, b: 1 }
+      ]),
       O.some({ a: 1, b: 2 })
     )
     assert.deepStrictEqual(findLast((x: string | null) => x === null)(['a', null]), O.some(null))
@@ -310,7 +322,10 @@ describe('Array', () => {
       a: number
       b: number
     }
-    const xs: Array<X> = [{ a: 1, b: 0 }, { a: 1, b: 1 }]
+    const xs: Array<X> = [
+      { a: 1, b: 0 },
+      { a: 1, b: 1 }
+    ]
     assert.deepStrictEqual(findLastIndex((x: X) => x.a === 1)(xs), O.some(1))
     assert.deepStrictEqual(findLastIndex((x: X) => x.a === 4)(xs), O.none)
     assert.deepStrictEqual(findLastIndex((x: X) => x.a === 1)([]), O.none)
@@ -357,15 +372,32 @@ describe('Array', () => {
   })
 
   it('zipWith', () => {
-    assert.deepStrictEqual(zipWith([1, 2, 3], ['a', 'b', 'c', 'd'], (n, s) => s + n), ['a1', 'b2', 'c3'])
+    assert.deepStrictEqual(
+      zipWith([1, 2, 3], ['a', 'b', 'c', 'd'], (n, s) => s + n),
+      ['a1', 'b2', 'c3']
+    )
   })
 
   it('zip', () => {
-    assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [[1, 'a'], [2, 'b'], [3, 'c']])
+    assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [
+      [1, 'a'],
+      [2, 'b'],
+      [3, 'c']
+    ])
   })
 
   it('unzip', () => {
-    assert.deepStrictEqual(unzip([[1, 'a'], [2, 'b'], [3, 'c']]), [[1, 2, 3], ['a', 'b', 'c']])
+    assert.deepStrictEqual(
+      unzip([
+        [1, 'a'],
+        [2, 'b'],
+        [3, 'c']
+      ]),
+      [
+        [1, 2, 3],
+        ['a', 'b', 'c']
+      ]
+    )
   })
 
   it('rights', () => {
@@ -395,11 +427,17 @@ describe('Array', () => {
   })
 
   it('map', () => {
-    assert.deepStrictEqual(array.map([1, 2, 3], n => n * 2), [2, 4, 6])
+    assert.deepStrictEqual(
+      array.map([1, 2, 3], n => n * 2),
+      [2, 4, 6]
+    )
   })
 
   it('mapWithIndex', () => {
-    assert.deepStrictEqual(array.mapWithIndex([1, 2, 3], (i, n) => n + i), [1, 3, 5])
+    assert.deepStrictEqual(
+      array.mapWithIndex([1, 2, 3], (i, n) => n + i),
+      [1, 3, 5]
+    )
   })
 
   it('ap', () => {
@@ -414,7 +452,10 @@ describe('Array', () => {
   })
 
   it('chain', () => {
-    assert.deepStrictEqual(array.chain([1, 2, 3], n => [n, n + 1]), [1, 2, 2, 3, 3, 4])
+    assert.deepStrictEqual(
+      array.chain([1, 2, 3], n => [n, n + 1]),
+      [1, 2, 2, 3, 3, 4]
+    )
   })
 
   it('reverse', () => {
@@ -422,7 +463,10 @@ describe('Array', () => {
   })
 
   it('reduce', () => {
-    assert.deepStrictEqual(array.reduce(['a', 'b', 'c'], '', (acc, a) => acc + a), 'abc')
+    assert.deepStrictEqual(
+      array.reduce(['a', 'b', 'c'], '', (acc, a) => acc + a),
+      'abc'
+    )
   })
 
   it('foldMap', () => {
@@ -445,12 +489,18 @@ describe('Array', () => {
   })
 
   it('foldLeft', () => {
-    const len: <A>(as: Array<A>) => number = foldLeft(() => 0, (_, tail) => 1 + len(tail))
+    const len: <A>(as: Array<A>) => number = foldLeft(
+      () => 0,
+      (_, tail) => 1 + len(tail)
+    )
     assert.strictEqual(len([1, 2, 3]), 3)
   })
 
   it('foldRight', () => {
-    const len: <A>(as: Array<A>) => number = foldRight(() => 0, (init, _) => 1 + len(init))
+    const len: <A>(as: Array<A>) => number = foldRight(
+      () => 0,
+      (init, _) => 1 + len(init)
+    )
     assert.strictEqual(len([1, 2, 3]), 3)
   })
 
@@ -509,7 +559,12 @@ describe('Array', () => {
     const byName = ord.contramap(ordString, (p: Person) => p.name)
     const byAge = ord.contramap(ordNumber, (p: Person) => p.age)
     const sortByNameByAge = sortBy([byName, byAge])
-    const persons = [{ name: 'a', age: 1 }, { name: 'b', age: 3 }, { name: 'c', age: 2 }, { name: 'b', age: 2 }]
+    const persons = [
+      { name: 'a', age: 1 },
+      { name: 'b', age: 3 },
+      { name: 'c', age: 2 },
+      { name: 'b', age: 2 }
+    ]
     assert.deepStrictEqual(sortByNameByAge(persons), [
       { name: 'a', age: 1 },
       { name: 'b', age: 2 },
@@ -602,7 +657,10 @@ describe('Array', () => {
   })
 
   it('splitAt', () => {
-    assert.deepStrictEqual(splitAt(2)([1, 2, 3, 4, 5]), [[1, 2], [3, 4, 5]])
+    assert.deepStrictEqual(splitAt(2)([1, 2, 3, 4, 5]), [
+      [1, 2],
+      [3, 4, 5]
+    ])
     assert.deepStrictEqual(splitAt(2)([]), [[], []])
     assert.deepStrictEqual(splitAt(2)([1]), [[1], []])
     assert.deepStrictEqual(splitAt(2)([1, 2]), [[1, 2], []])
@@ -614,7 +672,11 @@ describe('Array', () => {
   describe('chunksOf', () => {
     it('should split an array into length-n pieces', () => {
       assert.deepStrictEqual(chunksOf(2)([1, 2, 3, 4, 5]), [[1, 2], [3, 4], [5]])
-      assert.deepStrictEqual(chunksOf(2)([1, 2, 3, 4, 5, 6]), [[1, 2], [3, 4], [5, 6]])
+      assert.deepStrictEqual(chunksOf(2)([1, 2, 3, 4, 5, 6]), [
+        [1, 2],
+        [3, 4],
+        [5, 6]
+      ])
       assert.deepStrictEqual(chunksOf(5)([1, 2, 3, 4, 5]), [[1, 2, 3, 4, 5]])
       assert.deepStrictEqual(chunksOf(6)([1, 2, 3, 4, 5]), [[1, 2, 3, 4, 5]])
       assert.deepStrictEqual(chunksOf(1)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]])
@@ -667,33 +729,64 @@ describe('Array', () => {
   })
 
   it('comprehension', () => {
-    assert.deepStrictEqual(comprehension([[1, 2, 3]], a => a * 2), [2, 4, 6])
-    assert.deepStrictEqual(comprehension([[1, 2, 3], ['a', 'b']], tuple), [
-      [1, 'a'],
-      [1, 'b'],
-      [2, 'a'],
-      [2, 'b'],
-      [3, 'a'],
-      [3, 'b']
-    ])
-    assert.deepStrictEqual(comprehension([[1, 2, 3], ['a', 'b']], tuple, (a, b) => (a + b.length) % 2 === 0), [
-      [1, 'a'],
-      [1, 'b'],
-      [3, 'a'],
-      [3, 'b']
-    ])
+    assert.deepStrictEqual(
+      comprehension([[1, 2, 3]], a => a * 2),
+      [2, 4, 6]
+    )
+    assert.deepStrictEqual(
+      comprehension(
+        [
+          [1, 2, 3],
+          ['a', 'b']
+        ],
+        tuple
+      ),
+      [
+        [1, 'a'],
+        [1, 'b'],
+        [2, 'a'],
+        [2, 'b'],
+        [3, 'a'],
+        [3, 'b']
+      ]
+    )
+    assert.deepStrictEqual(
+      comprehension(
+        [
+          [1, 2, 3],
+          ['a', 'b']
+        ],
+        tuple,
+        (a, b) => (a + b.length) % 2 === 0
+      ),
+      [
+        [1, 'a'],
+        [1, 'b'],
+        [3, 'a'],
+        [3, 'b']
+      ]
+    )
   })
 
   it('reduceWithIndex', () => {
-    assert.deepStrictEqual(array.reduceWithIndex(['a', 'b'], '', (i, b, a) => b + i + a), '0a1b')
+    assert.deepStrictEqual(
+      array.reduceWithIndex(['a', 'b'], '', (i, b, a) => b + i + a),
+      '0a1b'
+    )
   })
 
   it('foldMapWithIndex', () => {
-    assert.deepStrictEqual(array.foldMapWithIndex(monoidString)(['a', 'b'], (i, a) => i + a), '0a1b')
+    assert.deepStrictEqual(
+      array.foldMapWithIndex(monoidString)(['a', 'b'], (i, a) => i + a),
+      '0a1b'
+    )
   })
 
   it('reduceRightWithIndex', () => {
-    assert.deepStrictEqual(array.reduceRightWithIndex(['a', 'b'], '', (i, a, b) => b + i + a), '1b0a')
+    assert.deepStrictEqual(
+      array.reduceRightWithIndex(['a', 'b'], '', (i, a, b) => b + i + a),
+      '1b0a'
+    )
   })
 
   it('traverseWithIndex', () => {
diff --git a/test/Compactable.ts b/test/Compactable.ts
index 8a9136a1..3f016884 100644
--- a/test/Compactable.ts
+++ b/test/Compactable.ts
@@ -7,10 +7,22 @@ import { left, right } from '../src/Either'
 describe('Compactable', () => {
   it('getCompactableComposition', () => {
     const C = getCompactableComposition(array, array)
-    assert.deepStrictEqual(C.compact([[some(1), none], [none, some(2)]]), [[1], [2]])
-    assert.deepStrictEqual(C.separate([[left('a'), right(1)], [right(2), left('b')]]), {
-      left: [['a'], ['b']],
-      right: [[1], [2]]
-    })
+    assert.deepStrictEqual(
+      C.compact([
+        [some(1), none],
+        [none, some(2)]
+      ]),
+      [[1], [2]]
+    )
+    assert.deepStrictEqual(
+      C.separate([
+        [left('a'), right(1)],
+        [right(2), left('b')]
+      ]),
+      {
+        left: [['a'], ['b']],
+        right: [[1], [2]]
+      }
+    )
   })
 })
diff --git a/test/Either.ts b/test/Either.ts
index 8135d66c..7c259bd8 100644
--- a/test/Either.ts
+++ b/test/Either.ts
@@ -83,27 +83,9 @@ describe('Either', () => {
     const isColor = (s: string): s is Color => s === 'red' || s === 'blue'
     const errorHandler = (s: string) => `invalid color ${s}`
 
-    assert.deepStrictEqual(
-      pipe(
-        _.right('red'),
-        _.filterOrElse(isColor, errorHandler)
-      ),
-      _.right('red')
-    )
-    assert.deepStrictEqual(
-      pipe(
-        _.right('foo'),
-        _.filterOrElse(isColor, errorHandler)
-      ),
-      _.left('invalid color foo')
-    )
-    assert.deepStrictEqual(
-      pipe(
-        _.left('err'),
-        _.filterOrElse(isColor, errorHandler)
-      ),
-      _.left('err')
-    )
+    assert.deepStrictEqual(pipe(_.right('red'), _.filterOrElse(isColor, errorHandler)), _.right('red'))
+    assert.deepStrictEqual(pipe(_.right('foo'), _.filterOrElse(isColor, errorHandler)), _.left('invalid color foo'))
+    assert.deepStrictEqual(pipe(_.left('err'), _.filterOrElse(isColor, errorHandler)), _.left('err'))
   })
 
   it('isLeft', () => {
@@ -148,10 +130,22 @@ describe('Either', () => {
   })
 
   it('alt', () => {
-    assert.deepStrictEqual(_.either.alt(_.right(1), () => _.right(2)), _.right(1))
-    assert.deepStrictEqual(_.either.alt(_.right(1), () => _.left('a')), _.right(1))
-    assert.deepStrictEqual(_.either.alt(_.left('a'), () => _.right(2)), _.right(2))
-    assert.deepStrictEqual(_.either.alt(_.left('a'), () => _.left('b')), _.left('b'))
+    assert.deepStrictEqual(
+      _.either.alt(_.right(1), () => _.right(2)),
+      _.right(1)
+    )
+    assert.deepStrictEqual(
+      _.either.alt(_.right(1), () => _.left('a')),
+      _.right(1)
+    )
+    assert.deepStrictEqual(
+      _.either.alt(_.left('a'), () => _.right(2)),
+      _.right(2)
+    )
+    assert.deepStrictEqual(
+      _.either.alt(_.left('a'), () => _.left('b')),
+      _.left('b')
+    )
   })
 
   it('swap', () => {
@@ -224,7 +218,10 @@ describe('Either', () => {
 
   describe('lifting functions', () => {
     it('fromPredicate', () => {
-      const gt2 = _.fromPredicate((n: number) => n >= 2, n => `Invalid number ${n}`)
+      const gt2 = _.fromPredicate(
+        (n: number) => n >= 2,
+        n => `Invalid number ${n}`
+      )
       assert.deepStrictEqual(gt2(3), _.right(3))
       assert.deepStrictEqual(gt2(1), _.left('Invalid number 1'))
 
@@ -278,8 +275,14 @@ describe('Either', () => {
         _.either.traverse(option)(_.left('foo'), a => (a >= 2 ? some(a) : none)),
         some(_.left('foo'))
       )
-      assert.deepStrictEqual(_.either.traverse(option)(_.right(1), a => (a >= 2 ? some(a) : none)), none)
-      assert.deepStrictEqual(_.either.traverse(option)(_.right(3), a => (a >= 2 ? some(a) : none)), some(_.right(3)))
+      assert.deepStrictEqual(
+        _.either.traverse(option)(_.right(1), a => (a >= 2 ? some(a) : none)),
+        none
+      )
+      assert.deepStrictEqual(
+        _.either.traverse(option)(_.right(3), a => (a >= 2 ? some(a) : none)),
+        some(_.right(3))
+      )
     })
 
     it('sequence', () => {
@@ -293,8 +296,14 @@ describe('Either', () => {
   describe('ChainRec', () => {
     it('chainRec', () => {
       const chainRec = _.either.chainRec
-      assert.deepStrictEqual(chainRec(1, () => _.left('foo')), _.left('foo'))
-      assert.deepStrictEqual(chainRec(1, () => _.right(_.right(1))), _.right(1))
+      assert.deepStrictEqual(
+        chainRec(1, () => _.left('foo')),
+        _.left('foo')
+      )
+      assert.deepStrictEqual(
+        chainRec(1, () => _.right(_.right(1))),
+        _.right(1)
+      )
       assert.deepStrictEqual(
         chainRec(1, a => {
           if (a < 5) {
@@ -310,15 +319,27 @@ describe('Either', () => {
 
   describe('Extend', () => {
     it('extend', () => {
-      assert.deepStrictEqual(_.either.extend(_.right(1), () => 2), _.right(2))
-      assert.deepStrictEqual(_.either.extend(_.left('err'), () => 2), _.left('err'))
+      assert.deepStrictEqual(
+        _.either.extend(_.right(1), () => 2),
+        _.right(2)
+      )
+      assert.deepStrictEqual(
+        _.either.extend(_.left('err'), () => 2),
+        _.left('err')
+      )
     })
   })
 
   describe('Foldable', () => {
     it('reduce', () => {
-      assert.deepStrictEqual(_.either.reduce(_.right('bar'), 'foo', (b, a) => b + a), 'foobar')
-      assert.deepStrictEqual(_.either.reduce(_.left('bar'), 'foo', (b, a) => b + a), 'foo')
+      assert.deepStrictEqual(
+        _.either.reduce(_.right('bar'), 'foo', (b, a) => b + a),
+        'foobar'
+      )
+      assert.deepStrictEqual(
+        _.either.reduce(_.left('bar'), 'foo', (b, a) => b + a),
+        'foo'
+      )
     })
 
     it('foldMap', () => {
@@ -481,16 +502,28 @@ describe('Either', () => {
       const f = (s: string) => _.right(s.length)
       assert.deepStrictEqual(M.chain(_.right('abc'), f), _.right(3))
       assert.deepStrictEqual(M.chain(_.left('a'), f), _.left('a'))
-      assert.deepStrictEqual(M.chain(_.left('a'), () => _.left('b')), _.left('a'))
+      assert.deepStrictEqual(
+        M.chain(_.left('a'), () => _.left('b')),
+        _.left('a')
+      )
       assert.deepStrictEqual(M.of(1), _.right(1))
       const double = (n: number) => n * 2
       assert.deepStrictEqual(M.ap(_.right(double), _.right(1)), _.right(2))
       assert.deepStrictEqual(M.ap(_.right(double), _.left('foo')), _.left('foo'))
       assert.deepStrictEqual(M.ap(_.left<string, (n: number) => number>('foo'), _.right(1)), _.left('foo'))
       assert.deepStrictEqual(M.ap(_.left('foo'), _.left('bar')), _.left('foobar'))
-      assert.deepStrictEqual(M.alt(_.left('a'), () => _.right(1)), _.right(1))
-      assert.deepStrictEqual(M.alt(_.right(1), () => _.left('a')), _.right(1))
-      assert.deepStrictEqual(M.alt(_.left('a'), () => _.left('b')), _.left('ab'))
+      assert.deepStrictEqual(
+        M.alt(_.left('a'), () => _.right(1)),
+        _.right(1)
+      )
+      assert.deepStrictEqual(
+        M.alt(_.right(1), () => _.left('a')),
+        _.right(1)
+      )
+      assert.deepStrictEqual(
+        M.alt(_.left('a'), () => _.left('b')),
+        _.left('ab')
+      )
     })
 
     it('getValidationMonoid', () => {
diff --git a/test/Filterable.ts b/test/Filterable.ts
index e3b8160d..0835a87e 100644
--- a/test/Filterable.ts
+++ b/test/Filterable.ts
@@ -7,20 +7,50 @@ import { right, left } from '../src/Either'
 describe('Filterable', () => {
   it('getFilterableComposition', () => {
     const F = getFilterableComposition(array, array)
-    assert.deepStrictEqual(F.filter([[1, 2], [3, 4]], a => a > 1), [[2], [3, 4]])
+    assert.deepStrictEqual(
+      F.filter(
+        [
+          [1, 2],
+          [3, 4]
+        ],
+        a => a > 1
+      ),
+      [[2], [3, 4]]
+    )
 
-    assert.deepStrictEqual(F.filterMap([['a', 'bb'], ['ccc', 'dddd']], a => (a.length > 1 ? some(a.length) : none)), [
-      [2],
-      [3, 4]
-    ])
+    assert.deepStrictEqual(
+      F.filterMap(
+        [
+          ['a', 'bb'],
+          ['ccc', 'dddd']
+        ],
+        a => (a.length > 1 ? some(a.length) : none)
+      ),
+      [[2], [3, 4]]
+    )
 
-    assert.deepStrictEqual(F.partition([['a', 'bb'], ['ccc', 'dddd']], a => a.length % 2 === 0), {
-      left: [['a'], ['ccc']],
-      right: [['bb'], ['dddd']]
-    })
+    assert.deepStrictEqual(
+      F.partition(
+        [
+          ['a', 'bb'],
+          ['ccc', 'dddd']
+        ],
+        a => a.length % 2 === 0
+      ),
+      {
+        left: [['a'], ['ccc']],
+        right: [['bb'], ['dddd']]
+      }
+    )
 
     assert.deepStrictEqual(
-      F.partitionMap([['a', 'bb'], ['ccc', 'dddd']], a => (a.length % 2 === 0 ? right(a.length) : left(a))),
+      F.partitionMap(
+        [
+          ['a', 'bb'],
+          ['ccc', 'dddd']
+        ],
+        a => (a.length % 2 === 0 ? right(a.length) : left(a))
+      ),
       {
         left: [['a'], ['ccc']],
         right: [[2], [4]]
diff --git a/test/Foldable.ts b/test/Foldable.ts
index 78602aa1..cecdb20e 100644
--- a/test/Foldable.ts
+++ b/test/Foldable.ts
@@ -18,10 +18,22 @@ describe('Foldable', () => {
     assert.strictEqual(F.reduce([option.none, option.none, option.none], '', monoidString.concat), '')
     assert.strictEqual(F.reduce([], '', monoidString.concat), '')
     // foldMap
-    assert.strictEqual(F.foldMap(monoidString)([option.some('a'), option.some('b'), option.some('c')], a => a), 'abc')
-    assert.strictEqual(F.foldMap(monoidString)([option.none, option.some('b'), option.none], a => a), 'b')
-    assert.strictEqual(F.foldMap(monoidString)([option.none, option.none, option.none], a => a), '')
-    assert.strictEqual(F.foldMap(monoidString)([], (a: string) => a), '')
+    assert.strictEqual(
+      F.foldMap(monoidString)([option.some('a'), option.some('b'), option.some('c')], a => a),
+      'abc'
+    )
+    assert.strictEqual(
+      F.foldMap(monoidString)([option.none, option.some('b'), option.none], a => a),
+      'b'
+    )
+    assert.strictEqual(
+      F.foldMap(monoidString)([option.none, option.none, option.none], a => a),
+      ''
+    )
+    assert.strictEqual(
+      F.foldMap(monoidString)([], (a: string) => a),
+      ''
+    )
     // reduceRight
     assert.strictEqual(
       F.reduceRight([option.some('a'), option.some('b'), option.some('c')], '', monoidString.concat),
@@ -44,8 +56,17 @@ describe('Foldable', () => {
   })
 
   it('foldM', () => {
-    assert.deepStrictEqual(foldM(option.option, array)([], 1, () => option.none), option.some(1))
-    assert.deepStrictEqual(foldM(option.option, array)([2], 1, () => option.none), option.none)
-    assert.deepStrictEqual(foldM(option.option, array)([2], 1, (b, a) => option.some(b + a)), option.some(3))
+    assert.deepStrictEqual(
+      foldM(option.option, array)([], 1, () => option.none),
+      option.some(1)
+    )
+    assert.deepStrictEqual(
+      foldM(option.option, array)([2], 1, () => option.none),
+      option.none
+    )
+    assert.deepStrictEqual(
+      foldM(option.option, array)([2], 1, (b, a) => option.some(b + a)),
+      option.some(3)
+    )
   })
 })
diff --git a/test/FoldableWithIndex.ts b/test/FoldableWithIndex.ts
index 2daa51a3..07df7888 100644
--- a/test/FoldableWithIndex.ts
+++ b/test/FoldableWithIndex.ts
@@ -6,14 +6,20 @@ import { monoidString } from '../src/Monoid'
 describe('FoldableWithIndex', () => {
   it('getFoldableWithIndexComposition', () => {
     const arrayOfArray = getFoldableWithIndexComposition(array, array)
-    const fa = [['a', 'b'], ['c', 'd']]
+    const fa = [
+      ['a', 'b'],
+      ['c', 'd']
+    ]
 
     assert.deepStrictEqual(
       arrayOfArray.reduceWithIndex(fa, '', ([i, j]: [number, number], b: string, a: string) => b + a + i + j),
       'a00b01c10d11'
     )
 
-    assert.deepStrictEqual(arrayOfArray.foldMapWithIndex(monoidString)(fa, ([i, j], a) => a + i + j), 'a00b01c10d11')
+    assert.deepStrictEqual(
+      arrayOfArray.foldMapWithIndex(monoidString)(fa, ([i, j], a) => a + i + j),
+      'a00b01c10d11'
+    )
 
     assert.deepStrictEqual(
       arrayOfArray.reduceRightWithIndex(fa, '', ([i, j]: [number, number], a: string, b: string) => b + a + i + j),
diff --git a/test/FunctorWithIndex.ts b/test/FunctorWithIndex.ts
index a4db68e2..947fc247 100644
--- a/test/FunctorWithIndex.ts
+++ b/test/FunctorWithIndex.ts
@@ -6,6 +6,18 @@ describe('FunctorWithIndex', () => {
   it('getFunctorComposition', () => {
     const arrayOfArray = getFunctorWithIndexComposition(array, array)
     const f = ([i, j]: [number, number], a: string) => a + i + j
-    assert.deepStrictEqual(arrayOfArray.mapWithIndex([['a', 'b'], ['c', 'd']], f), [['a00', 'b01'], ['c10', 'd11']])
+    assert.deepStrictEqual(
+      arrayOfArray.mapWithIndex(
+        [
+          ['a', 'b'],
+          ['c', 'd']
+        ],
+        f
+      ),
+      [
+        ['a00', 'b01'],
+        ['c10', 'd11']
+      ]
+    )
   })
 })
diff --git a/test/IO.ts b/test/IO.ts
index e0dfb260..e2ff3436 100644
--- a/test/IO.ts
+++ b/test/IO.ts
@@ -2,6 +2,7 @@ import * as assert from 'assert'
 import { IO, getSemigroup, io, getMonoid } from '../src/IO'
 import { semigroupSum } from '../src/Semigroup'
 import { monoidSum } from '../src/Monoid'
+import * as E from '../src/Either'
 
 describe('IO', () => {
   it('ap', () => {
@@ -32,4 +33,9 @@ describe('IO', () => {
     assert.strictEqual(M.concat(M.empty, append('b'))(), 2)
     assert.deepStrictEqual(log, ['a', 'b'])
   })
+
+  it('chainRec', () => {
+    const f = (n: number) => (n < 15000 ? io.of(E.left(n + 1)) : io.of(E.right('ok ' + n)))
+    assert.strictEqual(io.chainRec(0, f)(), 'ok 15000')
+  })
 })
diff --git a/test/IOEither.ts b/test/IOEither.ts
index 5dab9e3e..433c62ef 100644
--- a/test/IOEither.ts
+++ b/test/IOEither.ts
@@ -10,8 +10,20 @@ import { getMonoid } from '../src/Array'
 
 describe('IOEither', () => {
   it('fold', () => {
-    assert.deepStrictEqual(_.fold(() => io.of('left'), () => io.of('right'))(_.ioEither.of(1))(), 'right')
-    assert.deepStrictEqual(_.fold(() => io.of('left'), () => io.of('right'))(_.left(1))(), 'left')
+    assert.deepStrictEqual(
+      _.fold(
+        () => io.of('left'),
+        () => io.of('right')
+      )(_.ioEither.of(1))(),
+      'right'
+    )
+    assert.deepStrictEqual(
+      _.fold(
+        () => io.of('left'),
+        () => io.of('right')
+      )(_.left(1))(),
+      'left'
+    )
   })
 
   it('getOrElse', () => {
@@ -39,28 +51,40 @@ describe('IOEither', () => {
     assert.deepStrictEqual(
       pipe(
         _.right(12),
-        _.filterOrElse(n => n > 10, () => 'bar')
+        _.filterOrElse(
+          n => n > 10,
+          () => 'bar'
+        )
       )(),
       E.right(12)
     )
     assert.deepStrictEqual(
       pipe(
         _.right(7),
-        _.filterOrElse(n => n > 10, () => 'bar')
+        _.filterOrElse(
+          n => n > 10,
+          () => 'bar'
+        )
       )(),
       E.left('bar')
     )
     assert.deepStrictEqual(
       pipe(
         _.left('foo'),
-        _.filterOrElse(n => n > 10, () => 'bar')
+        _.filterOrElse(
+          n => n > 10,
+          () => 'bar'
+        )
       )(),
       E.left('foo')
     )
     assert.deepStrictEqual(
       pipe(
         _.right(7),
-        _.filterOrElse(n => n > 10, n => `invalid ${n}`)
+        _.filterOrElse(
+          n => n > 10,
+          n => `invalid ${n}`
+        )
       )(),
       E.left('invalid 7')
     )
@@ -79,7 +103,10 @@ describe('IOEither', () => {
   })
 
   it('fromPredicate', () => {
-    const gt2 = _.fromPredicate((n: number) => n >= 2, n => `Invalid number ${n}`)
+    const gt2 = _.fromPredicate(
+      (n: number) => n >= 2,
+      n => `Invalid number ${n}`
+    )
     assert.deepStrictEqual(gt2(3)(), E.right(3))
     assert.deepStrictEqual(gt2(1)(), E.left('Invalid number 1'))
 
diff --git a/test/Identity.ts b/test/Identity.ts
index a140130c..637671e4 100644
--- a/test/Identity.ts
+++ b/test/Identity.ts
@@ -33,7 +33,10 @@ describe('Identity', () => {
   it('reduce', () => {
     const x = I.identity.of('b')
     const expected = 'ab'
-    assert.deepStrictEqual(I.identity.reduce(x, 'a', (b, a) => b + a), expected)
+    assert.deepStrictEqual(
+      I.identity.reduce(x, 'a', (b, a) => b + a),
+      expected
+    )
   })
 
   it('foldMap', () => {
@@ -54,7 +57,10 @@ describe('Identity', () => {
   it('alt', () => {
     const x = I.identity.of(1)
     const y = I.identity.of(2)
-    assert.strictEqual(I.identity.alt(x, () => y), x)
+    assert.strictEqual(
+      I.identity.alt(x, () => y),
+      x
+    )
   })
 
   it('extract', () => {
diff --git a/test/Map.ts b/test/Map.ts
index 6dd5314f..bfc07fa7 100644
--- a/test/Map.ts
+++ b/test/Map.ts
@@ -39,7 +39,10 @@ const semigroupValue = getStructSemigroup({ value: semigroupSum })
 
 const key1 = { id: 1 }
 const value1 = { value: 1 }
-const repo = new Map<Key, Value>([[key1, value1], [{ id: 2 }, { value: 2 }]])
+const repo = new Map<Key, Value>([
+  [key1, value1],
+  [{ id: 2 }, { value: 2 }]
+])
 
 describe('Map', () => {
   it('URI', () => {
@@ -69,7 +72,10 @@ describe('Map', () => {
   })
 
   it('member', () => {
-    const a1b2 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
+    const a1b2 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
     const memberS = M.member(eqUser)
     assert.deepStrictEqual(memberS({ id: 'a' }, a1b2), true)
     assert.deepStrictEqual(memberS({ id: 'c' }, a1b2), false)
@@ -82,7 +88,10 @@ describe('Map', () => {
   })
 
   it('elem', () => {
-    const a1b2 = new Map<string, number>([['a', 1], ['b', 2]])
+    const a1b2 = new Map<string, number>([
+      ['a', 1],
+      ['b', 2]
+    ])
     const elemS = M.elem(eqNumber)
     assert.deepStrictEqual(elemS(2, a1b2), true)
     assert.deepStrictEqual(elemS(3, a1b2), false)
@@ -95,25 +104,53 @@ describe('Map', () => {
   })
 
   it('keys', () => {
-    const m = new Map<User, number>([[{ id: 'b' }, 2], [{ id: 'a' }, 1]])
+    const m = new Map<User, number>([
+      [{ id: 'b' }, 2],
+      [{ id: 'a' }, 1]
+    ])
     const ks = M.keys(ordUser)(m)
     assert.deepStrictEqual(ks, Array.from(m.keys()).sort(ordUser.compare))
     assert.deepStrictEqual(ks, [{ id: 'a' }, { id: 'b' }])
 
-    assert.deepStrictEqual(M.keys(ordString)(new Map([['a', 1], ['b', 2]])), ['a', 'b'])
-    assert.deepStrictEqual(M.keys(ordString)(new Map([['b', 2], ['a', 1]])), ['a', 'b'])
+    assert.deepStrictEqual(
+      M.keys(ordString)(
+        new Map([
+          ['a', 1],
+          ['b', 2]
+        ])
+      ),
+      ['a', 'b']
+    )
+    assert.deepStrictEqual(
+      M.keys(ordString)(
+        new Map([
+          ['b', 2],
+          ['a', 1]
+        ])
+      ),
+      ['a', 'b']
+    )
   })
 
   it('values', () => {
-    const m = new Map<number, User>([[2, { id: 'b' }], [1, { id: 'a' }]])
+    const m = new Map<number, User>([
+      [2, { id: 'b' }],
+      [1, { id: 'a' }]
+    ])
     const vals = M.values(ordUser)(m)
     assert.deepStrictEqual(vals, Array.from(m.values()).sort(ordUser.compare))
     assert.deepStrictEqual(vals, [{ id: 'a' }, { id: 'b' }])
   })
 
   it('collect', () => {
-    const m1 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
-    const m2 = new Map<User, number>([[{ id: 'b' }, 2], [{ id: 'a' }, 1]])
+    const m1 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
+    const m2 = new Map<User, number>([
+      [{ id: 'b' }, 2],
+      [{ id: 'a' }, 1]
+    ])
     const collectO = M.collect(ordUser)
     const f = (_k: User, a: number): number => a + 1
     assert.deepStrictEqual(collectO(f)(m1), [2, 3])
@@ -121,36 +158,124 @@ describe('Map', () => {
 
     const collect = M.collect(ordKey)
     const g = (k: Key, a: Value): [number, number] => [k.id, a.value]
-    assert.deepStrictEqual(collect(g)(new Map([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }]])), [
-      [1, 1],
-      [2, 2]
-    ])
-    assert.deepStrictEqual(collect(g)(new Map([[{ id: 2 }, { value: 2 }], [{ id: 1 }, { value: 1 }]])), [
-      [1, 1],
-      [2, 2]
-    ])
-    assert.deepStrictEqual(collect(g)(new Map([[{ id: 4 }, { value: 1 }], [{ id: 2 }, { value: 2 }]])), [
-      [4, 1],
-      [2, 2]
-    ])
-    assert.deepStrictEqual(collect(g)(new Map([[{ id: 2 }, { value: 2 }], [{ id: 4 }, { value: 1 }]])), [
-      [4, 1],
-      [2, 2]
-    ])
+    assert.deepStrictEqual(
+      collect(g)(
+        new Map([
+          [{ id: 1 }, { value: 1 }],
+          [{ id: 2 }, { value: 2 }]
+        ])
+      ),
+      [
+        [1, 1],
+        [2, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      collect(g)(
+        new Map([
+          [{ id: 2 }, { value: 2 }],
+          [{ id: 1 }, { value: 1 }]
+        ])
+      ),
+      [
+        [1, 1],
+        [2, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      collect(g)(
+        new Map([
+          [{ id: 4 }, { value: 1 }],
+          [{ id: 2 }, { value: 2 }]
+        ])
+      ),
+      [
+        [4, 1],
+        [2, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      collect(g)(
+        new Map([
+          [{ id: 2 }, { value: 2 }],
+          [{ id: 4 }, { value: 1 }]
+        ])
+      ),
+      [
+        [4, 1],
+        [2, 2]
+      ]
+    )
   })
 
   it('toArray', () => {
-    const m1 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
-    const m2 = new Map<User, number>([[{ id: 'b' }, 2], [{ id: 'a' }, 1]])
+    const m1 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
+    const m2 = new Map<User, number>([
+      [{ id: 'b' }, 2],
+      [{ id: 'a' }, 1]
+    ])
     const toArrayO = M.toArray(ordUser)
-    assert.deepStrictEqual(toArrayO(m1), [[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
-    assert.deepStrictEqual(toArrayO(m2), [[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
+    assert.deepStrictEqual(toArrayO(m1), [
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
+    assert.deepStrictEqual(toArrayO(m2), [
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
 
     const toArray = M.toArray(ordKey)
-    assert.deepStrictEqual(toArray(new Map([[{ id: 1 }, 1], [{ id: 2 }, 2]])), [[{ id: 1 }, 1], [{ id: 2 }, 2]])
-    assert.deepStrictEqual(toArray(new Map([[{ id: 2 }, 2], [{ id: 1 }, 1]])), [[{ id: 1 }, 1], [{ id: 2 }, 2]])
-    assert.deepStrictEqual(toArray(new Map([[{ id: 4 }, 1], [{ id: 2 }, 2]])), [[{ id: 4 }, 1], [{ id: 2 }, 2]])
-    assert.deepStrictEqual(toArray(new Map([[{ id: 2 }, 2], [{ id: 4 }, 1]])), [[{ id: 4 }, 1], [{ id: 2 }, 2]])
+    assert.deepStrictEqual(
+      toArray(
+        new Map([
+          [{ id: 1 }, 1],
+          [{ id: 2 }, 2]
+        ])
+      ),
+      [
+        [{ id: 1 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      toArray(
+        new Map([
+          [{ id: 2 }, 2],
+          [{ id: 1 }, 1]
+        ])
+      ),
+      [
+        [{ id: 1 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      toArray(
+        new Map([
+          [{ id: 4 }, 1],
+          [{ id: 2 }, 2]
+        ])
+      ),
+      [
+        [{ id: 4 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      toArray(
+        new Map([
+          [{ id: 2 }, 2],
+          [{ id: 4 }, 1]
+        ])
+      ),
+      [
+        [{ id: 4 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
   })
 
   it('toUnfoldable', () => {
@@ -159,18 +284,72 @@ describe('Map', () => {
     assert.deepStrictEqual(toUnfoldableO(a1), [[{ id: 'a' }, 1]])
 
     const toUnfoldable = M.toUnfoldable(ordKey, array)
-    assert.deepStrictEqual(toUnfoldable(new Map([[{ id: 1 }, 1], [{ id: 2 }, 2]])), [[{ id: 1 }, 1], [{ id: 2 }, 2]])
-    assert.deepStrictEqual(toUnfoldable(new Map([[{ id: 2 }, 2], [{ id: 1 }, 1]])), [[{ id: 1 }, 1], [{ id: 2 }, 2]])
-    assert.deepStrictEqual(toUnfoldable(new Map([[{ id: 4 }, 1], [{ id: 2 }, 2]])), [[{ id: 4 }, 1], [{ id: 2 }, 2]])
-    assert.deepStrictEqual(toUnfoldable(new Map([[{ id: 2 }, 2], [{ id: 4 }, 1]])), [[{ id: 4 }, 1], [{ id: 2 }, 2]])
+    assert.deepStrictEqual(
+      toUnfoldable(
+        new Map([
+          [{ id: 1 }, 1],
+          [{ id: 2 }, 2]
+        ])
+      ),
+      [
+        [{ id: 1 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      toUnfoldable(
+        new Map([
+          [{ id: 2 }, 2],
+          [{ id: 1 }, 1]
+        ])
+      ),
+      [
+        [{ id: 1 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      toUnfoldable(
+        new Map([
+          [{ id: 4 }, 1],
+          [{ id: 2 }, 2]
+        ])
+      ),
+      [
+        [{ id: 4 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
+    assert.deepStrictEqual(
+      toUnfoldable(
+        new Map([
+          [{ id: 2 }, 2],
+          [{ id: 4 }, 1]
+        ])
+      ),
+      [
+        [{ id: 4 }, 1],
+        [{ id: 2 }, 2]
+      ]
+    )
   })
 
   it('insertAt', () => {
     const emptyMap = new Map<User, number>()
     const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
-    const a1b2 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
-    const a2b2 = new Map<User, number>([[{ id: 'a' }, 2], [{ id: 'b' }, 2]])
-    const a1b2c3 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2], [{ id: 'c' }, 3]])
+    const a1b2 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
+    const a2b2 = new Map<User, number>([
+      [{ id: 'a' }, 2],
+      [{ id: 'b' }, 2]
+    ])
+    const a1b2c3 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2],
+      [{ id: 'c' }, 3]
+    ])
     const insertS = M.insertAt(eqUser)
     assert.deepStrictEqual(insertS({ id: 'a' }, 1)(emptyMap), a1)
     assert.deepStrictEqual(insertS({ id: 'a' }, 1)(a1b2), a1b2)
@@ -180,27 +359,55 @@ describe('Map', () => {
     const insert = M.insertAt(eqKey)
     assert.deepStrictEqual(insert({ id: 1 }, { value: 1 })(M.empty), new Map([[{ id: 1 }, { value: 1 }]]))
     const x = insert({ id: 1 }, value1)(repo)
-    assert.deepStrictEqual(x, new Map<Key, Value>([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }]]))
+    assert.deepStrictEqual(
+      x,
+      new Map<Key, Value>([
+        [{ id: 1 }, { value: 1 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
+    )
     assert.strictEqual(x.get(key1), value1)
     assert.deepStrictEqual(
       insert({ id: 1 }, { value: 2 })(repo),
-      new Map<Key, Value>([[{ id: 1 }, { value: 2 }], [{ id: 2 }, { value: 2 }]])
+      new Map<Key, Value>([
+        [{ id: 1 }, { value: 2 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
     )
     assert.deepStrictEqual(
       insert({ id: 4 }, { value: 2 })(repo),
-      new Map<Key, Value>([[{ id: 1 }, { value: 2 }], [{ id: 2 }, { value: 2 }]])
+      new Map<Key, Value>([
+        [{ id: 1 }, { value: 2 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
     )
     assert.deepStrictEqual(
       insert({ id: 3 }, { value: 3 })(repo),
-      new Map<Key, Value>([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }], [{ id: 3 }, { value: 3 }]])
+      new Map<Key, Value>([
+        [{ id: 1 }, { value: 1 }],
+        [{ id: 2 }, { value: 2 }],
+        [{ id: 3 }, { value: 3 }]
+      ])
     )
     // should not modify the source
-    assert.deepStrictEqual(repo, new Map([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }]]))
+    assert.deepStrictEqual(
+      repo,
+      new Map([
+        [{ id: 1 }, { value: 1 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
+    )
   })
 
   it('deleteAt', () => {
-    const a1b2 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
-    const a1b2_ = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
+    const a1b2 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
+    const a1b2_ = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
     const b2 = new Map<User, number>([[{ id: 'b' }, 2]])
     const removeS = M.deleteAt(eqUser)
     assert.deepStrictEqual(removeS({ id: 'a' })(a1b2), b2)
@@ -212,11 +419,20 @@ describe('Map', () => {
     assert.deepStrictEqual(remove({ id: 4 })(repo), new Map([[{ id: 2 }, { value: 2 }]]))
     assert.deepStrictEqual(remove({ id: 3 })(repo), repo)
     // should not modify the source
-    assert.deepStrictEqual(repo, new Map([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }]]))
+    assert.deepStrictEqual(
+      repo,
+      new Map([
+        [{ id: 1 }, { value: 1 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
+    )
   })
 
   it('pop', () => {
-    const a1b2 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
+    const a1b2 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
     const b2 = new Map<User, number>([[{ id: 'b' }, 2]])
     const popS = M.pop(eqUser)
     assert.deepStrictEqual(popS({ id: 'a' })(a1b2), some([1, b2]))
@@ -227,7 +443,13 @@ describe('Map', () => {
     assert.deepStrictEqual(pop({ id: 4 })(repo), some([{ value: 1 }, new Map([[{ id: 2 }, { value: 2 }]])]))
     assert.deepStrictEqual(pop({ id: 3 })(repo), none)
     // should not modify the source
-    assert.deepStrictEqual(repo, new Map([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }]]))
+    assert.deepStrictEqual(
+      repo,
+      new Map([
+        [{ id: 1 }, { value: 1 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
+    )
   })
 
   it('lookupWithKey', () => {
@@ -256,7 +478,10 @@ describe('Map', () => {
 
   it('isSubmap', () => {
     const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
-    const a1b2 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 2]])
+    const a1b2 = new Map<User, number>([
+      [{ id: 'a' }, 1],
+      [{ id: 'b' }, 2]
+    ])
     const isSubmapS = M.isSubmap(eqUser, eqNumber)
     assert.strictEqual(isSubmapS(a1, a1b2), true)
 
@@ -274,7 +499,10 @@ describe('Map', () => {
   })
 
   it('singleton', () => {
-    assert.deepStrictEqual(M.singleton('k1', 0), new Map<string, number>([['k1', 0]]))
+    assert.deepStrictEqual(
+      M.singleton('k1', 0),
+      new Map<string, number>([['k1', 0]])
+    )
   })
 
   it('getEq', () => {
@@ -293,17 +521,72 @@ describe('Map', () => {
 
     const equals = M.getEq(eqKey, eqValue).equals
     assert.strictEqual(equals(repo, repo), true)
-    assert.strictEqual(equals(new Map([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }]]), repo), true)
-    assert.strictEqual(equals(new Map([[{ id: 1 }, { value: 2 }], [{ id: 2 }, { value: 2 }]]), repo), false)
-    assert.strictEqual(equals(new Map([[{ id: 1 }, { value: 4 }], [{ id: 2 }, { value: 2 }]]), repo), true)
-    assert.strictEqual(equals(new Map([[{ id: 4 }, { value: 1 }], [{ id: 2 }, { value: 2 }]]), repo), true)
-    assert.strictEqual(equals(new Map([[{ id: 3 }, { value: 3 }], [{ id: 2 }, { value: 2 }]]), repo), false)
+    assert.strictEqual(
+      equals(
+        new Map([
+          [{ id: 1 }, { value: 1 }],
+          [{ id: 2 }, { value: 2 }]
+        ]),
+        repo
+      ),
+      true
+    )
+    assert.strictEqual(
+      equals(
+        new Map([
+          [{ id: 1 }, { value: 2 }],
+          [{ id: 2 }, { value: 2 }]
+        ]),
+        repo
+      ),
+      false
+    )
+    assert.strictEqual(
+      equals(
+        new Map([
+          [{ id: 1 }, { value: 4 }],
+          [{ id: 2 }, { value: 2 }]
+        ]),
+        repo
+      ),
+      true
+    )
+    assert.strictEqual(
+      equals(
+        new Map([
+          [{ id: 4 }, { value: 1 }],
+          [{ id: 2 }, { value: 2 }]
+        ]),
+        repo
+      ),
+      true
+    )
+    assert.strictEqual(
+      equals(
+        new Map([
+          [{ id: 3 }, { value: 3 }],
+          [{ id: 2 }, { value: 2 }]
+        ]),
+        repo
+      ),
+      false
+    )
   })
 
   it('getMonoid', () => {
-    const d1 = new Map<User, number>([[{ id: 'k1' }, 1], [{ id: 'k2' }, 3]])
-    const d2 = new Map<User, number>([[{ id: 'k2' }, 2], [{ id: 'k3' }, 4]])
-    const expected = new Map<User, number>([[{ id: 'k1' }, 1], [{ id: 'k2' }, 5], [{ id: 'k3' }, 4]])
+    const d1 = new Map<User, number>([
+      [{ id: 'k1' }, 1],
+      [{ id: 'k2' }, 3]
+    ])
+    const d2 = new Map<User, number>([
+      [{ id: 'k2' }, 2],
+      [{ id: 'k3' }, 4]
+    ])
+    const expected = new Map<User, number>([
+      [{ id: 'k1' }, 1],
+      [{ id: 'k2' }, 5],
+      [{ id: 'k3' }, 4]
+    ])
     const M1 = M.getMonoid(eqUser, semigroupSum)
     assert.deepStrictEqual(M1.concat(d1, d2), expected)
     assert.deepStrictEqual(M1.concat(d1, M1.empty), d1)
@@ -312,15 +595,25 @@ describe('Map', () => {
     const M2 = M.getMonoid(eqKey, semigroupValue)
     assert.deepStrictEqual(
       M2.concat(repo, new Map([[{ id: 3 }, { value: 3 }]])),
-      new Map([[{ id: 1 }, { value: 1 }], [{ id: 2 }, { value: 2 }], [{ id: 3 }, { value: 3 }]])
+      new Map([
+        [{ id: 1 }, { value: 1 }],
+        [{ id: 2 }, { value: 2 }],
+        [{ id: 3 }, { value: 3 }]
+      ])
     )
     assert.deepStrictEqual(
       M2.concat(repo, new Map([[{ id: 1 }, { value: 2 }]])),
-      new Map([[{ id: 1 }, { value: 3 }], [{ id: 2 }, { value: 2 }]])
+      new Map([
+        [{ id: 1 }, { value: 3 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
     )
     assert.deepStrictEqual(
       M2.concat(repo, new Map([[{ id: 4 }, { value: 2 }]])),
-      new Map([[{ id: 1 }, { value: 3 }], [{ id: 2 }, { value: 2 }]])
+      new Map([
+        [{ id: 1 }, { value: 3 }],
+        [{ id: 2 }, { value: 2 }]
+      ])
     )
   })
 
@@ -328,8 +621,14 @@ describe('Map', () => {
     describe('functor', () => {
       it('map', () => {
         const map = M.map_.map
-        const d1 = new Map<string, number>([['k1', 1], ['k2', 2]])
-        const expected = new Map<string, number>([['k1', 2], ['k2', 4]])
+        const d1 = new Map<string, number>([
+          ['k1', 1],
+          ['k2', 2]
+        ])
+        const expected = new Map<string, number>([
+          ['k1', 2],
+          ['k2', 4]
+        ])
         const double = (n: number): number => n * 2
         assert.deepStrictEqual(map(d1, double), expected)
       })
@@ -338,7 +637,10 @@ describe('Map', () => {
     describe('filterable', () => {
       it('compact', () => {
         const compact = M.map_.compact
-        const fooBar = new Map<string, Option<number>>([['foo', none], ['bar', some(123)]])
+        const fooBar = new Map<string, Option<number>>([
+          ['foo', none],
+          ['bar', some(123)]
+        ])
         const bar = new Map<string, number>([['bar', 123]])
         assert.deepStrictEqual(compact(fooBar), bar)
       })
@@ -346,7 +648,10 @@ describe('Map', () => {
       it('partitionMap', () => {
         const partitionMap = M.map_.partitionMap
         const emptyMap = new Map<string, number>()
-        const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+        const a1b3 = new Map<string, number>([
+          ['a', 1],
+          ['b', 3]
+        ])
         const a0 = new Map<string, number>([['a', 0]])
         const b4 = new Map<string, number>([['b', 4]])
         const f = (n: number) => (p(n) ? right(n + 1) : left(n - 1))
@@ -360,7 +665,10 @@ describe('Map', () => {
       it('partition', () => {
         const partition = M.map_.partition
         const emptyMap = new Map<string, number>()
-        const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+        const a1b3 = new Map<string, number>([
+          ['a', 1],
+          ['b', 3]
+        ])
         const a1 = new Map<string, number>([['a', 1]])
         const b3 = new Map<string, number>([['b', 3]])
         assert.deepStrictEqual(partition(emptyMap, p), { left: emptyMap, right: emptyMap })
@@ -372,7 +680,10 @@ describe('Map', () => {
 
       it('separate', () => {
         const separate = M.map_.separate
-        const fooBar = new Map<string, Either<number, number>>([['foo', left(123)], ['bar', right(123)]])
+        const fooBar = new Map<string, Either<number, number>>([
+          ['foo', left(123)],
+          ['bar', right(123)]
+        ])
         const foo = new Map<string, number>([['foo', 123]])
         const bar = new Map<string, number>([['bar', 123]])
         assert.deepStrictEqual(separate(fooBar), {
@@ -383,13 +694,19 @@ describe('Map', () => {
 
       it('filter', () => {
         const filter = M.map_.filter
-        const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+        const a1b3 = new Map<string, number>([
+          ['a', 1],
+          ['b', 3]
+        ])
         const b3 = new Map<string, number>([['b', 3]])
         assert.deepStrictEqual(filter(a1b3, p), b3)
 
         // refinements
         const isNumber = (u: string | number): u is number => typeof u === 'number'
-        const y = new Map<string, string | number>([['a', 1], ['b', 'foo']])
+        const y = new Map<string, string | number>([
+          ['a', 1],
+          ['b', 'foo']
+        ])
         const a1 = new Map<string, number>([['a', 1]])
         const actual = filter(y, isNumber)
         assert.deepStrictEqual(actual, a1)
@@ -398,7 +715,10 @@ describe('Map', () => {
       it('filterMap', () => {
         const filterMap = M.map_.filterMap
         const emptyMap = new Map<string, number>()
-        const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+        const a1b3 = new Map<string, number>([
+          ['a', 1],
+          ['b', 3]
+        ])
         const b4 = new Map<string, number>([['b', 4]])
         const f = (n: number) => (p(n) ? some(n + 1) : none)
         assert.deepStrictEqual(filterMap(emptyMap, f), emptyMap)
@@ -414,86 +734,166 @@ describe('Map', () => {
       const mapWithIndex = W.mapWithIndex
       const aa1 = new Map<User, number>([[{ id: 'aa' }, 1]])
       const aa3 = new Map<User, number>([[{ id: 'aa' }, 3]])
-      assert.deepStrictEqual(mapWithIndex(aa1, (k, a) => a + k.id.length), aa3)
+      assert.deepStrictEqual(
+        mapWithIndex(aa1, (k, a) => a + k.id.length),
+        aa3
+      )
     })
 
     it('reduce', () => {
-      const d1 = new Map<User, string>([[{ id: 'k1' }, 'a'], [{ id: 'k2' }, 'b']])
+      const d1 = new Map<User, string>([
+        [{ id: 'k1' }, 'a'],
+        [{ id: 'k2' }, 'b']
+      ])
       const reduceO = W.reduce
-      assert.strictEqual(reduceO(d1, '', (b, a) => b + a), 'ab')
-      const d2 = new Map<User, string>([[{ id: 'k2' }, 'b'], [{ id: 'k1' }, 'a']])
-      assert.strictEqual(reduceO(d2, '', (b, a) => b + a), 'ab')
+      assert.strictEqual(
+        reduceO(d1, '', (b, a) => b + a),
+        'ab'
+      )
+      const d2 = new Map<User, string>([
+        [{ id: 'k2' }, 'b'],
+        [{ id: 'k1' }, 'a']
+      ])
+      assert.strictEqual(
+        reduceO(d2, '', (b, a) => b + a),
+        'ab'
+      )
     })
 
     it('foldMap', () => {
       const foldMapOM = W.foldMap(monoidString)
-      const m = new Map<User, string>([[{ id: 'a' }, 'a'], [{ id: 'a' }, 'b']])
+      const m = new Map<User, string>([
+        [{ id: 'a' }, 'a'],
+        [{ id: 'a' }, 'b']
+      ])
       assert.strictEqual(foldMapOM(m, identity), 'ab')
     })
 
     it('reduceRight', () => {
       const reduceRightO = W.reduceRight
-      const m = new Map<User, string>([[{ id: 'a' }, 'a'], [{ id: 'b' }, 'b']])
+      const m = new Map<User, string>([
+        [{ id: 'a' }, 'a'],
+        [{ id: 'b' }, 'b']
+      ])
       const init = ''
       const f = (a: string, acc: string) => acc + a
       assert.strictEqual(reduceRightO(m, init, f), 'ba')
     })
 
     it('reduceWithIndex', () => {
-      const d1 = new Map<User, string>([[{ id: 'k1' }, 'a'], [{ id: 'k2' }, 'b']])
+      const d1 = new Map<User, string>([
+        [{ id: 'k1' }, 'a'],
+        [{ id: 'k2' }, 'b']
+      ])
       const reduceWithIndexO = W.reduceWithIndex
-      assert.strictEqual(reduceWithIndexO(d1, '', (k, b, a) => b + k.id + a), 'k1ak2b')
-      const d2 = new Map<User, string>([[{ id: 'k2' }, 'b'], [{ id: 'k1' }, 'a']])
-      assert.strictEqual(reduceWithIndexO(d2, '', (k, b, a) => b + k.id + a), 'k1ak2b')
+      assert.strictEqual(
+        reduceWithIndexO(d1, '', (k, b, a) => b + k.id + a),
+        'k1ak2b'
+      )
+      const d2 = new Map<User, string>([
+        [{ id: 'k2' }, 'b'],
+        [{ id: 'k1' }, 'a']
+      ])
+      assert.strictEqual(
+        reduceWithIndexO(d2, '', (k, b, a) => b + k.id + a),
+        'k1ak2b'
+      )
     })
 
     it('foldMapWithIndex', () => {
       const foldMapWithIndexOM = W.foldMapWithIndex(monoidString)
-      const m = new Map<User, string>([[{ id: 'k1' }, 'a'], [{ id: 'k2' }, 'b']])
-      assert.strictEqual(foldMapWithIndexOM(m, (k, a) => k.id + a), 'k1ak2b')
+      const m = new Map<User, string>([
+        [{ id: 'k1' }, 'a'],
+        [{ id: 'k2' }, 'b']
+      ])
+      assert.strictEqual(
+        foldMapWithIndexOM(m, (k, a) => k.id + a),
+        'k1ak2b'
+      )
     })
 
     it('reduceRightWithIndex', () => {
       const reduceRightWithIndexO = W.reduceRightWithIndex
-      const m = new Map<User, string>([[{ id: 'k1' }, 'a'], [{ id: 'k2' }, 'b']])
-      assert.strictEqual(reduceRightWithIndexO(m, '', (k, a, b) => b + k.id + a), 'k2bk1a')
+      const m = new Map<User, string>([
+        [{ id: 'k1' }, 'a'],
+        [{ id: 'k2' }, 'b']
+      ])
+      assert.strictEqual(
+        reduceRightWithIndexO(m, '', (k, a, b) => b + k.id + a),
+        'k2bk1a'
+      )
     })
 
     it('traverse', () => {
       const optionTraverse = W.traverse(option)
-      const x = new Map<User, number>([[{ id: 'k1' }, 1], [{ id: 'k2' }, 2]])
-      assert.deepStrictEqual(optionTraverse(x, n => (n <= 2 ? some(n) : none)), some(x))
-      assert.deepStrictEqual(optionTraverse(x, n => (n >= 2 ? some(n) : none)), none)
+      const x = new Map<User, number>([
+        [{ id: 'k1' }, 1],
+        [{ id: 'k2' }, 2]
+      ])
+      assert.deepStrictEqual(
+        optionTraverse(x, n => (n <= 2 ? some(n) : none)),
+        some(x)
+      )
+      assert.deepStrictEqual(
+        optionTraverse(x, n => (n >= 2 ? some(n) : none)),
+        none
+      )
     })
 
     it('sequence', () => {
       const optionSequence = W.sequence(option)
-      const m1 = new Map<User, Option<number>>([[{ id: 'k1' }, some(1)], [{ id: 'k2' }, some(2)]])
-      const m2 = new Map<User, Option<number>>([[{ id: 'k1' }, none], [{ id: 'k2' }, some(2)]])
-      assert.deepStrictEqual(optionSequence(m1), some(new Map<User, number>([[{ id: 'k1' }, 1], [{ id: 'k2' }, 2]])))
+      const m1 = new Map<User, Option<number>>([
+        [{ id: 'k1' }, some(1)],
+        [{ id: 'k2' }, some(2)]
+      ])
+      const m2 = new Map<User, Option<number>>([
+        [{ id: 'k1' }, none],
+        [{ id: 'k2' }, some(2)]
+      ])
+      assert.deepStrictEqual(
+        optionSequence(m1),
+        some(
+          new Map<User, number>([
+            [{ id: 'k1' }, 1],
+            [{ id: 'k2' }, 2]
+          ])
+        )
+      )
       assert.deepStrictEqual(optionSequence(m2), none)
     })
 
     it('traverseWithIndex', () => {
       const optionTraverseWithIndex = W.traverseWithIndex(option)
-      const d1 = new Map<User, number>([[{ id: 'k1' }, 1], [{ id: 'k2' }, 2]])
+      const d1 = new Map<User, number>([
+        [{ id: 'k1' }, 1],
+        [{ id: 'k2' }, 2]
+      ])
       const t1 = optionTraverseWithIndex(
         d1,
         (k, n): Option<number> => (!ordUser.equals(k, { id: 'k1' }) ? some(n) : none)
       )
       assert.deepStrictEqual(t1, none)
-      const d2 = new Map<User, number>([[{ id: 'k1' }, 2], [{ id: 'k2' }, 3]])
+      const d2 = new Map<User, number>([
+        [{ id: 'k1' }, 2],
+        [{ id: 'k2' }, 3]
+      ])
       const t2 = optionTraverseWithIndex(
         d2,
         (k, n): Option<number> => (!ordUser.equals(k, { id: 'k3' }) ? some(n) : none)
       )
-      const expected = new Map<User, number>([[{ id: 'k1' }, 2], [{ id: 'k2' }, 3]])
+      const expected = new Map<User, number>([
+        [{ id: 'k1' }, 2],
+        [{ id: 'k2' }, 3]
+      ])
       assert.deepStrictEqual(t2, some(expected))
     })
 
     it('wither', () => {
       const emptyMap = new Map<User, number>()
-      const a1b3 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 3]])
+      const a1b3 = new Map<User, number>([
+        [{ id: 'a' }, 1],
+        [{ id: 'b' }, 3]
+      ])
       const b4 = new Map<User, number>([[{ id: 'b' }, 4]])
       const witherIdentity = W.wither(I.identity)
       const f = (n: number) => I.identity.of(p(n) ? some(n + 1) : none)
@@ -503,7 +903,10 @@ describe('Map', () => {
 
     it('wilt', () => {
       const emptyMap = new Map<User, number>()
-      const a1b3 = new Map<User, number>([[{ id: 'a' }, 1], [{ id: 'b' }, 3]])
+      const a1b3 = new Map<User, number>([
+        [{ id: 'a' }, 1],
+        [{ id: 'b' }, 3]
+      ])
       const a0 = new Map<User, number>([[{ id: 'a' }, 0]])
       const b4 = new Map<User, number>([[{ id: 'b' }, 4]])
       const wiltIdentity = W.wilt(I.identity)
@@ -517,7 +920,10 @@ describe('Map', () => {
     it('partitionMapWithIndex', () => {
       const partitionMapWithIndex = M.getFilterableWithIndex<string>().partitionMapWithIndex
       const emptyMap = new Map<string, number>()
-      const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+      const a1b3 = new Map<string, number>([
+        ['a', 1],
+        ['b', 3]
+      ])
       const a0 = new Map<string, number>([['a', 0]])
       const b4 = new Map<string, number>([['b', 4]])
       const f = (_: string, n: number) => (p(n) ? right(n + 1) : left(n - 1))
@@ -531,7 +937,10 @@ describe('Map', () => {
     it('partitionWithIndex', () => {
       const partitionWithIndex = M.getFilterableWithIndex<string>().partitionWithIndex
       const emptyMap = new Map<string, number>()
-      const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+      const a1b3 = new Map<string, number>([
+        ['a', 1],
+        ['b', 3]
+      ])
       const a1 = new Map<string, number>([['a', 1]])
       const b3 = new Map<string, number>([['b', 3]])
       const f = (_: string, n: number) => p(n)
@@ -545,7 +954,10 @@ describe('Map', () => {
     it('filterMapWithIndex', () => {
       const filterMapWithIndex = M.getFilterableWithIndex<string>().filterMapWithIndex
       const emptyMap = new Map<string, number>()
-      const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+      const a1b3 = new Map<string, number>([
+        ['a', 1],
+        ['b', 3]
+      ])
       const b4 = new Map<string, number>([['b', 4]])
       const f = (_: string, n: number) => (p(n) ? some(n + 1) : none)
       assert.deepStrictEqual(filterMapWithIndex(emptyMap, f), emptyMap)
@@ -554,7 +966,10 @@ describe('Map', () => {
 
     it('filterWithIndex', () => {
       const filterWithIndex = M.getFilterableWithIndex<string>().filterWithIndex
-      const a1b3 = new Map<string, number>([['a', 1], ['b', 3]])
+      const a1b3 = new Map<string, number>([
+        ['a', 1],
+        ['b', 3]
+      ])
       const b3 = new Map<string, number>([['b', 3]])
       const f = (_: string, n: number) => p(n)
       assert.deepStrictEqual(filterWithIndex(a1b3, f), b3)
@@ -562,7 +977,10 @@ describe('Map', () => {
       // refinements
       const filterWithIndexStr = M.getFilterableWithIndex<string>().filterWithIndex
       const isNumber = (_: string, u: string | number): u is number => typeof u === 'number'
-      const y = new Map<string, string | number>([['a', 1], ['b', 'foo']])
+      const y = new Map<string, string | number>([
+        ['a', 1],
+        ['b', 'foo']
+      ])
       const a1 = new Map<string, number>([['a', 1]])
       const actual = filterWithIndexStr(y, isNumber)
       assert.deepStrictEqual(actual, a1)
@@ -574,9 +992,21 @@ describe('Map', () => {
     const a2 = new Map<User, number>([[{ id: 'a' }, 2]])
     const fromFoldableS1 = M.fromFoldable(eqUser, getFirstSemigroup<number>(), array)
     assert.deepStrictEqual(fromFoldableS1([[{ id: 'a' }, 1]]), a1)
-    assert.deepStrictEqual(fromFoldableS1([[{ id: 'a' }, 1], [{ id: 'a' }, 2]]), a1)
+    assert.deepStrictEqual(
+      fromFoldableS1([
+        [{ id: 'a' }, 1],
+        [{ id: 'a' }, 2]
+      ]),
+      a1
+    )
     const fromFoldableS2 = M.fromFoldable(eqUser, getLastSemigroup<number>(), array)
-    assert.deepStrictEqual(fromFoldableS2([[{ id: 'a' }, 1], [{ id: 'a' }, 2]]), a2)
+    assert.deepStrictEqual(
+      fromFoldableS2([
+        [{ id: 'a' }, 1],
+        [{ id: 'a' }, 2]
+      ]),
+      a2
+    )
   })
 
   it('getShow', () => {
@@ -586,7 +1016,10 @@ describe('Map', () => {
     assert.strictEqual(S.show(m1), `new Map([])`)
     const m2 = new Map<User, string>([[{ id: 'a' }, 'b']])
     assert.strictEqual(S.show(m2), `new Map([[{ id: "a" }, "b"]])`)
-    const m3 = new Map<User, string>([[{ id: 'a' }, 'b'], [{ id: 'c' }, 'd']])
+    const m3 = new Map<User, string>([
+      [{ id: 'a' }, 'b'],
+      [{ id: 'c' }, 'd']
+    ])
     assert.strictEqual(S.show(m3), `new Map([[{ id: "a" }, "b"], [{ id: "c" }, "d"]])`)
   })
 
@@ -594,7 +1027,12 @@ describe('Map', () => {
     const m1 = new Map<User, string>([])
     assert.deepStrictEqual(M.updateAt(eqUser)({ id: 'a' }, 'a')(m1), none)
     const m2 = new Map<User, string>([[{ id: 'a' }, 'b']])
-    assert.deepStrictEqual(M.updateAt(eqUser)({ id: 'a' }, 'a')(m2), some(new Map<User, string>([[{ id: 'a' }, 'a']])))
+    assert.deepStrictEqual(
+      M.updateAt(eqUser)({ id: 'a' }, 'a')(m2),
+      some(
+        new Map<User, string>([[{ id: 'a' }, 'a']])
+      )
+    )
   })
 
   it('modifyAt', () => {
@@ -603,7 +1041,9 @@ describe('Map', () => {
     const m2 = new Map<User, number>([[{ id: 'a' }, 1]])
     assert.deepStrictEqual(
       M.modifyAt(eqUser)({ id: 'a' }, (n: number) => n * 2)(m2),
-      some(new Map<User, number>([[{ id: 'a' }, 2]]))
+      some(
+        new Map<User, number>([[{ id: 'a' }, 2]])
+      )
     )
   })
 })
diff --git a/test/NonEmptyArray.ts b/test/NonEmptyArray.ts
index f4cef9e9..154e0a22 100644
--- a/test/NonEmptyArray.ts
+++ b/test/NonEmptyArray.ts
@@ -28,7 +28,8 @@ import {
   sort,
   tail,
   updateAt,
-  NonEmptyArray
+  NonEmptyArray,
+  init
 } from '../src/NonEmptyArray'
 import { isSome, none, option, some } from '../src/Option'
 import { ordNumber } from '../src/Ord'
@@ -77,8 +78,14 @@ describe('NonEmptyArray', () => {
   })
 
   it('traverse', () => {
-    assert.deepStrictEqual(nonEmptyArray.traverse(option)([1, 2, 3], n => (n >= 0 ? some(n) : none)), some([1, 2, 3]))
-    assert.deepStrictEqual(nonEmptyArray.traverse(option)([1, 2, 3], n => (n >= 2 ? some(n) : none)), none)
+    assert.deepStrictEqual(
+      nonEmptyArray.traverse(option)([1, 2, 3], n => (n >= 0 ? some(n) : none)),
+      some([1, 2, 3])
+    )
+    assert.deepStrictEqual(
+      nonEmptyArray.traverse(option)([1, 2, 3], n => (n >= 2 ? some(n) : none)),
+      none
+    )
   })
 
   it('sequence', () => {
@@ -98,7 +105,10 @@ describe('NonEmptyArray', () => {
   })
 
   it('reduce', () => {
-    assert.strictEqual(nonEmptyArray.reduce(['a', 'b'], '', (b, a) => b + a), 'ab')
+    assert.strictEqual(
+      nonEmptyArray.reduce(['a', 'b'], '', (b, a) => b + a),
+      'ab'
+    )
   })
 
   it('foldMap', () => {
@@ -149,6 +159,11 @@ describe('NonEmptyArray', () => {
     assert.deepStrictEqual(last([1]), 1)
   })
 
+  it('init', () => {
+    assert.deepStrictEqual(init([1, 2, 3]), [1, 2])
+    assert.deepStrictEqual(init([1]), [])
+  })
+
   it('sort', () => {
     assert.deepStrictEqual(sort(ordNumber)([3, 2, 1]), [1, 2, 3])
   })
@@ -248,15 +263,24 @@ describe('NonEmptyArray', () => {
   })
 
   it('reduceWithIndex', () => {
-    assert.deepStrictEqual(nonEmptyArray.reduceWithIndex(['a', 'b'], '', (i, b, a) => b + i + a), '0a1b')
+    assert.deepStrictEqual(
+      nonEmptyArray.reduceWithIndex(['a', 'b'], '', (i, b, a) => b + i + a),
+      '0a1b'
+    )
   })
 
   it('foldMapWithIndex', () => {
-    assert.deepStrictEqual(nonEmptyArray.foldMapWithIndex(monoidString)(['a', 'b'], (i, a) => i + a), '0a1b')
+    assert.deepStrictEqual(
+      nonEmptyArray.foldMapWithIndex(monoidString)(['a', 'b'], (i, a) => i + a),
+      '0a1b'
+    )
   })
 
   it('reduceRightWithIndex', () => {
-    assert.deepStrictEqual(nonEmptyArray.reduceRightWithIndex(['a', 'b'], '', (i, a, b) => b + i + a), '1b0a')
+    assert.deepStrictEqual(
+      nonEmptyArray.reduceRightWithIndex(['a', 'b'], '', (i, a, b) => b + i + a),
+      '1b0a'
+    )
   })
 
   it('traverseWithIndex', () => {
diff --git a/test/Option.ts b/test/Option.ts
index d425419d..69361c99 100644
--- a/test/Option.ts
+++ b/test/Option.ts
@@ -157,10 +157,22 @@ describe('Option', () => {
   })
 
   it('alt', () => {
-    assert.deepStrictEqual(O.option.alt(O.some(1), () => O.some(2)), O.some(1))
-    assert.deepStrictEqual(O.option.alt(O.some(2), () => O.none), O.some(2))
-    assert.deepStrictEqual(O.option.alt(O.none, () => O.some(1)), O.some(1))
-    assert.deepStrictEqual(O.option.alt(O.none, () => O.none), O.none)
+    assert.deepStrictEqual(
+      O.option.alt(O.some(1), () => O.some(2)),
+      O.some(1)
+    )
+    assert.deepStrictEqual(
+      O.option.alt(O.some(2), () => O.none),
+      O.some(2)
+    )
+    assert.deepStrictEqual(
+      O.option.alt(O.none, () => O.some(1)),
+      O.some(1)
+    )
+    assert.deepStrictEqual(
+      O.option.alt(O.none, () => O.none),
+      O.none
+    )
   })
 
   it('extend', () => {
@@ -187,9 +199,18 @@ describe('Option', () => {
   })
 
   it('traverse', () => {
-    assert.deepStrictEqual(O.option.traverse(array)(O.some('hello'), () => []), [])
-    assert.deepStrictEqual(O.option.traverse(array)(O.some('hello'), s => [s.length]), [O.some(5)])
-    assert.deepStrictEqual(O.option.traverse(array)(O.none, s => [s]), [O.none])
+    assert.deepStrictEqual(
+      O.option.traverse(array)(O.some('hello'), () => []),
+      []
+    )
+    assert.deepStrictEqual(
+      O.option.traverse(array)(O.some('hello'), s => [s.length]),
+      [O.some(5)]
+    )
+    assert.deepStrictEqual(
+      O.option.traverse(array)(O.none, s => [s]),
+      [O.none]
+    )
   })
 
   it('sequence', () => {
@@ -198,8 +219,14 @@ describe('Option', () => {
   })
 
   it('reduce', () => {
-    assert.strictEqual(O.option.reduce(O.none, 2, (b, a) => b + a), 2)
-    assert.strictEqual(O.option.reduce(O.some(3), 2, (b, a) => b + a), 5)
+    assert.strictEqual(
+      O.option.reduce(O.none, 2, (b, a) => b + a),
+      2
+    )
+    assert.strictEqual(
+      O.option.reduce(O.some(3), 2, (b, a) => b + a),
+      5
+    )
   })
 
   it('foldMap', () => {
@@ -271,34 +298,22 @@ describe('Option', () => {
 
   it('exists', () => {
     const predicate = (a: number) => a === 2
+    assert.deepStrictEqual(pipe(O.none, O.exists(predicate)), false)
+    assert.deepStrictEqual(pipe(O.some(1), O.exists(predicate)), false)
+    assert.deepStrictEqual(pipe(O.some(2), O.exists(predicate)), true)
+  })
+
+  it('tryCatch', () => {
     assert.deepStrictEqual(
-      pipe(
-        O.none,
-        O.exists(predicate)
-      ),
-      false
+      O.tryCatch(() => JSON.parse('2')),
+      O.some(2)
     )
     assert.deepStrictEqual(
-      pipe(
-        O.some(1),
-        O.exists(predicate)
-      ),
-      false
-    )
-    assert.deepStrictEqual(
-      pipe(
-        O.some(2),
-        O.exists(predicate)
-      ),
-      true
+      O.tryCatch(() => JSON.parse('(')),
+      O.none
     )
   })
 
-  it('tryCatch', () => {
-    assert.deepStrictEqual(O.tryCatch(() => JSON.parse('2')), O.some(2))
-    assert.deepStrictEqual(O.tryCatch(() => JSON.parse('(')), O.none)
-  })
-
   it('compact', () => {
     assert.deepStrictEqual(O.option.compact(O.none), O.none)
     assert.deepStrictEqual(O.option.compact(O.some(O.none)), O.none)
diff --git a/test/Ord.ts b/test/Ord.ts
index 7a611473..78b520ee 100644
--- a/test/Ord.ts
+++ b/test/Ord.ts
@@ -26,14 +26,29 @@ describe('Ord', () => {
 
   it('getSemigroup', () => {
     type T = [number, string]
-    const tuples: Array<T> = [[2, 'c'], [1, 'b'], [2, 'a'], [1, 'c']]
+    const tuples: Array<T> = [
+      [2, 'c'],
+      [1, 'b'],
+      [2, 'a'],
+      [1, 'c']
+    ]
     const S = getSemigroup<T>()
     const sortByFst = ord.contramap(ordNumber, (x: T) => x[0])
     const sortBySnd = ord.contramap(ordString, (x: T) => x[1])
     const O1 = S.concat(sortByFst, sortBySnd)
-    assert.deepStrictEqual(sort(O1)(tuples), [[1, 'b'], [1, 'c'], [2, 'a'], [2, 'c']])
+    assert.deepStrictEqual(sort(O1)(tuples), [
+      [1, 'b'],
+      [1, 'c'],
+      [2, 'a'],
+      [2, 'c']
+    ])
     const O2 = S.concat(sortBySnd, sortByFst)
-    assert.deepStrictEqual(sort(O2)(tuples), [[2, 'a'], [1, 'b'], [1, 'c'], [2, 'c']])
+    assert.deepStrictEqual(sort(O2)(tuples), [
+      [2, 'a'],
+      [1, 'b'],
+      [1, 'c'],
+      [2, 'c']
+    ])
   })
 
   it('ordNumber', () => {
diff --git a/test/Reader.ts b/test/Reader.ts
index b6c3e7be..62084ce3 100644
--- a/test/Reader.ts
+++ b/test/Reader.ts
@@ -44,7 +44,11 @@ describe('Reader', () => {
 
   it('promap', () => {
     const x = (s: string) => s.length
-    const y = R.reader.promap(x, (a: { name: string }) => a.name, n => n >= 2)
+    const y = R.reader.promap(
+      x,
+      (a: { name: string }) => a.name,
+      n => n >= 2
+    )
     assert.strictEqual(y({ name: 'foo' }), true)
     assert.strictEqual(y({ name: 'a' }), false)
   })
@@ -57,10 +61,7 @@ describe('Reader', () => {
   it('compose', () => {
     const x = (s: string) => s.length
     const y = (n: number) => n >= 2
-    const z = R.reader.compose(
-      y,
-      x
-    )
+    const z = R.reader.compose(y, x)
     assert.strictEqual(z('foo'), true)
     assert.strictEqual(z('a'), false)
   })
diff --git a/test/ReaderEither.ts b/test/ReaderEither.ts
index 1bb4f048..fb8f05d5 100644
--- a/test/ReaderEither.ts
+++ b/test/ReaderEither.ts
@@ -16,13 +16,19 @@ describe('ReaderEither', () => {
   })
 
   it('fromPredicate', () => {
-    const gt2 = _.fromPredicate((n: number) => n >= 2, n => `Invalid number ${n}`)
+    const gt2 = _.fromPredicate(
+      (n: number) => n >= 2,
+      n => `Invalid number ${n}`
+    )
     assert.deepStrictEqual(gt2(3)({}), E.right(3))
     assert.deepStrictEqual(gt2(1)({}), E.left('Invalid number 1'))
   })
 
   it('fold', () => {
-    const fold = _.fold((s: string) => reader.of(s.length), (n: number) => reader.of(n * 2))
+    const fold = _.fold(
+      (s: string) => reader.of(s.length),
+      (n: number) => reader.of(n * 2)
+    )
     assert.deepStrictEqual(fold(_.right(1))({}), 2)
     assert.deepStrictEqual(fold(_.left('aaa'))({}), 3)
   })
@@ -41,12 +47,18 @@ describe('ReaderEither', () => {
   it('filterOrElse', () => {
     const e1 = pipe(
       _.right(12),
-      _.filterOrElse(n => n > 10, () => 'a')
+      _.filterOrElse(
+        n => n > 10,
+        () => 'a'
+      )
     )({})
     assert.deepStrictEqual(e1, E.right(12))
     const e2 = pipe(
       _.right(7),
-      _.filterOrElse(n => n > 10, () => 'a')
+      _.filterOrElse(
+        n => n > 10,
+        () => 'a'
+      )
     )({})
     assert.deepStrictEqual(e2, E.left('a'))
   })
diff --git a/test/ReaderTaskEither.ts b/test/ReaderTaskEither.ts
index ecbaf46b..89fcb4b2 100644
--- a/test/ReaderTaskEither.ts
+++ b/test/ReaderTaskEither.ts
@@ -63,7 +63,10 @@ describe('ReaderTaskEither', () => {
   })
 
   it('asks', async () => {
-    const e = await _.run(_.asks((s: string) => s.length), 'foo')
+    const e = await _.run(
+      _.asks((s: string) => s.length),
+      'foo'
+    )
     return assert.deepStrictEqual(e, E.right(3))
   })
 
@@ -110,14 +113,23 @@ describe('ReaderTaskEither', () => {
   })
 
   it('fromIOEither', async () => {
-    const e1 = await _.run(_.fromIOEither(() => E.right(1)), {})
+    const e1 = await _.run(
+      _.fromIOEither(() => E.right(1)),
+      {}
+    )
     assert.deepStrictEqual(e1, E.right(1))
-    const e2 = await _.run(_.fromIOEither(() => E.left('error')), {})
+    const e2 = await _.run(
+      _.fromIOEither(() => E.left('error')),
+      {}
+    )
     assert.deepStrictEqual(e2, E.left('error'))
   })
 
   it('fold', async () => {
-    const fold = _.fold((l: string) => reader.of(task.of(l.length)), (a: number) => reader.of(task.of(a * 2)))
+    const fold = _.fold(
+      (l: string) => reader.of(task.of(l.length)),
+      (a: number) => reader.of(task.of(a * 2))
+    )
     const e1 = await fold(_.right(1))({})()
     assert.deepStrictEqual(e1, 2)
     const e2 = await fold(_.left('err'))({})()
@@ -157,11 +169,20 @@ describe('ReaderTaskEither', () => {
   })
 
   it('alt', async () => {
-    const e1 = await _.run(_.readerTaskEither.alt(_.right(1), () => _.right(2)), {})
+    const e1 = await _.run(
+      _.readerTaskEither.alt(_.right(1), () => _.right(2)),
+      {}
+    )
     assert.deepStrictEqual(e1, E.right(1))
-    const e2 = await _.run(_.readerTaskEither.alt(_.left('a'), () => _.right(2)), {})
+    const e2 = await _.run(
+      _.readerTaskEither.alt(_.left('a'), () => _.right(2)),
+      {}
+    )
     assert.deepStrictEqual(e2, E.right(2))
-    const e3 = await _.run(_.readerTaskEither.alt(_.left('a'), () => _.left('b')), {})
+    const e3 = await _.run(
+      _.readerTaskEither.alt(_.left('a'), () => _.left('b')),
+      {}
+    )
     assert.deepStrictEqual(e3, E.left('b'))
   })
 
@@ -206,7 +227,10 @@ describe('ReaderTaskEither', () => {
 
   describe('MonadIO', () => {
     it('fromIO', async () => {
-      const e = await _.run(_.readerTaskEither.fromIO(() => 1), {})
+      const e = await _.run(
+        _.readerTaskEither.fromIO(() => 1),
+        {}
+      )
       assert.deepStrictEqual(e, E.right(1))
     })
   })
@@ -270,7 +294,10 @@ describe('ReaderTaskEither', () => {
     const e1 = await _.run(
       pipe(
         _.right(12),
-        _.filterOrElse(n => n > 10, () => 'a')
+        _.filterOrElse(
+          n => n > 10,
+          () => 'a'
+        )
       ),
       {}
     )
@@ -279,7 +306,10 @@ describe('ReaderTaskEither', () => {
     const e2 = await _.run(
       pipe(
         _.right(8),
-        _.filterOrElse(n => n > 10, () => 'a')
+        _.filterOrElse(
+          n => n > 10,
+          () => 'a'
+        )
       ),
       {}
     )
diff --git a/test/Record.ts b/test/Record.ts
index 6a53ac63..99ed18a2 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -38,9 +38,15 @@ describe('Record', () => {
 
   it('reduce', () => {
     const d1 = { k1: 'a', k2: 'b' }
-    assert.strictEqual(R.record.reduce(d1, '', (b, a) => b + a), 'ab')
+    assert.strictEqual(
+      R.record.reduce(d1, '', (b, a) => b + a),
+      'ab'
+    )
     const d2 = { k2: 'b', k1: 'a' }
-    assert.strictEqual(R.record.reduce(d2, '', (b, a) => b + a), 'ab')
+    assert.strictEqual(
+      R.record.reduce(d2, '', (b, a) => b + a),
+      'ab'
+    )
   })
 
   it('foldMap', () => {
@@ -90,18 +96,42 @@ describe('Record', () => {
   it('fromFoldable', () => {
     const First = getFirstSemigroup<number>()
     assert.deepStrictEqual(R.fromFoldable(First, array)([['a', 1]]), { a: 1 })
-    assert.deepStrictEqual(R.fromFoldable(First, array)([['a', 1], ['a', 2]]), {
-      a: 1
-    })
+    assert.deepStrictEqual(
+      R.fromFoldable(
+        First,
+        array
+      )([
+        ['a', 1],
+        ['a', 2]
+      ]),
+      {
+        a: 1
+      }
+    )
     const Last = getLastSemigroup<number>()
-    assert.deepStrictEqual(R.fromFoldable(Last, array)([['a', 1], ['a', 2]]), {
-      a: 2
-    })
+    assert.deepStrictEqual(
+      R.fromFoldable(
+        Last,
+        array
+      )([
+        ['a', 1],
+        ['a', 2]
+      ]),
+      {
+        a: 2
+      }
+    )
   })
 
   it('toArray', () => {
-    assert.deepStrictEqual(R.toArray({ a: 1, b: 2 }), [['a', 1], ['b', 2]])
-    assert.deepStrictEqual(R.toArray({ b: 2, a: 1 }), [['a', 1], ['b', 2]])
+    assert.deepStrictEqual(R.toArray({ a: 1, b: 2 }), [
+      ['a', 1],
+      ['b', 2]
+    ])
+    assert.deepStrictEqual(R.toArray({ b: 2, a: 1 }), [
+      ['a', 1],
+      ['b', 2]
+    ])
   })
 
   it('toUnfoldable', () => {
@@ -168,7 +198,10 @@ describe('Record', () => {
     const actual = R.record.filter(y, isNumber)
     assert.deepStrictEqual(actual, { a: 1 })
 
-    assert.strictEqual(R.record.filter(y, _ => true), y)
+    assert.strictEqual(
+      R.record.filter(y, _ => true),
+      y
+    )
 
     const x = Object.assign(Object.create({ c: true }), { a: 1, b: 'foo' })
     assert.deepStrictEqual(R.record.filter(x, isNumber), { a: 1 })
@@ -266,10 +299,13 @@ describe('Record', () => {
       { id: 'id1', name: 'name3' }
     ]
 
-    assert.deepStrictEqual(R.fromFoldableMap(getLastSemigroup<User>(), array)(users, user => [user.id, user]), {
-      id1: { id: 'id1', name: 'name3' },
-      id2: { id: 'id2', name: 'name2' }
-    })
+    assert.deepStrictEqual(
+      R.fromFoldableMap(getLastSemigroup<User>(), array)(users, user => [user.id, user]),
+      {
+        id1: { id: 'id1', name: 'name3' },
+        id2: { id: 'id2', name: 'name2' }
+      }
+    )
   })
 
   it('getShow', () => {
diff --git a/test/Set.ts b/test/Set.ts
index 16002c4e..051d25d8 100644
--- a/test/Set.ts
+++ b/test/Set.ts
@@ -139,9 +139,12 @@ describe('Set', () => {
     const SL = getStructEq({ value: eqNumber })
     const SR = getStructEq({ value: eqString })
     assert.deepStrictEqual(
-      partitionMap(SL, SR)((x: { value: number }) =>
-        x.value % 2 === 0 ? left({ value: 2 }) : right({ value: 'odd' })
-      )(new Set([{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }])),
+      partitionMap(
+        SL,
+        SR
+      )((x: { value: number }) => (x.value % 2 === 0 ? left({ value: 2 }) : right({ value: 'odd' })))(
+        new Set([{ value: 1 }, { value: 2 }, { value: 3 }, { value: 4 }])
+      ),
       {
         left: new Set([{ value: 2 }]),
         right: new Set([{ value: 'odd' }])
@@ -222,9 +225,10 @@ describe('Set', () => {
     const SL: Eq<L> = eq.contramap(eqString, x => x.error)
     const SR: Eq<R> = eq.contramap(eqString, x => x.id)
     assert.deepStrictEqual(
-      separate(SL, SR)(
-        new Set([right({ id: 'a' }), left({ error: 'error' }), right({ id: 'a' }), left({ error: 'error' })])
-      ),
+      separate(
+        SL,
+        SR
+      )(new Set([right({ id: 'a' }), left({ error: 'error' }), right({ id: 'a' }), left({ error: 'error' })])),
       {
         left: new Set([{ error: 'error' }]),
         right: new Set([{ id: 'a' }])
diff --git a/test/Store.ts b/test/Store.ts
index 54e4744d..be361348 100644
--- a/test/Store.ts
+++ b/test/Store.ts
@@ -18,15 +18,7 @@ describe('Store', () => {
 
   it('seek', () => {
     const wa: Store<string, number> = { peek: len, pos: 'a' }
-    assert.strictEqual(
-      store.extract(
-        pipe(
-          wa,
-          seek('aa')
-        )
-      ),
-      2
-    )
+    assert.strictEqual(store.extract(pipe(wa, seek('aa'))), 2)
   })
 
   it('seeks', () => {
diff --git a/test/TaskEither.ts b/test/TaskEither.ts
index a054a818..0609dabb 100644
--- a/test/TaskEither.ts
+++ b/test/TaskEither.ts
@@ -122,9 +122,15 @@ describe('TaskEither', () => {
   })
 
   it('tryCatch', async () => {
-    const e1 = await _.tryCatch(() => Promise.resolve(1), () => 'error')()
+    const e1 = await _.tryCatch(
+      () => Promise.resolve(1),
+      () => 'error'
+    )()
     assert.deepStrictEqual(e1, E.right(1))
-    const e2 = await _.tryCatch(() => Promise.reject(undefined), () => 'error')()
+    const e2 = await _.tryCatch(
+      () => Promise.reject(undefined),
+      () => 'error'
+    )()
     assert.deepStrictEqual(e2, E.left('error'))
   })
 
@@ -166,7 +172,10 @@ describe('TaskEither', () => {
   })
 
   it('fromPredicate', async () => {
-    const gt2 = _.fromPredicate((n: number) => n >= 2, n => `Invalid number ${n}`)
+    const gt2 = _.fromPredicate(
+      (n: number) => n >= 2,
+      n => `Invalid number ${n}`
+    )
     const e1 = await gt2(3)()
     assert.deepStrictEqual(e1, E.right(3))
     const e2 = await gt2(1)()
@@ -246,12 +255,18 @@ describe('TaskEither', () => {
   it('filterOrElse', async () => {
     const e1 = await pipe(
       _.right(12),
-      _.filterOrElse(n => n > 10, () => 'a')
+      _.filterOrElse(
+        n => n > 10,
+        () => 'a'
+      )
     )()
     assert.deepStrictEqual(e1, E.right(12))
     const e2 = await pipe(
       _.right(7),
-      _.filterOrElse(n => n > 10, () => 'a')
+      _.filterOrElse(
+        n => n > 10,
+        () => 'a'
+      )
     )()
     assert.deepStrictEqual(e2, E.left('a'))
   })
@@ -272,14 +287,6 @@ describe('TaskEither', () => {
     assert.deepStrictEqual(e2, E.right('a'))
   })
 
-  it('tryCatch', async () => {
-    const onrejected = (e: any) => `Error is: ${String(e)}`
-    const e1 = await _.tryCatch(() => Promise.resolve(1), onrejected)()
-    assert.deepStrictEqual(e1, E.right(1))
-    const e2 = await _.tryCatch(() => Promise.reject('ouch!'), onrejected)()
-    assert.deepStrictEqual(e2, E.left('Error is: ouch!'))
-  })
-
   it('fromOption', async () => {
     const e1 = await _.fromOption(() => 'none')(none)()
     assert.deepStrictEqual(e1, E.left('none'))
diff --git a/test/These.ts b/test/These.ts
index bc34e755..9a8b94cc 100644
--- a/test/These.ts
+++ b/test/These.ts
@@ -80,38 +80,32 @@ describe('These', () => {
   })
 
   it('toTuple', () => {
+    assert.deepStrictEqual(pipe(_.left('b'), _.toTuple('a', 1)), ['b', 1])
+    assert.deepStrictEqual(pipe(_.right(2), _.toTuple('a', 1)), ['a', 2])
+    assert.deepStrictEqual(pipe(_.both('b', 2), _.toTuple('a', 1)), ['b', 2])
+  })
+
+  it('traverse', () => {
     assert.deepStrictEqual(
-      pipe(
-        _.left('b'),
-        _.toTuple('a', 1)
-      ),
-      ['b', 1]
+      _.these.traverse(option)(_.left('a'), n => (n >= 2 ? some(n) : none)),
+      some(_.left('a'))
     )
     assert.deepStrictEqual(
-      pipe(
-        _.right(2),
-        _.toTuple('a', 1)
-      ),
-      ['a', 2]
+      _.these.traverse(option)(_.right(2), n => (n >= 2 ? some(n) : none)),
+      some(_.right(2))
     )
     assert.deepStrictEqual(
-      pipe(
-        _.both('b', 2),
-        _.toTuple('a', 1)
-      ),
-      ['b', 2]
+      _.these.traverse(option)(_.right(1), n => (n >= 2 ? some(n) : none)),
+      none
     )
-  })
-
-  it('traverse', () => {
-    assert.deepStrictEqual(_.these.traverse(option)(_.left('a'), n => (n >= 2 ? some(n) : none)), some(_.left('a')))
-    assert.deepStrictEqual(_.these.traverse(option)(_.right(2), n => (n >= 2 ? some(n) : none)), some(_.right(2)))
-    assert.deepStrictEqual(_.these.traverse(option)(_.right(1), n => (n >= 2 ? some(n) : none)), none)
     assert.deepStrictEqual(
       _.these.traverse(option)(_.both('a', 2), n => (n >= 2 ? some(n) : none)),
       some(_.both('a', 2))
     )
-    assert.deepStrictEqual(_.these.traverse(option)(_.both('a', 1), n => (n >= 2 ? some(n) : none)), none)
+    assert.deepStrictEqual(
+      _.these.traverse(option)(_.both('a', 1), n => (n >= 2 ? some(n) : none)),
+      none
+    )
   })
 
   it('sequence', () => {
@@ -200,9 +194,18 @@ describe('These', () => {
   })
 
   it('reduce', () => {
-    assert.strictEqual(_.these.reduce(_.left('b'), 'a', (b, a) => b + a), 'a')
-    assert.strictEqual(_.these.reduce(_.right('b'), 'a', (b, a) => b + a), 'ab')
-    assert.strictEqual(_.these.reduce(_.both(1, 'b'), 'a', (b, a) => b + a), 'ab')
+    assert.strictEqual(
+      _.these.reduce(_.left('b'), 'a', (b, a) => b + a),
+      'a'
+    )
+    assert.strictEqual(
+      _.these.reduce(_.right('b'), 'a', (b, a) => b + a),
+      'ab'
+    )
+    assert.strictEqual(
+      _.these.reduce(_.both(1, 'b'), 'a', (b, a) => b + a),
+      'ab'
+    )
   })
 
   it('foldMap', () => {
diff --git a/test/Traversable.ts b/test/Traversable.ts
index 077a17e8..08fcffce 100644
--- a/test/Traversable.ts
+++ b/test/Traversable.ts
@@ -14,7 +14,10 @@ describe('Traversable', () => {
       T.traverse(option)([some(1), some(2)], (n: number) => (n <= 2 ? some(n * 2) : none)),
       some([some(2), some(4)])
     )
-    assert.deepStrictEqual(T.traverse(option)([some(1), some(3)], (n: number) => (n <= 2 ? some(n * 2) : none)), none)
+    assert.deepStrictEqual(
+      T.traverse(option)([some(1), some(3)], (n: number) => (n <= 2 ? some(n * 2) : none)),
+      none
+    )
     assert.deepStrictEqual(T.sequence(option)([some(some(1)), some(some(2))]), some([some(1), some(2)]))
     assert.deepStrictEqual(T.sequence(option)([some(some(1)), none]), some([some(1), none]))
     assert.deepStrictEqual(T.sequence(option)([some(some(1)), some(none)]), none)
diff --git a/test/Tree.ts b/test/Tree.ts
index d8538f64..504b3512 100644
--- a/test/Tree.ts
+++ b/test/Tree.ts
@@ -43,7 +43,10 @@ describe('Tree', () => {
 
   it('reduce', () => {
     const fa = make('a', [make('b'), make('c')])
-    assert.strictEqual(tree.reduce(fa, '', (b, a) => b + a), 'abc')
+    assert.strictEqual(
+      tree.reduce(fa, '', (b, a) => b + a),
+      'abc'
+    )
   })
 
   it('foldMap', () => {
@@ -63,7 +66,10 @@ describe('Tree', () => {
 
   it('traverse', () => {
     const fa = make('a', [make('b'), make('c')])
-    assert.deepStrictEqual(tree.traverse(I.identity)(fa, a => I.identity.of(a)), I.identity.of(fa))
+    assert.deepStrictEqual(
+      tree.traverse(I.identity)(fa, a => I.identity.of(a)),
+      I.identity.of(fa)
+    )
   })
 
   it('sequence', () => {
diff --git a/test/Tuple.ts b/test/Tuple.ts
index d916a81b..009cc3c3 100644
--- a/test/Tuple.ts
+++ b/test/Tuple.ts
@@ -8,13 +8,7 @@ import * as T from '../src/Tuple'
 
 describe('Tuple', () => {
   it('compose', () => {
-    assert.deepStrictEqual(
-      T.tuple.compose(
-        [true, 2],
-        [1, 'a']
-      ),
-      [true, 'a']
-    )
+    assert.deepStrictEqual(T.tuple.compose([true, 2], [1, 'a']), [true, 'a'])
   })
 
   it('map', () => {
@@ -62,7 +56,10 @@ describe('Tuple', () => {
   })
 
   it('reduce', () => {
-    assert.strictEqual(T.tuple.reduce(['b', 1], 'a', (acc, a) => acc + a), 'ab')
+    assert.strictEqual(
+      T.tuple.reduce(['b', 1], 'a', (acc, a) => acc + a),
+      'ab'
+    )
   })
 
   it('foldMap', () => {
@@ -70,7 +67,10 @@ describe('Tuple', () => {
   })
 
   it('reduceRight', () => {
-    assert.strictEqual(T.tuple.reduceRight(['b', 1], 'a', (acc, a) => acc + a), 'ba')
+    assert.strictEqual(
+      T.tuple.reduceRight(['b', 1], 'a', (acc, a) => acc + a),
+      'ba'
+    )
   })
 
   it('swap', () => {
@@ -90,7 +90,10 @@ describe('Tuple', () => {
 
   it('getMonad', () => {
     const monad = T.getMonad(monoidString)
-    assert.deepStrictEqual(monad.chain([1, 'a'], a => [a * 2, 'b']), [2, 'ab'])
+    assert.deepStrictEqual(
+      monad.chain([1, 'a'], a => [a * 2, 'b']),
+      [2, 'ab']
+    )
   })
 
   it('chainRec', () => {
@@ -105,8 +108,14 @@ describe('Tuple', () => {
   })
 
   it('traverse', () => {
-    assert.deepStrictEqual(T.tuple.traverse(option)([2, 'a'], n => (n >= 2 ? some(n) : none)), some([2, 'a']))
-    assert.deepStrictEqual(T.tuple.traverse(option)([1, 'a'], n => (n >= 2 ? some(n) : none)), none)
+    assert.deepStrictEqual(
+      T.tuple.traverse(option)([2, 'a'], n => (n >= 2 ? some(n) : none)),
+      some([2, 'a'])
+    )
+    assert.deepStrictEqual(
+      T.tuple.traverse(option)([1, 'a'], n => (n >= 2 ? some(n) : none)),
+      none
+    )
   })
 
   it('sequence', () => {
diff --git a/test/Writer.ts b/test/Writer.ts
index 282824a6..9e367aec 100644
--- a/test/Writer.ts
+++ b/test/Writer.ts
@@ -6,11 +6,17 @@ import { pipe } from '../src/pipeable'
 
 describe('Writer', () => {
   it('evalWriter', () => {
-    assert.strictEqual(W.evalWriter(() => [1, 'a']), 1)
+    assert.strictEqual(
+      W.evalWriter(() => [1, 'a']),
+      1
+    )
   })
 
   it('execWriter', () => {
-    assert.strictEqual(W.execWriter(() => [1, 'a']), 'a')
+    assert.strictEqual(
+      W.execWriter(() => [1, 'a']),
+      'a'
+    )
   })
 
   it('map', () => {
diff --git a/test/boolean.ts b/test/boolean.ts
new file mode 100644
index 00000000..7a6fc378
--- /dev/null
+++ b/test/boolean.ts
@@ -0,0 +1,21 @@
+import * as assert from 'assert'
+import * as B from '../src/boolean'
+
+describe('boolean', () => {
+  it('fold', () => {
+    assert.strictEqual(
+      B.fold(
+        () => 'false',
+        () => 'true'
+      )(true),
+      'true'
+    )
+    assert.strictEqual(
+      B.fold(
+        () => 'false',
+        () => 'true'
+      )(false),
+      'false'
+    )
+  })
+})
diff --git a/test/function.ts b/test/function.ts
index 2a5a417c..3b82e46b 100644
--- a/test/function.ts
+++ b/test/function.ts
@@ -69,89 +69,13 @@ describe('function', () => {
 
   it('flow', () => {
     assert.strictEqual(flow(f)(2), 3)
-    assert.strictEqual(
-      flow(
-        f,
-        g
-      )(2),
-      6
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f
-      )(2),
-      7
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f,
-        g
-      )(2),
-      14
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f,
-        g,
-        f
-      )(2),
-      15
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f,
-        g,
-        f,
-        g
-      )(2),
-      30
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f
-      )(2),
-      31
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g
-      )(2),
-      62
-    )
-    assert.strictEqual(
-      flow(
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f
-      )(2),
-      63
-    )
+    assert.strictEqual(flow(f, g)(2), 6)
+    assert.strictEqual(flow(f, g, f)(2), 7)
+    assert.strictEqual(flow(f, g, f, g)(2), 14)
+    assert.strictEqual(flow(f, g, f, g, f)(2), 15)
+    assert.strictEqual(flow(f, g, f, g, f, g)(2), 30)
+    assert.strictEqual(flow(f, g, f, g, f, g, f)(2), 31)
+    assert.strictEqual(flow(f, g, f, g, f, g, f, g)(2), 62)
+    assert.strictEqual(flow(f, g, f, g, f, g, f, g, f)(2), 63)
   })
 })
diff --git a/test/pipeable.ts b/test/pipeable.ts
index b3e60eeb..c6698f80 100644
--- a/test/pipeable.ts
+++ b/test/pipeable.ts
@@ -44,8 +44,20 @@ describe('pipeable', () => {
 
   it('Bifunctor', () => {
     const { bimap, mapLeft } = pipeable(either)
-    assert.deepStrictEqual(bimap((s: string) => s.length, (n: number) => n * 2)(right(1)), right(2))
-    assert.deepStrictEqual(bimap((s: string) => s.length, (n: number) => n * 2)(left('aa')), left(2))
+    assert.deepStrictEqual(
+      bimap(
+        (s: string) => s.length,
+        (n: number) => n * 2
+      )(right(1)),
+      right(2)
+    )
+    assert.deepStrictEqual(
+      bimap(
+        (s: string) => s.length,
+        (n: number) => n * 2
+      )(left('aa')),
+      left(2)
+    )
     assert.deepStrictEqual(mapLeft((s: string) => s.length)(right(1)), right(1))
     assert.deepStrictEqual(mapLeft((s: string) => s.length)(left('aa')), left(2))
   })
@@ -110,7 +122,10 @@ describe('pipeable', () => {
 
   it('Profunctor', () => {
     const { promap } = pipeable(reader)
-    const f = promap((s: string) => s + 'a', (n: number) => n > 2)((s: string) => s.length)
+    const f = promap(
+      (s: string) => s + 'a',
+      (n: number) => n > 2
+    )((s: string) => s.length)
     assert.strictEqual(f('a'), false)
     assert.strictEqual(f('aa'), true)
   })
@@ -124,104 +139,14 @@ describe('pipeable', () => {
     const f = (n: number) => n + 1
     const g = (n: number) => n * 2
     assert.strictEqual(pipe(2), 2)
-    assert.strictEqual(
-      pipe(
-        2,
-        f
-      ),
-      3
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g
-      ),
-      6
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f
-      ),
-      7
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f,
-        g
-      ),
-      14
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f,
-        g,
-        f
-      ),
-      15
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g
-      ),
-      30
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f
-      ),
-      31
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g
-      ),
-      62
-    )
-    assert.strictEqual(
-      pipe(
-        2,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f,
-        g,
-        f
-      ),
-      63
-    )
+    assert.strictEqual(pipe(2, f), 3)
+    assert.strictEqual(pipe(2, f, g), 6)
+    assert.strictEqual(pipe(2, f, g, f), 7)
+    assert.strictEqual(pipe(2, f, g, f, g), 14)
+    assert.strictEqual(pipe(2, f, g, f, g, f), 15)
+    assert.strictEqual(pipe(2, f, g, f, g, f, g), 30)
+    assert.strictEqual(pipe(2, f, g, f, g, f, g, f), 31)
+    assert.strictEqual(pipe(2, f, g, f, g, f, g, f, g), 62)
+    assert.strictEqual(pipe(2, f, g, f, g, f, g, f, g, f), 63)
   })
 })