Repository: gcanti/fp-ts
Pull request #1244 (2020-06-16 16:18:09)

version 2.6.6


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fc87831..805e8e73 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,66 @@ high state of flux, you're at risk of it changing without notice.
 
 # 2.6.5
 
+- **Polish**
+  - `Array`
+    - export `unfold` (@gcanti)
+    - make `lookup` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+    - make `difference` data-last (@gcanti)
+    - make `intersection` data-last (@gcanti)
+    - make `union` data-last (@gcanti)
+    - make `zip` data-last (@gcanti)
+    - make `cons` data-last (@gcanti)
+  - `Map`
+    - make `member` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+    - make `lookup` data-last (@gcanti)
+    - make `lookupWithKey` data-last (@gcanti)
+    - make `isSubmap` data-last (@gcanti)
+  - `NonEmptyArray`
+    - make `zip` data-last (@gcanti)
+  - `ReadonlyArray`
+    - export `unfold` (@gcanti)
+    - make `lookup` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+    - make `difference` data-last (@gcanti)
+    - make `intersection` data-last (@gcanti)
+    - make `union` data-last (@gcanti)
+    - make `zip` data-last (@gcanti)
+    - make `cons` data-last (@gcanti)
+  - `ReadonlyMap`
+    - make `member` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+    - make `lookup` data-last (@gcanti)
+    - make `lookupWithKey` data-last (@gcanti)
+    - make `isSubmap` data-last (@gcanti)
+  - `ReadonlyNonEmptyArray`
+    - make `zip` data-last (@gcanti)
+  - `ReadonlyRecord`
+    - make `isSubrecord` data-last (@gcanti)
+    - make `lookup` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+  - `ReadonlySet`
+    - make `isSubset` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+    - make `union` data-last (@gcanti)
+    - make `intersection` data-last (@gcanti)
+    - make `difference` data-last (@gcanti)
+  - `Record`
+    - make `isSubrecord` data-last (@gcanti)
+    - make `lookup` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+  - `Set`
+    - make `subset` data-last (@gcanti)
+    - make `elem` data-last (@gcanti)
+    - make `union` data-last (@gcanti)
+    - make `intersection` data-last (@gcanti)
+    - make `difference` data-last (@gcanti)
+  - `Semigroup`
+    - make `fold` data-last (@gcanti)
+
+# 2.6.5
+
 - **Polish**
   - export a pipeable `wither` function from all modules which admit a `Witherable` instance (@gcanti)
   - export a pipeable `wilt` function from all modules which admit a `Witherable` instance (@gcanti)
diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md
index 23ec17c9..67f72b7d 100644
--- a/docs/modules/Array.ts.md
+++ b/docs/modules/Array.ts.md
@@ -50,6 +50,11 @@ Added in v2.0.0
   - [chain](#chain)
   - [chainFirst](#chainfirst)
   - [flatten](#flatten)
+- [Traversable](#traversable)
+  - [sequence](#sequence)
+  - [traverse](#traverse)
+- [TraversableWithIndex](#traversablewithindex)
+  - [traverseWithIndex](#traversewithindex)
 - [Whitherable](#whitherable)
   - [wilt](#wilt)
   - [wither](#wither)
@@ -74,9 +79,6 @@ Added in v2.0.0
   - [takeRight](#takeright)
   - [union](#union)
   - [uniq](#uniq)
-  - [unsafeDeleteAt](#unsafedeleteat)
-  - [unsafeInsertAt](#unsafeinsertat)
-  - [unsafeUpdateAt](#unsafeupdateat)
   - [zip](#zip)
   - [zipWith](#zipwith)
 - [constructors](#constructors)
@@ -108,6 +110,10 @@ Added in v2.0.0
   - [getMonoid](#getmonoid)
   - [getOrd](#getord)
   - [getShow](#getshow)
+- [unsafe](#unsafe)
+  - [unsafeDeleteAt](#unsafedeleteat)
+  - [unsafeInsertAt](#unsafeinsertat)
+  - [unsafeUpdateAt](#unsafeupdateat)
 - [utils](#utils)
   - [chunksOf](#chunksof)
   - [comprehension](#comprehension)
@@ -121,10 +127,8 @@ Added in v2.0.0
   - [isOutOfBound](#isoutofbound)
   - [lookup](#lookup)
   - [modifyAt](#modifyat)
-  - [sequence](#sequence)
   - [splitAt](#splitat)
-  - [traverse](#traverse)
-  - [traverseWithIndex](#traversewithindex)
+  - [unfold](#unfold)
   - [unzip](#unzip)
   - [updateAt](#updateat)
 
@@ -463,6 +467,40 @@ assert.deepStrictEqual(flatten([[1], [2], [3]]), [1, 2, 3])
 
 Added in v2.0.0
 
+# Traversable
+
+## sequence
+
+**Signature**
+
+```ts
+export declare const sequence: Sequence1<'Array'>
+```
+
+Added in v2.6.3
+
+## traverse
+
+**Signature**
+
+```ts
+export declare const traverse: PipeableTraverse1<'Array'>
+```
+
+Added in v2.6.3
+
+# TraversableWithIndex
+
+## traverseWithIndex
+
+**Signature**
+
+```ts
+export declare const traverseWithIndex: PipeableTraverseWithIndex1<'Array', number>
+```
+
+Added in v2.6.3
+
 # Whitherable
 
 ## wilt
@@ -534,7 +572,7 @@ comparisons. The order and references of result values are determined by the fir
 **Signature**
 
 ```ts
-export declare const difference: <A>(E: Eq<A>) => (xs: A[], ys: A[]) => A[]
+export declare const difference: <A>(E: Eq<A>) => { (xs: A[]): (ys: A[]) => A[]; (xs: A[], ys: A[]): A[] }
 ```
 
 **Example**
@@ -542,8 +580,9 @@ export declare const difference: <A>(E: Eq<A>) => (xs: A[], ys: A[]) => A[]
 ```ts
 import { difference } from 'fp-ts/lib/Array'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(difference(eqNumber)([1, 2], [2, 3]), [1])
+assert.deepStrictEqual(pipe([1, 2], difference(eqNumber)([2, 3])), [1])
 ```
 
 Added in v2.0.0
@@ -616,7 +655,7 @@ comparisons. The order and references of result values are determined by the fir
 **Signature**
 
 ```ts
-export declare const intersection: <A>(E: Eq<A>) => (xs: A[], ys: A[]) => A[]
+export declare const intersection: <A>(E: Eq<A>) => { (xs: A[]): (ys: A[]) => A[]; (xs: A[], ys: A[]): A[] }
 ```
 
 **Example**
@@ -624,8 +663,9 @@ export declare const intersection: <A>(E: Eq<A>) => (xs: A[], ys: A[]) => A[]
 ```ts
 import { intersection } from 'fp-ts/lib/Array'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(intersection(eqNumber)([1, 2], [2, 3]), [2])
+assert.deepStrictEqual(pipe([1, 2], intersection(eqNumber)([2, 3])), [2])
 ```
 
 Added in v2.0.0
@@ -883,7 +923,7 @@ Creates an array of unique values, in order, from all given arrays using a `Eq`
 **Signature**
 
 ```ts
-export declare const union: <A>(E: Eq<A>) => (xs: A[], ys: A[]) => A[]
+export declare const union: <A>(E: Eq<A>) => { (xs: A[]): (ys: A[]) => A[]; (xs: A[], ys: A[]): A[] }
 ```
 
 **Example**
@@ -891,8 +931,9 @@ export declare const union: <A>(E: Eq<A>) => (xs: A[], ys: A[]) => A[]
 ```ts
 import { union } from 'fp-ts/lib/Array'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(union(eqNumber)([1, 2], [2, 3]), [1, 2, 3])
+assert.deepStrictEqual(pipe([1, 2], union(eqNumber)([2, 3])), [1, 2, 3])
 ```
 
 Added in v2.0.0
@@ -918,36 +959,6 @@ assert.deepStrictEqual(uniq(eqNumber)([1, 2, 1]), [1, 2])
 
 Added in v2.0.0
 
-## unsafeDeleteAt
-
-**Signature**
-
-```ts
-export declare const unsafeDeleteAt: <A>(i: number, as: A[]) => A[]
-```
-
-Added in v2.0.0
-
-## unsafeInsertAt
-
-**Signature**
-
-```ts
-export declare const unsafeInsertAt: <A>(i: number, a: A, as: A[]) => A[]
-```
-
-Added in v2.0.0
-
-## unsafeUpdateAt
-
-**Signature**
-
-```ts
-export declare const unsafeUpdateAt: <A>(i: number, a: A, as: A[]) => A[]
-```
-
-Added in v2.0.0
-
 ## zip
 
 Takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
@@ -956,15 +967,16 @@ longer array are discarded
 **Signature**
 
 ```ts
-export declare const zip: <A, B>(fa: A[], fb: B[]) => [A, B][]
+export declare const zip: { <B>(bs: B[]): <A>(as: A[]) => [A, B][]; <A, B>(as: A[], bs: B[]): [A, B][] }
 ```
 
 **Example**
 
 ```ts
 import { zip } from 'fp-ts/lib/Array'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [
+assert.deepStrictEqual(pipe([1, 2, 3], zip(['a', 'b', 'c', 'd'])), [
   [1, 'a'],
   [2, 'b'],
   [3, 'c'],
@@ -1006,15 +1018,16 @@ Attaches an element to the front of an array, creating a new non empty array
 **Signature**
 
 ```ts
-export declare const cons: <A>(head: A, tail: A[]) => NonEmptyArray<A>
+export declare const cons: { <A>(head: A): (tail: A[]) => NonEmptyArray<A>; <A>(head: A, tail: A[]): NonEmptyArray<A> }
 ```
 
 **Example**
 
 ```ts
 import { cons } from 'fp-ts/lib/Array'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(cons(0, [1, 2, 3]), [0, 1, 2, 3])
+assert.deepStrictEqual(pipe([1, 2, 3], cons(0)), [0, 1, 2, 3])
 ```
 
 Added in v2.0.0
@@ -1515,6 +1528,38 @@ export declare const getShow: <A>(S: Show<A>) => Show<A[]>
 
 Added in v2.0.0
 
+# unsafe
+
+## unsafeDeleteAt
+
+**Signature**
+
+```ts
+export declare const unsafeDeleteAt: <A>(i: number, as: A[]) => A[]
+```
+
+Added in v2.0.0
+
+## unsafeInsertAt
+
+**Signature**
+
+```ts
+export declare const unsafeInsertAt: <A>(i: number, a: A, as: A[]) => A[]
+```
+
+Added in v2.0.0
+
+## unsafeUpdateAt
+
+**Signature**
+
+```ts
+export declare const unsafeUpdateAt: <A>(i: number, a: A, as: A[]) => A[]
+```
+
+Added in v2.0.0
+
 # utils
 
 ## chunksOf
@@ -1632,7 +1677,7 @@ an array of type `Array<A>`.
 **Signature**
 
 ```ts
-export declare const elem: <A>(E: Eq<A>) => (a: A, as: A[]) => boolean
+export declare const elem: <A>(E: Eq<A>) => { (a: A): (as: A[]) => boolean; (a: A, as: A[]): boolean }
 ```
 
 **Example**
@@ -1640,9 +1685,10 @@ export declare const elem: <A>(E: Eq<A>) => (a: A, as: A[]) => boolean
 ```ts
 import { elem } from 'fp-ts/lib/Array'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.strictEqual(elem(eqNumber)(1, [1, 2, 3]), true)
-assert.strictEqual(elem(eqNumber)(4, [1, 2, 3]), false)
+assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(2)), true)
+assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(0)), false)
 ```
 
 Added in v2.0.0
@@ -1771,7 +1817,7 @@ This function provides a safe way to read a value at a particular index from an
 **Signature**
 
 ```ts
-export declare const lookup: <A>(i: number, as: A[]) => Option<A>
+export declare const lookup: { (i: number): <A>(as: A[]) => Option<A>; <A>(i: number, as: A[]): Option<A> }
 ```
 
 **Example**
@@ -1779,9 +1825,10 @@ export declare const lookup: <A>(i: number, as: A[]) => Option<A>
 ```ts
 import { lookup } from 'fp-ts/lib/Array'
 import { some, none } from 'fp-ts/lib/Option'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(lookup(1, [1, 2, 3]), some(2))
-assert.deepStrictEqual(lookup(3, [1, 2, 3]), none)
+assert.deepStrictEqual(pipe([1, 2, 3], lookup(1)), some(2))
+assert.deepStrictEqual(pipe([1, 2, 3], lookup(3)), none)
 ```
 
 Added in v2.0.0
@@ -1810,16 +1857,6 @@ assert.deepStrictEqual(modifyAt(1, double)([]), none)
 
 Added in v2.0.0
 
-## sequence
-
-**Signature**
-
-```ts
-export declare const sequence: Sequence1<'Array'>
-```
-
-Added in v2.6.3
-
 ## splitAt
 
 Splits an array into two pieces, the first piece has `n` elements.
@@ -1843,25 +1880,15 @@ assert.deepStrictEqual(splitAt(2)([1, 2, 3, 4, 5]), [
 
 Added in v2.0.0
 
-## traverse
-
-**Signature**
-
-```ts
-export declare const traverse: PipeableTraverse1<'Array'>
-```
-
-Added in v2.6.3
-
-## traverseWithIndex
+## unfold
 
 **Signature**
 
 ```ts
-export declare const traverseWithIndex: PipeableTraverseWithIndex1<'Array', number>
+export declare const unfold: <A, B>(b: B, f: (b: B) => Option<readonly [A, B]>) => A[]
 ```
 
-Added in v2.6.3
+Added in v2.6.6
 
 ## unzip
 
diff --git a/docs/modules/Map.ts.md b/docs/modules/Map.ts.md
index 072fb0e5..0dc461bc 100644
--- a/docs/modules/Map.ts.md
+++ b/docs/modules/Map.ts.md
@@ -303,7 +303,7 @@ Test whether or not a value is a member of a map
 **Signature**
 
 ```ts
-export declare const elem: <A>(E: Eq<A>) => <K>(a: A, m: Map<K, A>) => boolean
+export declare const elem: <A>(E: Eq<A>) => { (a: A): <K>(m: Map<K, A>) => boolean; <K>(a: A, m: Map<K, A>): boolean }
 ```
 
 Added in v2.0.0
@@ -332,12 +332,15 @@ Added in v2.0.0
 
 ## isSubmap
 
-Test whether or not one Map contains all of the keys and values contained in another Map
+Test whether or not one `Map` contains all of the keys and values contained in another `Map`
 
 **Signature**
 
 ```ts
-export declare const isSubmap: <K, A>(SK: Eq<K>, SA: Eq<A>) => (d1: Map<K, A>, d2: Map<K, A>) => boolean
+export declare const isSubmap: <K, A>(
+  SK: Eq<K>,
+  SA: Eq<A>
+) => { (that: Map<K, A>): (me: Map<K, A>) => boolean; (me: Map<K, A>, that: Map<K, A>): boolean }
 ```
 
 Added in v2.0.0
@@ -361,7 +364,9 @@ Lookup the value for a key in a `Map`.
 **Signature**
 
 ```ts
-export declare const lookup: <K>(E: Eq<K>) => <A>(k: K, m: Map<K, A>) => Option<A>
+export declare const lookup: <K>(
+  E: Eq<K>
+) => { (k: K): <A>(m: Map<K, A>) => Option<A>; <A>(k: K, m: Map<K, A>): Option<A> }
 ```
 
 Added in v2.0.0
@@ -374,7 +379,9 @@ If the result is a `Some`, the existing key is also returned.
 **Signature**
 
 ```ts
-export declare const lookupWithKey: <K>(E: Eq<K>) => <A>(k: K, m: Map<K, A>) => Option<[K, A]>
+export declare const lookupWithKey: <K>(
+  E: Eq<K>
+) => { (k: K): <A>(m: Map<K, A>) => Option<[K, A]>; <A>(k: K, m: Map<K, A>): Option<[K, A]> }
 ```
 
 Added in v2.0.0
@@ -386,7 +393,7 @@ Test whether or not a key exists in a map
 **Signature**
 
 ```ts
-export declare const member: <K>(E: Eq<K>) => <A>(k: K, m: Map<K, A>) => boolean
+export declare const member: <K>(E: Eq<K>) => { (k: K): <A>(m: Map<K, A>) => boolean; <A>(k: K, m: Map<K, A>): boolean }
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/NonEmptyArray.ts.md b/docs/modules/NonEmptyArray.ts.md
index df5f9283..5fe96edd 100644
--- a/docs/modules/NonEmptyArray.ts.md
+++ b/docs/modules/NonEmptyArray.ts.md
@@ -398,7 +398,10 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const zip: <A, B>(fa: NonEmptyArray<A>, fb: NonEmptyArray<B>) => NonEmptyArray<[A, B]>
+export declare const zip: {
+  <B>(bs: NonEmptyArray<B>): <A>(as: NonEmptyArray<A>) => NonEmptyArray<[A, B]>
+  <A, B>(as: NonEmptyArray<A>, bs: NonEmptyArray<B>): NonEmptyArray<[A, B]>
+}
 ```
 
 Added in v2.5.1
diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md
index 97253a63..db6f7aed 100644
--- a/docs/modules/ReadonlyArray.ts.md
+++ b/docs/modules/ReadonlyArray.ts.md
@@ -50,6 +50,11 @@ Added in v2.5.0
   - [chain](#chain)
   - [chainFirst](#chainfirst)
   - [flatten](#flatten)
+- [Traversable](#traversable)
+  - [sequence](#sequence)
+  - [traverse](#traverse)
+- [TraversableWithIndex](#traversablewithindex)
+  - [traverseWithIndex](#traversewithindex)
 - [Whitherable](#whitherable)
   - [wilt](#wilt)
   - [wither](#wither)
@@ -71,8 +76,6 @@ Added in v2.5.0
   - [takeLeftWhile](#takeleftwhile)
   - [union](#union)
   - [uniq](#uniq)
-  - [unsafeDeleteAt](#unsafedeleteat)
-  - [unsafeUpdateAt](#unsafeupdateat)
   - [zip](#zip)
   - [zipWith](#zipwith)
 - [constructors](#constructors)
@@ -96,6 +99,10 @@ Added in v2.5.0
   - [getOrd](#getord)
   - [getShow](#getshow)
   - [readonlyArray](#readonlyarray)
+- [unsafe](#unsafe)
+  - [unsafeDeleteAt](#unsafedeleteat)
+  - [unsafeInsertAt](#unsafeinsertat)
+  - [unsafeUpdateAt](#unsafeupdateat)
 - [utils](#utils)
   - [Spanned (interface)](#spanned-interface)
   - [chunksOf](#chunksof)
@@ -119,14 +126,11 @@ Added in v2.5.0
   - [lookup](#lookup)
   - [modifyAt](#modifyat)
   - [of](#of)
-  - [sequence](#sequence)
   - [spanLeft](#spanleft)
   - [splitAt](#splitat)
   - [tail](#tail)
   - [takeRight](#takeright)
-  - [traverse](#traverse)
-  - [traverseWithIndex](#traversewithindex)
-  - [unsafeInsertAt](#unsafeinsertat)
+  - [unfold](#unfold)
   - [unzip](#unzip)
   - [updateAt](#updateat)
 
@@ -469,6 +473,40 @@ assert.deepStrictEqual(flatten([[1], [2], [3]]), [1, 2, 3])
 
 Added in v2.5.0
 
+# Traversable
+
+## sequence
+
+**Signature**
+
+```ts
+export declare const sequence: Sequence1<'ReadonlyArray'>
+```
+
+Added in v2.6.3
+
+## traverse
+
+**Signature**
+
+```ts
+export declare const traverse: PipeableTraverse1<'ReadonlyArray'>
+```
+
+Added in v2.6.3
+
+# TraversableWithIndex
+
+## traverseWithIndex
+
+**Signature**
+
+```ts
+export declare const traverseWithIndex: PipeableTraverseWithIndex1<'ReadonlyArray', number>
+```
+
+Added in v2.6.3
+
 # Whitherable
 
 ## wilt
@@ -502,9 +540,9 @@ value and the rest of the array.
 **Signature**
 
 ```ts
-export declare function chop<A, B>(
-  f: (as: ReadonlyNonEmptyArray<A>) => readonly [B, ReadonlyArray<A>]
-): (as: ReadonlyArray<A>) => ReadonlyArray<B>
+export declare const chop: <A, B>(
+  f: (as: ReadonlyNonEmptyArray<A>) => readonly [B, readonly A[]]
+) => (as: readonly A[]) => readonly B[]
 ```
 
 **Example**
@@ -532,7 +570,12 @@ comparisons. The order and references of result values are determined by the fir
 **Signature**
 
 ```ts
-export declare function difference<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>) => ReadonlyArray<A>
+export declare function difference<A>(
+  E: Eq<A>
+): {
+  (xs: ReadonlyArray<A>): (ys: ReadonlyArray<A>) => ReadonlyArray<A>
+  (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>): ReadonlyArray<A>
+}
 ```
 
 **Example**
@@ -540,8 +583,9 @@ export declare function difference<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: Read
 ```ts
 import { difference } from 'fp-ts/lib/ReadonlyArray'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(difference(eqNumber)([1, 2], [2, 3]), [1])
+assert.deepStrictEqual(pipe([1, 2], difference(eqNumber)([2, 3])), [1])
 ```
 
 Added in v2.5.0
@@ -614,7 +658,12 @@ comparisons. The order and references of result values are determined by the fir
 **Signature**
 
 ```ts
-export declare function intersection<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>) => ReadonlyArray<A>
+export declare function intersection<A>(
+  E: Eq<A>
+): {
+  (xs: ReadonlyArray<A>): (ys: ReadonlyArray<A>) => ReadonlyArray<A>
+  (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>): ReadonlyArray<A>
+}
 ```
 
 **Example**
@@ -622,8 +671,9 @@ export declare function intersection<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: Re
 ```ts
 import { intersection } from 'fp-ts/lib/ReadonlyArray'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(intersection(eqNumber)([1, 2], [2, 3]), [2])
+assert.deepStrictEqual(pipe([1, 2], intersection(eqNumber)([2, 3])), [2])
 ```
 
 Added in v2.5.0
@@ -841,7 +891,12 @@ Creates an array of unique values, in order, from all given arrays using a `Eq`
 **Signature**
 
 ```ts
-export declare function union<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>) => ReadonlyArray<A>
+export declare function union<A>(
+  E: Eq<A>
+): {
+  (xs: ReadonlyArray<A>): (ys: ReadonlyArray<A>) => ReadonlyArray<A>
+  (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>): ReadonlyArray<A>
+}
 ```
 
 **Example**
@@ -849,8 +904,9 @@ export declare function union<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyA
 ```ts
 import { union } from 'fp-ts/lib/ReadonlyArray'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(union(eqNumber)([1, 2], [2, 3]), [1, 2, 3])
+assert.deepStrictEqual(pipe([1, 2], union(eqNumber)([2, 3])), [1, 2, 3])
 ```
 
 Added in v2.5.0
@@ -876,26 +932,6 @@ assert.deepStrictEqual(uniq(eqNumber)([1, 2, 1]), [1, 2])
 
 Added in v2.5.0
 
-## unsafeDeleteAt
-
-**Signature**
-
-```ts
-export declare function unsafeDeleteAt<A>(i: number, as: ReadonlyArray<A>): ReadonlyArray<A>
-```
-
-Added in v2.5.0
-
-## unsafeUpdateAt
-
-**Signature**
-
-```ts
-export declare function unsafeUpdateAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A>
-```
-
-Added in v2.5.0
-
 ## zip
 
 Takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
@@ -904,15 +940,17 @@ longer array are discarded
 **Signature**
 
 ```ts
-export declare function zip<A, B>(fa: ReadonlyArray<A>, fb: ReadonlyArray<B>): ReadonlyArray<readonly [A, B]>
+export declare function zip<B>(bs: ReadonlyArray<B>): <A>(as: ReadonlyArray<A>) => ReadonlyArray<readonly [A, B]>
+export declare function zip<A, B>(as: ReadonlyArray<A>, bs: ReadonlyArray<B>): ReadonlyArray<readonly [A, B]>
 ```
 
 **Example**
 
 ```ts
 import { zip } from 'fp-ts/lib/ReadonlyArray'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [
+assert.deepStrictEqual(pipe([1, 2, 3], zip(['a', 'b', 'c', 'd'])), [
   [1, 'a'],
   [2, 'b'],
   [3, 'c'],
@@ -958,6 +996,7 @@ Attaches an element to the front of an array, creating a new non empty array
 **Signature**
 
 ```ts
+export declare function cons<A>(head: A): (tail: ReadonlyArray<A>) => ReadonlyNonEmptyArray<A>
 export declare function cons<A>(head: A, tail: ReadonlyArray<A>): ReadonlyNonEmptyArray<A>
 ```
 
@@ -965,8 +1004,9 @@ export declare function cons<A>(head: A, tail: ReadonlyArray<A>): ReadonlyNonEmp
 
 ```ts
 import { cons } from 'fp-ts/lib/ReadonlyArray'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(cons(0, [1, 2, 3]), [0, 1, 2, 3])
+assert.deepStrictEqual(pipe([1, 2, 3], cons(0)), [0, 1, 2, 3])
 ```
 
 Added in v2.5.0
@@ -1254,6 +1294,38 @@ export declare const readonlyArray: Monad1<'ReadonlyArray'> &
 
 Added in v2.5.0
 
+# unsafe
+
+## unsafeDeleteAt
+
+**Signature**
+
+```ts
+export declare function unsafeDeleteAt<A>(i: number, as: ReadonlyArray<A>): ReadonlyArray<A>
+```
+
+Added in v2.5.0
+
+## unsafeInsertAt
+
+**Signature**
+
+```ts
+export declare function unsafeInsertAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A>
+```
+
+Added in v2.5.0
+
+## unsafeUpdateAt
+
+**Signature**
+
+```ts
+export declare function unsafeUpdateAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A>
+```
+
+Added in v2.5.0
+
 # utils
 
 ## Spanned (interface)
@@ -1392,7 +1464,12 @@ an array of type `ReadonlyArray<A>`.
 **Signature**
 
 ```ts
-export declare function elem<A>(E: Eq<A>): (a: A, as: ReadonlyArray<A>) => boolean
+export declare function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): (as: ReadonlyArray<A>) => boolean
+  (a: A, as: ReadonlyArray<A>): boolean
+}
 ```
 
 **Example**
@@ -1400,9 +1477,10 @@ export declare function elem<A>(E: Eq<A>): (a: A, as: ReadonlyArray<A>) => boole
 ```ts
 import { elem } from 'fp-ts/lib/ReadonlyArray'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.strictEqual(elem(eqNumber)(1, [1, 2, 3]), true)
-assert.strictEqual(elem(eqNumber)(4, [1, 2, 3]), false)
+assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(2)), true)
+assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(0)), false)
 ```
 
 Added in v2.5.0
@@ -1732,6 +1810,7 @@ This function provides a safe way to read a value at a particular index from an
 **Signature**
 
 ```ts
+export declare function lookup(i: number): <A>(as: ReadonlyArray<A>) => Option<A>
 export declare function lookup<A>(i: number, as: ReadonlyArray<A>): Option<A>
 ```
 
@@ -1740,9 +1819,10 @@ export declare function lookup<A>(i: number, as: ReadonlyArray<A>): Option<A>
 ```ts
 import { lookup } from 'fp-ts/lib/ReadonlyArray'
 import { some, none } from 'fp-ts/lib/Option'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(lookup(1, [1, 2, 3]), some(2))
-assert.deepStrictEqual(lookup(3, [1, 2, 3]), none)
+assert.deepStrictEqual(pipe([1, 2, 3], lookup(1)), some(2))
+assert.deepStrictEqual(pipe([1, 2, 3], lookup(3)), none)
 ```
 
 Added in v2.5.0
@@ -1781,16 +1861,6 @@ export declare const of: <A>(a: A) => readonly A[]
 
 Added in v2.5.0
 
-## sequence
-
-**Signature**
-
-```ts
-export declare const sequence: Sequence1<'ReadonlyArray'>
-```
-
-Added in v2.6.3
-
 ## spanLeft
 
 Split an array into two parts:
@@ -1881,35 +1951,15 @@ assert.deepStrictEqual(takeRight(2)([1, 2, 3, 4, 5]), [4, 5])
 
 Added in v2.5.0
 
-## traverse
+## unfold
 
 **Signature**
 
 ```ts
-export declare const traverse: PipeableTraverse1<'ReadonlyArray'>
+export declare const unfold: <A, B>(b: B, f: (b: B) => Option<readonly [A, B]>) => readonly A[]
 ```
 
-Added in v2.6.3
-
-## traverseWithIndex
-
-**Signature**
-
-```ts
-export declare const traverseWithIndex: PipeableTraverseWithIndex1<'ReadonlyArray', number>
-```
-
-Added in v2.6.3
-
-## unsafeInsertAt
-
-**Signature**
-
-```ts
-export declare function unsafeInsertAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A>
-```
-
-Added in v2.5.0
+Added in v2.6.6
 
 ## unzip
 
diff --git a/docs/modules/ReadonlyMap.ts.md b/docs/modules/ReadonlyMap.ts.md
index 44263424..c25305cd 100644
--- a/docs/modules/ReadonlyMap.ts.md
+++ b/docs/modules/ReadonlyMap.ts.md
@@ -381,7 +381,12 @@ Test whether or not a value is a member of a map
 **Signature**
 
 ```ts
-export declare function elem<A>(E: Eq<A>): <K>(a: A, m: ReadonlyMap<K, A>) => boolean
+export declare function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): <K>(m: ReadonlyMap<K, A>) => boolean
+  <K>(a: A, m: ReadonlyMap<K, A>): boolean
+}
 ```
 
 Added in v2.5.0
@@ -410,12 +415,18 @@ Added in v2.5.0
 
 ## isSubmap
 
-Test whether or not one Map contains all of the keys and values contained in another Map
+Test whether or not one `Map` contains all of the keys and values contained in another `Map`
 
 **Signature**
 
 ```ts
-export declare function isSubmap<K, A>(SK: Eq<K>, SA: Eq<A>): (d1: ReadonlyMap<K, A>, d2: ReadonlyMap<K, A>) => boolean
+export declare function isSubmap<K, A>(
+  SK: Eq<K>,
+  SA: Eq<A>
+): {
+  (that: ReadonlyMap<K, A>): (me: ReadonlyMap<K, A>) => boolean
+  (me: ReadonlyMap<K, A>, that: ReadonlyMap<K, A>): boolean
+}
 ```
 
 Added in v2.5.0
@@ -439,7 +450,12 @@ Lookup the value for a key in a `Map`.
 **Signature**
 
 ```ts
-export declare function lookup<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => Option<A>
+export declare function lookup<K>(
+  E: Eq<K>
+): {
+  (k: K): <A>(m: ReadonlyMap<K, A>) => Option<A>
+  <A>(k: K, m: ReadonlyMap<K, A>): Option<A>
+}
 ```
 
 Added in v2.5.0
@@ -452,7 +468,12 @@ If the result is a `Some`, the existing key is also returned.
 **Signature**
 
 ```ts
-export declare function lookupWithKey<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => Option<readonly [K, A]>
+export declare function lookupWithKey<K>(
+  E: Eq<K>
+): {
+  (k: K): <A>(m: ReadonlyMap<K, A>) => Option<readonly [K, A]>
+  <A>(k: K, m: ReadonlyMap<K, A>): Option<readonly [K, A]>
+}
 ```
 
 Added in v2.5.0
@@ -464,7 +485,12 @@ Test whether or not a key exists in a map
 **Signature**
 
 ```ts
-export declare function member<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => boolean
+export declare function member<K>(
+  E: Eq<K>
+): {
+  (k: K): <A>(m: ReadonlyMap<K, A>) => boolean
+  <A>(k: K, m: ReadonlyMap<K, A>): boolean
+}
 ```
 
 Added in v2.5.0
diff --git a/docs/modules/ReadonlyNonEmptyArray.ts.md b/docs/modules/ReadonlyNonEmptyArray.ts.md
index 4e4211a8..07a70a78 100644
--- a/docs/modules/ReadonlyNonEmptyArray.ts.md
+++ b/docs/modules/ReadonlyNonEmptyArray.ts.md
@@ -395,10 +395,10 @@ Added in v2.5.0
 **Signature**
 
 ```ts
-export declare const zip: <A, B>(
-  fa: ReadonlyNonEmptyArray<A>,
-  fb: ReadonlyNonEmptyArray<B>
-) => ReadonlyNonEmptyArray<readonly [A, B]>
+export declare const zip: {
+  <B>(bs: ReadonlyNonEmptyArray<B>): <A>(as: ReadonlyNonEmptyArray<A>) => ReadonlyNonEmptyArray<readonly [A, B]>
+  <A, B>(as: ReadonlyNonEmptyArray<A>, bs: ReadonlyNonEmptyArray<B>): ReadonlyNonEmptyArray<readonly [A, B]>
+}
 ```
 
 Added in v2.5.1
diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md
index b127c6e0..96636352 100644
--- a/docs/modules/ReadonlyRecord.ts.md
+++ b/docs/modules/ReadonlyRecord.ts.md
@@ -469,7 +469,12 @@ Added in v2.5.0
 **Signature**
 
 ```ts
-export declare function elem<A>(E: Eq<A>): (a: A, fa: ReadonlyRecord<string, A>) => boolean
+export declare function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): (fa: ReadonlyRecord<string, A>) => boolean
+  (a: A, fa: ReadonlyRecord<string, A>): boolean
+}
 ```
 
 Added in v2.5.0
@@ -647,7 +652,10 @@ Test whether one record contains all of the keys and values contained in another
 ```ts
 export declare function isSubrecord<A>(
   E: Eq<A>
-): (x: ReadonlyRecord<string, A>, y: ReadonlyRecord<string, A>) => boolean
+): {
+  (that: ReadonlyRecord<string, A>): (me: ReadonlyRecord<string, A>) => boolean
+  (me: ReadonlyRecord<string, A>, that: ReadonlyRecord<string, A>): boolean
+}
 ```
 
 Added in v2.5.0
@@ -669,6 +677,7 @@ Lookup the value for a key in a record
 **Signature**
 
 ```ts
+export declare function lookup(k: string): <A>(r: ReadonlyRecord<string, A>) => Option<A>
 export declare function lookup<A>(k: string, r: ReadonlyRecord<string, A>): Option<A>
 ```
 
diff --git a/docs/modules/ReadonlySet.ts.md b/docs/modules/ReadonlySet.ts.md
index f4941a84..a57e43c8 100644
--- a/docs/modules/ReadonlySet.ts.md
+++ b/docs/modules/ReadonlySet.ts.md
@@ -78,7 +78,12 @@ Form the set difference (`x` - `y`)
 **Signature**
 
 ```ts
-export declare function difference<A>(E: Eq<A>): (x: ReadonlySet<A>, y: ReadonlySet<A>) => ReadonlySet<A>
+export declare function difference<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => ReadonlySet<A>
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): ReadonlySet<A>
+}
 ```
 
 **Example**
@@ -86,8 +91,9 @@ export declare function difference<A>(E: Eq<A>): (x: ReadonlySet<A>, y: Readonly
 ```ts
 import { difference } from 'fp-ts/lib/ReadonlySet'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(difference(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+assert.deepStrictEqual(pipe(new Set([1, 2]), difference(eqNumber)(new Set([1, 3]))), new Set([2]))
 ```
 
 Added in v2.5.0
@@ -132,7 +138,12 @@ The set of elements which are in both the first and second set
 **Signature**
 
 ```ts
-export declare function intersection<A>(E: Eq<A>): (set: ReadonlySet<A>, y: ReadonlySet<A>) => ReadonlySet<A>
+export declare function intersection<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => ReadonlySet<A>
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): ReadonlySet<A>
+}
 ```
 
 Added in v2.5.0
@@ -168,7 +179,12 @@ Form the union of two sets
 **Signature**
 
 ```ts
-export declare function union<A>(E: Eq<A>): (set: ReadonlySet<A>, y: ReadonlySet<A>) => ReadonlySet<A>
+export declare function union<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => ReadonlySet<A>
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): ReadonlySet<A>
+}
 ```
 
 Added in v2.5.0
@@ -282,7 +298,12 @@ Test if a value is a member of a set
 **Signature**
 
 ```ts
-export declare function elem<A>(E: Eq<A>): (a: A, set: ReadonlySet<A>) => boolean
+export declare function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): (set: ReadonlySet<A>) => boolean
+  (a: A, set: ReadonlySet<A>): boolean
+}
 ```
 
 Added in v2.5.0
@@ -324,7 +345,12 @@ Added in v2.5.0
 **Signature**
 
 ```ts
-export declare function isSubset<A>(E: Eq<A>): (x: ReadonlySet<A>, y: ReadonlySet<A>) => boolean
+export declare function isSubset<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => boolean
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): boolean
+}
 ```
 
 Added in v2.5.0
diff --git a/docs/modules/Record.ts.md b/docs/modules/Record.ts.md
index 2028e5de..45716a6e 100644
--- a/docs/modules/Record.ts.md
+++ b/docs/modules/Record.ts.md
@@ -268,7 +268,9 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const elem: <A>(E: Eq<A>) => (a: A, fa: Record<string, A>) => boolean
+export declare const elem: <A>(
+  E: Eq<A>
+) => { (a: A): (fa: Record<string, A>) => boolean; (a: A, fa: Record<string, A>): boolean }
 ```
 
 Added in v2.0.0
@@ -511,7 +513,12 @@ Test whether one record contains all of the keys and values contained in another
 **Signature**
 
 ```ts
-export declare const isSubrecord: <A>(E: Eq<A>) => (x: Record<string, A>, y: Record<string, A>) => boolean
+export declare const isSubrecord: <A>(
+  E: Eq<A>
+) => {
+  (that: Record<string, A>): (me: Record<string, A>) => boolean
+  (me: Record<string, A>, that: Record<string, A>): boolean
+}
 ```
 
 Added in v2.0.0
@@ -533,7 +540,10 @@ Lookup the value for a key in a record
 **Signature**
 
 ```ts
-export declare const lookup: <A>(k: string, r: Record<string, A>) => Option<A>
+export declare const lookup: {
+  (k: string): <A>(r: Record<string, A>) => Option<A>
+  <A>(k: string, r: Record<string, A>): Option<A>
+}
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/Semigroup.ts.md b/docs/modules/Semigroup.ts.md
index 41dee204..e2f79f26 100644
--- a/docs/modules/Semigroup.ts.md
+++ b/docs/modules/Semigroup.ts.md
@@ -286,7 +286,22 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare function fold<A>(S: Semigroup<A>): (a: A, as: ReadonlyArray<A>) => A
+export declare function fold<A>(
+  S: Semigroup<A>
+): {
+  (a: A): (as: ReadonlyArray<A>) => A
+  (a: A, as: ReadonlyArray<A>): A
+}
+```
+
+**Example**
+
+```ts
+import * as S from 'fp-ts/lib/Semigroup'
+
+const sum = S.fold(S.semigroupSum)(0)
+
+assert.deepStrictEqual(sum([1, 2, 3]), 6)
 ```
 
 Added in v2.0.0
diff --git a/docs/modules/Set.ts.md b/docs/modules/Set.ts.md
index b87a1968..75330f57 100644
--- a/docs/modules/Set.ts.md
+++ b/docs/modules/Set.ts.md
@@ -76,7 +76,9 @@ Form the set difference (`x` - `y`)
 **Signature**
 
 ```ts
-export declare const difference: <A>(E: Eq<A>) => (x: Set<A>, y: Set<A>) => Set<A>
+export declare const difference: <A>(
+  E: Eq<A>
+) => { (that: Set<A>): (me: Set<A>) => Set<A>; (me: Set<A>, that: Set<A>): Set<A> }
 ```
 
 **Example**
@@ -84,8 +86,9 @@ export declare const difference: <A>(E: Eq<A>) => (x: Set<A>, y: Set<A>) => Set<
 ```ts
 import { difference } from 'fp-ts/lib/Set'
 import { eqNumber } from 'fp-ts/lib/Eq'
+import { pipe } from 'fp-ts/lib/function'
 
-assert.deepStrictEqual(difference(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+assert.deepStrictEqual(pipe(new Set([1, 2]), difference(eqNumber)(new Set([1, 3]))), new Set([2]))
 ```
 
 Added in v2.0.0
@@ -130,7 +133,9 @@ The set of elements which are in both the first and second set
 **Signature**
 
 ```ts
-export declare const intersection: <A>(E: Eq<A>) => (set: Set<A>, y: Set<A>) => Set<A>
+export declare const intersection: <A>(
+  E: Eq<A>
+) => { (that: Set<A>): (me: Set<A>) => Set<A>; (me: Set<A>, that: Set<A>): Set<A> }
 ```
 
 Added in v2.0.0
@@ -181,7 +186,9 @@ Form the union of two sets
 **Signature**
 
 ```ts
-export declare const union: <A>(E: Eq<A>) => (set: Set<A>, y: Set<A>) => Set<A>
+export declare const union: <A>(
+  E: Eq<A>
+) => { (that: Set<A>): (me: Set<A>) => Set<A>; (me: Set<A>, that: Set<A>): Set<A> }
 ```
 
 Added in v2.0.0
@@ -273,7 +280,7 @@ Test if a value is a member of a set
 **Signature**
 
 ```ts
-export declare const elem: <A>(E: Eq<A>) => (a: A, set: Set<A>) => boolean
+export declare const elem: <A>(E: Eq<A>) => { (a: A): (set: Set<A>) => boolean; (a: A, set: Set<A>): boolean }
 ```
 
 Added in v2.0.0
@@ -371,7 +378,9 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const subset: <A>(E: Eq<A>) => (x: Set<A>, y: Set<A>) => boolean
+export declare const subset: <A>(
+  E: Eq<A>
+) => { (that: Set<A>): (me: Set<A>) => boolean; (me: Set<A>, that: Set<A>): boolean }
 ```
 
 Added in v2.0.0
diff --git a/dtslint/ts3.5/Array.ts b/dtslint/ts3.5/Array.ts
index f0767f5f..320bf974 100644
--- a/dtslint/ts3.5/Array.ts
+++ b/dtslint/ts3.5/Array.ts
@@ -1,5 +1,6 @@
 import * as _ from '../../src/Array'
 import { pipe } from '../../src/pipeable'
+import { eqNumber } from '../../src/Eq'
 
 declare const us: Array<unknown>
 declare const ns: Array<number>
@@ -83,3 +84,52 @@ pipe(
   us,
   _.spanLeft((u: unknown): u is number => typeof u === 'number')
 )
+
+//
+// lookup
+//
+
+_.lookup(0, [1, 2, 3]) // $ExpectType Option<number>
+_.lookup(0) // $ExpectType <A>(as: A[]) => Option<A>
+
+//
+// elem
+//
+
+_.elem(eqNumber)(1, [1, 2, 3]) // $ExpectType boolean
+_.elem(eqNumber)(1) // $ExpectType (as: number[]) => boolean
+
+//
+// difference
+//
+
+_.difference(eqNumber)([1, 2], [3, 4]) // $ExpectType number[]
+_.difference(eqNumber)([3, 4]) // $ExpectType (ys: number[]) => number[]
+
+//
+// intersection
+//
+
+_.intersection(eqNumber)([1, 2], [3, 4]) // $ExpectType number[]
+_.intersection(eqNumber)([3, 4]) // $ExpectType (ys: number[]) => number[]
+
+//
+// union
+//
+
+_.union(eqNumber)([1, 2], [3, 4]) // $ExpectType number[]
+_.union(eqNumber)([3, 4]) // $ExpectType (ys: number[]) => number[]
+
+//
+// zip
+//
+
+_.zip([1, 2], ['a', 'b']) // $ExpectType [number, string][]
+_.zip(['a', 'b']) // $ExpectType <A>(as: A[]) => [A, string][]
+
+//
+// cons
+//
+
+_.cons(0, [1, 2]) // $ExpectType NonEmptyArray<number>
+_.cons(0) // $ExpectType (tail: number[]) => NonEmptyArray<number>
diff --git a/dtslint/ts3.5/Map.ts b/dtslint/ts3.5/Map.ts
index e61776aa..d394453a 100644
--- a/dtslint/ts3.5/Map.ts
+++ b/dtslint/ts3.5/Map.ts
@@ -1,4 +1,5 @@
 import * as _ from '../../src/Map'
+import { eqString, eqNumber } from '../../src/Eq'
 
 //
 // FilterableWithIndex overloadings
@@ -10,3 +11,38 @@ declare function isStringWithKey(i: 'a' | 'b', x: unknown): x is string
 
 FWI.filterWithIndex(_.empty as Map<'a' | 'b', string | number>, isStringWithKey) // $ExpectType Map<"a" | "b", string>
 FWI.partitionWithIndex(_.empty as Map<'a' | 'b', string | number>, isStringWithKey) // $ExpectType Separated<Map<"a" | "b", string | number>, Map<"a" | "b", string>>
+
+//
+// member
+//
+
+_.member(eqString)('a', new Map()) // $ExpectType boolean
+_.member(eqString)('a') // $ExpectType <A>(m: Map<string, A>) => boolean
+
+//
+// elem
+//
+
+_.elem(eqString)('a', new Map()) // $ExpectType boolean
+_.elem(eqString)('a') // $ExpectType <K>(m: Map<K, string>) => boolean
+
+//
+// lookup
+//
+
+_.lookup(eqString)('a', new Map([['a', 1]])) // $ExpectType Option<number>
+_.lookup(eqString)('a') // $ExpectType <A>(m: Map<string, A>) => Option<A>
+
+//
+// lookupWithKey
+//
+
+_.lookupWithKey(eqString)('a', new Map([['a', 1]])) // $ExpectType Option<[string, number]>
+_.lookupWithKey(eqString)('a') // $ExpectType <A>(m: Map<string, A>) => Option<[string, A]>
+
+//
+// isSubmap
+//
+
+_.isSubmap(eqString, eqNumber)(new Map([['a', 1]]), new Map([['a', 1]])) // $ExpectType boolean
+_.isSubmap(eqString, eqNumber)(new Map([['a', 1]])) // $ExpectType (me: Map<string, number>) => boolean
diff --git a/dtslint/ts3.5/NonEmptyArray.ts b/dtslint/ts3.5/NonEmptyArray.ts
index 32787977..3b25df90 100644
--- a/dtslint/ts3.5/NonEmptyArray.ts
+++ b/dtslint/ts3.5/NonEmptyArray.ts
@@ -13,6 +13,7 @@ declare const netns: _.NonEmptyArray<[number, string]>
 //
 
 _.zip(nens, neas) // $ExpectType NonEmptyArray<[number, string]>
+_.zip(neas) // $ExpectType <A>(as: NonEmptyArray<A>) => NonEmptyArray<[A, string]>
 
 //
 // zipWith
diff --git a/dtslint/ts3.5/ReadonlyArray.ts b/dtslint/ts3.5/ReadonlyArray.ts
index 1af40c9a..cc6ffc52 100644
--- a/dtslint/ts3.5/ReadonlyArray.ts
+++ b/dtslint/ts3.5/ReadonlyArray.ts
@@ -1,5 +1,6 @@
 import * as _ from '../../src/ReadonlyArray'
 import { pipe } from '../../src/pipeable'
+import { eqNumber } from '../../src/Eq'
 
 declare const rus: ReadonlyArray<unknown>
 declare const rns: ReadonlyArray<number>
@@ -74,3 +75,52 @@ pipe(
   rus,
   _.spanLeft((u: unknown): u is number => typeof u === 'number')
 )
+
+//
+// lookup
+//
+
+_.lookup(0, [1, 2, 3]) // $ExpectType Option<number>
+_.lookup(0) // $ExpectType <A>(as: readonly A[]) => Option<A>
+
+//
+// elem
+//
+
+_.elem(eqNumber)(1, [1, 2, 3]) // $ExpectType boolean
+_.elem(eqNumber)(1) // $ExpectType (as: readonly number[]) => boolean
+
+//
+// difference
+//
+
+_.difference(eqNumber)([1, 2], [3, 4]) // $ExpectType readonly number[]
+_.difference(eqNumber)([3, 4]) // $ExpectType (ys: readonly number[]) => readonly number[]
+
+//
+// intersection
+//
+
+_.intersection(eqNumber)([1, 2], [3, 4]) // $ExpectType readonly number[]
+_.intersection(eqNumber)([3, 4]) // $ExpectType (ys: readonly number[]) => readonly number[]
+
+//
+// union
+//
+
+_.union(eqNumber)([1, 2], [3, 4]) // $ExpectType readonly number[]
+_.union(eqNumber)([3, 4]) // $ExpectType (ys: readonly number[]) => readonly number[]
+
+//
+// zip
+//
+
+_.zip([1, 2], ['a', 'b']) // $ExpectType readonly (readonly [number, string])[]
+_.zip(['a', 'b']) // $ExpectType <A>(as: readonly A[]) => readonly (readonly [A, string])[]
+
+//
+// cons
+//
+
+_.cons(0, [1, 2]) // $ExpectType ReadonlyNonEmptyArray<number>
+_.cons(0) // $ExpectType (tail: readonly number[]) => ReadonlyNonEmptyArray<number>
diff --git a/dtslint/ts3.5/ReadonlyMap.ts b/dtslint/ts3.5/ReadonlyMap.ts
new file mode 100644
index 00000000..1ef49105
--- /dev/null
+++ b/dtslint/ts3.5/ReadonlyMap.ts
@@ -0,0 +1,48 @@
+import * as _ from '../../src/ReadonlyMap'
+import { eqString, eqNumber } from '../../src/Eq'
+
+//
+// FilterableWithIndex overloadings
+//
+
+const FWI = _.getFilterableWithIndex<'a' | 'b'>()
+
+declare function isStringWithKey(i: 'a' | 'b', x: unknown): x is string
+
+FWI.filterWithIndex(_.empty as ReadonlyMap<'a' | 'b', string | number>, isStringWithKey) // $ExpectType ReadonlyMap<"a" | "b", string>
+FWI.partitionWithIndex(_.empty as ReadonlyMap<'a' | 'b', string | number>, isStringWithKey) // $ExpectType Separated<ReadonlyMap<"a" | "b", string | number>, ReadonlyMap<"a" | "b", string>>
+
+//
+// member
+//
+
+_.member(eqString)('a', new Map()) // $ExpectType boolean
+_.member(eqString)('a') // $ExpectType <A>(m: ReadonlyMap<string, A>) => boolean
+
+//
+// elem
+//
+
+_.elem(eqString)('a', new Map()) // $ExpectType boolean
+_.elem(eqString)('a') // $ExpectType <K>(m: ReadonlyMap<K, string>) => boolean
+
+//
+// lookup
+//
+
+_.lookup(eqString)('a', new Map([['a', 1]])) // $ExpectType Option<number>
+_.lookup(eqString)('a') // $ExpectType <A>(m: ReadonlyMap<string, A>) => Option<A>
+
+//
+// lookupWithKey
+//
+
+_.lookupWithKey(eqString)('a', new Map([['a', 1]])) // $ExpectType Option<readonly [string, number]>
+_.lookupWithKey(eqString)('a') // $ExpectType <A>(m: ReadonlyMap<string, A>) => Option<readonly [string, A]>
+
+//
+// isSubmap
+//
+
+_.isSubmap(eqString, eqNumber)(new Map([['a', 1]]), new Map([['a', 1]])) // $ExpectType boolean
+_.isSubmap(eqString, eqNumber)(new Map([['a', 1]])) // $ExpectType (me: ReadonlyMap<string, number>) => boolean
diff --git a/dtslint/ts3.5/ReadonlyNonEmptyArray.ts b/dtslint/ts3.5/ReadonlyNonEmptyArray.ts
index ca316486..72f3054f 100644
--- a/dtslint/ts3.5/ReadonlyNonEmptyArray.ts
+++ b/dtslint/ts3.5/ReadonlyNonEmptyArray.ts
@@ -10,6 +10,7 @@ declare const rnetns: _.ReadonlyNonEmptyArray<[number, string]>
 //
 
 _.zip(rnens, rneas) // $ExpectType ReadonlyNonEmptyArray<readonly [number, string]>
+_.zip(rneas) // $ExpectType <A>(as: ReadonlyNonEmptyArray<A>) => ReadonlyNonEmptyArray<readonly [A, string]>
 
 //
 // zipWith
diff --git a/dtslint/ts3.5/ReadonlyRecord.ts b/dtslint/ts3.5/ReadonlyRecord.ts
new file mode 100644
index 00000000..cd902a9c
--- /dev/null
+++ b/dtslint/ts3.5/ReadonlyRecord.ts
@@ -0,0 +1,189 @@
+import { pipe } from '../../src/pipeable'
+import * as _ from '../../src/ReadonlyRecord'
+import { identity } from '../../src/function'
+import * as O from '../../src/Option'
+import * as A from '../../src/Array'
+import * as E from '../../src/Either'
+import { monoidString } from '../../src/Monoid'
+import { eqNumber } from '../../src/Eq'
+import { semigroupSum, getFirstSemigroup } from '../../src/Semigroup'
+import { Foldable } from '../../src/Foldable'
+import { HKT } from '../../src/HKT'
+
+declare const do1: { [key: string]: O.Option<number> }
+declare const ro1: Readonly<Record<'a' | 'b', O.Option<number>>>
+declare const stringKey: string
+declare const d1: { [key: string]: number }
+declare const recordString: Readonly<Record<string, number>>
+declare const r1: Readonly<Record<'a' | 'b', number>>
+const l1 = { a: 1 }
+
+declare const keyString: string
+
+//
+// hasOwnProperty
+//
+
+if (_.hasOwnProperty(keyString, d1)) {
+  keyString // $ExpectType string
+}
+if (_.hasOwnProperty(keyString, recordString)) {
+  keyString // $ExpectType string
+}
+if (_.hasOwnProperty(keyString, r1)) {
+  keyString // $ExpectType "a" | "b"
+}
+
+//
+// updateAt
+//
+
+pipe(d1, _.updateAt('a', 3)) // $ExpectType Option<Readonly<Record<string, number>>>
+pipe(recordString, _.updateAt('a', 3)) // $ExpectType Option<Readonly<Record<string, number>>>
+pipe(r1, _.updateAt('a', 3)) // $ExpectType Option<Readonly<Record<"a" | "b", number>>>
+
+//
+// modifyAt
+//
+
+pipe(d1, _.modifyAt('a', identity)) // $ExpectType Option<Readonly<Record<string, number>>>
+pipe(recordString, _.modifyAt('a', identity)) // $ExpectType Option<Readonly<Record<string, number>>>
+pipe(r1, _.modifyAt('a', identity)) // $ExpectType Option<Readonly<Record<"a" | "b", number>>>
+
+//
+// pop
+//
+
+_.pop('a')(r1) // $ExpectType Option<readonly [number, Readonly<Record<"b", number>>]>
+_.pop('a')(d1) // $ExpectType Option<readonly [number, Readonly<Record<string, number>>]>
+_.pop(stringKey)(r1) // $ExpectType Option<readonly [number, Readonly<Record<string, number>>]>
+
+//
+// collect
+//
+
+_.collect((_k: 'a', n: number) => n)({ a: 1 }) // $ExpectType readonly number[]
+_.collect((_k: 'a', n: number) => n)(l1) // $ExpectType readonly number[]
+_.collect((_k, n: number) => n)(d1) // $ExpectType readonly number[]
+_.collect((_k: 'a' | 'b', n: number) => n)(r1) // $ExpectType readonly number[]
+
+//
+// insertAt
+//
+
+_.insertAt('b', 0)({ a: 1 }) // $ExpectType Readonly<Record<"a" | "b", number>>
+_.insertAt('b', 0)(l1) // $ExpectType Readonly<Record<"a" | "b", number>>
+_.insertAt('b', 0)(d1) // $ExpectType Readonly<Record<string, number>>
+_.insertAt('b', 0)(r1) // $ExpectType Readonly<Record<"a" | "b", number>>
+_.insertAt(stringKey, 0)(r1) // $ExpectType Readonly<Record<string, number>>
+_.insertAt('c', 0)(r1) // $ExpectType Readonly<Record<"a" | "b" | "c", number>>
+
+//
+// deleteAt
+//
+
+_.deleteAt('a')({ a: 1 }) // $ExpectType Readonly<Record<never, number>>
+_.deleteAt('b')({ a: 1 }) // $ExpectType Readonly<Record<"a", number>>
+_.deleteAt('a')(l1) // $ExpectType Readonly<Record<never, number>>
+_.deleteAt('b')(l1) // $ExpectType Readonly<Record<"a", number>>
+_.deleteAt('b')(d1) // $ExpectType Readonly<Record<string, number>>
+_.deleteAt('c')(r1) // $ExpectType Readonly<Record<"a" | "b", number>>
+_.deleteAt('a')(r1) // $ExpectType Readonly<Record<"b", number>>
+_.deleteAt(stringKey)(r1) // $ExpectType Readonly<Record<string, number>>
+
+//
+// mapWithIndex
+//
+
+_.mapWithIndex((_k: 'a', n: number) => n > 2)({ a: 1 }) // $ExpectType Readonly<Record<"a", boolean>>
+_.mapWithIndex((_k: 'a', n: number) => n > 2)(l1) // $ExpectType Readonly<Record<"a", boolean>>
+_.mapWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Readonly<Record<string, boolean>>
+_.mapWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Readonly<Record<"a" | "b", boolean>>
+
+//
+// map
+//
+
+_.map((n: number) => n > 2)({ a: 1 }) // $ExpectType Readonly<Record<"a", boolean>>
+_.map((n: number) => n > 2)(l1) // $ExpectType Readonly<Record<"a", boolean>>
+_.map((n: number) => n > 2)(d1) // $ExpectType Readonly<Record<string, boolean>>
+_.map((n: number) => n > 2)(r1) // $ExpectType Readonly<Record<"a" | "b", boolean>>
+
+//
+// reduceWithIndex
+//
+
+_.reduceWithIndex('', (k: string, _n) => k)(d1) // $ExpectType string
+_.reduceWithIndex('', (k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
+
+_.foldMapWithIndex(monoidString)((k: string, _n) => k)(d1) // $ExpectType string
+_.foldMapWithIndex(monoidString)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
+
+_.reduceRightWithIndex('', (k: string, _n, _b) => k)(d1) // $ExpectType string
+_.reduceRightWithIndex('', (k: 'a' | 'b', _n, _b) => k)(r1) // $ExpectType string
+
+_.singleton('a', 1) // $ExpectType Readonly<Record<"a", number>>
+
+_.traverseWithIndex(O.option)((_k, n: number) => O.some(n))(d1) // $ExpectType Option<Readonly<Record<string, number>>>
+_.traverseWithIndex(O.option)((_k: 'a' | 'b', n: number) => O.some(n))(r1) // $ExpectType Option<Readonly<Record<"a" | "b", number>>>
+
+_.traverse(O.option)((n: number) => O.some(n))(d1) // $ExpectType Option<Readonly<Record<string, number>>>
+_.traverse(O.option)((n: number) => O.some(n))(r1) // $ExpectType Option<Readonly<Record<"a" | "b", number>>>
+
+_.sequence(O.option)(do1) // $ExpectType Option<Readonly<Record<string, number>>>
+_.sequence(O.option)(ro1) // $ExpectType Option<Readonly<Record<"a" | "b", number>>>
+
+_.readonlyRecord.compact(do1) // $ExpectType Readonly<Record<string, number>>
+
+_.partitionMapWithIndex((_k: string, n: number): E.Either<string, number> => E.right(n))(d1) // $ExpectType Separated<Readonly<Record<string, string>>, Readonly<Record<string, number>>>
+_.partitionMapWithIndex((_k: 'a' | 'b', n: number): E.Either<string, number> => E.right(n))(r1) // $ExpectType Separated<Readonly<Record<string, string>>, Readonly<Record<string, number>>>
+
+_.partitionWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Separated<Readonly<Record<string, number>>, Readonly<Record<string, number>>>
+_.partitionWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Separated<Readonly<Record<string, number>>, Readonly<Record<string, number>>>
+
+_.filterMapWithIndex((_k: string, n: number) => O.some(n))(d1) // $ExpectType Readonly<Record<string, number>>
+_.filterMapWithIndex((_k: 'a' | 'b', n: number) => O.some(n))(r1) // $ExpectType Readonly<Record<string, number>>
+
+_.filterWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Readonly<Record<string, number>>
+_.filterWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Readonly<Record<string, number>>
+
+declare const arr1: Array<[string, number]>
+declare const arr2: Array<['a' | 'b', number]>
+
+_.fromFoldable(getFirstSemigroup<number>(), A.array)(arr1) // $ExpectType Readonly<Record<string, number>>
+_.fromFoldable(getFirstSemigroup<number>(), A.array)(arr2) // $ExpectType Readonly<Record<"a" | "b", number>>
+
+type Keys = 'key1' | 'key2'
+_.getMonoid(semigroupSum) // $ExpectType Monoid<Readonly<Record<string, number>>>
+_.getMonoid<Keys, number>(semigroupSum) // $ExpectType Monoid<Readonly<Record<Keys, number>>>
+
+_.getEq<Keys, number>(eqNumber) // $ExpectType Eq<Readonly<Record<Keys, number>>>
+_.getEq(eqNumber) // $ExpectType Eq<Readonly<Record<string, number>>>
+
+_.toUnfoldable(A.array)({ a: 1 }) // $ExpectType (readonly ["a", number])[]
+_.toUnfoldable(A.array)({ a: 1, b: 2 }) // $ExpectType (readonly ["a" | "b", number])[]
+
+declare const fromFoldableF1: Foldable<'Test'>
+declare const fromFoldableInput1: HKT<'Test', ['a' | 'b', number]>
+_.fromFoldable(getFirstSemigroup<number>(), fromFoldableF1)(fromFoldableInput1) // $ExpectType Readonly<Record<"a" | "b", number>>
+
+//
+// isSubrecord
+//
+
+_.isSubrecord(eqNumber)(recordString, recordString) // $ExpectType boolean
+_.isSubrecord(eqNumber)(recordString) // $ExpectType (me: Readonly<Record<string, number>>) => boolean
+
+//
+// lookup
+//
+
+_.lookup('a', recordString) // $ExpectType Option<number>
+_.lookup('a') // $ExpectType <A>(r: Readonly<Record<string, A>>) => Option<A>
+
+//
+// elem
+//
+
+_.elem(eqNumber)(1, recordString) // $ExpectType boolean
+_.elem(eqNumber)(1) // $ExpectType (fa: Readonly<Record<string, number>>) => boolean
diff --git a/dtslint/ts3.5/ReadonlySet.ts b/dtslint/ts3.5/ReadonlySet.ts
new file mode 100644
index 00000000..deeacd42
--- /dev/null
+++ b/dtslint/ts3.5/ReadonlySet.ts
@@ -0,0 +1,39 @@
+import * as _ from '../../src/ReadonlySet'
+import { eqNumber } from '../../src/Eq'
+
+declare const me: ReadonlySet<number>
+
+//
+// isSubset
+//
+
+_.isSubset(eqNumber)(me, me) // $ExpectType boolean
+_.isSubset(eqNumber)(me) // $ExpectType (me: ReadonlySet<number>) => boolean
+
+//
+// elem
+//
+
+_.elem(eqNumber)(1, me) // $ExpectType boolean
+_.elem(eqNumber)(1) // $ExpectType (set: ReadonlySet<number>) => boolean
+
+//
+// union
+//
+
+_.union(eqNumber)(me, me) // $ExpectType ReadonlySet<number>
+_.union(eqNumber)(me) // $ExpectType (me: ReadonlySet<number>) => ReadonlySet<number>
+
+//
+// intersection
+//
+
+_.intersection(eqNumber)(me, me) // $ExpectType ReadonlySet<number>
+_.intersection(eqNumber)(me) // $ExpectType (me: ReadonlySet<number>) => ReadonlySet<number>
+
+//
+// difference
+//
+
+_.difference(eqNumber)(me, me) // $ExpectType ReadonlySet<number>
+_.difference(eqNumber)(me) // $ExpectType (me: ReadonlySet<number>) => ReadonlySet<number>
diff --git a/dtslint/ts3.5/Record.ts b/dtslint/ts3.5/Record.ts
index 46550579..cedc3daf 100644
--- a/dtslint/ts3.5/Record.ts
+++ b/dtslint/ts3.5/Record.ts
@@ -1,5 +1,5 @@
 import { pipe } from '../../src/pipeable'
-import * as R from '../../src/Record'
+import * as _ from '../../src/Record'
 import { identity } from '../../src/function'
 import * as O from '../../src/Option'
 import * as A from '../../src/Array'
@@ -24,13 +24,13 @@ declare const keyString: string
 // hasOwnProperty
 //
 
-if (R.hasOwnProperty(keyString, d1)) {
+if (_.hasOwnProperty(keyString, d1)) {
   keyString // $ExpectType string
 }
-if (R.hasOwnProperty(keyString, recordString)) {
+if (_.hasOwnProperty(keyString, recordString)) {
   keyString // $ExpectType string
 }
-if (R.hasOwnProperty(keyString, r1)) {
+if (_.hasOwnProperty(keyString, r1)) {
   keyString // $ExpectType "a" | "b"
 }
 
@@ -38,140 +38,161 @@ if (R.hasOwnProperty(keyString, r1)) {
 // updateAt
 //
 
-pipe(d1, R.updateAt('a', 3)) // $ExpectType Option<Record<string, number>>
-pipe(recordString, R.updateAt('a', 3)) // $ExpectType Option<Record<string, number>>
-pipe(r1, R.updateAt('a', 3)) // $ExpectType Option<Record<"a" | "b", number>>
+pipe(d1, _.updateAt('a', 3)) // $ExpectType Option<Record<string, number>>
+pipe(recordString, _.updateAt('a', 3)) // $ExpectType Option<Record<string, number>>
+pipe(r1, _.updateAt('a', 3)) // $ExpectType Option<Record<"a" | "b", number>>
 
 //
 // modifyAt
 //
 
-pipe(d1, R.modifyAt('a', identity)) // $ExpectType Option<Record<string, number>>
-pipe(recordString, R.modifyAt('a', identity)) // $ExpectType Option<Record<string, number>>
-pipe(r1, R.modifyAt('a', identity)) // $ExpectType Option<Record<"a" | "b", number>>
+pipe(d1, _.modifyAt('a', identity)) // $ExpectType Option<Record<string, number>>
+pipe(recordString, _.modifyAt('a', identity)) // $ExpectType Option<Record<string, number>>
+pipe(r1, _.modifyAt('a', identity)) // $ExpectType Option<Record<"a" | "b", number>>
 
 //
 // pop
 //
 
-R.pop('a')(r1) // $ExpectType Option<[number, Record<"b", number>]>
-R.pop('a')(d1) // $ExpectType Option<[number, Record<string, number>]>
-R.pop(stringKey)(r1) // $ExpectType Option<[number, Record<string, number>]>
+_.pop('a')(r1) // $ExpectType Option<[number, Record<"b", number>]>
+_.pop('a')(d1) // $ExpectType Option<[number, Record<string, number>]>
+_.pop(stringKey)(r1) // $ExpectType Option<[number, Record<string, number>]>
 
 //
 // collect
 //
 
-R.collect((_k: 'a', n: number) => n)({ a: 1 }) // $ExpectType number[]
-R.collect((_k: 'a', n: number) => n)(l1) // $ExpectType number[]
-R.collect((_k, n: number) => n)(d1) // $ExpectType number[]
-R.collect((_k: 'a' | 'b', n: number) => n)(r1) // $ExpectType number[]
+_.collect((_k: 'a', n: number) => n)({ a: 1 }) // $ExpectType number[]
+_.collect((_k: 'a', n: number) => n)(l1) // $ExpectType number[]
+_.collect((_k, n: number) => n)(d1) // $ExpectType number[]
+_.collect((_k: 'a' | 'b', n: number) => n)(r1) // $ExpectType number[]
 
 //
 // toArray
 //
 
-R.toArray({ a: 1 }) // $ExpectType ["a", number][]
-R.toArray(l1) // $ExpectType ["a", number][]
-R.toArray(d1) // $ExpectType [string, number][]
-R.toArray(r1) // $ExpectType ["a" | "b", number][]
+_.toArray({ a: 1 }) // $ExpectType ["a", number][]
+_.toArray(l1) // $ExpectType ["a", number][]
+_.toArray(d1) // $ExpectType [string, number][]
+_.toArray(r1) // $ExpectType ["a" | "b", number][]
 
 //
 // insertAt
 //
 
-R.insertAt('b', 0)({ a: 1 }) // $ExpectType Record<"a" | "b", number>
-R.insertAt('b', 0)(l1) // $ExpectType Record<"a" | "b", number>
-R.insertAt('b', 0)(d1) // $ExpectType Record<string, number>
-R.insertAt('b', 0)(r1) // $ExpectType Record<"a" | "b", number>
-R.insertAt(stringKey, 0)(r1) // $ExpectType Record<string, number>
-R.insertAt('c', 0)(r1) // $ExpectType Record<"a" | "b" | "c", number>
+_.insertAt('b', 0)({ a: 1 }) // $ExpectType Record<"a" | "b", number>
+_.insertAt('b', 0)(l1) // $ExpectType Record<"a" | "b", number>
+_.insertAt('b', 0)(d1) // $ExpectType Record<string, number>
+_.insertAt('b', 0)(r1) // $ExpectType Record<"a" | "b", number>
+_.insertAt(stringKey, 0)(r1) // $ExpectType Record<string, number>
+_.insertAt('c', 0)(r1) // $ExpectType Record<"a" | "b" | "c", number>
 
 //
 // deleteAt
 //
 
-R.deleteAt('a')({ a: 1 }) // $ExpectType Record<never, number>
-R.deleteAt('b')({ a: 1 }) // $ExpectType Record<"a", number>
-R.deleteAt('a')(l1) // $ExpectType Record<never, number>
-R.deleteAt('b')(l1) // $ExpectType Record<"a", number>
-R.deleteAt('b')(d1) // $ExpectType Record<string, number>
-R.deleteAt('c')(r1) // $ExpectType Record<"a" | "b", number>
-R.deleteAt('a')(r1) // $ExpectType Record<"b", number>
-R.deleteAt(stringKey)(r1) // $ExpectType Record<string, number>
+_.deleteAt('a')({ a: 1 }) // $ExpectType Record<never, number>
+_.deleteAt('b')({ a: 1 }) // $ExpectType Record<"a", number>
+_.deleteAt('a')(l1) // $ExpectType Record<never, number>
+_.deleteAt('b')(l1) // $ExpectType Record<"a", number>
+_.deleteAt('b')(d1) // $ExpectType Record<string, number>
+_.deleteAt('c')(r1) // $ExpectType Record<"a" | "b", number>
+_.deleteAt('a')(r1) // $ExpectType Record<"b", number>
+_.deleteAt(stringKey)(r1) // $ExpectType Record<string, number>
 
 //
 // mapWithIndex
 //
 
-R.mapWithIndex((_k: 'a', n: number) => n > 2)({ a: 1 }) // $ExpectType Record<"a", boolean>
-R.mapWithIndex((_k: 'a', n: number) => n > 2)(l1) // $ExpectType Record<"a", boolean>
-R.mapWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Record<string, boolean>
-R.mapWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Record<"a" | "b", boolean>
+_.mapWithIndex((_k: 'a', n: number) => n > 2)({ a: 1 }) // $ExpectType Record<"a", boolean>
+_.mapWithIndex((_k: 'a', n: number) => n > 2)(l1) // $ExpectType Record<"a", boolean>
+_.mapWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Record<string, boolean>
+_.mapWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Record<"a" | "b", boolean>
 
 //
 // map
 //
 
-R.map((n: number) => n > 2)({ a: 1 }) // $ExpectType Record<"a", boolean>
-R.map((n: number) => n > 2)(l1) // $ExpectType Record<"a", boolean>
-R.map((n: number) => n > 2)(d1) // $ExpectType Record<string, boolean>
-R.map((n: number) => n > 2)(r1) // $ExpectType Record<"a" | "b", boolean>
+_.map((n: number) => n > 2)({ a: 1 }) // $ExpectType Record<"a", boolean>
+_.map((n: number) => n > 2)(l1) // $ExpectType Record<"a", boolean>
+_.map((n: number) => n > 2)(d1) // $ExpectType Record<string, boolean>
+_.map((n: number) => n > 2)(r1) // $ExpectType Record<"a" | "b", boolean>
 
 //
 // reduceWithIndex
 //
 
-R.reduceWithIndex('', (k: string, _n) => k)(d1) // $ExpectType string
-R.reduceWithIndex('', (k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
+_.reduceWithIndex('', (k: string, _n) => k)(d1) // $ExpectType string
+_.reduceWithIndex('', (k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
 
-R.foldMapWithIndex(monoidString)((k: string, _n) => k)(d1) // $ExpectType string
-R.foldMapWithIndex(monoidString)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
+_.foldMapWithIndex(monoidString)((k: string, _n) => k)(d1) // $ExpectType string
+_.foldMapWithIndex(monoidString)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
 
-R.reduceRightWithIndex('', (k: string, _n, _b) => k)(d1) // $ExpectType string
-R.reduceRightWithIndex('', (k: 'a' | 'b', _n, _b) => k)(r1) // $ExpectType string
+_.reduceRightWithIndex('', (k: string, _n, _b) => k)(d1) // $ExpectType string
+_.reduceRightWithIndex('', (k: 'a' | 'b', _n, _b) => k)(r1) // $ExpectType string
 
-R.singleton('a', 1) // $ExpectType Record<"a", number>
+_.singleton('a', 1) // $ExpectType Record<"a", number>
 
-R.traverseWithIndex(O.option)((_k, n: number) => O.some(n))(d1) // $ExpectType Option<Record<string, number>>
-R.traverseWithIndex(O.option)((_k: 'a' | 'b', n: number) => O.some(n))(r1) // $ExpectType Option<Record<"a" | "b", number>>
+_.traverseWithIndex(O.option)((_k, n: number) => O.some(n))(d1) // $ExpectType Option<Record<string, number>>
+_.traverseWithIndex(O.option)((_k: 'a' | 'b', n: number) => O.some(n))(r1) // $ExpectType Option<Record<"a" | "b", number>>
 
-R.traverse(O.option)((n: number) => O.some(n))(d1) // $ExpectType Option<Record<string, number>>
-R.traverse(O.option)((n: number) => O.some(n))(r1) // $ExpectType Option<Record<"a" | "b", number>>
+_.traverse(O.option)((n: number) => O.some(n))(d1) // $ExpectType Option<Record<string, number>>
+_.traverse(O.option)((n: number) => O.some(n))(r1) // $ExpectType Option<Record<"a" | "b", number>>
 
-R.sequence(O.option)(do1) // $ExpectType Option<Record<string, number>>
-R.sequence(O.option)(ro1) // $ExpectType Option<Record<"a" | "b", number>>
+_.sequence(O.option)(do1) // $ExpectType Option<Record<string, number>>
+_.sequence(O.option)(ro1) // $ExpectType Option<Record<"a" | "b", number>>
 
-R.record.compact(do1) // $ExpectType Record<string, number>
+_.record.compact(do1) // $ExpectType Record<string, number>
 
-R.partitionMapWithIndex((_k: string, n: number): E.Either<string, number> => E.right(n))(d1) // $ExpectType Separated<Record<string, string>, Record<string, number>>
-R.partitionMapWithIndex((_k: 'a' | 'b', n: number): E.Either<string, number> => E.right(n))(r1) // $ExpectType Separated<Record<string, string>, Record<string, number>>
+_.partitionMapWithIndex((_k: string, n: number): E.Either<string, number> => E.right(n))(d1) // $ExpectType Separated<Record<string, string>, Record<string, number>>
+_.partitionMapWithIndex((_k: 'a' | 'b', n: number): E.Either<string, number> => E.right(n))(r1) // $ExpectType Separated<Record<string, string>, Record<string, number>>
 
-R.partitionWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Separated<Record<string, number>, Record<string, number>>
-R.partitionWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Separated<Record<string, number>, Record<string, number>>
+_.partitionWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Separated<Record<string, number>, Record<string, number>>
+_.partitionWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Separated<Record<string, number>, Record<string, number>>
 
-R.filterMapWithIndex((_k: string, n: number) => O.some(n))(d1) // $ExpectType Record<string, number>
-R.filterMapWithIndex((_k: 'a' | 'b', n: number) => O.some(n))(r1) // $ExpectType Record<string, number>
+_.filterMapWithIndex((_k: string, n: number) => O.some(n))(d1) // $ExpectType Record<string, number>
+_.filterMapWithIndex((_k: 'a' | 'b', n: number) => O.some(n))(r1) // $ExpectType Record<string, number>
 
-R.filterWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Record<string, number>
-R.filterWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Record<string, number>
+_.filterWithIndex((_k: string, n: number) => n > 2)(d1) // $ExpectType Record<string, number>
+_.filterWithIndex((_k: 'a' | 'b', n: number) => n > 2)(r1) // $ExpectType Record<string, number>
 
 declare const arr1: Array<[string, number]>
 declare const arr2: Array<['a' | 'b', number]>
 
-R.fromFoldable(getFirstSemigroup<number>(), A.array)(arr1) // $ExpectType Record<string, number>
-R.fromFoldable(getFirstSemigroup<number>(), A.array)(arr2) // $ExpectType Record<"a" | "b", number>
+_.fromFoldable(getFirstSemigroup<number>(), A.array)(arr1) // $ExpectType Record<string, number>
+_.fromFoldable(getFirstSemigroup<number>(), A.array)(arr2) // $ExpectType Record<"a" | "b", number>
 
 type Keys = 'key1' | 'key2'
-R.getMonoid(semigroupSum) // $ExpectType Monoid<Record<string, number>>
-R.getMonoid<Keys, number>(semigroupSum) // $ExpectType Monoid<Record<Keys, number>>
+_.getMonoid(semigroupSum) // $ExpectType Monoid<Record<string, number>>
+_.getMonoid<Keys, number>(semigroupSum) // $ExpectType Monoid<Record<Keys, number>>
 
-R.getEq<Keys, number>(eqNumber) // $ExpectType Eq<Record<Keys, number>>
-R.getEq(eqNumber) // $ExpectType Eq<Record<string, number>>
+_.getEq<Keys, number>(eqNumber) // $ExpectType Eq<Record<Keys, number>>
+_.getEq(eqNumber) // $ExpectType Eq<Record<string, number>>
 
-R.toUnfoldable(A.array)({ a: 1 }) // $ExpectType ["a", number][]
-R.toUnfoldable(A.array)({ a: 1, b: 2 }) // $ExpectType ["a" | "b", number][]
+_.toUnfoldable(A.array)({ a: 1 }) // $ExpectType ["a", number][]
+_.toUnfoldable(A.array)({ a: 1, b: 2 }) // $ExpectType ["a" | "b", number][]
 
 declare const fromFoldableF1: Foldable<'Test'>
 declare const fromFoldableInput1: HKT<'Test', ['a' | 'b', number]>
-R.fromFoldable(getFirstSemigroup<number>(), fromFoldableF1)(fromFoldableInput1) // $ExpectType Record<"a" | "b", number>
+_.fromFoldable(getFirstSemigroup<number>(), fromFoldableF1)(fromFoldableInput1) // $ExpectType Record<"a" | "b", number>
+
+//
+// isSubrecord
+//
+
+_.isSubrecord(eqNumber)(recordString, recordString) // $ExpectType boolean
+_.isSubrecord(eqNumber)(recordString) // $ExpectType (me: Record<string, number>) => boolean
+
+//
+// lookup
+//
+
+_.lookup('a', recordString) // $ExpectType Option<number>
+_.lookup('a') // $ExpectType <A>(r: Record<string, A>) => Option<A>
+
+//
+// elem
+//
+
+_.elem(eqNumber)(1, recordString) // $ExpectType boolean
+_.elem(eqNumber)(1) // $ExpectType (fa: Record<string, number>) => boolean
diff --git a/dtslint/ts3.5/Semigroup.ts b/dtslint/ts3.5/Semigroup.ts
index 185ede0a..6a33d9f4 100644
--- a/dtslint/ts3.5/Semigroup.ts
+++ b/dtslint/ts3.5/Semigroup.ts
@@ -5,3 +5,10 @@ import * as _ from '../../src/Semigroup'
 //
 
 _.getTupleSemigroup(_.semigroupString, _.semigroupSum, _.semigroupAll) // $ExpectType Semigroup<[string, number, boolean]>
+
+//
+// fold
+//
+
+_.fold(_.semigroupString)('', ['a']) // $ExpectType string
+_.fold(_.semigroupString)('') // $ExpectType (as: readonly string[]) => string
diff --git a/dtslint/ts3.5/Set.ts b/dtslint/ts3.5/Set.ts
new file mode 100644
index 00000000..392af653
--- /dev/null
+++ b/dtslint/ts3.5/Set.ts
@@ -0,0 +1,39 @@
+import * as _ from '../../src/Set'
+import { eqNumber } from '../../src/Eq'
+
+declare const me: Set<number>
+
+//
+// subset
+//
+
+_.subset(eqNumber)(me, me) // $ExpectType boolean
+_.subset(eqNumber)(me) // $ExpectType (me: Set<number>) => boolean
+
+//
+// elem
+//
+
+_.elem(eqNumber)(1, me) // $ExpectType boolean
+_.elem(eqNumber)(1) // $ExpectType (set: Set<number>) => boolean
+
+//
+// union
+//
+
+_.union(eqNumber)(me, me) // $ExpectType Set<number>
+_.union(eqNumber)(me) // $ExpectType (me: Set<number>) => Set<number>
+
+//
+// intersection
+//
+
+_.intersection(eqNumber)(me, me) // $ExpectType Set<number>
+_.intersection(eqNumber)(me) // $ExpectType (me: Set<number>) => Set<number>
+
+//
+// difference
+//
+
+_.difference(eqNumber)(me, me) // $ExpectType Set<number>
+_.difference(eqNumber)(me) // $ExpectType (me: Set<number>) => Set<number>
diff --git a/dtslint/ts3.5/function.ts b/dtslint/ts3.5/function.ts
index 14363877..d2cb3674 100644
--- a/dtslint/ts3.5/function.ts
+++ b/dtslint/ts3.5/function.ts
@@ -6,7 +6,7 @@ import * as A from '../../src/Array'
 //
 
 // should handle generics
-_.flip(A.cons) // $ExpectType <A>(b: A[], a: A) => NonEmptyArray<A>
+_.flip(A.snoc) // $ExpectType <A>(b: A, a: A[]) => NonEmptyArray<A>
 
 //
 // tuple
@@ -17,8 +17,8 @@ _.tuple(1) // $ExpectType [number]
 _.tuple(1, 'a') // $ExpectType [number, string]
 _.tuple(1, 'a', true) // $ExpectType [number, string, boolean]
 
-// $ExpectType <A>(head: A, tail: A[]) => Option<A>
-_.flow(A.cons, A.head)
+// $ExpectType <A>(init: A[], end: A) => Option<A>
+_.flow(A.snoc, A.head)
 
 //
 // tupled
diff --git a/package.json b/package.json
index 3612ab6b..cce7661e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "2.6.5",
+  "version": "2.6.6",
   "description": "Functional programming in TypeScript",
   "files": [
     "lib",
diff --git a/src/Applicative.ts b/src/Applicative.ts
index 2266148e..c92970b8 100644
--- a/src/Applicative.ts
+++ b/src/Applicative.ts
@@ -190,6 +190,7 @@ export interface ApplicativeComposition22C<F extends URIS2, G extends URIS2, E>
   ) => Kind2<F, FE, Kind2<G, E, B>>
 }
 
+// TODO: remove in v3
 /**
  * Like `Functor`, `Applicative`s compose. If `F` and `G` have `Applicative` instances, then so does `F<G<_>>`
  *
diff --git a/src/Array.ts b/src/Array.ts
index 8fffec77..c585ea32 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -87,17 +87,6 @@ export const getEq: <A>(E: Eq<A>) => Eq<Array<A>> = RA.getEq
  */
 export const getOrd: <A>(O: Ord<A>) => Ord<Array<A>> = RA.getOrd
 
-// -------------------------------------------------------------------------------------
-// utils
-// -------------------------------------------------------------------------------------
-
-/**
- * An empty array
- *
- * @since 2.0.0
- */
-export const empty: Array<never> = []
-
 // -------------------------------------------------------------------------------------
 // constructors
 // -------------------------------------------------------------------------------------
@@ -236,33 +225,44 @@ export const isNonEmpty: <A>(as: Array<A>) => as is NonEmptyArray<A> = RA.isNonE
  */
 export const isOutOfBound: <A>(i: number, as: Array<A>) => boolean = RA.isOutOfBound
 
+// TODO: remove non-curried overloading in v3
 /**
  * This function provides a safe way to read a value at a particular index from an array
  *
  * @example
  * import { lookup } from 'fp-ts/lib/Array'
  * import { some, none } from 'fp-ts/lib/Option'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(lookup(1, [1, 2, 3]), some(2))
- * assert.deepStrictEqual(lookup(3, [1, 2, 3]), none)
+ * assert.deepStrictEqual(pipe([1, 2, 3], lookup(1)), some(2))
+ * assert.deepStrictEqual(pipe([1, 2, 3], lookup(3)), none)
  *
  * @since 2.0.0
  */
-export const lookup: <A>(i: number, as: Array<A>) => Option<A> = RA.lookup
+export const lookup: {
+  (i: number): <A>(as: Array<A>) => Option<A>
+  <A>(i: number, as: Array<A>): Option<A>
+} = RA.lookup
 
+// TODO: remove non-curried overloading in v3
 /**
  * Attaches an element to the front of an array, creating a new non empty array
  *
  * @example
  * import { cons } from 'fp-ts/lib/Array'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(cons(0, [1, 2, 3]), [0, 1, 2, 3])
+ * assert.deepStrictEqual(pipe([1, 2, 3], cons(0)), [0, 1, 2, 3])
  *
  * @category constructors
  * @since 2.0.0
  */
-export const cons: <A>(head: A, tail: Array<A>) => NonEmptyArray<A> = RA.cons as any
+export const cons: {
+  <A>(head: A): (tail: Array<A>) => NonEmptyArray<A>
+  <A>(head: A, tail: Array<A>): NonEmptyArray<A>
+} = RA.cons as any
 
+// TODO: curry in v3
 /**
  * Append an element to the end of an array, creating a new non empty array
  *
@@ -562,12 +562,6 @@ export const findLastIndex: <A>(predicate: Predicate<A>) => (as: Array<A>) => Op
  */
 export const copy: <A>(as: Array<A>) => Array<A> = RA.toArray
 
-/**
- * @category combinators
- * @since 2.0.0
- */
-export const unsafeInsertAt: <A>(i: number, a: A, as: Array<A>) => Array<A> = RA.unsafeInsertAt as any
-
 /**
  * Insert an element at the specified index, creating a new array, or returning `None` if the index is out of bounds
  *
@@ -581,12 +575,6 @@ export const unsafeInsertAt: <A>(i: number, a: A, as: Array<A>) => Array<A> = RA
  */
 export const insertAt: <A>(i: number, a: A) => (as: Array<A>) => Option<Array<A>> = RA.insertAt as any
 
-/**
- * @category combinators
- * @since 2.0.0
- */
-export const unsafeUpdateAt: <A>(i: number, a: A, as: Array<A>) => Array<A> = RA.unsafeUpdateAt as any
-
 /**
  * Change the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
  *
@@ -601,12 +589,6 @@ export const unsafeUpdateAt: <A>(i: number, a: A, as: Array<A>) => Array<A> = RA
  */
 export const updateAt: <A>(i: number, a: A) => (as: Array<A>) => Option<Array<A>> = RA.updateAt as any
 
-/**
- * @category combinators
- * @since 2.0.0
- */
-export const unsafeDeleteAt: <A>(i: number, as: Array<A>) => Array<A> = RA.unsafeDeleteAt as any
-
 /**
  * Delete the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
  *
@@ -706,19 +688,24 @@ export const sort: <A>(O: Ord<A>) => (as: Array<A>) => Array<A> = RA.sort as any
  */
 export const zipWith: <A, B, C>(fa: Array<A>, fb: Array<B>, f: (a: A, b: B) => C) => Array<C> = RA.zipWith as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
  * longer array are discarded
  *
  * @example
  * import { zip } from 'fp-ts/lib/Array'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [[1, 'a'], [2, 'b'], [3, 'c']])
+ * assert.deepStrictEqual(pipe([1, 2, 3], zip(['a', 'b', 'c', 'd'])), [[1, 'a'], [2, 'b'], [3, 'c']])
  *
  * @category combinators
  * @since 2.0.0
  */
-export const zip: <A, B>(fa: Array<A>, fb: Array<B>) => Array<[A, B]> = RA.zip as any
+export const zip: {
+  <B>(bs: Array<B>): <A>(as: Array<A>) => Array<[A, B]>
+  <A, B>(as: Array<A>, bs: Array<B>): Array<[A, B]>
+} = RA.zip as any
 
 /**
  * The function is reverse of `zip`. Takes an array of pairs and return two corresponding arrays
@@ -745,6 +732,7 @@ export const unzip: <A, B>(as: Array<[A, B]>) => [Array<A>, Array<B>] = RA.unzip
  */
 export const rotate: (n: number) => <A>(as: Array<A>) => Array<A> = RA.rotate as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test if a value is a member of an array. Takes a `Eq<A>` as a single
  * argument which returns the function to use to search for a value of type `A` in
@@ -753,13 +741,19 @@ export const rotate: (n: number) => <A>(as: Array<A>) => Array<A> = RA.rotate as
  * @example
  * import { elem } from 'fp-ts/lib/Array'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.strictEqual(elem(eqNumber)(1, [1, 2, 3]), true)
- * assert.strictEqual(elem(eqNumber)(4, [1, 2, 3]), false)
+ * assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(2)), true)
+ * assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(0)), false)
  *
  * @since 2.0.0
  */
-export const elem: <A>(E: Eq<A>) => (a: A, as: Array<A>) => boolean = RA.elem
+export const elem: <A>(
+  E: Eq<A>
+) => {
+  (a: A): (as: Array<A>) => boolean
+  (a: A, as: Array<A>): boolean
+} = RA.elem
 
 /**
  * Remove duplicates from an array, keeping the first occurrence of an element.
@@ -904,20 +898,28 @@ export function comprehension<R>(
   return RA.comprehension(input as any, f, g) as any
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Creates an array of unique values, in order, from all given arrays using a `Eq` for equality comparisons
  *
  * @example
  * import { union } from 'fp-ts/lib/Array'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(union(eqNumber)([1, 2], [2, 3]), [1, 2, 3])
+ * assert.deepStrictEqual(pipe([1, 2], union(eqNumber)([2, 3])), [1, 2, 3])
  *
  * @category combinators
  * @since 2.0.0
  */
-export const union: <A>(E: Eq<A>) => (xs: Array<A>, ys: Array<A>) => Array<A> = RA.union as any
+export const union: <A>(
+  E: Eq<A>
+) => {
+  (xs: Array<A>): (ys: Array<A>) => Array<A>
+  (xs: Array<A>, ys: Array<A>): Array<A>
+} = RA.union as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Creates an array of unique values that are included in all given arrays using a `Eq` for equality
  * comparisons. The order and references of result values are determined by the first array.
@@ -925,14 +927,21 @@ export const union: <A>(E: Eq<A>) => (xs: Array<A>, ys: Array<A>) => Array<A> =
  * @example
  * import { intersection } from 'fp-ts/lib/Array'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(intersection(eqNumber)([1, 2], [2, 3]), [2])
+ * assert.deepStrictEqual(pipe([1, 2], intersection(eqNumber)([2, 3])), [2])
  *
  * @category combinators
  * @since 2.0.0
  */
-export const intersection: <A>(E: Eq<A>) => (xs: Array<A>, ys: Array<A>) => Array<A> = RA.intersection as any
+export const intersection: <A>(
+  E: Eq<A>
+) => {
+  (xs: Array<A>): (ys: Array<A>) => Array<A>
+  (xs: Array<A>, ys: Array<A>): Array<A>
+} = RA.intersection as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Creates an array of array values not included in the other given array using a `Eq` for equality
  * comparisons. The order and references of result values are determined by the first array.
@@ -940,13 +949,19 @@ export const intersection: <A>(E: Eq<A>) => (xs: Array<A>, ys: Array<A>) => Arra
  * @example
  * import { difference } from 'fp-ts/lib/Array'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(difference(eqNumber)([1, 2], [2, 3]), [1])
+ * assert.deepStrictEqual(pipe([1, 2], difference(eqNumber)([2, 3])), [1])
  *
  * @category combinators
  * @since 2.0.0
  */
-export const difference: <A>(E: Eq<A>) => (xs: Array<A>, ys: Array<A>) => Array<A> = RA.difference as any
+export const difference: <A>(
+  E: Eq<A>
+) => {
+  (xs: Array<A>): (ys: Array<A>) => Array<A>
+  (xs: Array<A>, ys: Array<A>): Array<A>
+} = RA.difference as any
 
 /**
  * @category constructors
@@ -1176,16 +1191,19 @@ declare module './HKT' {
 }
 
 /**
+ * @category Traversable
  * @since 2.6.3
  */
 export const traverse: PipeableTraverse1<URI> = RA.traverse as any
 
 /**
+ * @category Traversable
  * @since 2.6.3
  */
 export const sequence: Traversable1<URI>['sequence'] = RA.sequence as any
 
 /**
+ * @category TraversableWithIndex
  * @since 2.6.3
  */
 export const traverseWithIndex: PipeableTraverseWithIndex1<URI, number> = RA.traverseWithIndex as any
@@ -1202,8 +1220,10 @@ export const wither: PipeableWither1<URI> = RA.wither as any
  */
 export const wilt: PipeableWilt1<URI> = RA.wilt as any
 
-// TODO: export
-// export const unfold: <A, B>(b: B, f: (b: B) => Option<readonly [A, B]>) => Array<A> = RA.unfold as any
+/**
+ * @since 2.6.6
+ */
+export const unfold: <A, B>(b: B, f: (b: B) => Option<readonly [A, B]>) => Array<A> = RA.unfold as any
 
 /**
  * @category instances
@@ -1224,3 +1244,36 @@ export const array: Monad1<URI> &
   (() => {
     return Object.assign({}, RA.readonlyArray as any, { URI })
   })()
+
+// -------------------------------------------------------------------------------------
+// unsafe
+// -------------------------------------------------------------------------------------
+
+/**
+ * @category unsafe
+ * @since 2.0.0
+ */
+export const unsafeInsertAt: <A>(i: number, a: A, as: Array<A>) => Array<A> = RA.unsafeInsertAt as any
+
+/**
+ * @category unsafe
+ * @since 2.0.0
+ */
+export const unsafeUpdateAt: <A>(i: number, a: A, as: Array<A>) => Array<A> = RA.unsafeUpdateAt as any
+
+/**
+ * @category unsafe
+ * @since 2.0.0
+ */
+export const unsafeDeleteAt: <A>(i: number, as: Array<A>) => Array<A> = RA.unsafeDeleteAt as any
+
+// -------------------------------------------------------------------------------------
+// utils
+// -------------------------------------------------------------------------------------
+
+/**
+ * An empty array
+ *
+ * @since 2.0.0
+ */
+export const empty: Array<never> = []
diff --git a/src/Chain.ts b/src/Chain.ts
index 545c68a6..b3b7e3cc 100644
--- a/src/Chain.ts
+++ b/src/Chain.ts
@@ -13,6 +13,8 @@
 import { Apply, Apply1, Apply2, Apply2C, Apply3, Apply4, Apply3C } from './Apply'
 import { HKT, Kind, Kind2, Kind3, Kind4, URIS, URIS2, URIS3, URIS4 } from './HKT'
 
+// TODO: remove module in v3
+
 /**
  * @category type classes
  * @since 2.0.0
diff --git a/src/ChainRec.ts b/src/ChainRec.ts
index 2122a71a..a9b39f53 100644
--- a/src/ChainRec.ts
+++ b/src/ChainRec.ts
@@ -5,6 +5,8 @@ import { Chain, Chain1, Chain2, Chain2C, Chain3 } from './Chain'
 import { Either } from './Either'
 import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
 
+// TODO: remove module in v3
+
 /**
  * @category type classes
  * @since 2.0.0
diff --git a/src/Choice.ts b/src/Choice.ts
index 728fd6aa..5c596eb6 100644
--- a/src/Choice.ts
+++ b/src/Choice.ts
@@ -34,6 +34,8 @@ import { Profunctor, Profunctor2, Profunctor3, Profunctor4 } from './Profunctor'
 import { Category, Category2, Category3 } from './Category'
 import { identity } from './function'
 
+// TODO: remove module in v3
+
 /**
  * @category type classes
  * @since 2.0.0
diff --git a/src/Compactable.ts b/src/Compactable.ts
index ec6ca15e..66b5c3ae 100644
--- a/src/Compactable.ts
+++ b/src/Compactable.ts
@@ -216,6 +216,7 @@ export interface CompactableComposition23C<F extends URIS2, G extends URIS3, E>
   ) => Separated<Kind2<F, FE, Kind3<G, R, E, A>>, Kind2<F, FE, Kind3<G, R, E, B>>>
 }
 
+// TODO: remove in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/Either.ts b/src/Either.ts
index 1512e5d4..ef9ebe9e 100644
--- a/src/Either.ts
+++ b/src/Either.ts
@@ -116,6 +116,7 @@ export function right<E = never, A = never>(a: A): Either<E, A> {
   return { _tag: 'Right', right: a }
 }
 
+// TODO: make lazy in v3
 /**
  * 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`
@@ -135,6 +136,7 @@ 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>))
 }
 
+// TODO: `onError => Lazy<A> => Either` in v3
 /**
  * Constructs a new `Either` from a function that might throw
  *
@@ -703,6 +705,7 @@ export function getWitherable<E>(M: Monoid<E>): Witherable2C<URI, E> {
   }
 }
 
+// TODO: remove in v3
 /**
  * @category instances
  * @since 2.0.0
diff --git a/src/EitherT.ts b/src/EitherT.ts
index 3ce52275..0f6f97ca 100644
--- a/src/EitherT.ts
+++ b/src/EitherT.ts
@@ -8,6 +8,8 @@ import { flow, pipe } from './function'
 import { HKT, Kind, Kind2, URIS, URIS2 } from './HKT'
 import { Monad, Monad1, Monad2 } from './Monad'
 
+// TODO: remove module in v3
+
 import Either = E.Either
 import URI = E.URI
 
diff --git a/src/Filterable.ts b/src/Filterable.ts
index a1eb6dbd..f744069c 100644
--- a/src/Filterable.ts
+++ b/src/Filterable.ts
@@ -444,6 +444,7 @@ export interface FilterableComposition23C<F extends URIS2, G extends URIS3, E>
   ) => Kind2<F, FE, Kind3<G, R, E, A>>
 }
 
+// TODO: remove in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/Foldable.ts b/src/Foldable.ts
index c119e02e..0ef5dc1f 100644
--- a/src/Foldable.ts
+++ b/src/Foldable.ts
@@ -158,6 +158,7 @@ export interface FoldableComposition22C<F extends URIS2, G extends URIS2, E> {
   readonly reduceRight: <FE, A, B>(fa: Kind2<F, FE, Kind2<G, E, A>>, b: B, f: (a: A, b: B) => B) => B
 }
 
+// TODO: remove in v3
 /**
  * Returns the composition of two foldables
  *
@@ -214,6 +215,7 @@ export function getFoldableComposition<F, G>(F: Foldable<F>, G: Foldable<G>): Fo
   }
 }
 
+// TODO: rename to `reduceM` in v3
 /**
  * Similar to 'reduce', but the result is encapsulated in a monad.
  *
@@ -293,6 +295,7 @@ export function intercalate<M, F>(M: Monoid<M>, F: Foldable<F>): (sep: M, fm: HK
   }
 }
 
+// TODO: remove in v3
 /**
  * Traverse a data structure, performing some effects encoded by an `Applicative` functor at each value, ignoring the
  * final result.
diff --git a/src/FoldableWithIndex.ts b/src/FoldableWithIndex.ts
index e5280206..0b9dce5a 100644
--- a/src/FoldableWithIndex.ts
+++ b/src/FoldableWithIndex.ts
@@ -202,6 +202,7 @@ export interface FoldableWithIndexComposition22C<F extends URIS2, FI, G extends
 
 /* tslint:enable:readonly-array */
 
+// TODO: remove in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/Functor.ts b/src/Functor.ts
index 4ac24eb5..8ce077a2 100644
--- a/src/Functor.ts
+++ b/src/Functor.ts
@@ -169,6 +169,7 @@ export interface FunctorComposition23C<F extends URIS2, G extends URIS3, E> {
   readonly map: <FE, R, A, B>(fa: Kind2<F, FE, Kind3<G, R, E, A>>, f: (a: A) => B) => Kind2<F, FE, Kind3<G, R, E, B>>
 }
 
+// TODO: remove in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/FunctorWithIndex.ts b/src/FunctorWithIndex.ts
index a0212a16..0465c737 100644
--- a/src/FunctorWithIndex.ts
+++ b/src/FunctorWithIndex.ts
@@ -160,6 +160,7 @@ export interface FunctorWithIndexComposition22C<F extends URIS2, FI, G extends U
 
 /* tslint:enable:readonly-array */
 
+// TODO: remove in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/IOEither.ts b/src/IOEither.ts
index 031eb63c..2c869214 100644
--- a/src/IOEither.ts
+++ b/src/IOEither.ts
@@ -404,6 +404,7 @@ export function getApplyMonoid<E, A>(M: Monoid<A>): Monoid<IOEither<E, A>> {
   }
 }
 
+// TODO: remove in v3
 /**
  * @category instances
  * @since 2.0.0
diff --git a/src/Map.ts b/src/Map.ts
index 82fb2793..2d054499 100644
--- a/src/Map.ts
+++ b/src/Map.ts
@@ -42,19 +42,31 @@ export const size: <K, A>(d: Map<K, A>) => number = RM.size
  */
 export const isEmpty: <K, A>(d: Map<K, A>) => boolean = RM.isEmpty
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test whether or not a key exists in a map
  *
  * @since 2.0.0
  */
-export const member: <K>(E: Eq<K>) => <A>(k: K, m: Map<K, A>) => boolean = RM.member
+export const member: <K>(
+  E: Eq<K>
+) => {
+  (k: K): <A>(m: Map<K, A>) => boolean
+  <A>(k: K, m: Map<K, A>): boolean
+} = RM.member
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test whether or not a value is a member of a map
  *
  * @since 2.0.0
  */
-export const elem: <A>(E: Eq<A>) => <K>(a: A, m: Map<K, A>) => boolean = RM.elem
+export const elem: <A>(
+  E: Eq<A>
+) => {
+  (a: A): <K>(m: Map<K, A>) => boolean
+  <K>(a: A, m: Map<K, A>): boolean
+} = RM.elem
 
 /**
  * Get a sorted array of the keys contained in a map
@@ -128,27 +140,46 @@ export const modifyAt: <K>(
  */
 export const pop: <K>(E: Eq<K>) => (k: K) => <A>(m: Map<K, A>) => Option<[A, Map<K, A>]> = RM.pop as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Lookup the value for a key in a `Map`.
  * If the result is a `Some`, the existing key is also returned.
  *
  * @since 2.0.0
  */
-export const lookupWithKey: <K>(E: Eq<K>) => <A>(k: K, m: Map<K, A>) => Option<[K, A]> = RM.lookupWithKey as any
+export const lookupWithKey: <K>(
+  E: Eq<K>
+) => {
+  (k: K): <A>(m: Map<K, A>) => Option<[K, A]>
+  <A>(k: K, m: Map<K, A>): Option<[K, A]>
+} = RM.lookupWithKey as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Lookup the value for a key in a `Map`.
  *
  * @since 2.0.0
  */
-export const lookup: <K>(E: Eq<K>) => <A>(k: K, m: Map<K, A>) => Option<A> = RM.lookup
+export const lookup: <K>(
+  E: Eq<K>
+) => {
+  (k: K): <A>(m: Map<K, A>) => Option<A>
+  <A>(k: K, m: Map<K, A>): Option<A>
+} = RM.lookup
 
+// TODO: remove non-curried overloading in v3
 /**
- * Test whether or not one Map contains all of the keys and values contained in another Map
+ * Test whether or not one `Map` contains all of the keys and values contained in another `Map`
  *
  * @since 2.0.0
  */
-export const isSubmap: <K, A>(SK: Eq<K>, SA: Eq<A>) => (d1: Map<K, A>, d2: Map<K, A>) => boolean = RM.isSubmap
+export const isSubmap: <K, A>(
+  SK: Eq<K>,
+  SA: Eq<A>
+) => {
+  (that: Map<K, A>): (me: Map<K, A>) => boolean
+  (me: Map<K, A>, that: Map<K, A>): boolean
+} = RM.isSubmap
 
 /**
  * @since 2.0.0
diff --git a/src/NonEmptyArray.ts b/src/NonEmptyArray.ts
index 9868f000..1dc279b9 100644
--- a/src/NonEmptyArray.ts
+++ b/src/NonEmptyArray.ts
@@ -34,6 +34,7 @@ export interface NonEmptyArray<A> extends Array<A> {
 }
 /* tslint:enable:readonly-keyword */
 
+// TODO: remove in v3
 /**
  * Append an element to the front of an array, creating a new non empty array
  *
@@ -47,6 +48,7 @@ export interface NonEmptyArray<A> extends Array<A> {
  */
 export const cons: <A>(head: A, tail: Array<A>) => NonEmptyArray<A> = RNEA.cons as any
 
+// TODO: remove in v3
 /**
  * Append an element to the end of an array, creating a new non empty array
  *
@@ -68,6 +70,7 @@ export const snoc: <A>(init: Array<A>, end: A) => NonEmptyArray<A> = RNEA.snoc a
  */
 export const fromArray: <A>(as: Array<A>) => Option<NonEmptyArray<A>> = RNEA.fromArray as any
 
+// TODO: remove in v3
 /**
  * @category instances
  * @since 2.0.0
@@ -267,6 +270,7 @@ export const filterWithIndex: <A>(
  */
 export const of: <A>(a: A) => NonEmptyArray<A> = RNEA.of as any
 
+// TODO: curry in v3
 /**
  * @category constructors
  * @since 2.2.0
@@ -296,7 +300,10 @@ export const zipWith: <A, B, C>(
  * @category combinators
  * @since 2.5.1
  */
-export const zip: <A, B>(fa: NonEmptyArray<A>, fb: NonEmptyArray<B>) => NonEmptyArray<[A, B]> = RNEA.zip as any
+export const zip: {
+  <B>(bs: NonEmptyArray<B>): <A>(as: NonEmptyArray<A>) => NonEmptyArray<[A, B]>
+  <A, B>(as: NonEmptyArray<A>, bs: NonEmptyArray<B>): NonEmptyArray<[A, B]>
+} = RNEA.zip as any
 
 /**
  * @since 2.5.1
diff --git a/src/OptionT.ts b/src/OptionT.ts
index 8033bf2c..0535e3c5 100644
--- a/src/OptionT.ts
+++ b/src/OptionT.ts
@@ -12,6 +12,8 @@ import { HKT, Kind, Kind2, URIS, URIS2 } from './HKT'
 import { Monad, Monad1, Monad2, Monad2C } from './Monad'
 import { fold, none, Option, applicativeOption, some, URI } from './Option'
 
+// TODO: remove module in v3
+
 /**
  * @category model
  * @since 2.0.0
diff --git a/src/Ord.ts b/src/Ord.ts
index 6e7b212f..2f039ae6 100644
--- a/src/Ord.ts
+++ b/src/Ord.ts
@@ -63,6 +63,7 @@ export const ordBoolean: Ord<boolean> = {
   compare
 }
 
+// TODO: curry in v3
 /**
  * Test whether one value is _strictly less than_ another
  *
@@ -72,6 +73,7 @@ export function lt<A>(O: Ord<A>): (x: A, y: A) => boolean {
   return (x, y) => O.compare(x, y) === -1
 }
 
+// TODO: curry in v3
 /**
  * Test whether one value is _strictly greater than_ another
  *
@@ -81,6 +83,7 @@ export function gt<A>(O: Ord<A>): (x: A, y: A) => boolean {
   return (x, y) => O.compare(x, y) === 1
 }
 
+// TODO: curry in v3
 /**
  * Test whether one value is _non-strictly less than_ another
  *
@@ -90,6 +93,7 @@ export function leq<A>(O: Ord<A>): (x: A, y: A) => boolean {
   return (x, y) => O.compare(x, y) !== 1
 }
 
+// TODO: curry in v3
 /**
  * Test whether one value is _non-strictly greater than_ another
  *
@@ -99,6 +103,7 @@ export function geq<A>(O: Ord<A>): (x: A, y: A) => boolean {
   return (x, y) => O.compare(x, y) !== -1
 }
 
+// TODO: curry in v3
 /**
  * Take the minimum of two values. If they are considered equal, the first argument is chosen
  *
@@ -108,6 +113,7 @@ export function min<A>(O: Ord<A>): (x: A, y: A) => A {
   return (x, y) => (O.compare(x, y) === 1 ? y : x)
 }
 
+// TODO: curry in v3
 /**
  * Take the maximum of two values. If they are considered equal, the first argument is chosen
  *
diff --git a/src/ReaderEither.ts b/src/ReaderEither.ts
index fd9fdf86..78227f69 100644
--- a/src/ReaderEither.ts
+++ b/src/ReaderEither.ts
@@ -145,6 +145,7 @@ export const swap: <R, E, A>(ma: ReaderEither<R, E, A>) => ReaderEither<R, A, E>
   /*#__PURE__*/
   R.map(E.swap)
 
+// TODO: remove in v3
 /**
  * @category combinators
  * @since 2.0.0
@@ -395,6 +396,7 @@ export function getApplyMonoid<R, E, A>(M: Monoid<A>): Monoid<ReaderEither<R, E,
   }
 }
 
+// TODO: remove in v3
 /**
  * @category instances
  * @since 2.3.0
diff --git a/src/ReaderT.ts b/src/ReaderT.ts
index 7ac75aef..6a8c5bb6 100644
--- a/src/ReaderT.ts
+++ b/src/ReaderT.ts
@@ -5,6 +5,8 @@ import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
 import { Monad, Monad1, Monad2, Monad2C, Monad3 } from './Monad'
 import { Reader } from './Reader'
 
+// TODO: remove module in v3
+
 /**
  * @category model
  * @since 2.0.0
diff --git a/src/ReaderTask.ts b/src/ReaderTask.ts
index d1d6d241..2b554e86 100644
--- a/src/ReaderTask.ts
+++ b/src/ReaderTask.ts
@@ -67,6 +67,7 @@ export const asks: <R, A = never>(f: (r: R) => A) => ReaderTask<R, A> = (f) => (
 // combinators
 // -------------------------------------------------------------------------------------
 
+// TODO: remove in v3
 /**
  * @category combinators
  * @since 2.3.0
@@ -289,6 +290,7 @@ export const readerTaskSeq: typeof readerTask = {
 // utils
 // -------------------------------------------------------------------------------------
 
+// TODO: remove in v3
 /**
  * @since 2.4.0
  */
diff --git a/src/ReaderTaskEither.ts b/src/ReaderTaskEither.ts
index fe1333d7..30912af6 100644
--- a/src/ReaderTaskEither.ts
+++ b/src/ReaderTaskEither.ts
@@ -240,6 +240,7 @@ export function swap<R, E, A>(ma: ReaderTaskEither<R, E, A>): ReaderTaskEither<R
   return (e) => TE.swap(ma(e))
 }
 
+// TODO: remove in v3
 /**
  * @category combinators
  * @since 2.0.0
@@ -665,6 +666,7 @@ export const readerTaskEitherSeq: typeof readerTaskEither = {
 // utils
 // -------------------------------------------------------------------------------------
 
+// TODO: remove in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts
index 7e0988b9..803b1867 100644
--- a/src/ReadonlyArray.ts
+++ b/src/ReadonlyArray.ts
@@ -168,13 +168,6 @@ export function getOrd<A>(O: Ord<A>): Ord<ReadonlyArray<A>> {
   })
 }
 
-/**
- * An empty array
- *
- * @since 2.5.0
- */
-export const empty: ReadonlyArray<never> = []
-
 /**
  * Return a list of length `n` with element `i` initialized with `f(i)`
  *
@@ -370,34 +363,48 @@ export function isOutOfBound<A>(i: number, as: ReadonlyArray<A>): boolean {
   return i < 0 || i >= as.length
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * This function provides a safe way to read a value at a particular index from an array
  *
  * @example
  * import { lookup } from 'fp-ts/lib/ReadonlyArray'
  * import { some, none } from 'fp-ts/lib/Option'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(lookup(1, [1, 2, 3]), some(2))
- * assert.deepStrictEqual(lookup(3, [1, 2, 3]), none)
+ * assert.deepStrictEqual(pipe([1, 2, 3], lookup(1)), some(2))
+ * assert.deepStrictEqual(pipe([1, 2, 3], lookup(3)), none)
  *
  * @since 2.5.0
  */
-export function lookup<A>(i: number, as: ReadonlyArray<A>): Option<A> {
-  return isOutOfBound(i, as) ? none : some(as[i])
+export function lookup(i: number): <A>(as: ReadonlyArray<A>) => Option<A>
+export function lookup<A>(i: number, as: ReadonlyArray<A>): Option<A>
+export function lookup<A>(i: number, as?: ReadonlyArray<A>): Option<A> | (<A>(as: ReadonlyArray<A>) => Option<A>) {
+  return as === undefined ? (as) => lookup(i, as) : isOutOfBound(i, as) ? none : some(as[i])
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Attaches an element to the front of an array, creating a new non empty array
  *
  * @example
  * import { cons } from 'fp-ts/lib/ReadonlyArray'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(cons(0, [1, 2, 3]), [0, 1, 2, 3])
+ * assert.deepStrictEqual(pipe([1, 2, 3], cons(0)), [0, 1, 2, 3])
  *
  * @category constructors
  * @since 2.5.0
  */
-export function cons<A>(head: A, tail: ReadonlyArray<A>): ReadonlyNonEmptyArray<A> {
+export function cons<A>(head: A): (tail: ReadonlyArray<A>) => ReadonlyNonEmptyArray<A>
+export function cons<A>(head: A, tail: ReadonlyArray<A>): ReadonlyNonEmptyArray<A>
+export function cons<A>(
+  head: A,
+  tail?: ReadonlyArray<A>
+): ReadonlyNonEmptyArray<A> | ((tail: ReadonlyArray<A>) => ReadonlyNonEmptyArray<A>) {
+  if (tail === undefined) {
+    return (tail) => cons(head, tail)
+  }
   const len = tail.length
   const r = Array(len + 1)
   for (let i = 0; i < len; i++) {
@@ -407,6 +414,7 @@ export function cons<A>(head: A, tail: ReadonlyArray<A>): ReadonlyNonEmptyArray<
   return (r as unknown) as ReadonlyNonEmptyArray<A>
 }
 
+// TODO: curry and make data-last in v3
 /**
  * Append an element to the end of an array, creating a new non empty array
  *
@@ -818,16 +826,6 @@ export function findLastIndex<A>(predicate: Predicate<A>): (as: ReadonlyArray<A>
   }
 }
 
-/**
- * @since 2.5.0
- */
-export function unsafeInsertAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A> {
-  // tslint:disable-next-line: readonly-array
-  const xs = as.slice()
-  xs.splice(i, 0, a)
-  return xs
-}
-
 /**
  * Insert an element at the specified index, creating a new array, or returning `None` if the index is out of bounds
  *
@@ -843,21 +841,6 @@ export function insertAt<A>(i: number, a: A): (as: ReadonlyArray<A>) => Option<R
   return (as) => (i < 0 || i > as.length ? none : some(unsafeInsertAt(i, a, as)))
 }
 
-/**
- * @category combinators
- * @since 2.5.0
- */
-export function unsafeUpdateAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A> {
-  if (as[i] === a) {
-    return as
-  } else {
-    // tslint:disable-next-line: readonly-array
-    const xs = as.slice()
-    xs[i] = a
-    return xs
-  }
-}
-
 /**
  * Change the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
  *
@@ -874,17 +857,6 @@ export function updateAt<A>(i: number, a: A): (as: ReadonlyArray<A>) => Option<R
   return (as) => (isOutOfBound(i, as) ? none : some(unsafeUpdateAt(i, a, as)))
 }
 
-/**
- * @category combinators
- * @since 2.5.0
- */
-export function unsafeDeleteAt<A>(i: number, as: ReadonlyArray<A>): ReadonlyArray<A> {
-  // tslint:disable-next-line: readonly-array
-  const xs = as.slice()
-  xs.splice(i, 1)
-  return xs
-}
-
 /**
  * Delete the element at the specified index, creating a new array, or returning `None` if the index is out of bounds
  *
@@ -931,6 +903,9 @@ export function modifyAt<A>(i: number, f: (a: A) => A): (as: ReadonlyArray<A>) =
  * @since 2.5.0
  */
 export function reverse<A>(as: ReadonlyArray<A>): ReadonlyArray<A> {
+  if (isEmpty(as)) {
+    return as
+  }
   return as.slice().reverse()
 }
 
@@ -996,9 +971,10 @@ export function lefts<E, A>(as: ReadonlyArray<Either<E, A>>): ReadonlyArray<E> {
  * @since 2.5.0
  */
 export function sort<A>(O: Ord<A>): (as: ReadonlyArray<A>) => ReadonlyArray<A> {
-  return (as) => as.slice().sort(O.compare)
+  return (as) => (isEmpty(as) ? as : as.slice().sort(O.compare))
 }
 
+// TODO: curry and make data-last in v3
 /**
  * Apply a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
  * input array is short, excess elements of the longer array are discarded.
@@ -1021,20 +997,30 @@ export function zipWith<A, B, C>(fa: ReadonlyArray<A>, fb: ReadonlyArray<B>, f:
   return fc
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
  * longer array are discarded
  *
  * @example
  * import { zip } from 'fp-ts/lib/ReadonlyArray'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(zip([1, 2, 3], ['a', 'b', 'c', 'd']), [[1, 'a'], [2, 'b'], [3, 'c']])
+ * assert.deepStrictEqual(pipe([1, 2, 3], zip(['a', 'b', 'c', 'd'])), [[1, 'a'], [2, 'b'], [3, 'c']])
  *
  * @category combinators
  * @since 2.5.0
  */
-export function zip<A, B>(fa: ReadonlyArray<A>, fb: ReadonlyArray<B>): ReadonlyArray<readonly [A, B]> {
-  return zipWith(fa, fb, (a, b) => [a, b])
+export function zip<B>(bs: ReadonlyArray<B>): <A>(as: ReadonlyArray<A>) => ReadonlyArray<readonly [A, B]>
+export function zip<A, B>(as: ReadonlyArray<A>, bs: ReadonlyArray<B>): ReadonlyArray<readonly [A, B]>
+export function zip<A, B>(
+  as: ReadonlyArray<A>,
+  bs?: ReadonlyArray<B>
+): ReadonlyArray<readonly [A, B]> | ((bs: ReadonlyArray<B>) => ReadonlyArray<readonly [B, A]>) {
+  if (bs === undefined) {
+    return (bs) => zip(bs, as)
+  }
+  return zipWith(as, bs, (a, b) => [a, b])
 }
 
 /**
@@ -1085,6 +1071,7 @@ export function rotate(n: number): <A>(as: ReadonlyArray<A>) => ReadonlyArray<A>
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test if a value is a member of an array. Takes a `Eq<A>` as a single
  * argument which returns the function to use to search for a value of type `A` in
@@ -1093,14 +1080,25 @@ export function rotate(n: number): <A>(as: ReadonlyArray<A>) => ReadonlyArray<A>
  * @example
  * import { elem } from 'fp-ts/lib/ReadonlyArray'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.strictEqual(elem(eqNumber)(1, [1, 2, 3]), true)
- * assert.strictEqual(elem(eqNumber)(4, [1, 2, 3]), false)
+ * assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(2)), true)
+ * assert.strictEqual(pipe([1, 2, 3], elem(eqNumber)(0)), false)
  *
  * @since 2.5.0
  */
-export function elem<A>(E: Eq<A>): (a: A, as: ReadonlyArray<A>) => boolean {
-  return (a, as) => {
+export function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): (as: ReadonlyArray<A>) => boolean
+  (a: A, as: ReadonlyArray<A>): boolean
+}
+export function elem<A>(E: Eq<A>): (a: A, as?: ReadonlyArray<A>) => boolean | ((as: ReadonlyArray<A>) => boolean) {
+  return (a, as?) => {
+    if (as === undefined) {
+      const elemE = elem(E)
+      return (as) => elemE(a, as)
+    }
     const predicate = (element: A) => E.equals(element, a)
     let i = 0
     const len = as.length
@@ -1195,20 +1193,18 @@ export function sortBy<A>(ords: ReadonlyArray<Ord<A>>): (as: ReadonlyArray<A>) =
  * @category combinators
  * @since 2.5.0
  */
-export function chop<A, B>(
-  f: (as: ReadonlyNonEmptyArray<A>) => readonly [B, ReadonlyArray<A>]
-): (as: ReadonlyArray<A>) => ReadonlyArray<B> {
-  return (as) => {
-    // tslint:disable-next-line: readonly-array
-    const result: Array<B> = []
-    let cs: ReadonlyArray<A> = as
-    while (isNonEmpty(cs)) {
-      const [b, c] = f(cs)
-      result.push(b)
-      cs = c
-    }
-    return result
+export const chop = <A, B>(f: (as: ReadonlyNonEmptyArray<A>) => readonly [B, ReadonlyArray<A>]) => (
+  as: ReadonlyArray<A>
+): ReadonlyArray<B> => {
+  // tslint:disable-next-line: readonly-array
+  const result: Array<B> = []
+  let cs: ReadonlyArray<A> = as
+  while (isNonEmpty(cs)) {
+    const [b, c] = f(cs)
+    result.push(b)
+    cs = c
   }
+  return result
 }
 
 /**
@@ -1309,27 +1305,43 @@ export function comprehension<R>(
   return go(empty, input)
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Creates an array of unique values, in order, from all given arrays using a `Eq` for equality comparisons
  *
  * @example
  * import { union } from 'fp-ts/lib/ReadonlyArray'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(union(eqNumber)([1, 2], [2, 3]), [1, 2, 3])
+ * assert.deepStrictEqual(pipe([1, 2], union(eqNumber)([2, 3])), [1, 2, 3])
  *
  * @category combinators
  * @since 2.5.0
  */
-export function union<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>) => ReadonlyArray<A> {
+export function union<A>(
+  E: Eq<A>
+): {
+  (xs: ReadonlyArray<A>): (ys: ReadonlyArray<A>) => ReadonlyArray<A>
+  (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>): ReadonlyArray<A>
+}
+export function union<A>(
+  E: Eq<A>
+): (xs: ReadonlyArray<A>, ys?: ReadonlyArray<A>) => ReadonlyArray<A> | ((ys: ReadonlyArray<A>) => ReadonlyArray<A>) {
   const elemE = elem(E)
-  return (xs, ys) =>
-    concat(
+  return (xs, ys?) => {
+    if (ys === undefined) {
+      const unionE = union(E)
+      return (ys) => unionE(ys, xs)
+    }
+    return concat(
       xs,
       ys.filter((a) => !elemE(a, xs))
     )
+  }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Creates an array of unique values that are included in all given arrays using a `Eq` for equality
  * comparisons. The order and references of result values are determined by the first array.
@@ -1337,17 +1349,33 @@ export function union<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>)
  * @example
  * import { intersection } from 'fp-ts/lib/ReadonlyArray'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(intersection(eqNumber)([1, 2], [2, 3]), [2])
+ * assert.deepStrictEqual(pipe([1, 2], intersection(eqNumber)([2, 3])), [2])
  *
  * @category combinators
  * @since 2.5.0
  */
-export function intersection<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>) => ReadonlyArray<A> {
+export function intersection<A>(
+  E: Eq<A>
+): {
+  (xs: ReadonlyArray<A>): (ys: ReadonlyArray<A>) => ReadonlyArray<A>
+  (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>): ReadonlyArray<A>
+}
+export function intersection<A>(
+  E: Eq<A>
+): (xs: ReadonlyArray<A>, ys?: ReadonlyArray<A>) => ReadonlyArray<A> | ((ys: ReadonlyArray<A>) => ReadonlyArray<A>) {
   const elemE = elem(E)
-  return (xs, ys) => xs.filter((a) => elemE(a, ys))
+  return (xs, ys?) => {
+    if (ys === undefined) {
+      const intersectionE = intersection(E)
+      return (ys) => intersectionE(ys, xs)
+    }
+    return xs.filter((a) => elemE(a, ys))
+  }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Creates an array of array values not included in the other given array using a `Eq` for equality
  * comparisons. The order and references of result values are determined by the first array.
@@ -1355,15 +1383,30 @@ export function intersection<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyAr
  * @example
  * import { difference } from 'fp-ts/lib/ReadonlyArray'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(difference(eqNumber)([1, 2], [2, 3]), [1])
+ * assert.deepStrictEqual(pipe([1, 2], difference(eqNumber)([2, 3])), [1])
  *
  * @category combinators
  * @since 2.5.0
  */
-export function difference<A>(E: Eq<A>): (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>) => ReadonlyArray<A> {
+export function difference<A>(
+  E: Eq<A>
+): {
+  (xs: ReadonlyArray<A>): (ys: ReadonlyArray<A>) => ReadonlyArray<A>
+  (xs: ReadonlyArray<A>, ys: ReadonlyArray<A>): ReadonlyArray<A>
+}
+export function difference<A>(
+  E: Eq<A>
+): (xs: ReadonlyArray<A>, ys?: ReadonlyArray<A>) => ReadonlyArray<A> | ((ys: ReadonlyArray<A>) => ReadonlyArray<A>) {
   const elemE = elem(E)
-  return (xs, ys) => xs.filter((a) => !elemE(a, ys))
+  return (xs, ys?) => {
+    if (ys === undefined) {
+      const differenceE = difference(E)
+      return (ys) => differenceE(ys, xs)
+    }
+    return xs.filter((a) => !elemE(a, ys))
+  }
 }
 
 /**
@@ -1830,6 +1873,7 @@ declare module './HKT' {
 }
 
 /**
+ * @category Traversable
  * @since 2.6.3
  */
 export const traverse: PipeableTraverse1<URI> = <F>(
@@ -1840,6 +1884,7 @@ export const traverse: PipeableTraverse1<URI> = <F>(
 }
 
 /**
+ * @category Traversable
  * @since 2.6.3
  */
 export const sequence: Traversable1<URI>['sequence'] = <F>(F: Applicative<F>) => <A>(
@@ -1854,6 +1899,7 @@ export const sequence: Traversable1<URI>['sequence'] = <F>(F: Applicative<F>) =>
 }
 
 /**
+ * @category TraversableWithIndex
  * @since 2.6.3
  */
 export const traverseWithIndex: PipeableTraverseWithIndex1<URI, number> = <F>(
@@ -1887,8 +1933,10 @@ export const wilt: PipeableWilt1<URI> = <F>(
   return (f) => (ta) => wiltF(ta, f)
 }
 
-// TODO: export
-const unfold = <A, B>(b: B, f: (b: B) => Option<readonly [A, B]>): ReadonlyArray<A> => {
+/**
+ * @since 2.6.6
+ */
+export const unfold = <A, B>(b: B, f: (b: B) => Option<readonly [A, B]>): ReadonlyArray<A> => {
   // tslint:disable-next-line: readonly-array
   const ret: Array<A> = []
   let bb: B = b
@@ -1951,3 +1999,52 @@ export const readonlyArray: Monad1<URI> &
   wither: wither_,
   wilt: wilt_
 }
+
+// -------------------------------------------------------------------------------------
+// unsafe
+// -------------------------------------------------------------------------------------
+
+/**
+ * @category unsafe
+ * @since 2.5.0
+ */
+export function unsafeInsertAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A> {
+  const xs = as.slice()
+  xs.splice(i, 0, a)
+  return xs
+}
+
+/**
+ * @category unsafe
+ * @since 2.5.0
+ */
+export function unsafeUpdateAt<A>(i: number, a: A, as: ReadonlyArray<A>): ReadonlyArray<A> {
+  if (as[i] === a) {
+    return as
+  } else {
+    const xs = as.slice()
+    xs[i] = a
+    return xs
+  }
+}
+
+/**
+ * @category unsafe
+ * @since 2.5.0
+ */
+export function unsafeDeleteAt<A>(i: number, as: ReadonlyArray<A>): ReadonlyArray<A> {
+  const xs = as.slice()
+  xs.splice(i, 1)
+  return xs
+}
+
+// -------------------------------------------------------------------------------------
+// utils
+// -------------------------------------------------------------------------------------
+
+/**
+ * An empty array
+ *
+ * @since 2.5.0
+ */
+export const empty: ReadonlyArray<never> = []
diff --git a/src/ReadonlyMap.ts b/src/ReadonlyMap.ts
index 5b878a75..d54e6432 100644
--- a/src/ReadonlyMap.ts
+++ b/src/ReadonlyMap.ts
@@ -79,14 +79,27 @@ export function isEmpty<K, A>(d: ReadonlyMap<K, A>): boolean {
   return d.size === 0
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test whether or not a key exists in a map
  *
  * @since 2.5.0
  */
-export function member<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => boolean {
+export function member<K>(
+  E: Eq<K>
+): {
+  (k: K): <A>(m: ReadonlyMap<K, A>) => boolean
+  <A>(k: K, m: ReadonlyMap<K, A>): boolean
+}
+export function member<K>(E: Eq<K>): <A>(k: K, m?: ReadonlyMap<K, A>) => boolean | ((m: ReadonlyMap<K, A>) => boolean) {
   const lookupE = lookup(E)
-  return (k, m) => O.isSome(lookupE(k, m))
+  return (k, m?) => {
+    if (m === undefined) {
+      const memberE = member(E)
+      return (m) => memberE(k, m)
+    }
+    return O.isSome(lookupE(k, m))
+  }
 }
 
 interface Next<A> {
@@ -94,13 +107,24 @@ interface Next<A> {
   readonly value: A
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test whether or not a value is a member of a map
  *
  * @since 2.5.0
  */
-export function elem<A>(E: Eq<A>): <K>(a: A, m: ReadonlyMap<K, A>) => boolean {
-  return (a, m) => {
+export function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): <K>(m: ReadonlyMap<K, A>) => boolean
+  <K>(a: A, m: ReadonlyMap<K, A>): boolean
+}
+export function elem<A>(E: Eq<A>): <K>(a: A, m?: ReadonlyMap<K, A>) => boolean | ((m: ReadonlyMap<K, A>) => boolean) {
+  return (a, m?) => {
+    if (m === undefined) {
+      const elemE = elem(E)
+      return (m) => elemE(a, m)
+    }
     const values = m.values()
     let e: Next<A>
     // tslint:disable-next-line: strict-boolean-expressions
@@ -275,14 +299,27 @@ export function pop<K>(E: Eq<K>): (k: K) => <A>(m: ReadonlyMap<K, A>) => Option<
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Lookup the value for a key in a `Map`.
  * If the result is a `Some`, the existing key is also returned.
  *
  * @since 2.5.0
  */
-export function lookupWithKey<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => Option<readonly [K, A]> {
-  return <A>(k: K, m: ReadonlyMap<K, A>) => {
+export function lookupWithKey<K>(
+  E: Eq<K>
+): {
+  (k: K): <A>(m: ReadonlyMap<K, A>) => Option<readonly [K, A]>
+  <A>(k: K, m: ReadonlyMap<K, A>): Option<readonly [K, A]>
+}
+export function lookupWithKey<K>(
+  E: Eq<K>
+): <A>(k: K, m?: ReadonlyMap<K, A>) => Option<readonly [K, A]> | ((m: ReadonlyMap<K, A>) => Option<readonly [K, A]>) {
+  return <A>(k: K, m?: ReadonlyMap<K, A>) => {
+    if (m === undefined) {
+      const lookupWithKeyE = lookupWithKey(E)
+      return (m) => lookupWithKeyE(k, m)
+    }
     const entries = m.entries()
     let e: Next<readonly [K, A]>
     // tslint:disable-next-line: strict-boolean-expressions
@@ -296,34 +333,63 @@ export function lookupWithKey<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => O
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Lookup the value for a key in a `Map`.
  *
  * @since 2.5.0
  */
-export function lookup<K>(E: Eq<K>): <A>(k: K, m: ReadonlyMap<K, A>) => Option<A> {
+export function lookup<K>(
+  E: Eq<K>
+): {
+  (k: K): <A>(m: ReadonlyMap<K, A>) => Option<A>
+  <A>(k: K, m: ReadonlyMap<K, A>): Option<A>
+}
+export function lookup<K>(
+  E: Eq<K>
+): <A>(k: K, m?: ReadonlyMap<K, A>) => Option<A> | ((m: ReadonlyMap<K, A>) => Option<A>) {
   const lookupWithKeyE = lookupWithKey(E)
-  return (k, m) =>
-    pipe(
+  return (k, m?) => {
+    if (m === undefined) {
+      const lookupE = lookup(E)
+      return (m) => lookupE(k, m)
+    }
+    return pipe(
       lookupWithKeyE(k, m),
       O.map(([_, a]) => a)
     )
+  }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
- * Test whether or not one Map contains all of the keys and values contained in another Map
+ * Test whether or not one `Map` contains all of the keys and values contained in another `Map`
  *
  * @since 2.5.0
  */
-export function isSubmap<K, A>(SK: Eq<K>, SA: Eq<A>): (d1: ReadonlyMap<K, A>, d2: ReadonlyMap<K, A>) => boolean {
+export function isSubmap<K, A>(
+  SK: Eq<K>,
+  SA: Eq<A>
+): {
+  (that: ReadonlyMap<K, A>): (me: ReadonlyMap<K, A>) => boolean
+  (me: ReadonlyMap<K, A>, that: ReadonlyMap<K, A>): boolean
+}
+export function isSubmap<K, A>(
+  SK: Eq<K>,
+  SA: Eq<A>
+): (me: ReadonlyMap<K, A>, that?: ReadonlyMap<K, A>) => boolean | ((me: ReadonlyMap<K, A>) => boolean) {
   const lookupWithKeyS = lookupWithKey(SK)
-  return (d1: ReadonlyMap<K, A>, d2: ReadonlyMap<K, A>): boolean => {
-    const entries = d1.entries()
+  return (me: ReadonlyMap<K, A>, that?: ReadonlyMap<K, A>) => {
+    if (that === undefined) {
+      const isSubmapSKSA = isSubmap(SK, SA)
+      return (that) => isSubmapSKSA(that, me)
+    }
+    const entries = me.entries()
     let e: Next<readonly [K, A]>
     // tslint:disable-next-line: strict-boolean-expressions
     while (!(e = entries.next()).done) {
       const [k, a] = e.value
-      const d2OptA = lookupWithKeyS(k, d2)
+      const d2OptA = lookupWithKeyS(k, that)
       if (O.isNone(d2OptA) || !SK.equals(k, d2OptA.value[0]) || !SA.equals(a, d2OptA.value[1])) {
         return false
       }
diff --git a/src/ReadonlyNonEmptyArray.ts b/src/ReadonlyNonEmptyArray.ts
index 1d6ad3d3..1ebff86f 100644
--- a/src/ReadonlyNonEmptyArray.ts
+++ b/src/ReadonlyNonEmptyArray.ts
@@ -355,10 +355,10 @@ export const zipWith: <A, B, C>(
  * @category combinators
  * @since 2.5.1
  */
-export const zip: <A, B>(
-  fa: ReadonlyNonEmptyArray<A>,
-  fb: ReadonlyNonEmptyArray<B>
-) => ReadonlyNonEmptyArray<readonly [A, B]> = RA.zip as any
+export const zip: {
+  <B>(bs: ReadonlyNonEmptyArray<B>): <A>(as: ReadonlyNonEmptyArray<A>) => ReadonlyNonEmptyArray<readonly [A, B]>
+  <A, B>(as: ReadonlyNonEmptyArray<A>, bs: ReadonlyNonEmptyArray<B>): ReadonlyNonEmptyArray<readonly [A, B]>
+} = RA.zip as any
 
 /**
  * @since 2.5.1
diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts
index edcd6a46..c49c5d12 100644
--- a/src/ReadonlyRecord.ts
+++ b/src/ReadonlyRecord.ts
@@ -238,15 +238,31 @@ export function pop(k: string): <A>(r: ReadonlyRecord<string, A>) => Option<read
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test whether one record contains all of the keys and values contained in another record
  *
  * @since 2.5.0
  */
-export function isSubrecord<A>(E: Eq<A>): (x: ReadonlyRecord<string, A>, y: ReadonlyRecord<string, A>) => boolean {
-  return (x, y) => {
-    for (const k in x) {
-      if (!_hasOwnProperty.call(y, k) || !E.equals(x[k], y[k])) {
+export function isSubrecord<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlyRecord<string, A>): (me: ReadonlyRecord<string, A>) => boolean
+  (me: ReadonlyRecord<string, A>, that: ReadonlyRecord<string, A>): boolean
+}
+export function isSubrecord<A>(
+  E: Eq<A>
+): (
+  me: ReadonlyRecord<string, A>,
+  that?: ReadonlyRecord<string, A>
+) => boolean | ((me: ReadonlyRecord<string, A>) => boolean) {
+  return (me, that?) => {
+    if (that === undefined) {
+      const isSubrecordE = isSubrecord(E)
+      return (that) => isSubrecordE(that, me)
+    }
+    for (const k in me) {
+      if (!_hasOwnProperty.call(that, k) || !E.equals(me[k], that[k])) {
         return false
       }
     }
@@ -261,7 +277,7 @@ export function isSubrecord<A>(E: Eq<A>): (x: ReadonlyRecord<string, A>, y: Read
 export function getEq<K extends string, A>(E: Eq<A>): Eq<ReadonlyRecord<K, A>>
 export function getEq<A>(E: Eq<A>): Eq<ReadonlyRecord<string, A>> {
   const isSubrecordE = isSubrecord(E)
-  return fromEquals((x, y) => isSubrecordE(x, y) && isSubrecordE(y, x))
+  return fromEquals((x, y) => isSubrecordE(x)(y) && isSubrecordE(y)(x))
 }
 
 /**
@@ -292,7 +308,7 @@ export function getMonoid<A>(S: Semigroup<A>): Monoid<ReadonlyRecord<string, A>>
       if (len === 0) {
         return x
       }
-      const r: Record<string, A> = { ...x }
+      const r: Record<string, A> = Object.assign({}, x)
       for (let i = 0; i < len; i++) {
         const k = keys[i]
         r[k] = _hasOwnProperty.call(x, k) ? S.concat(x[k], y[k]) : y[k]
@@ -303,12 +319,21 @@ export function getMonoid<A>(S: Semigroup<A>): Monoid<ReadonlyRecord<string, A>>
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Lookup the value for a key in a record
  *
  * @since 2.5.0
  */
-export function lookup<A>(k: string, r: ReadonlyRecord<string, A>): Option<A> {
+export function lookup(k: string): <A>(r: ReadonlyRecord<string, A>) => Option<A>
+export function lookup<A>(k: string, r: ReadonlyRecord<string, A>): Option<A>
+export function lookup<A>(
+  k: string,
+  r?: ReadonlyRecord<string, A>
+): Option<A> | ((r: ReadonlyRecord<string, A>) => Option<A>) {
+  if (r === undefined) {
+    return (r) => lookup(k, r)
+  }
   return _hasOwnProperty.call(r, k) ? optionSome(r[k]) : none
 }
 
@@ -695,11 +720,24 @@ export function some<A>(predicate: (a: A) => boolean): (r: ReadonlyRecord<string
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * @since 2.5.0
  */
-export function elem<A>(E: Eq<A>): (a: A, fa: ReadonlyRecord<string, A>) => boolean {
-  return (a, fa) => {
+export function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): (fa: ReadonlyRecord<string, A>) => boolean
+  (a: A, fa: ReadonlyRecord<string, A>): boolean
+}
+export function elem<A>(
+  E: Eq<A>
+): (a: A, fa?: ReadonlyRecord<string, A>) => boolean | ((fa: ReadonlyRecord<string, A>) => boolean) {
+  return (a, fa?) => {
+    if (fa === undefined) {
+      const elemE = elem(E)
+      return (fa) => elemE(a, fa)
+    }
     for (const k in fa) {
       if (E.equals(fa[k], a)) {
         return true
diff --git a/src/ReadonlySet.ts b/src/ReadonlySet.ts
index a6ea342e..59564bd0 100644
--- a/src/ReadonlySet.ts
+++ b/src/ReadonlySet.ts
@@ -140,14 +140,29 @@ export function chain<B>(E: Eq<B>): <A>(f: (x: A) => ReadonlySet<B>) => (set: Re
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * `true` if and only if every element in the first set is an element of the second set
  *
  * @since 2.5.0
  */
-export function isSubset<A>(E: Eq<A>): (x: ReadonlySet<A>, y: ReadonlySet<A>) => boolean {
+export function isSubset<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => boolean
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): boolean
+}
+export function isSubset<A>(
+  E: Eq<A>
+): (me: ReadonlySet<A>, that?: ReadonlySet<A>) => boolean | ((me: ReadonlySet<A>) => boolean) {
   const elemE = elem(E)
-  return (x, y) => every((a: A) => elemE(a, y))(x)
+  return (me, that?) => {
+    if (that === undefined) {
+      const isSubsetE = isSubset(E)
+      return (that) => isSubsetE(that, me)
+    }
+    return every((a: A) => elemE(a, that))(me)
+  }
 }
 
 /**
@@ -202,13 +217,24 @@ export function partition<A>(
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test if a value is a member of a set
  *
  * @since 2.5.0
  */
-export function elem<A>(E: Eq<A>): (a: A, set: ReadonlySet<A>) => boolean {
-  return (a, set) => {
+export function elem<A>(
+  E: Eq<A>
+): {
+  (a: A): (set: ReadonlySet<A>) => boolean
+  (a: A, set: ReadonlySet<A>): boolean
+}
+export function elem<A>(E: Eq<A>): (a: A, set?: ReadonlySet<A>) => boolean | ((set: ReadonlySet<A>) => boolean) {
+  return (a, set?) => {
+    if (set === undefined) {
+      const elemE = elem(E)
+      return (set) => elemE(a, set)
+    }
     const values = set.values()
     let e: Next<A>
     let found = false
@@ -220,23 +246,36 @@ export function elem<A>(E: Eq<A>): (a: A, set: ReadonlySet<A>) => boolean {
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Form the union of two sets
  *
  * @category combinators
  * @since 2.5.0
  */
-export function union<A>(E: Eq<A>): (set: ReadonlySet<A>, y: ReadonlySet<A>) => ReadonlySet<A> {
+export function union<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => ReadonlySet<A>
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): ReadonlySet<A>
+}
+export function union<A>(
+  E: Eq<A>
+): (me: ReadonlySet<A>, that?: ReadonlySet<A>) => ReadonlySet<A> | ((me: ReadonlySet<A>) => ReadonlySet<A>) {
   const elemE = elem(E)
-  return (x, y) => {
-    if (x === empty) {
-      return y
+  return (me, that?) => {
+    if (that === undefined) {
+      const unionE = union(E)
+      return (that) => unionE(me, that)
     }
-    if (y === empty) {
-      return x
+    if (me === empty) {
+      return that
     }
-    const r = new Set(x)
-    y.forEach((e) => {
+    if (that === empty) {
+      return me
+    }
+    const r = new Set(me)
+    that.forEach((e) => {
       if (!elemE(e, r)) {
         r.add(e)
       }
@@ -245,21 +284,34 @@ export function union<A>(E: Eq<A>): (set: ReadonlySet<A>, y: ReadonlySet<A>) =>
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * The set of elements which are in both the first and second set
  *
  * @category combinators
  * @since 2.5.0
  */
-export function intersection<A>(E: Eq<A>): (set: ReadonlySet<A>, y: ReadonlySet<A>) => ReadonlySet<A> {
+export function intersection<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => ReadonlySet<A>
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): ReadonlySet<A>
+}
+export function intersection<A>(
+  E: Eq<A>
+): (me: ReadonlySet<A>, that?: ReadonlySet<A>) => ReadonlySet<A> | ((that: ReadonlySet<A>) => ReadonlySet<A>) {
   const elemE = elem(E)
-  return (x, y) => {
-    if (x === empty || y === empty) {
+  return (me, that?) => {
+    if (that === undefined) {
+      const intersectionE = intersection(E)
+      return (that) => intersectionE(that, me)
+    }
+    if (me === empty || that === empty) {
       return empty
     }
     const r = new Set<A>()
-    x.forEach((e) => {
-      if (elemE(e, y)) {
+    me.forEach((e) => {
+      if (elemE(e, that)) {
         r.add(e)
       }
     })
@@ -301,21 +353,37 @@ export function partitionMap<B, C>(
   }
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Form the set difference (`x` - `y`)
  *
  * @example
  * import { difference } from 'fp-ts/lib/ReadonlySet'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(difference(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+ * assert.deepStrictEqual(pipe(new Set([1, 2]), difference(eqNumber)(new Set([1, 3]))), new Set([2]))
  *
  * @category combinators
  * @since 2.5.0
  */
-export function difference<A>(E: Eq<A>): (x: ReadonlySet<A>, y: ReadonlySet<A>) => ReadonlySet<A> {
+export function difference<A>(
+  E: Eq<A>
+): {
+  (that: ReadonlySet<A>): (me: ReadonlySet<A>) => ReadonlySet<A>
+  (me: ReadonlySet<A>, that: ReadonlySet<A>): ReadonlySet<A>
+}
+export function difference<A>(
+  E: Eq<A>
+): (me: ReadonlySet<A>, that?: ReadonlySet<A>) => ReadonlySet<A> | ((me: ReadonlySet<A>) => ReadonlySet<A>) {
   const elemE = elem(E)
-  return (x, y) => filter((a: A) => !elemE(a, y))(x)
+  return (me, that?) => {
+    if (that === undefined) {
+      const differenceE = difference(E)
+      return (that) => differenceE(that, me)
+    }
+    return filter((a: A) => !elemE(a, that))(me)
+  }
 }
 
 /**
@@ -374,7 +442,7 @@ export function singleton<A>(a: A): ReadonlySet<A> {
 export function insert<A>(E: Eq<A>): (a: A) => (set: ReadonlySet<A>) => ReadonlySet<A> {
   const elemE = elem(E)
   return (a) => (set) => {
-    if (!elemE(a, set)) {
+    if (!elemE(a)(set)) {
       const r = new Set(set)
       r.add(a)
       return r
diff --git a/src/ReadonlyTuple.ts b/src/ReadonlyTuple.ts
index 3b4b6091..cae3344c 100644
--- a/src/ReadonlyTuple.ts
+++ b/src/ReadonlyTuple.ts
@@ -111,6 +111,7 @@ export function getMonad<S>(M: Monoid<S>): Monad2C<URI, S> {
   }
 }
 
+// TODO: remove in v3
 /**
  * @category instances
  * @since 2.5.0
diff --git a/src/Record.ts b/src/Record.ts
index f6feb008..0a7636ee 100644
--- a/src/Record.ts
+++ b/src/Record.ts
@@ -137,12 +137,18 @@ export function pop(k: string): <A>(r: Record<string, A>) => Option<[A, Record<s
   return RR.pop(k) as any
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test whether one record contains all of the keys and values contained in another record
  *
  * @since 2.0.0
  */
-export const isSubrecord: <A>(E: Eq<A>) => (x: Record<string, A>, y: Record<string, A>) => boolean = RR.isSubrecord
+export const isSubrecord: <A>(
+  E: Eq<A>
+) => {
+  (that: Record<string, A>): (me: Record<string, A>) => boolean
+  (me: Record<string, A>, that: Record<string, A>): boolean
+} = RR.isSubrecord
 
 /**
  * @since 2.0.0
@@ -169,12 +175,16 @@ export function getMonoid<A>(S: Semigroup<A>): Monoid<Record<string, A>> {
   return RR.getMonoid(S)
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Lookup the value for a key in a record
  *
  * @since 2.0.0
  */
-export const lookup: <A>(k: string, r: Record<string, A>) => Option<A> = RR.lookup
+export const lookup: {
+  (k: string): <A>(r: Record<string, A>) => Option<A>
+  <A>(k: string, r: Record<string, A>): Option<A>
+} = RR.lookup
 
 /**
  * @since 2.0.0
@@ -474,10 +484,16 @@ export const every: <A>(predicate: Predicate<A>) => (r: Record<string, A>) => bo
  */
 export const some: <A>(predicate: (a: A) => boolean) => (r: Record<string, A>) => boolean = RR.some
 
+// TODO: remove non-curried overloading in v3
 /**
  * @since 2.0.0
  */
-export const elem: <A>(E: Eq<A>) => (a: A, fa: Record<string, A>) => boolean = RR.elem
+export const elem: <A>(
+  E: Eq<A>
+) => {
+  (a: A): (fa: Record<string, A>) => boolean
+  (a: A, fa: Record<string, A>): boolean
+} = RR.elem
 
 // -------------------------------------------------------------------------------------
 // pipeables
diff --git a/src/Semigroup.ts b/src/Semigroup.ts
index 7321c5bd..998db1b7 100644
--- a/src/Semigroup.ts
+++ b/src/Semigroup.ts
@@ -16,11 +16,31 @@ import { ReadonlyRecord } from './ReadonlyRecord'
  */
 export interface Semigroup<A> extends Magma<A> {}
 
+// TODO: remove non-curried overloading in v3
 /**
+ * @example
+ * import * as S from 'fp-ts/lib/Semigroup'
+ *
+ * const sum = S.fold(S.semigroupSum)(0)
+ *
+ * assert.deepStrictEqual(sum([1, 2, 3]), 6)
+ *
  * @since 2.0.0
  */
-export function fold<A>(S: Semigroup<A>): (a: A, as: ReadonlyArray<A>) => A {
-  return (a, as) => as.reduce(S.concat, a)
+export function fold<A>(
+  S: Semigroup<A>
+): {
+  (a: A): (as: ReadonlyArray<A>) => A
+  (a: A, as: ReadonlyArray<A>): A
+}
+export function fold<A>(S: Semigroup<A>): (a: A, as?: ReadonlyArray<A>) => A | ((as: ReadonlyArray<A>) => A) {
+  return (a, as?) => {
+    if (as === undefined) {
+      const foldS = fold(S)
+      return (as) => foldS(a, as)
+    }
+    return as.reduce(S.concat, a)
+  }
 }
 
 /**
diff --git a/src/Set.ts b/src/Set.ts
index e2c8b120..40b0af7f 100644
--- a/src/Set.ts
+++ b/src/Set.ts
@@ -61,12 +61,18 @@ export const every: <A>(predicate: Predicate<A>) => (set: Set<A>) => boolean = R
  */
 export const chain: <B>(E: Eq<B>) => <A>(f: (x: A) => Set<B>) => (set: Set<A>) => Set<B> = RS.chain as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * `true` if and only if every element in the first set is an element of the second set
  *
  * @since 2.0.0
  */
-export const subset: <A>(E: Eq<A>) => (x: Set<A>, y: Set<A>) => boolean = RS.isSubset
+export const subset: <A>(
+  E: Eq<A>
+) => {
+  (that: Set<A>): (me: Set<A>) => boolean
+  (me: Set<A>, that: Set<A>): boolean
+} = RS.isSubset
 
 /**
  * @category combinators
@@ -87,28 +93,46 @@ export function partition<A>(predicate: Predicate<A>): (set: Set<A>) => Separate
   return RS.partition(predicate) as any
 }
 
+// TODO: remove non-curried overloading in v3
 /**
  * Test if a value is a member of a set
  *
  * @since 2.0.0
  */
-export const elem: <A>(E: Eq<A>) => (a: A, set: Set<A>) => boolean = RS.elem
+export const elem: <A>(
+  E: Eq<A>
+) => {
+  (a: A): (set: Set<A>) => boolean
+  (a: A, set: Set<A>): boolean
+} = RS.elem
 
+// TODO: remove non-curried overloading in v3
 /**
  * Form the union of two sets
  *
  * @category combinators
  * @since 2.0.0
  */
-export const union: <A>(E: Eq<A>) => (set: Set<A>, y: Set<A>) => Set<A> = RS.union as any
+export const union: <A>(
+  E: Eq<A>
+) => {
+  (that: Set<A>): (me: Set<A>) => Set<A>
+  (me: Set<A>, that: Set<A>): Set<A>
+} = RS.union as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * The set of elements which are in both the first and second set
  *
  * @category combinators
  * @since 2.0.0
  */
-export const intersection: <A>(E: Eq<A>) => (set: Set<A>, y: Set<A>) => Set<A> = RS.intersection as any
+export const intersection: <A>(
+  E: Eq<A>
+) => {
+  (that: Set<A>): (me: Set<A>) => Set<A>
+  (me: Set<A>, that: Set<A>): Set<A>
+} = RS.intersection as any
 
 /**
  * @since 2.0.0
@@ -118,19 +142,26 @@ export const partitionMap: <B, C>(
   EC: Eq<C>
 ) => <A>(f: (a: A) => Either<B, C>) => (set: Set<A>) => Separated<Set<B>, Set<C>> = RS.partitionMap as any
 
+// TODO: remove non-curried overloading in v3
 /**
  * Form the set difference (`x` - `y`)
  *
  * @example
  * import { difference } from 'fp-ts/lib/Set'
  * import { eqNumber } from 'fp-ts/lib/Eq'
+ * import { pipe } from 'fp-ts/lib/function'
  *
- * assert.deepStrictEqual(difference(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+ * assert.deepStrictEqual(pipe(new Set([1, 2]), difference(eqNumber)(new Set([1, 3]))), new Set([2]))
  *
  * @category combinators
  * @since 2.0.0
  */
-export const difference: <A>(E: Eq<A>) => (x: Set<A>, y: Set<A>) => Set<A> = RS.difference as any
+export const difference: <A>(
+  E: Eq<A>
+) => {
+  (that: Set<A>): (me: Set<A>) => Set<A>
+  (me: Set<A>, that: Set<A>): Set<A>
+} = RS.difference as any
 
 /**
  * @category instances
diff --git a/src/State.ts b/src/State.ts
index 589bab21..488d3bb4 100644
--- a/src/State.ts
+++ b/src/State.ts
@@ -193,6 +193,7 @@ export const state: Monad2<URI> = {
 // utils
 // -------------------------------------------------------------------------------------
 
+// TODO: curry and rename to `evaluate` in v3
 /**
  * Run a computation in the `State` monad, discarding the final state
  *
@@ -200,6 +201,7 @@ export const state: Monad2<URI> = {
  */
 export const evalState: <S, A>(ma: State<S, A>, s: S) => A = (ma, s) => ma(s)[0]
 
+// TODO: curry and rename to `execute` in v3
 /**
  * Run a computation in the `State` monad discarding the result
  *
diff --git a/src/StateReaderTaskEither.ts b/src/StateReaderTaskEither.ts
index 7396b5cd..86f7f141 100644
--- a/src/StateReaderTaskEither.ts
+++ b/src/StateReaderTaskEither.ts
@@ -603,6 +603,7 @@ export const stateReaderTaskEitherSeq: typeof stateReaderTaskEither = {
 // utils
 // -------------------------------------------------------------------------------------
 
+// TODO: remove in v3
 /* tslint:disable:readonly-array */
 /**
  * @since 2.0.0
@@ -612,6 +613,7 @@ export function run<S, R, E, A>(ma: StateReaderTaskEither<S, R, E, A>, s: S, r:
 }
 /* tslint:enable:readonly-array */
 
+// TODO: curry and rename to `evaluate` in v3
 /**
  * Run a computation in the `StateReaderTaskEither` monad, discarding the final state
  *
@@ -626,6 +628,7 @@ export const evalState: <S, R, E, A>(ma: StateReaderTaskEither<S, R, E, A>, s: S
     RTE.map(([a]) => a)
   )
 
+// TODO: curry and rename to `execute` in v3
 /**
  * Run a computation in the `StateReaderTaskEither` monad discarding the result
  *
diff --git a/src/StateT.ts b/src/StateT.ts
index ee72f0ee..a0176a15 100644
--- a/src/StateT.ts
+++ b/src/StateT.ts
@@ -5,6 +5,8 @@ import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
 import { Monad, Monad1, Monad2, Monad2C, Monad3, Monad3C } from './Monad'
 import { State } from './State'
 
+// TODO: remove module in v3
+
 /* tslint:disable:readonly-array */
 /**
  * @category model
diff --git a/src/Strong.ts b/src/Strong.ts
index a56f4bb9..16a5049b 100644
--- a/src/Strong.ts
+++ b/src/Strong.ts
@@ -32,6 +32,8 @@ import { identity } from './function'
 import { HKT2, Kind2, Kind3, URIS2, URIS3, URIS4, Kind4 } from './HKT'
 import { Profunctor, Profunctor2, Profunctor3, Profunctor4 } from './Profunctor'
 
+// TODO: remove module in v3
+
 /* tslint:disable:readonly-array */
 
 /**
diff --git a/src/TaskThese.ts b/src/TaskThese.ts
index 4dc97931..3db4dcfa 100644
--- a/src/TaskThese.ts
+++ b/src/TaskThese.ts
@@ -106,6 +106,7 @@ export const fold: <E, B, A>(
   /*#__PURE__*/
   flow(TH.fold, T.chain)
 
+// TODO: make lazy in v3
 /* tslint:disable:readonly-array */
 /**
  * @category destructors
diff --git a/src/These.ts b/src/These.ts
index a75efda7..2543c385 100644
--- a/src/These.ts
+++ b/src/These.ts
@@ -191,6 +191,7 @@ export function getMonad<E>(S: Semigroup<E>): Monad2C<URI, E> & MonadThrow2C<URI
   }
 }
 
+// TODO: make lazy in v3
 /* tslint:disable:readonly-array */
 /**
  * @example
@@ -274,6 +275,7 @@ export function isBoth<E, A>(fa: These<E, A>): fa is Both<E, A> {
   return fa._tag === 'Both'
 }
 
+// TODO: make lazy in v3
 /**
  * @example
  * import { leftOrBoth, left, both } from 'fp-ts/lib/These'
@@ -289,6 +291,7 @@ export function leftOrBoth<E>(e: E): <A>(ma: Option<A>) => These<E, A> {
   return (ma) => (isNone(ma) ? left(e) : both(e, ma.value))
 }
 
+// TODO: make lazy in v3
 /**
  * @example
  * import { rightOrBoth, right, both } from 'fp-ts/lib/These'
diff --git a/src/TheseT.ts b/src/TheseT.ts
index 76366ec2..66a3910f 100644
--- a/src/TheseT.ts
+++ b/src/TheseT.ts
@@ -6,6 +6,8 @@ import { Monad, Monad1, Monad2 } from './Monad'
 import { Semigroup } from './Semigroup'
 import { bimap, both, fold, left, map, mapLeft, right, swap, These, toTuple } from './These'
 
+// TODO: remove module in v3
+
 /**
  * @category model
  * @since 2.4.0
diff --git a/src/Traced.ts b/src/Traced.ts
index 5cc59c57..bc79832c 100644
--- a/src/Traced.ts
+++ b/src/Traced.ts
@@ -17,6 +17,7 @@ export interface Traced<P, A> {
   (p: P): A
 }
 
+// TODO: curry in v3
 /**
  * Extracts a value at a relative position which depends on the current value.
  *
diff --git a/src/Traversable.ts b/src/Traversable.ts
index 1f597600..bea97e07 100644
--- a/src/Traversable.ts
+++ b/src/Traversable.ts
@@ -337,6 +337,7 @@ export interface TraversableComposition11<F extends URIS, G extends URIS>
   readonly sequence: SequenceComposition11<F, G>
 }
 
+// TODO: remove in v3
 /**
  * Returns the composition of two traversables
  *
diff --git a/src/Tree.ts b/src/Tree.ts
index 109f3c18..3ed361b5 100644
--- a/src/Tree.ts
+++ b/src/Tree.ts
@@ -208,6 +208,7 @@ export function unfoldForestM<M>(
     )
 }
 
+// TODO: curry in v3
 /**
  * @since 2.0.0
  */
diff --git a/src/Tuple.ts b/src/Tuple.ts
index a86f3a8c..d51ffce3 100644
--- a/src/Tuple.ts
+++ b/src/Tuple.ts
@@ -63,6 +63,7 @@ export const getChain: <S>(S: Semigroup<S>) => Chain2C<URI, S> = RT.getChain as
  */
 export const getMonad: <S>(M: Monoid<S>) => Monad2C<URI, S> = RT.getMonad as any
 
+// TODO: remove in v3
 /**
  * @category instances
  * @since 2.0.0
diff --git a/src/function.ts b/src/function.ts
index f5e6980c..8a27130f 100644
--- a/src/function.ts
+++ b/src/function.ts
@@ -115,6 +115,7 @@ export const constVoid = (): void => {
   return
 }
 
+// TODO: remove in v3
 /**
  * Flips the order of the arguments of a function of two arguments.
  *
diff --git a/src/pipeable.ts b/src/pipeable.ts
index 19d4fa98..5f38a565 100644
--- a/src/pipeable.ts
+++ b/src/pipeable.ts
@@ -89,6 +89,8 @@ import {
   Semigroupoid3C
 } from './Semigroupoid'
 
+// TODO: remove module in v3
+
 /**
  * Use [`pipe`](https://gcanti.github.io/fp-ts/modules/function.ts.html#flow) from `function` module instead.
  *


Test patch:
diff --git a/test/Array.ts b/test/Array.ts
index bd8d42cb..38989791 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -46,8 +46,22 @@ describe('Array', () => {
       )
     })
 
+    it('lookup', () => {
+      assert.deepStrictEqual(_.lookup(0, [1, 2, 3]), O.some(1))
+      assert.deepStrictEqual(_.lookup(3, [1, 2, 3]), O.none)
+      assert.deepStrictEqual(pipe([1, 2, 3], _.lookup(0)), O.some(1))
+      assert.deepStrictEqual(pipe([1, 2, 3], _.lookup(3)), O.none)
+    })
+
+    it('elem', () => {
+      assert.deepStrictEqual(_.elem(Eq.eqNumber)(2, [1, 2, 3]), true)
+      assert.deepStrictEqual(_.elem(Eq.eqNumber)(0, [1, 2, 3]), false)
+      assert.deepStrictEqual(pipe([1, 2, 3], _.elem(Eq.eqNumber)(2)), true)
+      assert.deepStrictEqual(pipe([1, 2, 3], _.elem(Eq.eqNumber)(0)), false)
+    })
+
     it('unfold', () => {
-      const as = _.array.unfold(5, (n) => (n > 0 ? O.some([n, n - 1]) : O.none))
+      const as = _.unfold(5, (n) => (n > 0 ? O.some([n, n - 1]) : O.none))
       assert.deepStrictEqual(as, [5, 4, 3, 2, 1])
     })
 
@@ -357,9 +371,10 @@ describe('Array', () => {
   })
 
   it('cons', () => {
-    const as: Array<number> = [1, 2, 3]
-    assert.deepStrictEqual(_.cons(0, as), [0, 1, 2, 3])
+    assert.deepStrictEqual(_.cons(0, [1, 2, 3]), [0, 1, 2, 3])
     assert.deepStrictEqual(_.cons([1], [[2]]), [[1], [2]])
+    assert.deepStrictEqual(pipe([1, 2, 3], _.cons(0)), [0, 1, 2, 3])
+    assert.deepStrictEqual(pipe([[2]], _.cons([1])), [[1], [2]])
   })
 
   it('snoc', () => {
@@ -591,6 +606,11 @@ describe('Array', () => {
       [2, 'b'],
       [3, 'c']
     ])
+    assert.deepStrictEqual(pipe([1, 2, 3], _.zip(['a', 'b', 'c', 'd'])), [
+      [1, 'a'],
+      [2, 'b'],
+      [3, 'c']
+    ])
   })
 
   it('unzip', () => {
@@ -857,18 +877,27 @@ describe('Array', () => {
     assert.deepStrictEqual(_.union(Eq.eqNumber)([1, 2], [3, 4]), [1, 2, 3, 4])
     assert.deepStrictEqual(_.union(Eq.eqNumber)([1, 2], [2, 3]), [1, 2, 3])
     assert.deepStrictEqual(_.union(Eq.eqNumber)([1, 2], [1, 2]), [1, 2])
+    assert.deepStrictEqual(pipe([1, 2], _.union(Eq.eqNumber)([3, 4])), [1, 2, 3, 4])
+    assert.deepStrictEqual(pipe([1, 2], _.union(Eq.eqNumber)([2, 3])), [1, 2, 3])
+    assert.deepStrictEqual(pipe([1, 2], _.union(Eq.eqNumber)([1, 2])), [1, 2])
   })
 
   it('intersection', () => {
     assert.deepStrictEqual(_.intersection(Eq.eqNumber)([1, 2], [3, 4]), [])
     assert.deepStrictEqual(_.intersection(Eq.eqNumber)([1, 2], [2, 3]), [2])
     assert.deepStrictEqual(_.intersection(Eq.eqNumber)([1, 2], [1, 2]), [1, 2])
+    assert.deepStrictEqual(pipe([1, 2], _.intersection(Eq.eqNumber)([3, 4])), [])
+    assert.deepStrictEqual(pipe([1, 2], _.intersection(Eq.eqNumber)([2, 3])), [2])
+    assert.deepStrictEqual(pipe([1, 2], _.intersection(Eq.eqNumber)([1, 2])), [1, 2])
   })
 
   it('difference', () => {
     assert.deepStrictEqual(_.difference(Eq.eqNumber)([1, 2], [3, 4]), [1, 2])
     assert.deepStrictEqual(_.difference(Eq.eqNumber)([1, 2], [2, 3]), [1])
     assert.deepStrictEqual(_.difference(Eq.eqNumber)([1, 2], [1, 2]), [])
+    assert.deepStrictEqual(pipe([1, 2], _.difference(Eq.eqNumber)([3, 4])), [1, 2])
+    assert.deepStrictEqual(pipe([1, 2], _.difference(Eq.eqNumber)([2, 3])), [1])
+    assert.deepStrictEqual(pipe([1, 2], _.difference(Eq.eqNumber)([1, 2])), [])
   })
 
   it('should be safe when calling map with a binary function', () => {
diff --git a/test/Map.ts b/test/Map.ts
index 2e1ac3b8..32199174 100644
--- a/test/Map.ts
+++ b/test/Map.ts
@@ -2,7 +2,7 @@ import * as assert from 'assert'
 import { array } from '../src/Array'
 import { Either, left, right } from '../src/Either'
 import { Eq, eqNumber, fromEquals } from '../src/Eq'
-import { identity, Refinement } from '../src/function'
+import { identity, Refinement, pipe } from '../src/function'
 import * as _ from '../src/Map'
 import { monoidString } from '../src/Monoid'
 import { none, option, Option, some } from '../src/Option'
@@ -72,35 +72,47 @@ describe('Map', () => {
   })
 
   it('member', () => {
-    const a1b2 = new Map<User, number>([
+    const x = new Map<User, number>([
       [{ id: 'a' }, 1],
       [{ id: 'b' }, 2]
     ])
     const memberS = _.member(eqUser)
-    assert.deepStrictEqual(memberS({ id: 'a' }, a1b2), true)
-    assert.deepStrictEqual(memberS({ id: 'c' }, a1b2), false)
+    assert.deepStrictEqual(memberS({ id: 'a' }, x), true)
+    assert.deepStrictEqual(memberS({ id: 'c' }, x), false)
+    assert.deepStrictEqual(memberS({ id: 'a' })(x), true)
+    assert.deepStrictEqual(memberS({ id: 'c' })(x), false)
 
     const member = _.member(eqKey)
     assert.deepStrictEqual(member({ id: 1 }, repo), true)
     assert.deepStrictEqual(member({ id: 2 }, repo), true)
     assert.deepStrictEqual(member({ id: 4 }, repo), true)
     assert.deepStrictEqual(member({ id: 3 }, repo), false)
+    assert.deepStrictEqual(member({ id: 1 })(repo), true)
+    assert.deepStrictEqual(member({ id: 2 })(repo), true)
+    assert.deepStrictEqual(member({ id: 4 })(repo), true)
+    assert.deepStrictEqual(member({ id: 3 })(repo), false)
   })
 
   it('elem', () => {
-    const a1b2 = new Map<string, number>([
+    const x = new Map<string, number>([
       ['a', 1],
       ['b', 2]
     ])
     const elemS = _.elem(eqNumber)
-    assert.deepStrictEqual(elemS(2, a1b2), true)
-    assert.deepStrictEqual(elemS(3, a1b2), false)
+    assert.deepStrictEqual(elemS(2, x), true)
+    assert.deepStrictEqual(elemS(3, x), false)
+    assert.deepStrictEqual(elemS(2)(x), true)
+    assert.deepStrictEqual(elemS(3)(x), false)
 
     const elem = _.elem(eqValue)
-    assert.deepStrictEqual(elem({ value: 1 }, repo), true)
-    assert.deepStrictEqual(elem({ value: 2 }, repo), true)
-    assert.deepStrictEqual(elem({ value: 4 }, repo), true)
-    assert.deepStrictEqual(elem({ value: 3 }, repo), false)
+    assert.deepStrictEqual(elem({ value: 1 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 2 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 4 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 3 })(repo), false)
+    assert.deepStrictEqual(elem({ value: 1 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 2 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 4 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 3 })(repo), false)
   })
 
   it('keys', () => {
@@ -453,37 +465,48 @@ describe('Map', () => {
   })
 
   it('lookupWithKey', () => {
-    const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
+    const x = new Map<User, number>([[{ id: 'a' }, 1]])
     const lookupWithKeyS = _.lookupWithKey(eqUser)
-    assert.deepStrictEqual(lookupWithKeyS({ id: 'a' }, a1), some([{ id: 'a' }, 1]))
-    assert.deepStrictEqual(lookupWithKeyS({ id: 'b' }, a1), none)
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'a' }, x), some([{ id: 'a' }, 1]))
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'b' }, x), none)
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'a' })(x), some([{ id: 'a' }, 1]))
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'b' })(x), none)
 
     const lookupWithKey = _.lookupWithKey(eqKey)
     assert.deepStrictEqual(lookupWithKey({ id: 1 }, repo), some([{ id: 1 }, { value: 1 }]))
     assert.deepStrictEqual(lookupWithKey({ id: 4 }, repo), some([{ id: 1 }, { value: 1 }]))
     assert.deepStrictEqual(lookupWithKey({ id: 3 }, repo), none)
+    assert.deepStrictEqual(lookupWithKey({ id: 1 })(repo), some([{ id: 1 }, { value: 1 }]))
+    assert.deepStrictEqual(lookupWithKey({ id: 4 })(repo), some([{ id: 1 }, { value: 1 }]))
+    assert.deepStrictEqual(lookupWithKey({ id: 3 })(repo), none)
   })
 
   it('lookup', () => {
-    const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
+    const x = new Map<User, number>([[{ id: 'a' }, 1]])
     const lookupS = _.lookup(eqUser)
-    assert.deepStrictEqual(lookupS({ id: 'a' }, a1), some(1))
-    assert.deepStrictEqual(lookupS({ id: 'b' }, a1), none)
+    assert.deepStrictEqual(lookupS({ id: 'a' }, x), some(1))
+    assert.deepStrictEqual(lookupS({ id: 'b' }, x), none)
+    assert.deepStrictEqual(lookupS({ id: 'a' })(x), some(1))
+    assert.deepStrictEqual(lookupS({ id: 'b' })(x), none)
 
     const lookup = _.lookup(eqKey)
     assert.deepStrictEqual(lookup({ id: 1 }, repo), some({ value: 1 }))
     assert.deepStrictEqual(lookup({ id: 4 }, repo), some({ value: 1 }))
     assert.deepStrictEqual(lookup({ id: 3 }, repo), none)
+    assert.deepStrictEqual(lookup({ id: 1 })(repo), some({ value: 1 }))
+    assert.deepStrictEqual(lookup({ id: 4 })(repo), some({ value: 1 }))
+    assert.deepStrictEqual(lookup({ id: 3 })(repo), none)
   })
 
   it('isSubmap', () => {
-    const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
-    const a1b2 = new Map<User, number>([
+    const me = new Map<User, number>([[{ id: 'a' }, 1]])
+    const that = new Map<User, number>([
       [{ id: 'a' }, 1],
       [{ id: 'b' }, 2]
     ])
     const isSubmapS = _.isSubmap(eqUser, eqNumber)
-    assert.deepStrictEqual(isSubmapS(a1, a1b2), true)
+    assert.deepStrictEqual(isSubmapS(me, that), true)
+    assert.deepStrictEqual(isSubmapS(that)(me), true)
 
     const isSubmap = _.isSubmap(eqKey, eqValue)
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 1 }, { value: 1 }]]), repo), true)
@@ -491,6 +514,12 @@ describe('Map', () => {
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 1 }, { value: 4 }]]), repo), true)
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 4 }, { value: 1 }]]), repo), true)
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 3 }, { value: 3 }]]), repo), false)
+
+    assert.deepStrictEqual(pipe(new Map([[{ id: 1 }, { value: 1 }]]), isSubmap(repo)), true)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 1 }, { value: 2 }]]), isSubmap(repo)), false)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 1 }, { value: 4 }]]), isSubmap(repo)), true)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 4 }, { value: 1 }]]), isSubmap(repo)), true)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 3 }, { value: 3 }]]), isSubmap(repo)), false)
   })
 
   it('empty', () => {
diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts
index ea948e70..5d36b79d 100644
--- a/test/ReadonlyArray.ts
+++ b/test/ReadonlyArray.ts
@@ -44,8 +44,22 @@ describe('ReadonlyArray', () => {
       )
     })
 
+    it('lookup', () => {
+      assert.deepStrictEqual(_.lookup(0, [1, 2, 3]), O.some(1))
+      assert.deepStrictEqual(_.lookup(3, [1, 2, 3]), O.none)
+      assert.deepStrictEqual(pipe([1, 2, 3], _.lookup(0)), O.some(1))
+      assert.deepStrictEqual(pipe([1, 2, 3], _.lookup(3)), O.none)
+    })
+
+    it('elem', () => {
+      assert.deepStrictEqual(_.elem(Eq.eqNumber)(2, [1, 2, 3]), true)
+      assert.deepStrictEqual(_.elem(Eq.eqNumber)(0, [1, 2, 3]), false)
+      assert.deepStrictEqual(pipe([1, 2, 3], _.elem(Eq.eqNumber)(2)), true)
+      assert.deepStrictEqual(pipe([1, 2, 3], _.elem(Eq.eqNumber)(0)), false)
+    })
+
     it('unfold', () => {
-      const as = _.readonlyArray.unfold(5, (n) => (n > 0 ? O.some([n, n - 1]) : O.none))
+      const as = _.unfold(5, (n) => (n > 0 ? O.some([n, n - 1]) : O.none))
       assert.deepStrictEqual(as, [5, 4, 3, 2, 1])
     })
 
@@ -353,9 +367,10 @@ describe('ReadonlyArray', () => {
   })
 
   it('cons', () => {
-    const as: ReadonlyArray<number> = [1, 2, 3]
-    assert.deepStrictEqual(_.cons(0, as), [0, 1, 2, 3])
+    assert.deepStrictEqual(_.cons(0, [1, 2, 3]), [0, 1, 2, 3])
     assert.deepStrictEqual(_.cons([1], [[2]]), [[1], [2]])
+    assert.deepStrictEqual(pipe([1, 2, 3], _.cons(0)), [0, 1, 2, 3])
+    assert.deepStrictEqual(pipe([[2]], _.cons([1])), [[1], [2]])
   })
 
   it('snoc', () => {
@@ -572,6 +587,7 @@ describe('ReadonlyArray', () => {
 
   it('sort', () => {
     assert.deepStrictEqual(_.sort(Ord.ordNumber)([3, 2, 1]), [1, 2, 3])
+    assert.strictEqual(_.sort(Ord.ordNumber)(_.empty), _.empty)
   })
 
   it('zipWith', () => {
@@ -587,6 +603,11 @@ describe('ReadonlyArray', () => {
       [2, 'b'],
       [3, 'c']
     ])
+    assert.deepStrictEqual(pipe([1, 2, 3], _.zip(['a', 'b', 'c', 'd'])), [
+      [1, 'a'],
+      [2, 'b'],
+      [3, 'c']
+    ])
   })
 
   it('unzip', () => {
@@ -631,6 +652,7 @@ describe('ReadonlyArray', () => {
 
   it('reverse', () => {
     assert.deepStrictEqual(_.reverse([1, 2, 3]), [3, 2, 1])
+    assert.strictEqual(_.reverse(_.empty), _.empty)
   })
 
   it('foldLeft', () => {
@@ -853,18 +875,27 @@ describe('ReadonlyArray', () => {
     assert.deepStrictEqual(_.union(Eq.eqNumber)([1, 2], [3, 4]), [1, 2, 3, 4])
     assert.deepStrictEqual(_.union(Eq.eqNumber)([1, 2], [2, 3]), [1, 2, 3])
     assert.deepStrictEqual(_.union(Eq.eqNumber)([1, 2], [1, 2]), [1, 2])
+    assert.deepStrictEqual(pipe([1, 2], _.union(Eq.eqNumber)([3, 4])), [1, 2, 3, 4])
+    assert.deepStrictEqual(pipe([1, 2], _.union(Eq.eqNumber)([2, 3])), [1, 2, 3])
+    assert.deepStrictEqual(pipe([1, 2], _.union(Eq.eqNumber)([1, 2])), [1, 2])
   })
 
   it('intersection', () => {
     assert.deepStrictEqual(_.intersection(Eq.eqNumber)([1, 2], [3, 4]), [])
     assert.deepStrictEqual(_.intersection(Eq.eqNumber)([1, 2], [2, 3]), [2])
     assert.deepStrictEqual(_.intersection(Eq.eqNumber)([1, 2], [1, 2]), [1, 2])
+    assert.deepStrictEqual(pipe([1, 2], _.intersection(Eq.eqNumber)([3, 4])), [])
+    assert.deepStrictEqual(pipe([1, 2], _.intersection(Eq.eqNumber)([2, 3])), [2])
+    assert.deepStrictEqual(pipe([1, 2], _.intersection(Eq.eqNumber)([1, 2])), [1, 2])
   })
 
   it('difference', () => {
     assert.deepStrictEqual(_.difference(Eq.eqNumber)([1, 2], [3, 4]), [1, 2])
     assert.deepStrictEqual(_.difference(Eq.eqNumber)([1, 2], [2, 3]), [1])
     assert.deepStrictEqual(_.difference(Eq.eqNumber)([1, 2], [1, 2]), [])
+    assert.deepStrictEqual(pipe([1, 2], _.difference(Eq.eqNumber)([3, 4])), [1, 2])
+    assert.deepStrictEqual(pipe([1, 2], _.difference(Eq.eqNumber)([2, 3])), [1])
+    assert.deepStrictEqual(pipe([1, 2], _.difference(Eq.eqNumber)([1, 2])), [])
   })
 
   it('should be safe when calling map with a binary function', () => {
@@ -901,4 +932,8 @@ describe('ReadonlyArray', () => {
     assert.deepStrictEqual(bs, as)
     assert.notStrictEqual(bs, as)
   })
+
+  it('empty', () => {
+    assert.deepStrictEqual(_.empty.length, 0)
+  })
 })
diff --git a/test/ReadonlyMap.ts b/test/ReadonlyMap.ts
index fb48b715..d1db7733 100644
--- a/test/ReadonlyMap.ts
+++ b/test/ReadonlyMap.ts
@@ -167,35 +167,47 @@ describe('ReadonlyMap', () => {
   })
 
   it('member', () => {
-    const a1b2 = new Map<User, number>([
+    const x = new Map<User, number>([
       [{ id: 'a' }, 1],
       [{ id: 'b' }, 2]
     ])
     const memberS = _.member(eqUser)
-    assert.deepStrictEqual(memberS({ id: 'a' }, a1b2), true)
-    assert.deepStrictEqual(memberS({ id: 'c' }, a1b2), false)
+    assert.deepStrictEqual(memberS({ id: 'a' }, x), true)
+    assert.deepStrictEqual(memberS({ id: 'c' }, x), false)
+    assert.deepStrictEqual(memberS({ id: 'a' })(x), true)
+    assert.deepStrictEqual(memberS({ id: 'c' })(x), false)
 
     const member = _.member(eqKey)
     assert.deepStrictEqual(member({ id: 1 }, repo), true)
     assert.deepStrictEqual(member({ id: 2 }, repo), true)
     assert.deepStrictEqual(member({ id: 4 }, repo), true)
     assert.deepStrictEqual(member({ id: 3 }, repo), false)
+    assert.deepStrictEqual(member({ id: 1 })(repo), true)
+    assert.deepStrictEqual(member({ id: 2 })(repo), true)
+    assert.deepStrictEqual(member({ id: 4 })(repo), true)
+    assert.deepStrictEqual(member({ id: 3 })(repo), false)
   })
 
   it('elem', () => {
-    const a1b2 = new Map<string, number>([
+    const x = new Map<string, number>([
       ['a', 1],
       ['b', 2]
     ])
     const elemS = _.elem(eqNumber)
-    assert.deepStrictEqual(elemS(2, a1b2), true)
-    assert.deepStrictEqual(elemS(3, a1b2), false)
+    assert.deepStrictEqual(elemS(2, x), true)
+    assert.deepStrictEqual(elemS(3, x), false)
+    assert.deepStrictEqual(elemS(2)(x), true)
+    assert.deepStrictEqual(elemS(3)(x), false)
 
     const elem = _.elem(eqValue)
-    assert.deepStrictEqual(elem({ value: 1 }, repo), true)
-    assert.deepStrictEqual(elem({ value: 2 }, repo), true)
-    assert.deepStrictEqual(elem({ value: 4 }, repo), true)
-    assert.deepStrictEqual(elem({ value: 3 }, repo), false)
+    assert.deepStrictEqual(elem({ value: 1 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 2 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 4 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 3 })(repo), false)
+    assert.deepStrictEqual(elem({ value: 1 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 2 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 4 })(repo), true)
+    assert.deepStrictEqual(elem({ value: 3 })(repo), false)
   })
 
   it('keys', () => {
@@ -548,37 +560,48 @@ describe('ReadonlyMap', () => {
   })
 
   it('lookupWithKey', () => {
-    const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
+    const x = new Map<User, number>([[{ id: 'a' }, 1]])
     const lookupWithKeyS = _.lookupWithKey(eqUser)
-    assert.deepStrictEqual(lookupWithKeyS({ id: 'a' }, a1), some([{ id: 'a' }, 1]))
-    assert.deepStrictEqual(lookupWithKeyS({ id: 'b' }, a1), none)
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'a' }, x), some([{ id: 'a' }, 1]))
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'b' }, x), none)
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'a' })(x), some([{ id: 'a' }, 1]))
+    assert.deepStrictEqual(lookupWithKeyS({ id: 'b' })(x), none)
 
     const lookupWithKey = _.lookupWithKey(eqKey)
     assert.deepStrictEqual(lookupWithKey({ id: 1 }, repo), some([{ id: 1 }, { value: 1 }]))
     assert.deepStrictEqual(lookupWithKey({ id: 4 }, repo), some([{ id: 1 }, { value: 1 }]))
     assert.deepStrictEqual(lookupWithKey({ id: 3 }, repo), none)
+    assert.deepStrictEqual(lookupWithKey({ id: 1 })(repo), some([{ id: 1 }, { value: 1 }]))
+    assert.deepStrictEqual(lookupWithKey({ id: 4 })(repo), some([{ id: 1 }, { value: 1 }]))
+    assert.deepStrictEqual(lookupWithKey({ id: 3 })(repo), none)
   })
 
   it('lookup', () => {
-    const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
+    const x = new Map<User, number>([[{ id: 'a' }, 1]])
     const lookupS = _.lookup(eqUser)
-    assert.deepStrictEqual(lookupS({ id: 'a' }, a1), some(1))
-    assert.deepStrictEqual(lookupS({ id: 'b' }, a1), none)
+    assert.deepStrictEqual(lookupS({ id: 'a' }, x), some(1))
+    assert.deepStrictEqual(lookupS({ id: 'b' }, x), none)
+    assert.deepStrictEqual(lookupS({ id: 'a' })(x), some(1))
+    assert.deepStrictEqual(lookupS({ id: 'b' })(x), none)
 
     const lookup = _.lookup(eqKey)
     assert.deepStrictEqual(lookup({ id: 1 }, repo), some({ value: 1 }))
     assert.deepStrictEqual(lookup({ id: 4 }, repo), some({ value: 1 }))
     assert.deepStrictEqual(lookup({ id: 3 }, repo), none)
+    assert.deepStrictEqual(lookup({ id: 1 })(repo), some({ value: 1 }))
+    assert.deepStrictEqual(lookup({ id: 4 })(repo), some({ value: 1 }))
+    assert.deepStrictEqual(lookup({ id: 3 })(repo), none)
   })
 
   it('isSubmap', () => {
-    const a1 = new Map<User, number>([[{ id: 'a' }, 1]])
-    const a1b2 = new Map<User, number>([
+    const me = new Map<User, number>([[{ id: 'a' }, 1]])
+    const that = new Map<User, number>([
       [{ id: 'a' }, 1],
       [{ id: 'b' }, 2]
     ])
     const isSubmapS = _.isSubmap(eqUser, eqNumber)
-    assert.deepStrictEqual(isSubmapS(a1, a1b2), true)
+    assert.deepStrictEqual(isSubmapS(me, that), true)
+    assert.deepStrictEqual(isSubmapS(that)(me), true)
 
     const isSubmap = _.isSubmap(eqKey, eqValue)
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 1 }, { value: 1 }]]), repo), true)
@@ -586,6 +609,12 @@ describe('ReadonlyMap', () => {
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 1 }, { value: 4 }]]), repo), true)
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 4 }, { value: 1 }]]), repo), true)
     assert.deepStrictEqual(isSubmap(new Map([[{ id: 3 }, { value: 3 }]]), repo), false)
+
+    assert.deepStrictEqual(pipe(new Map([[{ id: 1 }, { value: 1 }]]), isSubmap(repo)), true)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 1 }, { value: 2 }]]), isSubmap(repo)), false)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 1 }, { value: 4 }]]), isSubmap(repo)), true)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 4 }, { value: 1 }]]), isSubmap(repo)), true)
+    assert.deepStrictEqual(pipe(new Map([[{ id: 3 }, { value: 3 }]]), isSubmap(repo)), false)
   })
 
   it('empty', () => {
diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts
index 0a109c90..7b42ca9a 100644
--- a/test/ReadonlyRecord.ts
+++ b/test/ReadonlyRecord.ts
@@ -244,6 +244,10 @@ describe('ReadonlyRecord', () => {
     assert.deepStrictEqual(_.lookup('a', { a: 1 }), some(1))
     assert.deepStrictEqual(_.lookup('b', { a: 1 }), none)
     assert.deepStrictEqual(_.lookup('b', noPrototype), none)
+
+    assert.deepStrictEqual(_.lookup('a')({ a: 1 }), some(1))
+    assert.deepStrictEqual(_.lookup('b')({ a: 1 }), none)
+    assert.deepStrictEqual(_.lookup('b')(noPrototype), none)
   })
 
   it('fromFoldable', () => {
@@ -353,6 +357,9 @@ describe('ReadonlyRecord', () => {
   it('elem', () => {
     assert.deepStrictEqual(_.elem(eqNumber)(1, { a: 1, b: 2 }), true)
     assert.deepStrictEqual(_.elem(eqNumber)(3, { a: 1, b: 2 }), false)
+
+    assert.deepStrictEqual(_.elem(eqNumber)(1)({ a: 1, b: 2 }), true)
+    assert.deepStrictEqual(_.elem(eqNumber)(3)({ a: 1, b: 2 }), false)
   })
 
   it('fromFoldableMap', () => {
diff --git a/test/ReadonlySet.ts b/test/ReadonlySet.ts
index ac33e2f7..4988bfd4 100644
--- a/test/ReadonlySet.ts
+++ b/test/ReadonlySet.ts
@@ -6,6 +6,7 @@ import { Eq, eqNumber, eqString, eq, getStructEq } from '../src/Eq'
 import { none, some as optionSome } from '../src/Option'
 import { showString } from '../src/Show'
 import { getMonoid } from '../src/Array'
+import { pipe } from '../src/function'
 
 const gte2 = (n: number) => n >= 2
 
@@ -60,6 +61,9 @@ describe('ReadonlySet', () => {
   it('isSubset', () => {
     assert.deepStrictEqual(_.isSubset(eqNumber)(new Set([1, 2]), new Set([1, 2, 3])), true)
     assert.deepStrictEqual(_.isSubset(eqNumber)(new Set([1, 2, 4]), new Set([1, 2, 3])), false)
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), _.isSubset(eqNumber)(new Set([1, 2, 3]))), true)
+    assert.deepStrictEqual(pipe(new Set([1, 2, 4]), _.isSubset(eqNumber)(new Set([1, 2, 3]))), false)
   })
 
   it('filter', () => {
@@ -91,10 +95,14 @@ describe('ReadonlySet', () => {
 
   it('union', () => {
     assert.deepStrictEqual(_.union(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([1, 2, 3]))
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), _.union(eqNumber)(new Set([1, 3]))), new Set([1, 2, 3]))
   })
 
   it('intersection', () => {
     assert.deepStrictEqual(_.intersection(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([1]))
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), _.intersection(eqNumber)(new Set([1, 3]))), new Set([1]))
   })
 
   it('partitionMap', () => {
@@ -141,6 +149,8 @@ describe('ReadonlySet', () => {
 
   it('difference', () => {
     assert.deepStrictEqual(_.difference(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), _.difference(eqNumber)(new Set([1, 3]))), new Set([2]))
   })
 
   it('reduce', () => {
diff --git a/test/Record.ts b/test/Record.ts
index e23d3915..68e3af98 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -111,6 +111,10 @@ describe('Record', () => {
     assert.deepStrictEqual(_.lookup('a', { a: 1 }), some(1))
     assert.deepStrictEqual(_.lookup('b', { a: 1 }), none)
     assert.deepStrictEqual(_.lookup('b', noPrototype), none)
+
+    assert.deepStrictEqual(_.lookup('a')({ a: 1 }), some(1))
+    assert.deepStrictEqual(_.lookup('b')({ a: 1 }), none)
+    assert.deepStrictEqual(_.lookup('b')(noPrototype), none)
   })
 
   it('fromFoldable', () => {
@@ -278,6 +282,9 @@ describe('Record', () => {
   it('elem', () => {
     assert.deepStrictEqual(_.elem(eqNumber)(1, { a: 1, b: 2 }), true)
     assert.deepStrictEqual(_.elem(eqNumber)(3, { a: 1, b: 2 }), false)
+
+    assert.deepStrictEqual(_.elem(eqNumber)(1)({ a: 1, b: 2 }), true)
+    assert.deepStrictEqual(_.elem(eqNumber)(3)({ a: 1, b: 2 }), false)
   })
 
   it('fromFoldableMap', () => {
diff --git a/test/Semigroup.ts b/test/Semigroup.ts
index 2064e843..848d2e07 100644
--- a/test/Semigroup.ts
+++ b/test/Semigroup.ts
@@ -1,40 +1,27 @@
 import * as assert from 'assert'
 import { monoidString } from '../src/Monoid'
 import { ordNumber } from '../src/Ord'
-import {
-  fold,
-  getFirstSemigroup,
-  getJoinSemigroup,
-  getMeetSemigroup,
-  getObjectSemigroup,
-  getTupleSemigroup,
-  semigroupAll,
-  semigroupProduct,
-  semigroupString,
-  semigroupSum,
-  semigroupVoid,
-  getDualSemigroup,
-  getIntercalateSemigroup
-} from '../src/Semigroup'
+import * as _ from '../src/Semigroup'
 
 describe('Semigroup', () => {
   it('getTupleSemigroup', () => {
-    const S1 = getTupleSemigroup(semigroupString, semigroupSum)
+    const S1 = _.getTupleSemigroup(_.semigroupString, _.semigroupSum)
     assert.deepStrictEqual(S1.concat(['a', 1], ['b', 2]), ['ab', 3])
-    const S2 = getTupleSemigroup(semigroupString, semigroupSum, semigroupAll)
+    const S2 = _.getTupleSemigroup(_.semigroupString, _.semigroupSum, _.semigroupAll)
     assert.deepStrictEqual(S2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
   })
 
   it('fold', () => {
-    assert.deepStrictEqual(fold(monoidString)('', ['a', 'b', 'c']), 'abc')
+    assert.deepStrictEqual(_.fold(monoidString)('', ['a', 'b', 'c']), 'abc')
+    assert.deepStrictEqual(_.fold(monoidString)('')(['a', 'b', 'c']), 'abc')
   })
 
   it('getMeetSemigroup', () => {
-    assert.deepStrictEqual(getMeetSemigroup(ordNumber).concat(1, 2), 1)
+    assert.deepStrictEqual(_.getMeetSemigroup(ordNumber).concat(1, 2), 1)
   })
 
   it('getJoinSemigroup', () => {
-    assert.deepStrictEqual(getJoinSemigroup(ordNumber).concat(1, 2), 2)
+    assert.deepStrictEqual(_.getJoinSemigroup(ordNumber).concat(1, 2), 2)
   })
 
   it('getObjectSemigroup', () => {
@@ -49,7 +36,7 @@ describe('Semigroup', () => {
     const bar: T = {
       bar: '123'
     }
-    const S = getObjectSemigroup<T>()
+    const S = _.getObjectSemigroup<T>()
     const result = S.concat(foo, bar)
     const expected = Object.assign({}, foo, bar)
     assert.deepStrictEqual(result.foo, expected.foo)
@@ -57,24 +44,24 @@ describe('Semigroup', () => {
   })
 
   it('semigroupProduct', () => {
-    assert.deepStrictEqual(semigroupProduct.concat(2, 3), 6)
+    assert.deepStrictEqual(_.semigroupProduct.concat(2, 3), 6)
   })
 
   it('getFirstSemigroup', () => {
-    assert.deepStrictEqual(getFirstSemigroup<number>().concat(1, 2), 1)
+    assert.deepStrictEqual(_.getFirstSemigroup<number>().concat(1, 2), 1)
   })
 
   it('semigroupVoid', () => {
-    assert.deepStrictEqual(semigroupVoid.concat(undefined, undefined), undefined)
+    assert.deepStrictEqual(_.semigroupVoid.concat(undefined, undefined), undefined)
   })
 
   it('getDualSemigroup', () => {
-    const S = getDualSemigroup(semigroupString)
+    const S = _.getDualSemigroup(_.semigroupString)
     assert.deepStrictEqual(S.concat('a', 'b'), 'ba')
   })
 
   it('getIntercalateSemigroup', () => {
-    const S = getIntercalateSemigroup(' ')(semigroupString)
+    const S = _.getIntercalateSemigroup(' ')(_.semigroupString)
     assert.strictEqual(S.concat('a', 'b'), 'a b')
     assert.strictEqual(S.concat(S.concat('a', 'b'), 'c'), S.concat('a', S.concat('b', 'c')))
   })
diff --git a/test/Set.ts b/test/Set.ts
index 170419ff..4b94fc7e 100644
--- a/test/Set.ts
+++ b/test/Set.ts
@@ -34,6 +34,7 @@ import { Eq, eqNumber, eqString, eq, getStructEq } from '../src/Eq'
 import { none, some as optionSome } from '../src/Option'
 import { showString } from '../src/Show'
 import { getMonoid } from '../src/Array'
+import { pipe } from '../src/function'
 
 const gte2 = (n: number) => n >= 2
 
@@ -88,6 +89,9 @@ describe('Set', () => {
   it('subset', () => {
     assert.deepStrictEqual(subset(eqNumber)(new Set([1, 2]), new Set([1, 2, 3])), true)
     assert.deepStrictEqual(subset(eqNumber)(new Set([1, 2, 4]), new Set([1, 2, 3])), false)
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), subset(eqNumber)(new Set([1, 2, 3]))), true)
+    assert.deepStrictEqual(pipe(new Set([1, 2, 4]), subset(eqNumber)(new Set([1, 2, 3]))), false)
   })
 
   it('filter', () => {
@@ -119,10 +123,14 @@ describe('Set', () => {
 
   it('union', () => {
     assert.deepStrictEqual(union(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([1, 2, 3]))
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), union(eqNumber)(new Set([1, 3]))), new Set([1, 2, 3]))
   })
 
   it('intersection', () => {
     assert.deepStrictEqual(intersection(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([1]))
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), intersection(eqNumber)(new Set([1, 3]))), new Set([1]))
   })
 
   it('partitionMap', () => {
@@ -169,6 +177,8 @@ describe('Set', () => {
 
   it('difference', () => {
     assert.deepStrictEqual(difference(eqNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+
+    assert.deepStrictEqual(pipe(new Set([1, 2]), difference(eqNumber)(new Set([1, 3]))), new Set([2]))
   })
 
   it('reduce', () => {