Repository: gcanti/fp-ts
Pull request #1455 (2021-03-28 16:17:27)

Backport ReadonlyRecord & Record
Backports `ReadonlyRecord` from 3.0.0 based on the 2.11 roadmap https://github.com/gcanti/fp-ts/issues/1446

I agree w/ the `Ord` idea outlined in the roadmap, but I can change if desired.

Notes:
- I used `Ord` constraints in `Record` as well, I can change it to use `Ord.trivial` if desired
- I wasn't sure why `ReadonlyRecord.wilt` and `ReadonlyRecord.wither` [use `Ord.trivial`  in 3.0.0](https://github.com/gcanti/fp-ts/blob/f7ae980afcab8f68d46b801f35462e644a64a65c/src/ReadonlyRecord.ts#L756), but I mirrored that - I'm not sure if that was correct
- I also added `Ord` instances to these, which were unspecified - we can use `Ord.trivial` instead if desired
  - `traverse`
  - `sequence`
  - `getShow`
  - typeclass instances (`Traversable` -> `getTraversable: (O: Ord<string>) => ...`)

gcanti: > I agree w/ the Ord idea outlined in the roadmap

We can't just change the signatures though, this PR contains the following breaking changes:

- `keys`
- `collect`
- `toReadonlyArray`
- `toUnfoldable`
- `reduceWithIndex`
- `foldMapWithIndex`
- `reduceRightWithIndex`
- `traverseWithIndex`
- `traverse`
- `sequence`
- `reduce`
- `foldMap`
- `reduceRight`
- `getShow`
- `Foldable` -> `getFoldable`
- `FoldableWithIndex` -> `getFoldableWithIndex`
- `Traversable` -> `getTraversable`
- `TraversableWithIndex` -> `getTraversableWithIndex`
- `Witherable` -> `getWitherable`

> I wasn't sure why ReadonlyRecord.wilt and ReadonlyRecord.wither...

This was a mistake, thanks for pointing out (fixed now in v3)
anthonyjoeseph: Oh, ok - I misunderstood the roadmap & the release process, my bad. Do you think it would make sense to new functions w/ `*WithOrd` signatures (e.g. `keysWithOrd`)? Or maybe it's best to leave all that out for the moment?
gcanti: Yeah, I'm sorry, the roadmap wan't clear on this point, I put a "?" on the item list because I'm not even sure is possible to backport the new constraint.

In general we can do whatever we want in the `3.0.0` branch (with an eye on the migration path though) but in the `2.x` series we can't introduce breaking changes.

In the past I used the following technique:

- add a new signature as an overload to the API
- deprecate the old signature

Let's pick `keys` for example:

```ts
export const keys = <K extends string>(r: ReadonlyRecord<K, unknown>): ReadonlyArray<K> =>
  (Object.keys(r) as any).sort()
```

The new definition would be something like:

```ts
declare const isOrd: (r: Ord<string> | ReadonlyRecord<string, unknown>) => r is Ord<string>

/**
 * @since 2.5.0
 */
export function keys(O: Ord<string>): <K extends string>(r: ReadonlyRecord<K, unknown>) => ReadonlyArray<K>
/**
 * Use the other overload instead
 *
 * @deprecated
 */
export function keys<K extends string>(r: ReadonlyRecord<K, unknown>): ReadonlyArray<K>
export function keys(
  or: Ord<string> | ReadonlyRecord<string, unknown>
): ((r: ReadonlyRecord<string, unknown>) => ReadonlyArray<string>) | ReadonlyArray<string> {
  return isOrd(or) ? keys(or) : (Object.keys(or) as any).sort()
}
```

The problem is the `isOrd` guard: how can we reliably distinguish between an `Ord` and a `ReadonlyRecord`?
anthonyjoeseph: No worries! Oh good question. Maybe something like this?

```ts
const isOrd = <A>(a: Record<string, unknown> | Ord<A>): a is Ord<A> =>
  keys(a as Record<string, unknown>).length === 2
  && 'equals' in a
  && typeof a.equals === 'function'
  && 'compare' in a && typeof a
  && typeof a.compare === 'function'
```

I know it's super kludgy, but we could _probably_ assume that would work
gcanti: I would:

- keep as is:
  - `keys` (you can always sort the output, or, if you want the insertion order, use `Object.keys`)
  - `toReadonlyArray` (you can always sort the output, or, if you want the insertion order, use `Object.values`)
  - `toUnfoldable`, `traverseWithIndex`, `traverse`, `sequence` (it doesn't worth it)
- apply the technique to: 
  - `collect` (this first parameter is a function so we are safe)
  - `reduceWithIndex`, `reduceRightWithIndex`, `reduce`, `reduceRight` (checking the `arguments` length I guess)
  - `foldMapWithIndex`, `foldMap`, `getShow` (checking `compare`? ugly...)
- add a new API and deprecate the old one (which we keep as is to not introduce breaking changes):
  - `Foldable` -> `getFoldable`
  - `FoldableWithIndex` -> `getFoldableWithIndex`
  - `Traversable` -> `getTraversable`
  - `TraversableWithIndex` -> `getTraversableWithIndex`
  - `Witherable` -> `getWitherable`

gcanti: > I would...

btw I know this is an horrible task, so feel free to close this PR or just clean it up by keeping only the new additions like `union`, `intersection`, etc...
anthonyjoeseph: Not at all - it's my pleasure! It should be good now.

By the way, I saw your comment in the Roadmap - please feel free to close this or steal from it if that'd be easier for you. Or I can remove the `Ord` stuff if that's easiest

Patch:
diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md
index 5e4dec11..c7a4be8d 100644
--- a/docs/modules/ReadonlyRecord.ts.md
+++ b/docs/modules/ReadonlyRecord.ts.md
@@ -43,18 +43,27 @@ Added in v2.5.0
   - [Compactable](#compactable-1)
   - [Filterable](#filterable-1)
   - [FilterableWithIndex](#filterablewithindex)
-  - [Foldable](#foldable-1)
-  - [FoldableWithIndex](#foldablewithindex)
   - [Functor](#functor)
   - [FunctorWithIndex](#functorwithindex)
-  - [Traversable](#traversable)
-  - [TraversableWithIndex](#traversablewithindex)
   - [URI](#uri)
   - [URI (type alias)](#uri-type-alias)
-  - [Witherable](#witherable-1)
+  - [getDifferenceMagma](#getdifferencemagma)
   - [getEq](#geteq)
+  - [getFoldable](#getfoldable)
+  - [getFoldableWithIndex](#getfoldablewithindex)
+  - [getIntersectionSemigroup](#getintersectionsemigroup)
   - [getMonoid](#getmonoid)
   - [getShow](#getshow)
+  - [getTraversable](#gettraversable)
+  - [getTraversableWithIndex](#gettraversablewithindex)
+  - [getUnionMonoid](#getunionmonoid)
+  - [getUnionSemigroup](#getunionsemigroup)
+  - [getWitherable](#getwitherable)
+  - [~~FoldableWithIndex~~](#foldablewithindex)
+  - [~~Foldable~~](#foldable)
+  - [~~TraversableWithIndex~~](#traversablewithindex)
+  - [~~Traversable~~](#traversable)
+  - [~~Witherable~~](#witherable)
   - [~~readonlyRecord~~](#readonlyrecord)
 - [interop](#interop)
   - [fromRecord](#fromrecord)
@@ -63,6 +72,7 @@ Added in v2.5.0
   - [ReadonlyRecord (type alias)](#readonlyrecord-type-alias)
 - [utils](#utils)
   - [collect](#collect)
+  - [difference](#difference)
   - [elem](#elem)
   - [empty](#empty)
   - [every](#every)
@@ -71,6 +81,7 @@ Added in v2.5.0
   - [fromFoldable](#fromfoldable)
   - [fromFoldableMap](#fromfoldablemap)
   - [has](#has)
+  - [intersection](#intersection)
   - [isEmpty](#isempty)
   - [isSubrecord](#issubrecord)
   - [keys](#keys)
@@ -87,6 +98,7 @@ Added in v2.5.0
   - [toReadonlyArray](#toreadonlyarray)
   - [traverse](#traverse)
   - [traverseWithIndex](#traversewithindex)
+  - [union](#union)
   - [updateAt](#updateat)
   - [~~hasOwnProperty (function)~~](#hasownproperty-function)
 
@@ -179,7 +191,10 @@ Added in v2.5.0
 **Signature**
 
 ```ts
-export declare const foldMap: <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Readonly<Record<string, A>>) => M
+export declare function foldMap(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Readonly<Record<string, A>>) => M
+export declare function foldMap<M>(M: Monoid<M>): <A>(f: (a: A) => M) => (fa: Readonly<Record<string, A>>) => M
 ```
 
 Added in v2.5.0
@@ -189,7 +204,10 @@ Added in v2.5.0
 **Signature**
 
 ```ts
-export declare const reduce: <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Readonly<Record<string, A>>) => B
+export declare function reduce(
+  O: Ord<string>
+): <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Readonly<Record<string, A>>) => B
+export declare function reduce<A, B>(b: B, f: (b: B, a: A) => B): (fa: Readonly<Record<string, A>>) => B
 ```
 
 Added in v2.5.0
@@ -199,10 +217,13 @@ Added in v2.5.0
 **Signature**
 
 ```ts
-export declare const reduceRight: <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Readonly<Record<string, A>>) => B
+export declare function reduceRight(
+  O: Ord<string>
+): <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Readonly<Record<string, A>>) => B
+export declare function reduceRight<A, B>(b: B, f: (a: A, b: B) => B): (fa: Readonly<Record<string, A>>) => B
 ```
 
-Added in v2.5.0
+Added in v2.11.0
 
 # Witherable
 
@@ -381,105 +402,95 @@ export declare const FilterableWithIndex: FilterableWithIndex1<'ReadonlyRecord',
 
 Added in v2.7.0
 
-## Foldable
-
-**Signature**
-
-```ts
-export declare const Foldable: Foldable1<'ReadonlyRecord'>
-```
-
-Added in v2.7.0
-
-## FoldableWithIndex
+## Functor
 
 **Signature**
 
 ```ts
-export declare const FoldableWithIndex: FoldableWithIndex1<'ReadonlyRecord', string>
+export declare const Functor: Functor1<'ReadonlyRecord'>
 ```
 
 Added in v2.7.0
 
-## Functor
+## FunctorWithIndex
 
 **Signature**
 
 ```ts
-export declare const Functor: Functor1<'ReadonlyRecord'>
+export declare const FunctorWithIndex: FunctorWithIndex1<'ReadonlyRecord', string>
 ```
 
 Added in v2.7.0
 
-## FunctorWithIndex
+## URI
 
 **Signature**
 
 ```ts
-export declare const FunctorWithIndex: FunctorWithIndex1<'ReadonlyRecord', string>
+export declare const URI: 'ReadonlyRecord'
 ```
 
-Added in v2.7.0
+Added in v2.5.0
 
-## Traversable
+## URI (type alias)
 
 **Signature**
 
 ```ts
-export declare const Traversable: Traversable1<'ReadonlyRecord'>
+export type URI = typeof URI
 ```
 
-Added in v2.7.0
+Added in v2.5.0
 
-## TraversableWithIndex
+## getDifferenceMagma
 
 **Signature**
 
 ```ts
-export declare const TraversableWithIndex: TraversableWithIndex1<'ReadonlyRecord', string>
+export declare const getDifferenceMagma: <A>() => Magma<Readonly<Record<string, A>>>
 ```
 
-Added in v2.7.0
+Added in v2.11.0
 
-## URI
+## getEq
 
 **Signature**
 
 ```ts
-export declare const URI: 'ReadonlyRecord'
+export declare function getEq<K extends string, A>(E: Eq<A>): Eq<ReadonlyRecord<K, A>>
 ```
 
 Added in v2.5.0
 
-## URI (type alias)
+## getFoldable
 
 **Signature**
 
 ```ts
-export type URI = typeof URI
+export declare const getFoldable: (O: Ord<string>) => Foldable1<URI>
 ```
 
-Added in v2.5.0
+Added in v2.7.0
 
-## Witherable
+## getFoldableWithIndex
 
 **Signature**
 
 ```ts
-export declare const Witherable: Witherable1<'ReadonlyRecord'>
+export declare const getFoldableWithIndex: (O: Ord<string>) => FoldableWithIndex1<URI, string>
 ```
 
-Added in v2.7.0
+Added in v2.11.0
 
-## getEq
+## getIntersectionSemigroup
 
 **Signature**
 
 ```ts
-export declare function getEq<K extends string, A>(E: Eq<A>): Eq<ReadonlyRecord<K, A>>
+export declare const getIntersectionSemigroup: <A>(S: Semigroup<A>) => Semigroup<Readonly<Record<string, A>>>
 ```
 
-Added in v2.5.0
+Added in v2.11.0
 
 ## getMonoid
 
@@ -508,11 +519,122 @@ Added in v2.5.0
 **Signature**
 
 ```ts
+export declare function getShow(O: Ord<string>): <A>(S: Show<A>) => Show<ReadonlyRecord<string, A>>
 export declare function getShow<A>(S: Show<A>): Show<ReadonlyRecord<string, A>>
 ```
 
 Added in v2.5.0
 
+## getTraversable
+
+**Signature**
+
+```ts
+export declare const getTraversable: (O: Ord<string>) => Traversable1<URI>
+```
+
+Added in v2.11.0
+
+## getTraversableWithIndex
+
+**Signature**
+
+```ts
+export declare const getTraversableWithIndex: (O: Ord<string>) => TraversableWithIndex1<URI, string>
+```
+
+Added in v2.11.0
+
+## getUnionMonoid
+
+**Signature**
+
+```ts
+export declare const getUnionMonoid: <A>(S: Semigroup<A>) => Monoid<Readonly<Record<string, A>>>
+```
+
+Added in v2.11.0
+
+## getUnionSemigroup
+
+**Signature**
+
+```ts
+export declare const getUnionSemigroup: <A>(S: Semigroup<A>) => Semigroup<Readonly<Record<string, A>>>
+```
+
+Added in v2.11.0
+
+## getWitherable
+
+**Signature**
+
+```ts
+export declare const getWitherable: (O: Ord<string>) => Witherable1<URI>
+```
+
+Added in v2.11.0
+
+## ~~FoldableWithIndex~~
+
+Use `getFoldableWithIndex` instead
+
+**Signature**
+
+```ts
+export declare const FoldableWithIndex: FoldableWithIndex1<'ReadonlyRecord', string>
+```
+
+Added in v2.7.0
+
+## ~~Foldable~~
+
+Use `getFoldable` instead
+
+**Signature**
+
+```ts
+export declare const Foldable: Foldable1<'ReadonlyRecord'>
+```
+
+Added in v2.7.0
+
+## ~~TraversableWithIndex~~
+
+Use `getTraversableWithIndex` instead
+
+**Signature**
+
+```ts
+export declare const TraversableWithIndex: TraversableWithIndex1<'ReadonlyRecord', string>
+```
+
+Added in v2.7.0
+
+## ~~Traversable~~
+
+Use `getTraversable` instead
+
+**Signature**
+
+```ts
+export declare const Traversable: Traversable1<'ReadonlyRecord'>
+```
+
+Added in v2.7.0
+
+## ~~Witherable~~
+
+Use `getWitherable` instead
+
+**Signature**
+
+```ts
+export declare const Witherable: Witherable1<'ReadonlyRecord'>
+```
+
+Added in v2.7.0
+
 ## ~~readonlyRecord~~
 
 Use small, specific instances instead.
@@ -572,24 +694,40 @@ Map a `ReadonlyRecord` into an `ReadonlyArray`.
 **Signature**
 
 ```ts
-export declare const collect: <K extends string, A, B>(
+export declare function collect(
+  O: Ord<string>
+): <K extends string, A, B>(f: (k: K, a: A) => B) => (r: ReadonlyRecord<K, A>) => ReadonlyArray<B>
+export declare function collect<K extends string, A, B>(
   f: (k: K, a: A) => B
-) => (r: Readonly<Record<K, A>>) => readonly B[]
+): (r: ReadonlyRecord<K, A>) => ReadonlyArray<B>
 ```
 
 **Example**
 
 ```ts
 import { collect } from 'fp-ts/ReadonlyRecord'
+import { Ord } from 'fp-ts/string'
 
 const x: { readonly a: string; readonly b: boolean } = { a: 'c', b: false }
-assert.deepStrictEqual(collect((key, val) => ({ key: key, value: val }))(x), [
+assert.deepStrictEqual(collect(Ord)((key, val) => ({ key: key, value: val }))(x), [
   { key: 'a', value: 'c' },
   { key: 'b', value: false },
 ])
 ```
 
-Added in v2.5.0
+Added in v2.11.0
+
+## difference
+
+**Signature**
+
+```ts
+export declare const difference: <A>(
+  second: Readonly<Record<string, A>>
+) => (first: Readonly<Record<string, A>>) => Readonly<Record<string, A>>
+```
+
+Added in v2.11.0
 
 ## elem
 
@@ -646,12 +784,21 @@ Added in v2.5.0
 **Signature**
 
 ```ts
+export declare function foldMapWithIndex(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <K extends string, A>(f: (k: K, a: A) => M) => (fa: ReadonlyRecord<K, A>) => M
+export declare function foldMapWithIndex(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <A>(f: (k: string, a: A) => M) => (fa: ReadonlyRecord<string, A>) => M
 export declare function foldMapWithIndex<M>(
   M: Monoid<M>
 ): <K extends string, A>(f: (k: K, a: A) => M) => (fa: ReadonlyRecord<K, A>) => M
+export declare function foldMapWithIndex<M>(
+  M: Monoid<M>
+): <A>(f: (k: string, a: A) => M) => (fa: ReadonlyRecord<string, A>) => M
 ```
 
-Added in v2.5.0
+Added in v2.11.0
 
 ## fromFoldable
 
@@ -760,6 +907,18 @@ export declare const has: <K extends string>(k: string, r: Readonly<Record<K, un
 
 Added in v2.10.0
 
+## intersection
+
+**Signature**
+
+```ts
+export declare const intersection: <A>(
+  M: Magma<A>
+) => (second: Readonly<Record<string, A>>) => (first: Readonly<Record<string, A>>) => Readonly<Record<string, A>>
+```
+
+Added in v2.11.0
+
 ## isEmpty
 
 Test whether a `ReadonlyRecord` is empty.
@@ -873,26 +1032,52 @@ Added in v2.5.0
 **Signature**
 
 ```ts
+export declare function reduceRightWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, a: A, b: B) => B) => (fa: ReadonlyRecord<K, A>) => B
+export declare function reduceRightWithIndex(
+  O: Ord<string>
+): <A, B>(b: B, f: (k: string, a: A, b: B) => B) => (fa: ReadonlyRecord<string, A>) => B
 export declare function reduceRightWithIndex<K extends string, A, B>(
   b: B,
   f: (k: K, a: A, b: B) => B
 ): (fa: ReadonlyRecord<K, A>) => B
+export declare function reduceRightWithIndex<A, B>(
+  b: B,
+  f: (k: string, a: A, b: B) => B
+): (fa: ReadonlyRecord<string, A>) => B
 ```
 
-Added in v2.5.0
+Added in v2.11.0
 
 ## reduceWithIndex
 
 **Signature**
 
 ```ts
+export declare function reduceWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: ReadonlyRecord<K, A>) => B
+export declare function reduceWithIndex(
+  O: Ord<string>
+): <A, B>(b: B, f: (k: string, b: B, a: A) => B) => (fa: ReadonlyRecord<string, A>) => B
 export declare function reduceWithIndex<K extends string, A, B>(
   b: B,
   f: (k: K, b: B, a: A) => B
 ): (fa: ReadonlyRecord<K, A>) => B
+export declare function reduceWithIndex<A, B>(
+  b: B,
+  f: (k: string, b: B, a: A) => B
+): (fa: ReadonlyRecord<string, A>) => B
+export declare function reduceWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: ReadonlyRecord<K, A>) => B
+export declare function reduceWithIndex(
+  O: Ord<string>
+): <A, B>(b: B, f: (k: string, b: B, a: A) => B) => (fa: ReadonlyRecord<string, A>) => B
 ```
 
-Added in v2.5.0
+Added in v2.11.0
 
 ## sequence
 
@@ -1027,6 +1212,18 @@ export declare function traverseWithIndex<F>(
 
 Added in v2.5.0
 
+## union
+
+**Signature**
+
+```ts
+export declare const union: <A>(
+  M: Magma<A>
+) => (second: Readonly<Record<string, A>>) => (first: Readonly<Record<string, A>>) => Readonly<Record<string, A>>
+```
+
+Added in v2.11.0
+
 ## updateAt
 
 **Signature**
diff --git a/docs/modules/Record.ts.md b/docs/modules/Record.ts.md
index dba70f83..c613e13d 100644
--- a/docs/modules/Record.ts.md
+++ b/docs/modules/Record.ts.md
@@ -34,18 +34,23 @@ Added in v2.0.0
   - [Compactable](#compactable-1)
   - [Filterable](#filterable-1)
   - [FilterableWithIndex](#filterablewithindex)
-  - [Foldable](#foldable-1)
-  - [FoldableWithIndex](#foldablewithindex)
   - [Functor](#functor)
   - [FunctorWithIndex](#functorwithindex)
-  - [Traversable](#traversable)
-  - [TraversableWithIndex](#traversablewithindex)
   - [URI](#uri)
   - [URI (type alias)](#uri-type-alias)
-  - [Witherable](#witherable-1)
   - [getEq](#geteq)
+  - [getFoldable](#getfoldable)
+  - [getFoldableWithIndex](#getfoldablewithindex)
   - [getMonoid](#getmonoid)
   - [getShow](#getshow)
+  - [getTraversable](#gettraversable)
+  - [getTraversableWithIndex](#gettraversablewithindex)
+  - [getWitherable](#getwitherable)
+  - [~~FoldableWithIndex~~](#foldablewithindex)
+  - [~~Foldable~~](#foldable)
+  - [~~TraversableWithIndex~~](#traversablewithindex)
+  - [~~Traversable~~](#traversable)
+  - [~~Witherable~~](#witherable)
   - [~~record~~](#record)
 - [utils](#utils)
   - [collect](#collect)
@@ -168,7 +173,10 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const foldMap: <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Record<string, A>) => M
+export declare function foldMap(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Record<string, A>) => M
+export declare function foldMap<M>(M: Monoid<M>): <A>(f: (a: A) => M) => (fa: Record<string, A>) => M
 ```
 
 Added in v2.0.0
@@ -178,7 +186,8 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const reduce: <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Record<string, A>) => B
+export declare function reduce(O: Ord<string>): <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Record<string, A>) => B
+export declare function reduce<A, B>(b: B, f: (b: B, a: A) => B): (fa: Record<string, A>) => B
 ```
 
 Added in v2.0.0
@@ -188,7 +197,8 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const reduceRight: <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Record<string, A>) => B
+export declare function reduceRight(O: Ord<string>): <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Record<string, A>) => B
+export declare function reduceRight<A, B>(b: B, f: (a: A, b: B) => B): (fa: Record<string, A>) => B
 ```
 
 Added in v2.0.0
@@ -273,137 +283,198 @@ export declare const FilterableWithIndex: FilterableWithIndex1<'Record', string>
 
 Added in v2.7.0
 
-## Foldable
+## Functor
 
 **Signature**
 
 ```ts
-export declare const Foldable: Foldable1<'Record'>
+export declare const Functor: Functor1<'Record'>
 ```
 
 Added in v2.7.0
 
-## FoldableWithIndex
+## FunctorWithIndex
 
 **Signature**
 
 ```ts
-export declare const FoldableWithIndex: FoldableWithIndex1<'Record', string>
+export declare const FunctorWithIndex: FunctorWithIndex1<'Record', string>
 ```
 
 Added in v2.7.0
 
-## Functor
+## URI
 
 **Signature**
 
 ```ts
-export declare const Functor: Functor1<'Record'>
+export declare const URI: 'Record'
 ```
 
-Added in v2.7.0
+Added in v2.0.0
 
-## FunctorWithIndex
+## URI (type alias)
 
 **Signature**
 
 ```ts
-export declare const FunctorWithIndex: FunctorWithIndex1<'Record', string>
+export type URI = typeof URI
 ```
 
-Added in v2.7.0
+Added in v2.0.0
 
-## Traversable
+## getEq
 
 **Signature**
 
 ```ts
-export declare const Traversable: Traversable1<'Record'>
+export declare const getEq: <K extends string, A>(E: Eq<A>) => Eq<Record<K, A>>
+```
+
+Added in v2.0.0
+
+## getFoldable
+
+**Signature**
+
+```ts
+export declare const getFoldable: (O: Ord<string>) => Foldable1<URI>
 ```
 
 Added in v2.7.0
 
-## TraversableWithIndex
+## getFoldableWithIndex
 
 **Signature**
 
 ```ts
-export declare const TraversableWithIndex: TraversableWithIndex1<'Record', string>
+export declare const getFoldableWithIndex: (O: Ord<string>) => FoldableWithIndex1<URI, string>
 ```
 
 Added in v2.7.0
 
-## URI
+## getMonoid
+
+Returns a `Monoid` instance for `Record`s given a `Semigroup` instance for their values.
 
 **Signature**
 
 ```ts
-export declare const URI: 'Record'
+export declare const getMonoid: <K extends string, A>(S: Semigroup<A>) => Monoid<Record<K, A>>
+```
+
+**Example**
+
+```ts
+import { SemigroupSum } from 'fp-ts/number'
+import { getMonoid } from 'fp-ts/Record'
+
+const M = getMonoid(SemigroupSum)
+assert.deepStrictEqual(M.concat({ foo: 123 }, { foo: 456 }), { foo: 579 })
 ```
 
 Added in v2.0.0
 
-## URI (type alias)
+## getShow
 
 **Signature**
 
 ```ts
-export type URI = typeof URI
+export declare function getShow(O: Ord<string>): <A>(S: Show<A>) => Show<Record<string, A>>
+export declare function getShow<A>(S: Show<A>): Show<Record<string, A>>
 ```
 
 Added in v2.0.0
 
-## Witherable
+## getTraversable
 
 **Signature**
 
 ```ts
-export declare const Witherable: Witherable1<'Record'>
+export declare const getTraversable: (O: Ord<string>) => Traversable1<URI>
+```
+
+Added in v2.11.0
+
+## getTraversableWithIndex
+
+**Signature**
+
+```ts
+export declare const getTraversableWithIndex: (O: Ord<string>) => TraversableWithIndex1<URI, string>
 ```
 
 Added in v2.7.0
 
-## getEq
+## getWitherable
 
 **Signature**
 
 ```ts
-export declare const getEq: <K extends string, A>(E: Eq<A>) => Eq<Record<K, A>>
+export declare const getWitherable: (O: Ord<string>) => Witherable1<URI>
 ```
 
-Added in v2.0.0
+Added in v2.7.0
 
-## getMonoid
+## ~~FoldableWithIndex~~
 
-Returns a `Monoid` instance for `Record`s given a `Semigroup` instance for their values.
+Use `getFoldableWithIndex` instead
 
 **Signature**
 
 ```ts
-export declare const getMonoid: <K extends string, A>(S: Semigroup<A>) => Monoid<Record<K, A>>
+export declare const FoldableWithIndex: FoldableWithIndex1<'Record', string>
 ```
 
-**Example**
+Added in v2.7.0
+
+## ~~Foldable~~
+
+Use `getFoldable` instead
+
+**Signature**
 
 ```ts
-import { SemigroupSum } from 'fp-ts/number'
-import { getMonoid } from 'fp-ts/Record'
+export declare const Foldable: Foldable1<'Record'>
+```
 
-const M = getMonoid(SemigroupSum)
-assert.deepStrictEqual(M.concat({ foo: 123 }, { foo: 456 }), { foo: 579 })
+Added in v2.7.0
+
+## ~~TraversableWithIndex~~
+
+Use the `getTraversableWithIndex` instead
+
+**Signature**
+
+```ts
+export declare const TraversableWithIndex: TraversableWithIndex1<'Record', string>
 ```
 
-Added in v2.0.0
+Added in v2.7.0
 
-## getShow
+## ~~Traversable~~
+
+Use `getTraversable` instead
 
 **Signature**
 
 ```ts
-export declare const getShow: <A>(S: Show<A>) => Show<Record<string, A>>
+export declare const Traversable: Traversable1<'Record'>
 ```
 
-Added in v2.0.0
+Added in v2.7.0
+
+## ~~Witherable~~
+
+Use `getWitherable` instead
+
+**Signature**
+
+```ts
+export declare const Witherable: Witherable1<'Record'>
+```
+
+Added in v2.7.0
 
 ## ~~record~~
 
@@ -430,16 +501,20 @@ Map a `Record` into an `Array`.
 **Signature**
 
 ```ts
-export declare const collect: <K extends string, A, B>(f: (k: K, a: A) => B) => (r: Record<K, A>) => B[]
+export declare function collect(
+  O: Ord<string>
+): <K extends string, A, B>(f: (k: K, a: A) => B) => (r: Record<K, A>) => Array<B>
+export declare function collect<K extends string, A, B>(f: (k: K, a: A) => B): (r: Record<K, A>) => Array<B>
 ```
 
 **Example**
 
 ```ts
 import { collect } from 'fp-ts/Record'
+import { Ord } from 'fp-ts/string'
 
 const x: { readonly a: string; readonly b: boolean } = { a: 'c', b: false }
-assert.deepStrictEqual(collect((key, val) => ({ key: key, value: val }))(x), [
+assert.deepStrictEqual(collect(Ord)((key, val) => ({ key: key, value: val }))(x), [
   { key: 'a', value: 'c' },
   { key: 'b', value: false },
 ])
@@ -515,9 +590,12 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const foldMapWithIndex: <M>(
+export declare function foldMapWithIndex(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <K extends string, A>(f: (k: K, a: A) => M) => (fa: Record<K, A>) => M
+export declare function foldMapWithIndex<M>(
   M: Monoid<M>
-) => <K extends string, A>(f: (k: K, a: A) => M) => (fa: Record<K, A>) => M
+): <K extends string, A>(f: (k: K, a: A) => M) => (fa: Record<K, A>) => M
 ```
 
 Added in v2.0.0
@@ -764,26 +842,32 @@ Added in v2.0.0
 **Signature**
 
 ```ts
-export declare const reduceRightWithIndex: <K extends string, A, B>(
+export declare function reduceRightWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, a: A, b: B) => B) => (fa: Record<K, A>) => B
+export declare function reduceRightWithIndex<K extends string, A, B>(
   b: B,
   f: (k: K, a: A, b: B) => B
-) => (fa: Record<K, A>) => B
+): (fa: Record<K, A>) => B
 ```
 
-Added in v2.0.0
+Added in v2.11.0
 
 ## reduceWithIndex
 
 **Signature**
 
 ```ts
-export declare const reduceWithIndex: <K extends string, A, B>(
+export declare function reduceWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: Record<K, A>) => B
+export declare function reduceWithIndex<K extends string, A, B>(
   b: B,
   f: (k: K, b: B, a: A) => B
-) => (fa: Record<K, A>) => B
+): (fa: Record<K, A>) => B
 ```
 
-Added in v2.0.0
+Added in v2.11.0
 
 ## sequence
 
diff --git a/docs/modules/function.ts.md b/docs/modules/function.ts.md
index 90672c5f..914ca72f 100644
--- a/docs/modules/function.ts.md
+++ b/docs/modules/function.ts.md
@@ -25,6 +25,7 @@ Added in v2.0.0
   - [Lazy (interface)](#lazy-interface)
   - [Predicate (interface)](#predicate-interface)
   - [Refinement (interface)](#refinement-interface)
+  - [SK](#sk)
   - [absurd](#absurd)
   - [constFalse](#constfalse)
   - [constNull](#constnull)
@@ -227,6 +228,16 @@ export interface Refinement<A, B extends A> {
 
 Added in v2.0.0
 
+## SK
+
+**Signature**
+
+```ts
+export declare const SK: <A, B>(_: A, b: B) => B
+```
+
+Added in v2.11.0
+
 ## absurd
 
 **Signature**
diff --git a/dtslint/ts3.5/ReadonlyRecord.ts b/dtslint/ts3.5/ReadonlyRecord.ts
index 86be63e9..0ba2ab16 100644
--- a/dtslint/ts3.5/ReadonlyRecord.ts
+++ b/dtslint/ts3.5/ReadonlyRecord.ts
@@ -66,6 +66,11 @@ _.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[]
 
+_.collect(S.Ord)((_k: 'a', n: number) => n)({ a: 1 }) // $ExpectType readonly number[]
+_.collect(S.Ord)((_k: 'a', n: number) => n)(l1) // $ExpectType readonly number[]
+_.collect(S.Ord)((_k, n: number) => n)(d1) // $ExpectType readonly number[]
+_.collect(S.Ord)((_k: 'a' | 'b', n: number) => n)(r1) // $ExpectType readonly number[]
+
 //
 // insertAt
 //
@@ -108,12 +113,21 @@ _.map((n: number) => n > 2)(r1) // $ExpectType Readonly<Record<"a" | "b", boolea
 // reduceWithIndex
 //
 
+_.reduceWithIndex(S.Ord)('', (k: string, _n) => k)(d1) // $ExpectType string
+_.reduceWithIndex(S.Ord)('', (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
 
+_.foldMapWithIndex(S.Ord)(S.Monoid)((k: string, _n) => k)(d1) // $ExpectType string
+_.foldMapWithIndex(S.Ord)(S.Monoid)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
+
 _.foldMapWithIndex(S.Monoid)((k: string, _n) => k)(d1) // $ExpectType string
 _.foldMapWithIndex(S.Monoid)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
 
+_.reduceRightWithIndex(S.Ord)('', (k: string, _n, _b) => k)(d1) // $ExpectType string
+_.reduceRightWithIndex(S.Ord)('', (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
 
diff --git a/dtslint/ts3.5/Record.ts b/dtslint/ts3.5/Record.ts
index d3d33537..3c5f50c8 100644
--- a/dtslint/ts3.5/Record.ts
+++ b/dtslint/ts3.5/Record.ts
@@ -66,6 +66,11 @@ _.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[]
 
+_.collect(S.Ord)((_k: 'a', n: number) => n)({ a: 1 }) // $ExpectType number[]
+_.collect(S.Ord)((_k: 'a', n: number) => n)(l1) // $ExpectType number[]
+_.collect(S.Ord)((_k, n: number) => n)(d1) // $ExpectType number[]
+_.collect(S.Ord)((_k: 'a' | 'b', n: number) => n)(r1) // $ExpectType number[]
+
 //
 // toArray
 //
@@ -117,12 +122,21 @@ _.map((n: number) => n > 2)(r1) // $ExpectType Record<"a" | "b", boolean>
 // reduceWithIndex
 //
 
+_.reduceWithIndex(S.Ord)('', (k: string, _n) => k)(d1) // $ExpectType string
+_.reduceWithIndex(S.Ord)('', (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
 
+_.foldMapWithIndex(S.Ord)(S.Monoid)((k: string, _n) => k)(d1) // $ExpectType string
+_.foldMapWithIndex(S.Ord)(S.Monoid)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
+
 _.foldMapWithIndex(S.Monoid)((k: string, _n) => k)(d1) // $ExpectType string
 _.foldMapWithIndex(S.Monoid)((k: 'a' | 'b', _n) => k)(r1) // $ExpectType string
 
+_.reduceRightWithIndex(S.Ord)('', (k: string, _n, _b) => k)(d1) // $ExpectType string
+_.reduceRightWithIndex(S.Ord)('', (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
 
diff --git a/src/Array.ts b/src/Array.ts
index c2512b9c..9feb663e 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -6,6 +6,7 @@ import { Alternative1 } from './Alternative'
 import { Applicative as ApplicativeHKT, Applicative1 } from './Applicative'
 import { apFirst as apFirst_, Apply1, apS as apS_, apSecond as apSecond_ } from './Apply'
 import { bind as bind_, Chain1, chainFirst as chainFirst_ } from './Chain'
+import { ChainRec1 } from './ChainRec'
 import { Compactable1 } from './Compactable'
 import { Either } from './Either'
 import { Eq } from './Eq'
@@ -1273,6 +1274,10 @@ const _wilt: Witherable1<URI>['wilt'] = <F>(
   const wiltF = wilt(F)
   return (fa, f) => pipe(fa, wiltF(f))
 }
+/* istanbul ignore next */
+const _chainRecDepthFirst: ChainRec1<URI>['chainRec'] = RA.ChainRecDepthFirst.chainRec as any
+/* istanbul ignore next */
+const _chainRecBreadthFirst: ChainRec1<URI>['chainRec'] = RA.ChainRecBreadthFirst.chainRec as any
 
 // -------------------------------------------------------------------------------------
 // type class members
@@ -1994,6 +1999,31 @@ export const Witherable: Witherable1<URI> = {
   wilt: _wilt
 }
 
+/**
+ * Exposing depth first recursion by default
+ * @category instances
+ * @since 2.10.0
+ */
+export const ChainRecDepthFirst: ChainRec1<URI> = {
+  URI,
+  map: _map,
+  ap: _ap,
+  chain: _chain,
+  chainRec: _chainRecDepthFirst
+}
+
+/**
+ * @category instances
+ * @since 2.10.0
+ */
+export const ChainRecBreadthFirst: ChainRec1<URI> = {
+  URI,
+  map: _map,
+  ap: _ap,
+  chain: _chain,
+  chainRec: _chainRecBreadthFirst
+}
+
 /**
  * Filter values inside a context.
  *
diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts
index bf9ae91f..ed11a9f3 100644
--- a/src/ReadonlyArray.ts
+++ b/src/ReadonlyArray.ts
@@ -6,6 +6,7 @@ import { Alternative1 } from './Alternative'
 import { Applicative as ApplicativeHKT, Applicative1 } from './Applicative'
 import { apFirst as apFirst_, Apply1, apS as apS_, apSecond as apSecond_ } from './Apply'
 import { bind as bind_, Chain1, chainFirst as chainFirst_ } from './Chain'
+import { ChainRec1 } from './ChainRec'
 import { Compactable1 } from './Compactable'
 import { Either } from './Either'
 import { Eq, fromEquals } from './Eq'
@@ -1337,6 +1338,54 @@ const _wilt: Witherable1<URI>['wilt'] = <F>(
   const wiltF = wilt(F)
   return (fa, f) => pipe(fa, wiltF(f))
 }
+const _chainRecDepthFirst: ChainRec1<URI>['chainRec'] = <A, B>(
+  a: A,
+  f: (a: A) => ReadonlyArray<Either<A, B>>
+): ReadonlyArray<B> => {
+  // tslint:disable-next-line: readonly-array
+  const todo: Array<Either<A, B>> = [...f(a)]
+  // tslint:disable-next-line: readonly-array
+  const result: Array<B> = []
+
+  while (todo.length > 0) {
+    const e = todo.shift()!
+    if (e._tag === 'Left') {
+      todo.unshift(...f(e.left))
+    } else {
+      result.push(e.right)
+    }
+  }
+
+  return result
+}
+const _chainRecBreadthFirst: ChainRec1<URI>['chainRec'] = <A, B>(
+  a: A,
+  f: (a: A) => ReadonlyArray<Either<A, B>>
+): ReadonlyArray<B> => {
+  const initial = f(a)
+  // tslint:disable-next-line: readonly-array
+  const todo: Array<Either<A, B>> = []
+  // tslint:disable-next-line: readonly-array
+  const result: Array<B> = []
+
+  function go(e: Either<A, B>): void {
+    if (e._tag === 'Left') {
+      f(e.left).forEach((v) => todo.push(v))
+    } else {
+      result.push(e.right)
+    }
+  }
+
+  for (const e of initial) {
+    go(e)
+  }
+
+  while (todo.length > 0) {
+    go(todo.shift()!)
+  }
+
+  return result
+}
 
 // -------------------------------------------------------------------------------------
 // type class members
@@ -2084,6 +2133,31 @@ export const TraversableWithIndex: TraversableWithIndex1<URI, number> = {
   traverseWithIndex: _traverseWithIndex
 }
 
+/**
+ * Exposing depth first recursion by default
+ * @category instances
+ * @since 2.10.0
+ */
+export const ChainRecDepthFirst: ChainRec1<URI> = {
+  URI,
+  map: _map,
+  ap: _ap,
+  chain: _chain,
+  chainRec: _chainRecDepthFirst
+}
+
+/**
+ * @category instances
+ * @since 2.10.0
+ */
+export const ChainRecBreadthFirst: ChainRec1<URI> = {
+  URI,
+  map: _map,
+  ap: _ap,
+  chain: _chain,
+  chainRec: _chainRecBreadthFirst
+}
+
 /**
  * @category instances
  * @since 2.7.0
diff --git a/src/ReadonlyMap.ts b/src/ReadonlyMap.ts
index 554f2d0a..178b2881 100644
--- a/src/ReadonlyMap.ts
+++ b/src/ReadonlyMap.ts
@@ -9,7 +9,7 @@ import { Filterable2 } from './Filterable'
 import { FilterableWithIndex2C } from './FilterableWithIndex'
 import { Foldable, Foldable1, Foldable2, Foldable2C, Foldable3 } from './Foldable'
 import { FoldableWithIndex2C } from './FoldableWithIndex'
-import { pipe, Predicate, Refinement } from './function'
+import { pipe, Predicate, Refinement, SK } from './function'
 import { flap as flap_, Functor2 } from './Functor'
 import { FunctorWithIndex2C } from './FunctorWithIndex'
 import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
@@ -937,7 +937,7 @@ export const getTraversableWithIndex = <K>(O: Ord<K>): TraversableWithIndex2C<UR
 
   const sequence = <F>(F: Applicative<F>): (<A>(ta: ReadonlyMap<K, HKT<F, A>>) => HKT<F, ReadonlyMap<K, A>>) => {
     const traverseWithIndexF = traverseWithIndex(F)
-    return (ta) => traverseWithIndexF(ta, (_, a) => a)
+    return (ta) => traverseWithIndexF(ta, SK)
   }
   return {
     URI,
diff --git a/src/ReadonlyNonEmptyArray.ts b/src/ReadonlyNonEmptyArray.ts
index 091cc9b5..73600abb 100644
--- a/src/ReadonlyNonEmptyArray.ts
+++ b/src/ReadonlyNonEmptyArray.ts
@@ -21,7 +21,7 @@ import { Eq, fromEquals } from './Eq'
 import { Extend1 } from './Extend'
 import { Foldable1 } from './Foldable'
 import { FoldableWithIndex1 } from './FoldableWithIndex'
-import { Endomorphism, identity, Lazy, pipe, Predicate, Refinement } from './function'
+import { Endomorphism, identity, Lazy, pipe, Predicate, Refinement, SK } from './function'
 import { bindTo as bindTo_, flap as flap_, Functor1 } from './Functor'
 import { FunctorWithIndex1 } from './FunctorWithIndex'
 import { HKT } from './HKT'
@@ -749,7 +749,7 @@ export const traverse: PipeableTraverse1<URI> = <F>(
  */
 export const sequence: Traversable1<URI>['sequence'] = <F>(
   F: ApplicativeHKT<F>
-): (<A>(as: ReadonlyNonEmptyArray<HKT<F, A>>) => HKT<F, ReadonlyNonEmptyArray<A>>) => traverseWithIndex(F)((_, a) => a)
+): (<A>(as: ReadonlyNonEmptyArray<HKT<F, A>>) => HKT<F, ReadonlyNonEmptyArray<A>>) => traverseWithIndex(F)(SK)
 
 /**
  * @category TraversableWithIndex
diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts
index 2734e624..d893b33d 100644
--- a/src/ReadonlyRecord.ts
+++ b/src/ReadonlyRecord.ts
@@ -9,7 +9,7 @@ import { Filterable1 } from './Filterable'
 import { FilterableWithIndex1, PredicateWithIndex, RefinementWithIndex } from './FilterableWithIndex'
 import { Foldable as FoldableHKT, Foldable1, Foldable2, Foldable3 } from './Foldable'
 import { FoldableWithIndex1 } from './FoldableWithIndex'
-import { identity, pipe, Predicate, Refinement } from './function'
+import { identity, pipe, Predicate, Refinement, SK } from './function'
 import { flap as flap_, Functor1 } from './Functor'
 import { FunctorWithIndex1 } from './FunctorWithIndex'
 import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
@@ -17,9 +17,11 @@ import * as _ from './internal'
 import { Magma } from './Magma'
 import { Monoid } from './Monoid'
 import * as O from './Option'
+import { Ord } from './Ord'
 import { Semigroup } from './Semigroup'
 import { Separated, separated } from './Separated'
 import { Show } from './Show'
+import { Ord as OrdString } from './string'
 import { Traversable1 } from './Traversable'
 import { TraversableWithIndex1 } from './TraversableWithIndex'
 import { Unfoldable, Unfoldable1 } from './Unfoldable'
@@ -84,28 +86,61 @@ export const isEmpty = (r: ReadonlyRecord<string, unknown>): boolean => {
 export const keys = <K extends string>(r: ReadonlyRecord<K, unknown>): ReadonlyArray<K> =>
   (Object.keys(r) as any).sort()
 
+/**
+ *
+ * @internal
+ * @since 2.11.0
+ */
+const keysWithOrd = (O: Ord<string>) => <K extends string>(r: ReadonlyRecord<K, unknown>): ReadonlyArray<K> =>
+  (Object.keys(r) as any).sort(O.compare)
+
 /**
  * Map a `ReadonlyRecord` into an `ReadonlyArray`.
  *
  * @example
  * import { collect } from 'fp-ts/ReadonlyRecord'
+ * import { Ord } from 'fp-ts/string'
  *
  * const x: { readonly a: string, readonly b: boolean } = { a: 'c', b: false }
  * assert.deepStrictEqual(
- *   collect((key, val) => ({ key: key, value: val }))(x),
+ *   collect(Ord)((key, val) => ({ key: key, value: val }))(x),
  *   [{ key: 'a', value: 'c' }, { key: 'b', value: false }]
  * )
  *
+ * @since 2.11.0
+ */
+export function collect(
+  O: Ord<string>
+): <K extends string, A, B>(f: (k: K, a: A) => B) => (r: ReadonlyRecord<K, A>) => ReadonlyArray<B>
+
+/**
+ * Use the other overload instead
+ *
+ * @deprecated
  * @since 2.5.0
  */
-export const collect = <K extends string, A, B>(f: (k: K, a: A) => B) => (
-  r: ReadonlyRecord<K, A>
-): ReadonlyArray<B> => {
-  const out: Array<B> = []
-  for (const key of keys(r)) {
-    out.push(f(key, r[key]))
+export function collect<K extends string, A, B>(f: (k: K, a: A) => B): (r: ReadonlyRecord<K, A>) => ReadonlyArray<B>
+export function collect(
+  O: Ord<string> | ((k: string, a: unknown) => unknown)
+):
+  | (<K extends string, A, B>(f: (k: K, a: A) => B) => (r: ReadonlyRecord<K, A>) => ReadonlyArray<B>)
+  | ((r: ReadonlyRecord<string, unknown>) => ReadonlyArray<unknown>) {
+  if (typeof O === 'function') {
+    return (r: ReadonlyRecord<string, unknown>) => {
+      const out: Array<unknown> = []
+      for (const key of keys(r)) {
+        out.push(O(key, r[key]))
+      }
+      return out
+    }
+  }
+  return <K extends string, A, B>(f: (k: K, a: A) => B) => (r: ReadonlyRecord<K, A>) => {
+    const out: Array<B> = []
+    for (const key of keysWithOrd(O)(r)) {
+      out.push(f(key, r[key]))
+    }
+    return out
   }
-  return out
 }
 
 /**
@@ -115,7 +150,7 @@ export const collect = <K extends string, A, B>(f: (k: K, a: A) => B) => (
  */
 export const toReadonlyArray: <K extends string, A>(r: ReadonlyRecord<K, A>) => ReadonlyArray<readonly [K, A]> =
   /*#__PURE__*/
-  collect((k, a) => [k, a])
+  collect(OrdString)((k, a) => [k, a])
 
 /**
  * Unfolds a `ReadonlyRecord` into a list of key/value pairs.
@@ -324,16 +359,59 @@ export function map<A, B>(f: (a: A) => B): (fa: ReadonlyRecord<string, A>) => Re
 }
 
 /**
+ * @since 2.11.0
+ */
+export function reduceWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: ReadonlyRecord<K, A>) => B
+export function reduceWithIndex(
+  O: Ord<string>
+): <A, B>(b: B, f: (k: string, b: B, a: A) => B) => (fa: ReadonlyRecord<string, A>) => B
+
+/**
+ * Use the other overloads instead
+ *
  * @since 2.5.0
+ * @deprecated
  */
 export function reduceWithIndex<K extends string, A, B>(
   b: B,
   f: (k: K, b: B, a: A) => B
 ): (fa: ReadonlyRecord<K, A>) => B
-export function reduceWithIndex<A, B>(b: B, f: (k: string, b: B, a: A) => B): (fa: ReadonlyRecord<string, A>) => B {
-  return (fa) => {
+export function reduceWithIndex<A, B>(b: B, f: (k: string, b: B, a: A) => B): (fa: ReadonlyRecord<string, A>) => B
+
+/**
+ * @since 2.11.0
+ */
+export function reduceWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: ReadonlyRecord<K, A>) => B
+export function reduceWithIndex(
+  O: Ord<string>
+): <A, B>(b: B, f: (k: string, b: B, a: A) => B) => (fa: ReadonlyRecord<string, A>) => B
+export function reduceWithIndex(
+  ...args: [Ord<string>] | [unknown, (k: string, b: unknown, a: unknown) => unknown]
+):
+  | ((
+      b: unknown,
+      f: (k: string, b: unknown, a: unknown) => unknown
+    ) => (fa: ReadonlyRecord<string, unknown>) => unknown)
+  | ((fa: ReadonlyRecord<string, unknown>) => unknown) {
+  if (args.length === 2) {
+    return (fa: ReadonlyRecord<string, unknown>) => {
+      let out = args[0]
+      const ks = keys(fa)
+      const len = ks.length
+      for (let i = 0; i < len; i++) {
+        const k = ks[i]
+        out = args[1](k, out, fa[k])
+      }
+      return out
+    }
+  }
+  return (b, f) => (fa) => {
     let out = b
-    const ks = keys(fa)
+    const ks = keysWithOrd(args[0])(fa)
     const len = ks.length
     for (let i = 0; i < len; i++) {
       const k = ks[i]
@@ -344,40 +422,103 @@ export function reduceWithIndex<A, B>(b: B, f: (k: string, b: B, a: A) => B): (f
 }
 
 /**
+ * @since 2.11.0
+ */
+export function foldMapWithIndex(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <K extends string, A>(f: (k: K, a: A) => M) => (fa: ReadonlyRecord<K, A>) => M
+export function foldMapWithIndex(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <A>(f: (k: string, a: A) => M) => (fa: ReadonlyRecord<string, A>) => M
+
+/**
+ * Use the other overloads instead
+ *
  * @since 2.5.0
+ * @deprecated
  */
 export function foldMapWithIndex<M>(
   M: Monoid<M>
 ): <K extends string, A>(f: (k: K, a: A) => M) => (fa: ReadonlyRecord<K, A>) => M
 export function foldMapWithIndex<M>(
   M: Monoid<M>
-): <A>(f: (k: string, a: A) => M) => (fa: ReadonlyRecord<string, A>) => M {
-  return (f) => (fa) => {
-    let out = M.empty
+): <A>(f: (k: string, a: A) => M) => (fa: ReadonlyRecord<string, A>) => M
+
+export function foldMapWithIndex(
+  arg: Ord<string> | Monoid<unknown>
+):
+  | ((
+      M: Monoid<unknown>
+    ) => (f: (k: string, a: unknown) => unknown) => (fa: ReadonlyRecord<string, unknown>) => unknown)
+  | ((f: (k: string, a: unknown) => unknown) => (fa: ReadonlyRecord<string, unknown>) => unknown) {
+  if ('compare' in arg) {
+    return (M: Monoid<unknown>) => (f: (k: string, a: unknown) => unknown) => (fa: ReadonlyRecord<string, unknown>) => {
+      let out = M.empty
+      const ks = keysWithOrd(arg)(fa)
+      const len = ks.length
+      for (let i = 0; i < len; i++) {
+        const k = ks[i]
+        out = M.concat(out, f(k, fa[k]))
+      }
+      return out
+    }
+  }
+  return (f: (k: string, a: unknown) => unknown) => (fa: ReadonlyRecord<string, unknown>) => {
+    let out = arg.empty
     const ks = keys(fa)
     const len = ks.length
     for (let i = 0; i < len; i++) {
       const k = ks[i]
-      out = M.concat(out, f(k, fa[k]))
+      out = arg.concat(out, f(k, fa[k]))
     }
     return out
   }
 }
 
 /**
+ * @since 2.11.0
+ */
+export function reduceRightWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, a: A, b: B) => B) => (fa: ReadonlyRecord<K, A>) => B
+export function reduceRightWithIndex(
+  O: Ord<string>
+): <A, B>(b: B, f: (k: string, a: A, b: B) => B) => (fa: ReadonlyRecord<string, A>) => B
+
+/**
+ * Use the other overloads instead
+ *
  * @since 2.5.0
+ * @deprecated
  */
 export function reduceRightWithIndex<K extends string, A, B>(
   b: B,
   f: (k: K, a: A, b: B) => B
 ): (fa: ReadonlyRecord<K, A>) => B
-export function reduceRightWithIndex<A, B>(
-  b: B,
-  f: (k: string, a: A, b: B) => B
-): (fa: ReadonlyRecord<string, A>) => B {
-  return (fa) => {
+export function reduceRightWithIndex<A, B>(b: B, f: (k: string, a: A, b: B) => B): (fa: ReadonlyRecord<string, A>) => B
+export function reduceRightWithIndex(
+  ...args: [Ord<string>] | [unknown, (k: string, a: unknown, b: unknown) => unknown]
+):
+  | ((
+      b: unknown,
+      f: (k: string, a: unknown, b: unknown) => unknown
+    ) => (fa: ReadonlyRecord<string, unknown>) => unknown)
+  | ((fa: ReadonlyRecord<string, unknown>) => unknown) {
+  if (args.length === 2) {
+    return (fa: ReadonlyRecord<string, unknown>) => {
+      let out = args[0]
+      const ks = keys(fa)
+      const len = ks.length
+      for (let i = len - 1; i >= 0; i--) {
+        const k = ks[i]
+        out = args[1](k, fa[k], out)
+      }
+      return out
+    }
+  }
+  return (b, f) => (fa) => {
     let out = b
-    const ks = keys(fa)
+    const ks = keysWithOrd(args[0])(fa)
     const len = ks.length
     for (let i = len - 1; i >= 0; i--) {
       const k = ks[i]
@@ -508,7 +649,7 @@ export function sequence<F>(
 export function sequence<F>(
   F: Applicative<F>
 ): <A>(ta: ReadonlyRecord<string, HKT<F, A>>) => HKT<F, ReadonlyRecord<string, A>> {
-  return traverseWithIndex(F)((_, a) => a)
+  return traverseWithIndex(F)(SK)
 }
 
 /**
@@ -795,6 +936,78 @@ export function elem<A>(
   }
 }
 
+/**
+ * @since 2.11.0
+ */
+export const union = <A>(M: Magma<A>) => (second: ReadonlyRecord<string, A>) => (
+  first: ReadonlyRecord<string, A>
+): ReadonlyRecord<string, A> => {
+  if (isEmpty(first)) {
+    return second
+  }
+  if (isEmpty(second)) {
+    return first
+  }
+  const out: Record<string, A> = {}
+  for (const k in first) {
+    if (has(k, second)) {
+      out[k] = M.concat(first[k], second[k])
+    } else {
+      out[k] = first[k]
+    }
+  }
+  for (const k in second) {
+    if (!has(k, out)) {
+      out[k] = second[k]
+    }
+  }
+  return out
+}
+
+/**
+ * @since 2.11.0
+ */
+export const intersection = <A>(M: Magma<A>) => (second: ReadonlyRecord<string, A>) => (
+  first: ReadonlyRecord<string, A>
+): ReadonlyRecord<string, A> => {
+  if (isEmpty(first) || isEmpty(second)) {
+    return empty
+  }
+  const out: Record<string, A> = {}
+  for (const k in first) {
+    if (has(k, second)) {
+      out[k] = M.concat(first[k], second[k])
+    }
+  }
+  return out
+}
+
+/**
+ * @since 2.11.0
+ */
+export const difference = <A>(second: ReadonlyRecord<string, A>) => (
+  first: ReadonlyRecord<string, A>
+): ReadonlyRecord<string, A> => {
+  if (isEmpty(first)) {
+    return second
+  }
+  if (isEmpty(second)) {
+    return first
+  }
+  const out: Record<string, A> = {}
+  for (const k in first) {
+    if (!has(k, second)) {
+      out[k] = first[k]
+    }
+  }
+  for (const k in second) {
+    if (!has(k, first)) {
+      out[k] = second[k]
+    }
+  }
+  return out
+}
+
 // -------------------------------------------------------------------------------------
 // non-pipeables
 // -------------------------------------------------------------------------------------
@@ -803,14 +1016,16 @@ const _map: Functor1<URI>['map'] = (fa, f) => pipe(fa, map(f))
 /* istanbul ignore next */
 const _mapWithIndex: FunctorWithIndex1<URI, string>['mapWithIndex'] = (fa, f) => pipe(fa, mapWithIndex(f))
 /* istanbul ignore next */
-const _reduce: Foldable1<URI>['reduce'] = (fa, b, f) => pipe(fa, reduce(b, f))
+const _reduce: (O: Ord<string>) => Foldable1<URI>['reduce'] = (O: Ord<string>) => (fa, b, f) =>
+  pipe(fa, reduce(O)(b, f))
 /* istanbul ignore next */
-const _foldMap: Foldable1<URI>['foldMap'] = (M) => {
-  const foldMapM = foldMap(M)
+const _foldMap: (O: Ord<string>) => Foldable1<URI>['foldMap'] = (O) => (M) => {
+  const foldMapM = foldMap(O)(M)
   return (fa, f) => pipe(fa, foldMapM(f))
 }
 /* istanbul ignore next */
-const _reduceRight: Foldable1<URI>['reduceRight'] = (fa, b, f) => pipe(fa, reduceRight(b, f))
+const _reduceRight: (O: Ord<string>) => Foldable1<URI>['reduceRight'] = (O) => (fa, b, f) =>
+  pipe(fa, reduceRight(O)(b, f))
 /* istanbul ignore next */
 const _traverse = <F>(
   F: Applicative<F>
@@ -831,16 +1046,19 @@ const _partition = <A>(
 /* istanbul ignore next */
 const _partitionMap: Filterable1<URI>['partitionMap'] = (fa, f) => pipe(fa, partitionMap(f))
 /* istanbul ignore next */
-const _reduceWithIndex: FoldableWithIndex1<URI, string>['reduceWithIndex'] = (fa, b, f) =>
-  pipe(fa, reduceWithIndex(b, f))
+const _reduceWithIndex: (O: Ord<string>) => FoldableWithIndex1<URI, string>['reduceWithIndex'] = (O) => (fa, b, f) =>
+  pipe(fa, reduceWithIndex(O)(b, f))
 /* istanbul ignore next */
-const _foldMapWithIndex: FoldableWithIndex1<URI, string>['foldMapWithIndex'] = (M) => {
-  const foldMapWithIndexM = foldMapWithIndex(M)
+const _foldMapWithIndex: (O: Ord<string>) => FoldableWithIndex1<URI, string>['foldMapWithIndex'] = (O) => (M) => {
+  const foldMapWithIndexM = foldMapWithIndex(O)(M)
   return (fa, f) => pipe(fa, foldMapWithIndexM(f))
 }
 /* istanbul ignore next */
-const _reduceRightWithIndex: FoldableWithIndex1<URI, string>['reduceRightWithIndex'] = (fa, b, f) =>
-  pipe(fa, reduceRightWithIndex(b, f))
+const _reduceRightWithIndex: (O: Ord<string>) => FoldableWithIndex1<URI, string>['reduceRightWithIndex'] = (O) => (
+  fa,
+  b,
+  f
+) => pipe(fa, reduceRightWithIndex(O)(b, f))
 /* istanbul ignore next */
 const _partitionMapWithIndex = <A, B, C>(
   fa: ReadonlyRecord<string, A>,
@@ -931,24 +1149,87 @@ export const partitionMap: <A, B, C>(
  * @category Foldable
  * @since 2.5.0
  */
-export const reduce: <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Readonly<Record<string, A>>) => B = (b, f) =>
-  reduceWithIndex(b, (_, b, a) => f(b, a))
+export function reduce(O: Ord<string>): <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Readonly<Record<string, A>>) => B
 
 /**
+ * Use other overload instead
+ *
  * @category Foldable
  * @since 2.5.0
+ * @deprecated
  */
-export const foldMap: <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Readonly<Record<string, A>>) => M = (M) => {
-  const foldMapWithIndexM = foldMapWithIndex(M)
-  return (f) => foldMapWithIndexM((_, a) => f(a))
+export function reduce<A, B>(b: B, f: (b: B, a: A) => B): (fa: Readonly<Record<string, A>>) => B
+export function reduce(
+  ...args: [Ord<string>] | [unknown, (b: unknown, A: unknown) => unknown]
+):
+  | ((b: unknown, f: (b: unknown, a: unknown) => unknown) => (fa: Readonly<Record<string, unknown>>) => unknown)
+  | ((fa: Readonly<Record<string, unknown>>) => unknown) {
+  if (args.length === 1) {
+    return (b: unknown, f: (b: unknown, a: unknown) => unknown) => reduceWithIndex(args[0])(b, (_, b, a) => f(b, a))
+  }
+  // tslint:disable-next-line: deprecation
+  return reduceWithIndex(args[0], (_, b, a) => args[1](b, a))
 }
 
 /**
  * @category Foldable
  * @since 2.5.0
  */
-export const reduceRight: <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Readonly<Record<string, A>>) => B = (b, f) =>
-  reduceRightWithIndex(b, (_, a, b) => f(a, b))
+export function foldMap(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Readonly<Record<string, A>>) => M
+
+/**
+ * Use the other overload instead
+ *
+ * @category Foldable
+ * @since 2.5.0
+ * @deprecated
+ */
+export function foldMap<M>(M: Monoid<M>): <A>(f: (a: A) => M) => (fa: Readonly<Record<string, A>>) => M
+export function foldMap(
+  arg: Ord<string> | Monoid<unknown>
+):
+  | ((M: Monoid<unknown>) => (f: (a: unknown) => unknown) => (fa: Readonly<Record<string, unknown>>) => unknown)
+  | ((f: (a: unknown) => unknown) => (fa: Readonly<Record<string, unknown>>) => unknown) {
+  if ('compare' in arg) {
+    return (M: Monoid<unknown>) => {
+      const foldMapWithIndexM = foldMapWithIndex(arg)(M)
+      return (f: (a: unknown) => unknown) => foldMapWithIndexM((_, a) => f(a))
+    }
+  }
+  // tslint:disable-next-line: deprecation
+  const foldMapWithIndexM = foldMapWithIndex(arg)
+  return (f: (a: unknown) => unknown) => foldMapWithIndexM((_, a) => f(a))
+}
+
+/**
+ * @category Foldable
+ * @since 2.11.0
+ */
+export function reduceRight(
+  O: Ord<string>
+): <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Readonly<Record<string, A>>) => B
+
+/**
+ * Use the other overload instead
+ *
+ * @category Foldable
+ * @since 2.5.0
+ * @deprecated
+ */
+export function reduceRight<A, B>(b: B, f: (a: A, b: B) => B): (fa: Readonly<Record<string, A>>) => B
+export function reduceRight(
+  ...args: [Ord<string>] | [unknown, (a: unknown, b: unknown) => unknown]
+):
+  | ((b: unknown, f: (a: unknown, b: unknown) => unknown) => (fa: Readonly<Record<string, unknown>>) => unknown)
+  | ((fa: Readonly<Record<string, unknown>>) => unknown) {
+  if (args.length === 2) {
+    // tslint:disable-next-line: deprecation
+    return reduceRightWithIndex(args[0], (_, a, b) => args[1](a, b))
+  }
+  return (b, f) => reduceRightWithIndex(args[0])(b, (_, a, b) => f(a, b))
+}
 
 /**
  * @category Compactable
@@ -1015,10 +1296,31 @@ declare module './HKT' {
  * @category instances
  * @since 2.5.0
  */
-export function getShow<A>(S: Show<A>): Show<ReadonlyRecord<string, A>> {
+export function getShow(O: Ord<string>): <A>(S: Show<A>) => Show<ReadonlyRecord<string, A>>
+
+/**
+ * Use the other overload instead
+ *
+ * @category instances
+ * @since 2.5.0
+ * @deprecated
+ */
+export function getShow<A>(S: Show<A>): Show<ReadonlyRecord<string, A>>
+export function getShow(
+  arg: Ord<string> | Show<unknown>
+): ((S: Show<unknown>) => Show<ReadonlyRecord<string, unknown>>) | Show<ReadonlyRecord<string, unknown>> {
+  if ('compare' in arg) {
+    return (S: Show<unknown>) => ({
+      show: (r: ReadonlyRecord<string, unknown>) => {
+        const elements = collect(arg)((k, a: unknown) => `${JSON.stringify(k)}: ${S.show(a)}`)(r).join(', ')
+        return elements === '' ? '{}' : `{ ${elements} }`
+      }
+    })
+  }
   return {
-    show: (r) => {
-      const elements = collect((k, a: A) => `${JSON.stringify(k)}: ${S.show(a)}`)(r).join(', ')
+    show: (r: ReadonlyRecord<string, unknown>) => {
+      // tslint:disable-next-line: deprecation
+      const elements = collect((k, a: unknown) => `${JSON.stringify(k)}: ${arg.show(a)}`)(r).join(', ')
       return elements === '' ? '{}' : `{ ${elements} }`
     }
   }
@@ -1099,30 +1401,61 @@ export const FunctorWithIndex: FunctorWithIndex1<URI, string> = {
 }
 
 /**
+ * Use `getFoldable` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const Foldable: Foldable1<URI> = {
   URI,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString)
 }
 
 /**
  * @category instances
  * @since 2.7.0
  */
+export const getFoldable = (O: Ord<string>): Foldable1<URI> => ({
+  URI,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O)
+})
+
+/**
+ * Use `getFoldableWithIndex` instead
+ *
+ * @category instances
+ * @since 2.7.0
+ * @deprecated
+ */
 export const FoldableWithIndex: FoldableWithIndex1<URI, string> = {
   URI,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
-  reduceWithIndex: _reduceWithIndex,
-  foldMapWithIndex: _foldMapWithIndex,
-  reduceRightWithIndex: _reduceRightWithIndex
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
+  reduceWithIndex: _reduceWithIndex(OrdString),
+  foldMapWithIndex: _foldMapWithIndex(OrdString),
+  reduceRightWithIndex: _reduceRightWithIndex(OrdString)
 }
 
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getFoldableWithIndex = (O: Ord<string>): FoldableWithIndex1<URI, string> => ({
+  URI,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  reduceWithIndex: _reduceWithIndex(O),
+  foldMapWithIndex: _foldMapWithIndex(O),
+  reduceRightWithIndex: _reduceRightWithIndex(O)
+})
+
 /**
  * @category instances
  * @since 2.7.0
@@ -1169,48 +1502,90 @@ export const FilterableWithIndex: FilterableWithIndex1<URI, string> = {
 }
 
 /**
+ * Use `getTraversable` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const Traversable: Traversable1<URI> = {
   URI,
   map: _map,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
   traverse: _traverse,
   sequence
 }
 
 /**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getTraversable = (O: Ord<string>): Traversable1<URI> => ({
+  URI,
+  map: _map,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  traverse: _traverse,
+  sequence
+})
+
+/**
+ * Use `getTraversableWithIndex` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const TraversableWithIndex: TraversableWithIndex1<URI, string> = {
   URI,
   map: _map,
   mapWithIndex: _mapWithIndex,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
-  reduceWithIndex: _reduceWithIndex,
-  foldMapWithIndex: _foldMapWithIndex,
-  reduceRightWithIndex: _reduceRightWithIndex,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
+  reduceWithIndex: _reduceWithIndex(OrdString),
+  foldMapWithIndex: _foldMapWithIndex(OrdString),
+  reduceRightWithIndex: _reduceRightWithIndex(OrdString),
   traverse: _traverse,
   sequence,
   traverseWithIndex: _traverseWithIndex
 }
 
 /**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getTraversableWithIndex = (O: Ord<string>): TraversableWithIndex1<URI, string> => ({
+  URI,
+  map: _map,
+  mapWithIndex: _mapWithIndex,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  reduceWithIndex: _reduceWithIndex(O),
+  foldMapWithIndex: _foldMapWithIndex(O),
+  reduceRightWithIndex: _reduceRightWithIndex(O),
+  traverse: _traverse,
+  sequence,
+  traverseWithIndex: _traverseWithIndex
+})
+
+/**
+ * Use `getWitherable` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const Witherable: Witherable1<URI> = {
   URI,
   map: _map,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
   traverse: _traverse,
   sequence,
   compact,
@@ -1223,6 +1598,61 @@ export const Witherable: Witherable1<URI> = {
   wilt: _wilt
 }
 
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getWitherable: (O: Ord<string>) => Witherable1<URI> = (O) => ({
+  URI,
+  map: _map,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  traverse: _traverse,
+  sequence,
+  compact,
+  separate,
+  filter: _filter,
+  filterMap: _filterMap,
+  partition: _partition,
+  partitionMap: _partitionMap,
+  wither: _wither,
+  wilt: _wilt
+})
+
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getUnionSemigroup = <A>(S: Semigroup<A>): Semigroup<ReadonlyRecord<string, A>> => ({
+  concat: (first, second) => union(S)(second)(first)
+})
+
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getUnionMonoid = <A>(S: Semigroup<A>): Monoid<ReadonlyRecord<string, A>> => ({
+  concat: getUnionSemigroup(S).concat,
+  empty
+})
+
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getIntersectionSemigroup = <A>(S: Semigroup<A>): Semigroup<ReadonlyRecord<string, A>> => ({
+  concat: (first, second) => intersection(S)(second)(first)
+})
+
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getDifferenceMagma = <A>(): Magma<ReadonlyRecord<string, A>> => ({
+  concat: (first, second) => difference(second)(first)
+})
+
 // -------------------------------------------------------------------------------------
 // deprecated
 // -------------------------------------------------------------------------------------
@@ -1264,9 +1694,9 @@ export const readonlyRecord: FunctorWithIndex1<URI, string> &
   Witherable1<URI> = {
   URI,
   map: _map,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
   traverse: _traverse,
   sequence,
   compact,
@@ -1276,9 +1706,9 @@ export const readonlyRecord: FunctorWithIndex1<URI, string> &
   partition: _partition,
   partitionMap: _partitionMap,
   mapWithIndex: _mapWithIndex,
-  reduceWithIndex: _reduceWithIndex,
-  foldMapWithIndex: _foldMapWithIndex,
-  reduceRightWithIndex: _reduceRightWithIndex,
+  reduceWithIndex: _reduceWithIndex(OrdString),
+  foldMapWithIndex: _foldMapWithIndex(OrdString),
+  reduceRightWithIndex: _reduceRightWithIndex(OrdString),
   filterMapWithIndex: _filterMapWithIndex,
   filterWithIndex: _filterWithIndex,
   partitionMapWithIndex: _partitionMapWithIndex,
diff --git a/src/Record.ts b/src/Record.ts
index 86a52a0e..ef2952cc 100644
--- a/src/Record.ts
+++ b/src/Record.ts
@@ -16,10 +16,12 @@ import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from './HKT'
 import { Magma } from './Magma'
 import { Monoid } from './Monoid'
 import * as O from './Option'
+import { Ord } from './Ord'
 import * as RR from './ReadonlyRecord'
 import { Semigroup } from './Semigroup'
 import { Separated } from './Separated'
 import { Show } from './Show'
+import { Ord as OrdString } from './string'
 import { Traversable1 } from './Traversable'
 import { TraversableWithIndex1 } from './TraversableWithIndex'
 import { Unfoldable, Unfoldable1 } from './Unfoldable'
@@ -50,26 +52,59 @@ export const isEmpty: (r: Record<string, unknown>) => boolean = RR.isEmpty
  */
 export const keys: <K extends string>(r: Record<K, unknown>) => Array<K> = RR.keys as any
 
+/**
+ *
+ * @internal
+ * @since 2.11.0
+ */
+const keysWithOrd = (O: Ord<string>) => <K extends string>(r: Record<K, unknown>): ReadonlyArray<K> =>
+  (Object.keys(r) as any).sort(O.compare)
+
 /**
  * Map a `Record` into an `Array`.
  *
  * @example
  * import { collect } from 'fp-ts/Record'
+ * import { Ord } from 'fp-ts/string'
  *
  * const x: { readonly a: string, readonly b: boolean } = { a: 'c', b: false }
  * assert.deepStrictEqual(
- *   collect((key, val) => ({ key: key, value: val }))(x),
+ *   collect(Ord)((key, val) => ({ key: key, value: val }))(x),
  *   [{ key: 'a', value: 'c' }, { key: 'b', value: false }]
  * )
  *
  * @since 2.0.0
  */
-export const collect = <K extends string, A, B>(f: (k: K, a: A) => B) => (r: Record<K, A>): Array<B> => {
-  const out: Array<B> = []
-  for (const key of keys(r)) {
-    out.push(f(key, r[key]))
+export function collect(O: Ord<string>): <K extends string, A, B>(f: (k: K, a: A) => B) => (r: Record<K, A>) => Array<B>
+
+/**
+ * Use the other overload
+ *
+ * @since 2.0.0
+ * @deprecated
+ */
+export function collect<K extends string, A, B>(f: (k: K, a: A) => B): (r: Record<K, A>) => Array<B>
+export function collect(
+  arg: Ord<string> | ((k: string, a: unknown) => unknown)
+):
+  | ((r: Record<string, unknown>) => Array<unknown>)
+  | ((f: (k: string, a: unknown) => unknown) => (r: Record<string, unknown>) => Array<unknown>) {
+  if (typeof arg === 'function') {
+    return (r: Record<string, unknown>) => {
+      const out: Array<unknown> = []
+      for (const key of keys(r)) {
+        out.push(arg(key, r[key]))
+      }
+      return out
+    }
+  }
+  return (f: (k: string, a: unknown) => unknown) => (r: Record<string, unknown>) => {
+    const out: Array<unknown> = []
+    for (const key of keysWithOrd(arg)(r)) {
+      out.push(f(key, r[key]))
+    }
+    return out
   }
-  return out
 }
 
 /**
@@ -79,7 +114,7 @@ export const collect = <K extends string, A, B>(f: (k: K, a: A) => B) => (r: Rec
  */
 export const toArray: <K extends string, A>(r: Record<K, A>) => Array<[K, A]> =
   /*#__PURE__*/
-  collect((k, a) => [k, a])
+  collect(OrdString)((k, a) => [k, a])
 
 /**
  * Unfolds a `Record` into a list of key/value pairs.
@@ -209,26 +244,85 @@ export const mapWithIndex: <K extends string, A, B>(f: (k: K, a: A) => B) => (fa
  */
 export const map: <A, B>(f: (a: A) => B) => <K extends string>(fa: Record<K, A>) => Record<K, B> = RR.map
 
+/**
+ * @since 2.11.0
+ */
+export function reduceWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: Record<K, A>) => B
+
+/**
+ * Use the other overload
+ *
+ * @since 2.0.0
+ * @deprecated
+ */
+export function reduceWithIndex<K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B): (fa: Record<K, A>) => B
+export function reduceWithIndex(
+  ...args: [Ord<string>] | [unknown, (k: unknown, b: unknown, a: unknown) => unknown]
+):
+  | ((b: unknown, f: (k: unknown, b: unknown, a: unknown) => unknown) => (fa: Record<string, unknown>) => unknown)
+  | ((fa: Record<string, unknown>) => unknown) {
+  if (args.length === 2) {
+    // tslint:disable-next-line: deprecation
+    return RR.reduceWithIndex(args[0], args[1])
+  }
+  return RR.reduceWithIndex(args[0])
+}
+
 /**
  * @since 2.0.0
  */
-export const reduceWithIndex: <K extends string, A, B>(b: B, f: (k: K, b: B, a: A) => B) => (fa: Record<K, A>) => B =
-  RR.reduceWithIndex
+export function foldMapWithIndex(
+  O: Ord<string>
+): <M>(M: Monoid<M>) => <K extends string, A>(f: (k: K, a: A) => M) => (fa: Record<K, A>) => M
 
 /**
+ * Use the other overload
+ *
  * @since 2.0.0
+ * @deprecated
  */
-export const foldMapWithIndex: <M>(
+export function foldMapWithIndex<M>(
   M: Monoid<M>
-) => <K extends string, A>(f: (k: K, a: A) => M) => (fa: Record<K, A>) => M = RR.foldMapWithIndex
+): <K extends string, A>(f: (k: K, a: A) => M) => (fa: Record<K, A>) => M
+export function foldMapWithIndex(
+  arg: Ord<string> | Monoid<unknown>
+):
+  | ((M: Monoid<unknown>) => (f: (k: string, a: unknown) => unknown) => (fa: Record<string, unknown>) => unknown)
+  | ((f: (k: string, a: unknown) => unknown) => (fa: Record<string, unknown>) => unknown) {
+  if ('compare' in arg) {
+    return RR.foldMapWithIndex(arg)
+  }
+  // tslint:disable-next-line: deprecation
+  return RR.foldMapWithIndex(arg)
+}
+
+/**
+ * @since 2.11.0
+ */
+export function reduceRightWithIndex(
+  O: Ord<string>
+): <K extends string, A, B>(b: B, f: (k: K, a: A, b: B) => B) => (fa: Record<K, A>) => B
 
 /**
+ * Use the other overload
+ *
  * @since 2.0.0
+ * @deprecated
  */
-export const reduceRightWithIndex: <K extends string, A, B>(
-  b: B,
-  f: (k: K, a: A, b: B) => B
-) => (fa: Record<K, A>) => B = RR.reduceRightWithIndex
+export function reduceRightWithIndex<K extends string, A, B>(b: B, f: (k: K, a: A, b: B) => B): (fa: Record<K, A>) => B
+export function reduceRightWithIndex(
+  ...args: [Ord<string>] | [unknown, (k: string, a: unknown, b: unknown) => unknown]
+):
+  | ((b: unknown, f: (k: string, a: unknown, b: unknown) => unknown) => (fa: Record<string, unknown>) => unknown)
+  | ((fa: Record<string, unknown>) => unknown) {
+  if (args.length === 2) {
+    // tslint:disable-next-line: deprecation
+    return RR.reduceRightWithIndex(args[0], args[1])
+  }
+  return RR.reduceRightWithIndex(args[0])
+}
 
 /**
  * Create a `Record` with one key/value pair.
@@ -497,14 +591,14 @@ const _map: Functor1<URI>['map'] = (fa, f) => pipe(fa, map(f))
 /* istanbul ignore next */
 const _mapWithIndex: FunctorWithIndex1<URI, string>['mapWithIndex'] = (fa, f) => pipe(fa, mapWithIndex(f))
 /* istanbul ignore next */
-const _reduce: Foldable1<URI>['reduce'] = (fa, b, f) => pipe(fa, reduce(b, f))
+const _reduce = (O: Ord<string>): Foldable1<URI>['reduce'] => (fa, b, f) => pipe(fa, reduce(O)(b, f))
 /* istanbul ignore next */
-const _foldMap: Foldable1<URI>['foldMap'] = (M) => {
-  const foldMapM = foldMap(M)
-  return (fa, f) => pipe(fa, foldMapM(f))
+const _foldMap = (O: Ord<string>): Foldable1<URI>['foldMap'] => (M) => {
+  const foldMapOM = foldMap(O)(M)
+  return (fa, f) => pipe(fa, foldMapOM(f))
 }
 /* istanbul ignore next */
-const _reduceRight: Foldable1<URI>['reduceRight'] = (fa, b, f) => pipe(fa, reduceRight(b, f))
+const _reduceRight = (O: Ord<string>): Foldable1<URI>['reduceRight'] => (fa, b, f) => pipe(fa, reduceRight(O)(b, f))
 /* istanbul ignore next */
 const _traverse = <F>(
   F: Applicative<F>
@@ -524,16 +618,16 @@ const _partition = <A>(
 /* istanbul ignore next */
 const _partitionMap: Filterable1<URI>['partitionMap'] = (fa, f) => pipe(fa, partitionMap(f))
 /* istanbul ignore next */
-const _reduceWithIndex: FoldableWithIndex1<URI, string>['reduceWithIndex'] = (fa, b, f) =>
-  pipe(fa, reduceWithIndex(b, f))
+const _reduceWithIndex = (O: Ord<string>): FoldableWithIndex1<URI, string>['reduceWithIndex'] => (fa, b, f) =>
+  pipe(fa, reduceWithIndex(O)(b, f))
 /* istanbul ignore next */
-const _foldMapWithIndex: FoldableWithIndex1<URI, string>['foldMapWithIndex'] = (M) => {
-  const foldMapWithIndexM = foldMapWithIndex(M)
-  return (fa, f) => pipe(fa, foldMapWithIndexM(f))
+const _foldMapWithIndex = (O: Ord<string>): FoldableWithIndex1<URI, string>['foldMapWithIndex'] => (M) => {
+  const foldMapWithIndexOM = foldMapWithIndex(O)(M)
+  return (fa, f) => pipe(fa, foldMapWithIndexOM(f))
 }
 /* istanbul ignore next */
-const _reduceRightWithIndex: FoldableWithIndex1<URI, string>['reduceRightWithIndex'] = (fa, b, f) =>
-  pipe(fa, reduceRightWithIndex(b, f))
+const _reduceRightWithIndex = (O: Ord<string>): FoldableWithIndex1<URI, string>['reduceRightWithIndex'] => (fa, b, f) =>
+  pipe(fa, reduceRightWithIndex(O)(b, f))
 /* istanbul ignore next */
 const _partitionMapWithIndex = <A, B, C>(
   fa: Record<string, A>,
@@ -596,7 +690,27 @@ export const filterMap: <A, B>(f: (a: A) => Option<B>) => (fa: Record<string, A>
  * @category Foldable
  * @since 2.0.0
  */
-export const foldMap: <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Record<string, A>) => M = RR.foldMap
+export function foldMap(O: Ord<string>): <M>(M: Monoid<M>) => <A>(f: (a: A) => M) => (fa: Record<string, A>) => M
+
+/**
+ * Use the other overload
+ *
+ * @category Foldable
+ * @since 2.0.0
+ * @deprecated
+ */
+export function foldMap<M>(M: Monoid<M>): <A>(f: (a: A) => M) => (fa: Record<string, A>) => M
+export function foldMap(
+  O: Ord<string> | Monoid<unknown>
+):
+  | ((M: Monoid<unknown>) => (f: (a: unknown) => unknown) => (fa: Record<string, unknown>) => unknown)
+  | ((f: (a: unknown) => unknown) => (fa: Record<string, unknown>) => unknown) {
+  if ('compare' in O) {
+    return RR.foldMap(O)
+  }
+  // tslint:disable-next-line: deprecation
+  return RR.foldMap(O)
+}
 
 /**
  * @category Filterable
@@ -621,13 +735,52 @@ export const partitionMap: <A, B, C>(
  * @category Foldable
  * @since 2.0.0
  */
-export const reduce: <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Record<string, A>) => B = RR.reduce
+export function reduce(O: Ord<string>): <A, B>(b: B, f: (b: B, a: A) => B) => (fa: Record<string, A>) => B
+
+/**
+ * Use the other overload
+ *
+ * @category Foldable
+ * @since 2.0.0
+ * @deprecated
+ */
+export function reduce<A, B>(b: B, f: (b: B, a: A) => B): (fa: Record<string, A>) => B
+export function reduce(
+  ...args: [Ord<string>] | [unknown, (b: unknown, a: unknown) => unknown]
+):
+  | ((b: unknown, f: (b: unknown, a: unknown) => unknown) => (fa: Record<string, unknown>) => unknown)
+  | ((fa: Record<string, unknown>) => unknown) {
+  if (args.length === 2) {
+    // tslint:disable-next-line: deprecation
+    return RR.reduce(args[0], args[1])
+  }
+  return RR.reduce(args[0])
+}
+/**
+ * @category Foldable
+ * @since 2.0.0
+ */
+export function reduceRight(O: Ord<string>): <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Record<string, A>) => B
 
 /**
+ * Use the other overload
+ *
  * @category Foldable
  * @since 2.0.0
+ * @deprecated
  */
-export const reduceRight: <A, B>(b: B, f: (a: A, b: B) => B) => (fa: Record<string, A>) => B = RR.reduceRight
+export function reduceRight<A, B>(b: B, f: (a: A, b: B) => B): (fa: Record<string, A>) => B
+export function reduceRight(
+  ...args: [Ord<string>] | [unknown, (a: unknown, b: unknown) => unknown]
+):
+  | ((b: unknown, f: (a: unknown, b: unknown) => unknown) => (fa: Record<string, unknown>) => unknown)
+  | ((fa: Record<string, unknown>) => unknown) {
+  if (args.length === 2) {
+    // tslint:disable-next-line: deprecation
+    return RR.reduceRight(args[0], args[1])
+  }
+  return RR.reduceRight(args[0])
+}
 
 /**
  * @category Compactable
@@ -668,7 +821,25 @@ declare module './HKT' {
  * @category instances
  * @since 2.0.0
  */
-export const getShow: <A>(S: Show<A>) => Show<Record<string, A>> = RR.getShow
+export function getShow(O: Ord<string>): <A>(S: Show<A>) => Show<Record<string, A>>
+
+/**
+ * Use the other overload
+ *
+ * @category instances
+ * @since 2.0.0
+ * @deprecated
+ */
+export function getShow<A>(S: Show<A>): Show<Record<string, A>>
+export function getShow(
+  arg: Ord<string> | Show<unknown>
+): ((S: Show<unknown>) => Show<Record<string, unknown>>) | Show<Record<string, unknown>> {
+  if ('compare' in arg) {
+    return RR.getShow(arg)
+  }
+  // tslint:disable-next-line: deprecation
+  return RR.getShow(arg)
+}
 
 /**
  * @category instances
@@ -721,30 +892,61 @@ export const FunctorWithIndex: FunctorWithIndex1<URI, string> = {
 }
 
 /**
+ * Use `getFoldable` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const Foldable: Foldable1<URI> = {
   URI,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString)
 }
 
 /**
  * @category instances
  * @since 2.7.0
  */
+export const getFoldable = (O: Ord<string>): Foldable1<URI> => ({
+  URI,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O)
+})
+
+/**
+ * Use `getFoldableWithIndex` instead
+ *
+ * @category instances
+ * @since 2.7.0
+ * @deprecated
+ */
 export const FoldableWithIndex: FoldableWithIndex1<URI, string> = {
   URI,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
-  reduceWithIndex: _reduceWithIndex,
-  foldMapWithIndex: _foldMapWithIndex,
-  reduceRightWithIndex: _reduceRightWithIndex
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
+  reduceWithIndex: _reduceWithIndex(OrdString),
+  foldMapWithIndex: _foldMapWithIndex(OrdString),
+  reduceRightWithIndex: _reduceRightWithIndex(OrdString)
 }
 
+/**
+ * @category instances
+ * @since 2.7.0
+ */
+export const getFoldableWithIndex = (O: Ord<string>): FoldableWithIndex1<URI, string> => ({
+  URI,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  reduceWithIndex: _reduceWithIndex(O),
+  foldMapWithIndex: _foldMapWithIndex(O),
+  reduceRightWithIndex: _reduceRightWithIndex(O)
+})
+
 /**
  * @category instances
  * @since 2.7.0
@@ -791,33 +993,52 @@ export const FilterableWithIndex: FilterableWithIndex1<URI, string> = {
 }
 
 /**
+ * Use `getTraversable` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const Traversable: Traversable1<URI> = {
   URI,
   map: _map,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
   traverse: _traverse,
   sequence
 }
+/**
+ * @category instances
+ * @since 2.11.0
+ */
+export const getTraversable = (O: Ord<string>): Traversable1<URI> => ({
+  URI,
+  map: _map,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  traverse: _traverse,
+  sequence
+})
 
 /**
+ * Use the `getTraversableWithIndex` instead
+ *
  * @category instances
  * @since 2.7.0
+ * @deprecated
  */
 export const TraversableWithIndex: TraversableWithIndex1<URI, string> = {
   URI,
   map: _map,
   mapWithIndex: _mapWithIndex,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
-  reduceWithIndex: _reduceWithIndex,
-  foldMapWithIndex: _foldMapWithIndex,
-  reduceRightWithIndex: _reduceRightWithIndex,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
+  reduceWithIndex: _reduceWithIndex(OrdString),
+  foldMapWithIndex: _foldMapWithIndex(OrdString),
+  reduceRightWithIndex: _reduceRightWithIndex(OrdString),
   traverse: _traverse,
   sequence,
   traverseWithIndex: _traverseWithIndex
@@ -827,12 +1048,34 @@ export const TraversableWithIndex: TraversableWithIndex1<URI, string> = {
  * @category instances
  * @since 2.7.0
  */
+export const getTraversableWithIndex = (O: Ord<string>): TraversableWithIndex1<URI, string> => ({
+  URI,
+  map: _map,
+  mapWithIndex: _mapWithIndex,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  reduceWithIndex: _reduceWithIndex(O),
+  foldMapWithIndex: _foldMapWithIndex(O),
+  reduceRightWithIndex: _reduceRightWithIndex(O),
+  traverse: _traverse,
+  sequence,
+  traverseWithIndex: _traverseWithIndex
+})
+
+/**
+ * Use `getWitherable` instead
+ *
+ * @category instances
+ * @since 2.7.0
+ * @deprecated
+ */
 export const Witherable: Witherable1<URI> = {
   URI,
   map: _map,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
   traverse: _traverse,
   sequence,
   compact,
@@ -845,6 +1088,28 @@ export const Witherable: Witherable1<URI> = {
   wilt: _wilt
 }
 
+/**
+ * @category instances
+ * @since 2.7.0
+ */
+export const getWitherable = (O: Ord<string>): Witherable1<URI> => ({
+  URI,
+  map: _map,
+  reduce: _reduce(O),
+  foldMap: _foldMap(O),
+  reduceRight: _reduceRight(O),
+  traverse: _traverse,
+  sequence,
+  compact,
+  separate,
+  filter: _filter,
+  filterMap: _filterMap,
+  partition: _partition,
+  partitionMap: _partitionMap,
+  wither: _wither,
+  wilt: _wilt
+})
+
 // -------------------------------------------------------------------------------------
 // deprecated
 // -------------------------------------------------------------------------------------
@@ -887,9 +1152,9 @@ export const record: FunctorWithIndex1<URI, string> &
   Witherable1<URI> = {
   URI,
   map: _map,
-  reduce: _reduce,
-  foldMap: _foldMap,
-  reduceRight: _reduceRight,
+  reduce: _reduce(OrdString),
+  foldMap: _foldMap(OrdString),
+  reduceRight: _reduceRight(OrdString),
   traverse: _traverse,
   sequence,
   compact,
@@ -899,9 +1164,9 @@ export const record: FunctorWithIndex1<URI, string> &
   partition: _partition,
   partitionMap: _partitionMap,
   mapWithIndex: _mapWithIndex,
-  reduceWithIndex: _reduceWithIndex,
-  foldMapWithIndex: _foldMapWithIndex,
-  reduceRightWithIndex: _reduceRightWithIndex,
+  reduceWithIndex: _reduceWithIndex(OrdString),
+  foldMapWithIndex: _foldMapWithIndex(OrdString),
+  reduceRightWithIndex: _reduceRightWithIndex(OrdString),
   filterMapWithIndex: _filterMapWithIndex,
   filterWithIndex: _filterWithIndex,
   partitionMapWithIndex: _partitionMapWithIndex,
diff --git a/src/function.ts b/src/function.ts
index 5e114f35..05d68ff5 100644
--- a/src/function.ts
+++ b/src/function.ts
@@ -748,3 +748,8 @@ export function pipe(
  * @since 2.7.0
  */
 export const hole: <T>() => T = absurd as any
+
+/**
+ * @since 2.11.0
+ */
+export const SK = <A, B>(_: A, b: B): B => b


Test patch:
diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts
index b2ee1feb..4b4a576d 100644
--- a/test/ReadonlyArray.ts
+++ b/test/ReadonlyArray.ts
@@ -1220,4 +1220,135 @@ describe('ReadonlyArray', () => {
     U.deepStrictEqual(_.size([]), 0)
     U.deepStrictEqual(_.size(['a']), 1)
   })
+
+  describe('chainRec', () => {
+    it('depth-first', () => {
+      const chainRec = _.ChainRecDepthFirst.chainRec
+      assert.deepStrictEqual(
+        chainRec(1, () => []),
+        []
+      )
+      assert.deepStrictEqual(
+        chainRec(1, () => [E.right('foo')]),
+        ['foo']
+      )
+      assert.deepStrictEqual(
+        chainRec(1, (a) => {
+          if (a < 5) {
+            return [E.right(a), E.left(a + 1)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [1, 2, 3, 4, 5]
+      )
+      assert.deepStrictEqual(
+        chainRec(1, (a) => {
+          if (a < 5) {
+            return [E.left(a + 1), E.right(a)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [5, 4, 3, 2, 1]
+      )
+      assert.deepStrictEqual(
+        chainRec(1, (a) => {
+          if (a < 5) {
+            return a % 2 === 0 ? [E.right(a), E.left(a + 1)] : [E.left(a + 1), E.right(a)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [2, 4, 5, 3, 1]
+      )
+      assert.deepStrictEqual(
+        chainRec(0, (a) => {
+          if (a === 0) {
+            return [E.right(a), E.left(a - 1), E.left(a + 1)]
+          } else if (0 < a && a < 5) {
+            return [E.right(a), E.left(a + 1)]
+          } else if (-5 < a && a < 0) {
+            return [E.right(a), E.left(a - 1)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [0, -1, -2, -3, -4, -5, 1, 2, 3, 4, 5]
+      )
+      assert.deepStrictEqual(
+        chainRec(0, (a) => {
+          if (a === 0) {
+            return [E.left(a - 1), E.right(a), E.left(a + 1)]
+          } else if (0 < a && a < 5) {
+            return [E.right(a), E.left(a + 1)]
+          } else if (-5 < a && a < 0) {
+            return [E.left(a - 1), E.right(a)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
+      )
+    })
+    it('breadth-first', () => {
+      const chainRec = _.ChainRecBreadthFirst.chainRec
+      assert.deepStrictEqual(
+        chainRec(1, () => []),
+        []
+      )
+      assert.deepStrictEqual(
+        chainRec(1, () => [E.right('foo')]),
+        ['foo']
+      )
+      assert.deepStrictEqual(
+        chainRec(1, (a) => {
+          if (a < 5) {
+            return [E.right(a), E.left(a + 1)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [1, 2, 3, 4, 5]
+      )
+      assert.deepStrictEqual(
+        chainRec(1, (a) => {
+          if (a < 5) {
+            return [E.left(a + 1), E.right(a)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [1, 2, 3, 4, 5]
+      )
+      assert.deepStrictEqual(
+        chainRec(0, (a) => {
+          if (a === 0) {
+            return [E.right(a), E.left(a - 1), E.left(a + 1)]
+          } else if (0 < a && a < 5) {
+            return [E.right(a), E.left(a + 1)]
+          } else if (-5 < a && a < 0) {
+            return [E.right(a), E.left(a - 1)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5]
+      )
+      assert.deepStrictEqual(
+        chainRec(0, (a) => {
+          if (a === 0) {
+            return [E.left(a - 1), E.right(a), E.left(a + 1)]
+          } else if (0 < a && a < 5) {
+            return [E.right(a), E.left(a + 1)]
+          } else if (-5 < a && a < 0) {
+            return [E.left(a - 1), E.right(a)]
+          } else {
+            return [E.right(a)]
+          }
+        }),
+        [0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5]
+      )
+    })
+  })
 })
diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts
index 9afd5235..8150305a 100644
--- a/test/ReadonlyRecord.ts
+++ b/test/ReadonlyRecord.ts
@@ -28,6 +28,21 @@ describe('ReadonlyRecord', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.reduce(S.Ord)('', (b, a) => b + a)
+        ),
+        'ab'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k2: 'b', k1: 'a' },
+          _.reduce(S.Ord)('', (b, a) => b + a)
+        ),
+        'ab'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.reduce('', (b, a) => b + a)
         ),
         'ab'
@@ -35,6 +50,7 @@ describe('ReadonlyRecord', () => {
       U.deepStrictEqual(
         pipe(
           { k2: 'b', k1: 'a' },
+          // tslint:disable-next-line: deprecation
           _.reduce('', (b, a) => b + a)
         ),
         'ab'
@@ -42,11 +58,20 @@ describe('ReadonlyRecord', () => {
     })
 
     it('foldMap', () => {
+      U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.foldMap(S.Ord)(S.Monoid)(identity)), 'ab')
+      U.deepStrictEqual(_.getFoldable(S.Ord).foldMap(S.Monoid)({ a: 'a', b: 'b' }, identity), 'ab')
+
+      // tslint:disable-next-line: deprecation
       U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.foldMap(S.Monoid)(identity)), 'ab')
+      // tslint:disable-next-line: deprecation
+      U.deepStrictEqual(_.Foldable.foldMap(S.Monoid)({ a: 'a', b: 'b' }, identity), 'ab')
     })
 
     it('reduceRight', () => {
       const f = (a: string, acc: string) => acc + a
+      U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.reduceRight(S.Ord)('', f)), 'ba')
+
+      // tslint:disable-next-line: deprecation
       U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.reduceRight('', f)), 'ba')
     })
 
@@ -107,6 +132,22 @@ describe('ReadonlyRecord', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.reduceWithIndex(S.Ord)('', (k, b, a) => b + k + a)
+        ),
+        'k1ak2b'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k2: 'b', k1: 'a' },
+          _.reduceWithIndex(S.Ord)('', (k, b, a) => b + k + a)
+        ),
+        'k1ak2b'
+      )
+
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.reduceWithIndex('', (k, b, a) => b + k + a)
         ),
         'k1ak2b'
@@ -114,6 +155,7 @@ describe('ReadonlyRecord', () => {
       U.deepStrictEqual(
         pipe(
           { k2: 'b', k1: 'a' },
+          // tslint:disable-next-line: deprecation
           _.reduceWithIndex('', (k, b, a) => b + k + a)
         ),
         'k1ak2b'
@@ -124,16 +166,42 @@ describe('ReadonlyRecord', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.foldMapWithIndex(S.Ord)(S.Monoid)((k, a) => k + a)
+        ),
+        'k1ak2b'
+      )
+      U.deepStrictEqual(
+        _.getFoldableWithIndex(S.Ord).foldMapWithIndex(S.Monoid)({ k1: 'a', k2: 'b' }, (k, a) => k + a),
+        'k1ak2b'
+      )
+
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.foldMapWithIndex(S.Monoid)((k, a) => k + a)
         ),
         'k1ak2b'
       )
+      U.deepStrictEqual(
+        // tslint:disable-next-line: deprecation
+        _.FoldableWithIndex.foldMapWithIndex(S.Monoid)({ k1: 'a', k2: 'b' }, (k, a) => k + a),
+        'k1ak2b'
+      )
     })
 
     it('reduceRightWithIndex', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.reduceRightWithIndex(S.Ord)('', (k, a, b) => b + k + a)
+        ),
+        'k2bk1a'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.reduceRightWithIndex('', (k, a, b) => b + k + a)
         ),
         'k2bk1a'
@@ -180,26 +248,48 @@ describe('ReadonlyRecord', () => {
         O.some({ a: 1, b: 2 })
       )
       U.deepStrictEqual(_.traverse(O.Applicative)((n: number) => (n >= 2 ? O.some(n) : O.none))({ a: 1, b: 2 }), O.none)
+
+      U.deepStrictEqual(
+        _.getTraversable(S.Ord).traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n <= 2 ? O.some(n) : O.none)),
+        O.some({ a: 1, b: 2 })
+      )
+      U.deepStrictEqual(
+        _.getTraversable(S.Ord).traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n >= 2 ? O.some(n) : O.none)),
+        O.none
+      )
     })
 
     it('sequence', () => {
       const sequence = _.sequence(O.Applicative)
       U.deepStrictEqual(sequence({ a: O.some(1), b: O.some(2) }), O.some({ a: 1, b: 2 }))
       U.deepStrictEqual(sequence({ a: O.none, b: O.some(2) }), O.none)
+
+      U.deepStrictEqual(
+        // tslint:disable-next-line: deprecation
+        _.readonlyRecord.sequence(O.Applicative)({ a: O.some(1), b: O.some(2) }),
+        O.some({ a: 1, b: 2 })
+      )
     })
 
     it('traverseWithIndex', () => {
-      const traverseWithIndex = _.traverseWithIndex(O.Applicative)(
-        (k, n: number): O.Option<number> => (k !== 'a' ? O.some(n) : O.none)
-      )
+      const f = (k: string, n: number): O.Option<number> => (k !== 'a' ? O.some(n) : O.none)
+      const traverseWithIndex = _.traverseWithIndex(O.Applicative)(f)
       U.deepStrictEqual(pipe({ a: 1, b: 2 }, traverseWithIndex), O.none)
       U.deepStrictEqual(pipe({ b: 2 }, traverseWithIndex), O.some({ b: 2 }))
+
+      U.deepStrictEqual(
+        _.getTraversableWithIndex(S.Ord).traverseWithIndex(O.Applicative)({ b: 2 }, f),
+        O.some({ b: 2 })
+      )
     })
 
     it('wither', async () => {
-      const wither = _.wither(T.ApplicativePar)((n: number) => T.of(p(n) ? O.some(n + 1) : O.none))
+      const f = (n: number) => T.of(p(n) ? O.some(n + 1) : O.none)
+      const wither = _.wither(T.ApplicativePar)(f)
       U.deepStrictEqual(await pipe({}, wither)(), {})
       U.deepStrictEqual(await pipe({ a: 1, b: 3 }, wither)(), { b: 4 })
+
+      U.deepStrictEqual(await _.getWitherable(S.Ord).wither(T.ApplicativePar)({ a: 1, b: 3 }, f)(), { b: 4 })
     })
 
     it('wilt', async () => {
@@ -386,10 +476,16 @@ describe('ReadonlyRecord', () => {
   })
 
   it('getShow', () => {
-    const Sh = _.getShow(S.Show)
+    const Sh = _.getShow(S.Ord)(S.Show)
     U.deepStrictEqual(Sh.show({}), `{}`)
     U.deepStrictEqual(Sh.show({ a: 'a' }), `{ "a": "a" }`)
     U.deepStrictEqual(Sh.show({ a: 'a', b: 'b' }), `{ "a": "a", "b": "b" }`)
+
+    // tslint:disable-next-line: deprecation
+    const DepSh = _.getShow(S.Show)
+    U.deepStrictEqual(DepSh.show({}), `{}`)
+    U.deepStrictEqual(DepSh.show({ a: 'a' }), `{ "a": "a" }`)
+    U.deepStrictEqual(DepSh.show({ a: 'a', b: 'b' }), `{ "a": "a", "b": "b" }`)
   })
 
   it('singleton', () => {
@@ -454,6 +550,74 @@ describe('ReadonlyRecord', () => {
     assert.notStrictEqual(bs, as)
   })
 
+  it('getUnionMonoid', () => {
+    const M = _.getUnionMonoid(S.Semigroup)
+    const x: _.ReadonlyRecord<string, string> = {
+      a: 'a1',
+      b: 'b1',
+      c: 'c1'
+    }
+    const y: _.ReadonlyRecord<string, string> = {
+      b: 'b2',
+      c: 'c2',
+      d: 'd2'
+    }
+    U.strictEqual(M.concat(x, M.empty), x)
+    U.strictEqual(M.concat(M.empty, x), x)
+    U.strictEqual(M.concat(x, {}), x)
+    U.strictEqual(M.concat({}, x), x)
+    U.deepStrictEqual(M.concat(x, y), {
+      a: 'a1',
+      b: 'b1b2',
+      c: 'c1c2',
+      d: 'd2'
+    })
+  })
+
+  it('getIntersectionSemigroup', () => {
+    const M = _.getIntersectionSemigroup(S.Semigroup)
+    const x: _.ReadonlyRecord<string, string> = {
+      a: 'a1',
+      b: 'b1',
+      c: 'c1'
+    }
+    const y: _.ReadonlyRecord<string, string> = {
+      b: 'b2',
+      c: 'c2',
+      d: 'd2'
+    }
+    U.strictEqual(M.concat(x, _.empty), _.empty)
+    U.strictEqual(M.concat(x, _.empty), _.empty)
+    U.strictEqual(M.concat(x, {}), _.empty)
+    U.strictEqual(M.concat(x, {}), _.empty)
+    U.deepStrictEqual(M.concat(x, y), {
+      b: 'b1b2',
+      c: 'c1c2'
+    })
+  })
+
+  it('getDifferenceMagma', () => {
+    const M = _.getDifferenceMagma<string>()
+    const x: _.ReadonlyRecord<string, string> = {
+      a: 'a1',
+      b: 'b1',
+      c: 'c1'
+    }
+    const y: _.ReadonlyRecord<string, string> = {
+      b: 'b2',
+      c: 'c2',
+      d: 'd2'
+    }
+    U.strictEqual(M.concat(_.empty, x), x)
+    U.strictEqual(M.concat(x, _.empty), x)
+    U.strictEqual(M.concat({}, x), x)
+    U.strictEqual(M.concat(x, {}), x)
+    U.deepStrictEqual(M.concat(x, y), {
+      a: 'a1',
+      d: 'd2'
+    })
+  })
+
   it('mapWithIndex', () => {
     // should ignore non own properties
     const o: _.ReadonlyRecord<string, number> = Object.create({ a: 1 })
diff --git a/test/Record.ts b/test/Record.ts
index 6e9da06d..bc5fdfbb 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -18,6 +18,19 @@ const noPrototype = Object.create(null)
 
 describe('Record', () => {
   describe('pipeables', () => {
+    it('collect', () => {
+      const x: { readonly a: string; readonly b: boolean } = { a: 'c', b: false }
+      U.deepStrictEqual(_.collect(S.Ord)((key, val) => ({ key: key, value: val }))(x), [
+        { key: 'a', value: 'c' },
+        { key: 'b', value: false }
+      ])
+      // tslint:disable-next-line: deprecation
+      U.deepStrictEqual(_.collect((key, val) => ({ key: key, value: val }))(x), [
+        { key: 'a', value: 'c' },
+        { key: 'b', value: false }
+      ])
+    })
+
     it('map', () => {
       U.deepStrictEqual(pipe({ k1: 1, k2: 2 }, _.map(U.double)), { k1: 2, k2: 4 })
       U.deepStrictEqual(pipe({ a: 1, b: 2 }, _.map(U.double)), { a: 2, b: 4 })
@@ -32,6 +45,22 @@ describe('Record', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.reduce(S.Ord)('', (b, a) => b + a)
+        ),
+        'ab'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k2: 'b', k1: 'a' },
+          _.reduce(S.Ord)('', (b, a) => b + a)
+        ),
+        'ab'
+      )
+
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.reduce('', (b, a) => b + a)
         ),
         'ab'
@@ -39,6 +68,7 @@ describe('Record', () => {
       U.deepStrictEqual(
         pipe(
           { k2: 'b', k1: 'a' },
+          // tslint:disable-next-line: deprecation
           _.reduce('', (b, a) => b + a)
         ),
         'ab'
@@ -46,11 +76,20 @@ describe('Record', () => {
     })
 
     it('foldMap', () => {
+      U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.foldMap(S.Ord)(S.Monoid)(identity)), 'ab')
+      U.deepStrictEqual(_.getFoldable(S.Ord).foldMap(S.Monoid)({ a: 'a', b: 'b' }, identity), 'ab')
+
+      // tslint:disable-next-line: deprecation
       U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.foldMap(S.Monoid)(identity)), 'ab')
+      // tslint:disable-next-line: deprecation
+      U.deepStrictEqual(_.Foldable.foldMap(S.Monoid)({ a: 'a', b: 'b' }, identity), 'ab')
     })
 
     it('reduceRight', () => {
       const f = (a: string, acc: string) => acc + a
+      U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.reduceRight(S.Ord)('', f)), 'ba')
+
+      // tslint:disable-next-line: deprecation
       U.deepStrictEqual(pipe({ a: 'a', b: 'b' }, _.reduceRight('', f)), 'ba')
     })
 
@@ -105,6 +144,22 @@ describe('Record', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.reduceWithIndex(S.Ord)('', (k, b, a) => b + k + a)
+        ),
+        'k1ak2b'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k2: 'b', k1: 'a' },
+          _.reduceWithIndex(S.Ord)('', (k, b, a) => b + k + a)
+        ),
+        'k1ak2b'
+      )
+
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.reduceWithIndex('', (k, b, a) => b + k + a)
         ),
         'k1ak2b'
@@ -112,6 +167,7 @@ describe('Record', () => {
       U.deepStrictEqual(
         pipe(
           { k2: 'b', k1: 'a' },
+          // tslint:disable-next-line: deprecation
           _.reduceWithIndex('', (k, b, a) => b + k + a)
         ),
         'k1ak2b'
@@ -122,16 +178,42 @@ describe('Record', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.foldMapWithIndex(S.Ord)(S.Monoid)((k, a) => k + a)
+        ),
+        'k1ak2b'
+      )
+      U.deepStrictEqual(
+        _.getFoldableWithIndex(S.Ord).foldMapWithIndex(S.Monoid)({ k1: 'a', k2: 'b' }, (k, a) => k + a),
+        'k1ak2b'
+      )
+
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.foldMapWithIndex(S.Monoid)((k, a) => k + a)
         ),
         'k1ak2b'
       )
+      U.deepStrictEqual(
+        // tslint:disable-next-line: deprecation
+        _.FoldableWithIndex.foldMapWithIndex(S.Monoid)({ k1: 'a', k2: 'b' }, (k, a) => k + a),
+        'k1ak2b'
+      )
     })
 
     it('reduceRightWithIndex', () => {
       U.deepStrictEqual(
         pipe(
           { k1: 'a', k2: 'b' },
+          _.reduceRightWithIndex(S.Ord)('', (k, a, b) => b + k + a)
+        ),
+        'k2bk1a'
+      )
+      U.deepStrictEqual(
+        pipe(
+          { k1: 'a', k2: 'b' },
+          // tslint:disable-next-line: deprecation
           _.reduceRightWithIndex('', (k, a, b) => b + k + a)
         ),
         'k2bk1a'
@@ -186,11 +268,11 @@ describe('Record', () => {
       U.deepStrictEqual(_.traverse(O.Applicative)((n: number) => (n >= 2 ? O.some(n) : O.none))({ a: 1, b: 2 }), O.none)
 
       U.deepStrictEqual(
-        _.Traversable.traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n <= 2 ? O.some(n) : O.none)),
+        _.getTraversable(S.Ord).traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n <= 2 ? O.some(n) : O.none)),
         O.some({ a: 1, b: 2 })
       )
       U.deepStrictEqual(
-        _.Traversable.traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n >= 2 ? O.some(n) : O.none)),
+        _.getTraversable(S.Ord).traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n >= 2 ? O.some(n) : O.none)),
         O.none
       )
     })
@@ -199,20 +281,33 @@ describe('Record', () => {
       const sequence = _.sequence(O.Applicative)
       U.deepStrictEqual(sequence({ a: O.some(1), b: O.some(2) }), O.some({ a: 1, b: 2 }))
       U.deepStrictEqual(sequence({ a: O.none, b: O.some(2) }), O.none)
+
+      U.deepStrictEqual(
+        // tslint:disable-next-line: deprecation
+        _.record.sequence(O.Applicative)({ a: O.some(1), b: O.some(2) }),
+        O.some({ a: 1, b: 2 })
+      )
     })
 
     it('traverseWithIndex', () => {
-      const traverseWithIndex = _.traverseWithIndex(O.Applicative)(
-        (k, n: number): O.Option<number> => (k !== 'a' ? O.some(n) : O.none)
-      )
+      const f = (k: string, n: number): O.Option<number> => (k !== 'a' ? O.some(n) : O.none)
+      const traverseWithIndex = _.traverseWithIndex(O.Applicative)(f)
       U.deepStrictEqual(pipe({ a: 1, b: 2 }, traverseWithIndex), O.none)
       U.deepStrictEqual(pipe({ b: 2 }, traverseWithIndex), O.some({ b: 2 }))
+
+      U.deepStrictEqual(
+        _.getTraversableWithIndex(S.Ord).traverseWithIndex(O.Applicative)({ b: 2 }, f),
+        O.some({ b: 2 })
+      )
     })
 
     it('wither', async () => {
-      const wither = _.wither(T.ApplicativePar)((n: number) => T.of(p(n) ? O.some(n + 1) : O.none))
+      const f = (n: number) => T.of(p(n) ? O.some(n + 1) : O.none)
+      const wither = _.wither(T.ApplicativePar)(f)
       U.deepStrictEqual(await pipe({}, wither)(), {})
       U.deepStrictEqual(await pipe({ a: 1, b: 3 }, wither)(), { b: 4 })
+
+      U.deepStrictEqual(await _.getWitherable(S.Ord).wither(T.ApplicativePar)({ a: 1, b: 3 }, f)(), { b: 4 })
     })
 
     it('wilt', async () => {
@@ -382,10 +477,16 @@ describe('Record', () => {
   })
 
   it('getShow', () => {
-    const Sh = _.getShow(S.Show)
+    const Sh = _.getShow(S.Ord)(S.Show)
     U.deepStrictEqual(Sh.show({}), `{}`)
     U.deepStrictEqual(Sh.show({ a: 'a' }), `{ "a": "a" }`)
     U.deepStrictEqual(Sh.show({ a: 'a', b: 'b' }), `{ "a": "a", "b": "b" }`)
+
+    // tslint:disable-next-line: deprecation
+    const DepSh = _.getShow(S.Show)
+    U.deepStrictEqual(DepSh.show({}), `{}`)
+    U.deepStrictEqual(DepSh.show({ a: 'a' }), `{ "a": "a" }`)
+    U.deepStrictEqual(DepSh.show({ a: 'a', b: 'b' }), `{ "a": "a", "b": "b" }`)
   })
 
   it('singleton', () => {